Skip to content

Conversation

@fly602
Copy link
Contributor

@fly602 fly602 commented Jan 26, 2026

Added Polkit authorization checks to backlight helper service and created policy files for multiple system services. Modified SetBrightness method to accept sender parameter and perform authorization before executing privileged operations. Added 10 new policy files for various DDE services including bluetooth, display, power, timedate, etc. Removed unused Apps1 service configuration.

The changes enhance system security by requiring proper authorization for sensitive operations. The backlight helper now checks if the caller has permission to adjust brightness settings through Polkit. Multiple policy files define the authorization requirements for different system services, ensuring only authorized users can perform privileged actions.

Log: Added security authorization for system service operations

Influence:

  1. Test brightness adjustment functionality with authorized and unauthorized users
  2. Verify Polkit authorization prompts appear when required
  3. Check that privileged operations fail without proper authorization
  4. Test different service operations with various user privilege levels
  5. Verify policy files are correctly installed and recognized by the system
  6. Test backward compatibility with existing applications

feat: 为系统服务添加 Polkit 授权机制

为背光助手服务添加 Polkit 授权检查,并为多个系统服务创建策略文件。修改
SetBrightness 方法以接受发送者参数,并在执行特权操作前进行授权验证。新增
10 个 DDE 服务的策略文件,包括蓝牙、显示、电源、时间日期等。移除未使用的
Apps1 服务配置。

这些更改通过要求对敏感操作进行适当授权来增强系统安全性。背光助手现在会检
查调用者是否具有通过 Polkit 调整亮度设置的权限。多个策略文件定义了不同系
统服务的授权要求,确保只有授权用户才能执行特权操作。

Log: 新增系统服务操作的安全授权机制
https://bugzilla.opensuse.org/show_bug.cgi?id=1257149
Influence:

  1. 测试授权和未授权用户的亮度调节功能
  2. 验证需要时 Polkit 授权提示是否正确显示
  3. 检查无适当授权时特权操作是否失败
  4. 测试不同用户权限级别下的各种服务操作
  5. 验证策略文件是否正确安装并被系统识别
  6. 测试与现有应用程序的向后兼容性

Summary by Sourcery

Add Polkit-based authorization for system services and backlight brightness changes to harden privileged operations.

New Features:

  • Require Polkit authorization for backlight_helper brightness adjustment requests.
  • Introduce Polkit policy definitions for multiple DDE system services, including bluetooth, display, power, timedate, and related helpers.

Enhancements:

  • Enforce centralized authorization checks in the backlight helper before performing privileged sysfs writes.

Chores:

  • Remove the unused org.deepin.dde.Apps1 system service unit.

Added Polkit authorization checks to backlight helper service
and created policy files for multiple system services. Modified
SetBrightness method to accept sender parameter and perform
authorization before executing privileged operations. Added 10 new
policy files for various DDE services including bluetooth, display,
power, timedate, etc. Removed unused Apps1 service configuration.

The changes enhance system security by requiring proper authorization
for sensitive operations. The backlight helper now checks if the caller
has permission to adjust brightness settings through Polkit. Multiple
policy files define the authorization requirements for different system
services, ensuring only authorized users can perform privileged actions.

Log: Added security authorization for system service operations

Influence:
1. Test brightness adjustment functionality with authorized and
unauthorized users
2. Verify Polkit authorization prompts appear when required
3. Check that privileged operations fail without proper authorization
4. Test different service operations with various user privilege levels
5. Verify policy files are correctly installed and recognized by the
system
6. Test backward compatibility with existing applications

feat: 为系统服务添加 Polkit 授权机制

为背光助手服务添加 Polkit 授权检查,并为多个系统服务创建策略文件。修改
SetBrightness 方法以接受发送者参数,并在执行特权操作前进行授权验证。新增
10 个 DDE 服务的策略文件,包括蓝牙、显示、电源、时间日期等。移除未使用的
Apps1 服务配置。

这些更改通过要求对敏感操作进行适当授权来增强系统安全性。背光助手现在会检
查调用者是否具有通过 Polkit 调整亮度设置的权限。多个策略文件定义了不同系
统服务的授权要求,确保只有授权用户才能执行特权操作。

Log: 新增系统服务操作的安全授权机制

Influence:
1. 测试授权和未授权用户的亮度调节功能
2. 验证需要时 Polkit 授权提示是否正确显示
3. 检查无适当授权时特权操作是否失败
4. 测试不同用户权限级别下的各种服务操作
5. 验证策略文件是否正确安装并被系统识别
6. 测试与现有应用程序的向后兼容性
@deepin-ci-robot
Copy link

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: fly602

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@sourcery-ai
Copy link

sourcery-ai bot commented Jan 26, 2026

Reviewer's Guide

Adds Polkit-based authorization checks to the backlight helper service and introduces dedicated Polkit policy files for multiple DDE system services while removing an unused system service configuration.

Sequence diagram for Polkit-guarded SetBrightness call

sequenceDiagram
    actor UserApp
    participant SystemBus
    participant BacklightHelper
    participant PolkitAuthority
    participant SysFsBacklight

    UserApp->>SystemBus: Call SetBrightness(sender, type0, name, value)
    SystemBus->>BacklightHelper: SetBrightness(sender, type0, name, value)
    BacklightHelper->>BacklightHelper: DelayAutoQuit()

    BacklightHelper->>BacklightHelper: checkAuthorization(actionId, sender)
    BacklightHelper->>SystemBus: Connect SystemBus()
    SystemBus-->>BacklightHelper: SystemBus connection
    BacklightHelper->>PolkitAuthority: CheckAuthorization(subject SystemBusName, actionId, flags AllowUserInteraction)
    PolkitAuthority-->>BacklightHelper: AuthorizationResult(IsAuthorized)

    alt Authorized
        BacklightHelper->>BacklightHelper: getBrightnessFilename(type0, name)
        BacklightHelper->>SysFsBacklight: Write brightness value
        SysFsBacklight-->>BacklightHelper: Write result
        BacklightHelper-->>SystemBus: Return success
        SystemBus-->>UserApp: Success
    else Not authorized
        BacklightHelper-->>SystemBus: Return dbus.Error(not authorized)
        SystemBus-->>UserApp: Error not authorized
    end
Loading

Class diagram for Manager and Polkit authorization helper

classDiagram
    class Manager {
        +dbusutilService service
        +GetInterfaceName() string
        +SetBrightness(sender dbus.Sender, type0 byte, name string, value int32) *dbus.Error
        -getBacklightGs(name string) bool
    }

    class AuthHelper {
        <<utility>>
        +checkAuthorization(actionId string, sysBusName string) error
    }

    class PolkitAuthority {
        +CheckAuthorization(cookie uint32, subject Subject, actionId string, details map, flags uint32, cancellationId string) AuthorizationResult
    }

    class Subject {
        +SetDetail(key string, value string)
    }

    class AuthorizationResult {
        +IsAuthorized bool
    }

    Manager ..> AuthHelper : uses
    AuthHelper ..> PolkitAuthority : creates and calls
    AuthHelper ..> Subject : configures
    PolkitAuthority ..> AuthorizationResult : returns
Loading

File-Level Changes

Change Details Files
Gate backlight brightness changes behind Polkit authorization in the helper service.
  • Extend SetBrightness D-Bus method signature to accept the caller's dbus.Sender so the service can identify the caller
  • Invoke a new checkAuthorization helper at the start of SetBrightness to validate the caller against a Polkit action ID before performing file writes
  • Log failed authorization attempts and convert them to D-Bus errors using dbusutil.ToError
  • Implement checkAuthorization to talk to org.freedesktop.PolicyKit1 on the system bus, construct a SystemBusName subject, and call CheckAuthorization with AllowUserInteraction flags
bin/backlight_helper/main.go
Define Polkit policies for DDE services and clean up an unused systemd service unit.
  • Add org.deepin.dde.backlight-helper.policy defining the action used by the backlight helper authorization check
  • Introduce additional .policy files (bluetooth, display, gesture, greeter, imageeffect, lockservice, power, swapschedhelper, timedate, uadp) describing authorization rules for corresponding DDE system services
  • Remove the obsolete org.deepin.dde.Apps1.service system service unit and retain org.deepin.dde.Accounts1.service configuration
misc/polkit-action/org.deepin.dde.backlight-helper.policy
misc/polkit-action/org.deepin.dde.bluetooth.policy
misc/polkit-action/org.deepin.dde.display.policy
misc/polkit-action/org.deepin.dde.gesture.policy
misc/polkit-action/org.deepin.dde.greeter.policy
misc/polkit-action/org.deepin.dde.imageeffect.policy
misc/polkit-action/org.deepin.dde.lockservice.policy
misc/polkit-action/org.deepin.dde.power.policy
misc/polkit-action/org.deepin.dde.swapschedhelper.policy
misc/polkit-action/org.deepin.dde.timedate.policy
misc/polkit-action/org.deepin.dde.uadp.policy
misc/system-services/org.deepin.dde.Apps1.service
misc/system-services/org.deepin.dde.Accounts1.service

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • The new SetBrightness signature now requires a dbus.Sender; please ensure all D-Bus registrations and callers are updated consistently so the method remains callable and introspection stays in sync with the implementation.
  • checkAuthorization creates a new SystemBus connection on each call; consider reusing the existing service connection or caching the bus/authority to avoid repeated connection setup on every brightness change.
  • The Polkit action ID string used in SetBrightness is hard-coded; extracting it into a named constant (shared with the corresponding .policy file if possible) would reduce the risk of mismatches and make future changes safer.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The new SetBrightness signature now requires a dbus.Sender; please ensure all D-Bus registrations and callers are updated consistently so the method remains callable and introspection stays in sync with the implementation.
- checkAuthorization creates a new SystemBus connection on each call; consider reusing the existing service connection or caching the bus/authority to avoid repeated connection setup on every brightness change.
- The Polkit action ID string used in SetBrightness is hard-coded; extracting it into a named constant (shared with the corresponding .policy file if possible) would reduce the risk of mismatches and make future changes safer.

## Individual Comments

### Comment 1
<location> `bin/backlight_helper/main.go:105-110` </location>
<code_context>
 	return filepath.Join("/sys/class", subsystem, name, "brightness"), nil
 }

+func checkAuthorization(actionId string, sysBusName string) error {
+	systemBus, err := dbus.SystemBus()
+	if err != nil {
+		return err
+	}
+	authority := polkit.NewAuthority(systemBus)
+	subject := polkit.MakeSubject(polkit.SubjectKindSystemBusName)
+	subject.SetDetail("name", sysBusName)
</code_context>

<issue_to_address>
**suggestion (performance):** Reuse the existing D-Bus connection (or cache the Authority) instead of creating a new system bus and Authority on each call.

Each `SetBrightness` call now creates a new `dbus.SystemBus()` connection and `polkit.Authority`, which is relatively expensive and can stress the bus under frequent brightness updates. Since this helper already runs on the system bus, consider reusing `m.service.Conn()` (or passing the system bus into `checkAuthorization`) and using a singleton or cached `Authority` instance to keep the Polkit check cheap and avoid potential connection leaks.

Suggested implementation:

```golang
func checkAuthorization(actionId string, sysBusName string, authority *polkit.Authority) error {
	if authority == nil {
		return errors.New("polkit authority is not initialized")
	}

	subject := polkit.MakeSubject(polkit.SubjectKindSystemBusName)
	subject.SetDetail("name", sysBusName)

	ret, err := authority.CheckAuthorization(
		0,
		subject,
		actionId,
		nil,
		polkit.CheckAuthorizationFlagsAllowUserInteraction,
		"",
	)
	if err != nil {
		return err
	}
	if !ret.IsAuthorized {
		return errors.New("not authorized")
	}
	return nil
}

```

To fully implement the optimization and reuse the existing D-Bus connection, you should also:

1. **Cache a single `*polkit.Authority` instance**, initialized from the existing system bus connection, likely on your main helper/service struct:
   - Add a field, e.g.:
     ```go
     type Manager struct {
         // existing fields...
         polkitAuthority *polkit.Authority
     }
     ```
   - Initialize it once where you construct `Manager`, using the existing D-Bus connection:
     ```go
     m.polkitAuthority = polkit.NewAuthority(m.service.Conn())
     if m.polkitAuthority == nil {
         // handle error as appropriate (NewAuthority may return nil + error in your version)
     }
     ```

2. **Update all callers of `checkAuthorization`** to pass the cached authority instead of relying on the internal `dbus.SystemBus()` call. For example, change:
   ```go
   if err := checkAuthorization(actionId, sender); err != nil {
       // ...
   }
   ```
   to:
   ```go
   if err := checkAuthorization(actionId, sender, m.polkitAuthority); err != nil {
       // ...
   }
   ```

3. **Ensure imports are correct**:
   - `polkit` is already imported; no new imports are required for the change above.
   - If your `polkit.NewAuthority` returns `(*polkit.Authority, error)` in this codebase instead of just `*polkit.Authority`, adjust the initialization accordingly and handle the error.

These additional changes will ensure that `SetBrightness` and any other authorization-using operations reuse the same system bus connection and `polkit.Authority`, avoiding per-call overhead and potential connection leaks.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +105 to +110
func checkAuthorization(actionId string, sysBusName string) error {
systemBus, err := dbus.SystemBus()
if err != nil {
return err
}
authority := polkit.NewAuthority(systemBus)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (performance): Reuse the existing D-Bus connection (or cache the Authority) instead of creating a new system bus and Authority on each call.

Each SetBrightness call now creates a new dbus.SystemBus() connection and polkit.Authority, which is relatively expensive and can stress the bus under frequent brightness updates. Since this helper already runs on the system bus, consider reusing m.service.Conn() (or passing the system bus into checkAuthorization) and using a singleton or cached Authority instance to keep the Polkit check cheap and avoid potential connection leaks.

Suggested implementation:

func checkAuthorization(actionId string, sysBusName string, authority *polkit.Authority) error {
	if authority == nil {
		return errors.New("polkit authority is not initialized")
	}

	subject := polkit.MakeSubject(polkit.SubjectKindSystemBusName)
	subject.SetDetail("name", sysBusName)

	ret, err := authority.CheckAuthorization(
		0,
		subject,
		actionId,
		nil,
		polkit.CheckAuthorizationFlagsAllowUserInteraction,
		"",
	)
	if err != nil {
		return err
	}
	if !ret.IsAuthorized {
		return errors.New("not authorized")
	}
	return nil
}

To fully implement the optimization and reuse the existing D-Bus connection, you should also:

  1. Cache a single *polkit.Authority instance, initialized from the existing system bus connection, likely on your main helper/service struct:

    • Add a field, e.g.:
      type Manager struct {
          // existing fields...
          polkitAuthority *polkit.Authority
      }
    • Initialize it once where you construct Manager, using the existing D-Bus connection:
      m.polkitAuthority = polkit.NewAuthority(m.service.Conn())
      if m.polkitAuthority == nil {
          // handle error as appropriate (NewAuthority may return nil + error in your version)
      }
  2. Update all callers of checkAuthorization to pass the cached authority instead of relying on the internal dbus.SystemBus() call. For example, change:

    if err := checkAuthorization(actionId, sender); err != nil {
        // ...
    }

    to:

    if err := checkAuthorization(actionId, sender, m.polkitAuthority); err != nil {
        // ...
    }
  3. Ensure imports are correct:

    • polkit is already imported; no new imports are required for the change above.
    • If your polkit.NewAuthority returns (*polkit.Authority, error) in this codebase instead of just *polkit.Authority, adjust the initialization accordingly and handle the error.

These additional changes will ensure that SetBrightness and any other authorization-using operations reuse the same system bus connection and polkit.Authority, avoiding per-call overhead and potential connection leaks.

@deepin-ci-robot
Copy link

deepin pr auto review

这份代码diff主要涉及对DDE(Deepin Desktop Environment)系统服务的安全增强,通过引入Polkit(PolicyKit)来控制对系统资源的访问。以下是对代码的详细审查和改进建议:

1. 语法和逻辑审查

主要修改点:

  • SetBrightness方法中增加了Polkit授权检查
  • 新增了多个Polkit策略文件
  • 修改了部分系统服务配置

潜在问题:

  1. Polkit策略文件不一致

    • org.deepin.dde.backlight-helper.policyallow_active设置为yes,而其他策略文件设置为auth_admin
    • 建议统一为auth_admin或根据实际安全需求设置更严格的策略
  2. Polkit策略描述不明确

    • 所有策略的描述都是"Check Authentication",没有说明具体操作内容
    • 建议为每个策略添加更具描述性的文本,如"Change screen brightness"或"Configure system time"
  3. 系统服务配置修改

    • org.deepin.dde.Accounts1.service删除了deepin-accounts1-daemon.service引用
    • org.deepin.dde.Apps1.service被完全删除
    • 需要确认这些修改是否符合预期,可能影响相关服务功能

2. 代码质量改进

  1. 授权检查函数可以优化

    func checkAuthorization(actionId string, sysBusName string) error {
        systemBus, err := dbus.SystemBus()
        if err != nil {
            return fmt.Errorf("failed to get system bus: %w", err)
        }
        
        authority := polkit.NewAuthority(systemBus)
        subject := polkit.MakeSubject(polkit.SubjectKindSystemBusName)
        subject.SetDetail("name", sysBusName)
    
        ret, err := authority.CheckAuthorization(0, subject, actionId,
            nil, polkit.CheckAuthorizationFlagsAllowUserInteraction, "")
        if err != nil {
            return fmt.Errorf("authorization check failed: %w", err)
        }
        
        if !ret.IsAuthorized {
            return errors.New("not authorized")
        }
        
        return nil
    }
  2. SetBrightness方法改进

    func (m *Manager) SetBrightness(sender dbus.Sender, type0 byte, name string, value int32) *dbus.Error {
        m.service.DelayAutoQuit()
    
        // Validate input parameters
        if value < 0 {
            return dbusutil.ToError(errors.New("brightness value cannot be negative"))
        }
    
        // Check Polkit authorization
        if err := checkAuthorization("org.deepin.dde.backlight-helper.doAction", string(sender)); err != nil {
            logger.Warning("SetBrightness authorization failed:", err)
            return dbusutil.ToError(fmt.Errorf("authorization failed: %w", err))
        }
    
        filename, err := getBrightnessFilename(type0, name)
        if err != nil {
            return dbusutil.ToError(fmt.Errorf("failed to get brightness filename: %w", err))
        }
    
        // Rest of the implementation...
    }

3. 性能考虑

  1. 系统总线连接

    • checkAuthorization每次调用都会获取新的系统总线连接
    • 建议在Manager结构体中缓存系统总线连接
  2. 授权检查频率

    • 对于频繁调用的操作如亮度调节,可以考虑缓存授权结果
    • 但需要权衡安全性和性能

4. 安全建议

  1. Polkit策略改进

    <!-- 示例改进的backlight策略 -->
    <action id="org.deepin.dde.backlight-helper.doAction">
        <description>Change screen brightness</description>
        <message>Authentication is required to change the screen brightness</message>
        <defaults>
            <allow_any>no</allow_any>
            <allow_inactive>no</allow_inactive>
            <allow_active>auth_admin_keep</allow_active>
        </defaults>
        <!-- 添加更详细的描述 -->
        <description xml:lang="zh_CN">调整屏幕亮度</description>
        <message xml:lang="zh_CN">调整屏幕亮度需要密码认证</message>
    </action>
  2. 输入验证

    • SetBrightness中添加对value范围的验证
    • 验证type0name参数的有效性
  3. 日志记录

    • 记录授权失败事件,包括请求者和操作类型
    • 考虑添加审计日志
  4. 服务配置

    • 确认org.deepin.dde.Accounts1.service的修改不会导致功能缺失
    • 验证删除org.deepin.dde.Apps1.service的影响

5. 其他建议

  1. 错误处理

    • 使用更具体的错误类型,便于调用者区分不同错误情况
    • 考虑定义自定义错误类型
  2. 代码组织

    • 将授权检查相关代码抽取到单独的包中
    • 统一管理Polkit策略ID
  3. 测试

    • 添加单元测试验证授权逻辑
    • 测试各种授权失败场景
  4. 文档

    • 添加代码注释说明授权流程
    • 记录Polkit策略的设计决策

这些改进建议旨在提高代码的安全性、可维护性和可靠性,同时保持良好的性能。建议根据实际项目需求和优先级逐步实施这些改进。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants