Skip to content

Fix security - #1199

Open
fly602 wants to merge 7 commits into
linuxdeepin:masterfrom
fly602:fix-security
Open

Fix security#1199
fly602 wants to merge 7 commits into
linuxdeepin:masterfrom
fly602:fix-security

Conversation

@fly602

@fly602 fly602 commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Summary by Sourcery

Integrate deepin-security-loader into system daemons and hardware-control services to enforce caller-based authorization while preserving existing Polkit fallback.

New Features:

  • Introduce a securityloader allow-caller registry with persistent state and process-ancestry validation for D-Bus callers.
  • Add security-loader handshake support to session and system daemons and langselector for secure startup under deepin-security-loader.
  • Expose SetAllowCaller D-Bus methods for Daemon1, Power1, InputDevices1, AirplaneMode1, and related components to register authorized callers dynamically.
  • Add security-loader integration in touchpad, power, airplane mode, and idle/screen state controls to gate hardware actions on registered callers with Polkit fallback when not loader-launched.

Bug Fixes:

  • Harden hardware and power control paths by rejecting unauthorized D-Bus callers rather than relying solely on global Polkit rules.

Enhancements:

  • Update D-Bus policies to restrict SetAllowCaller usage to root or the deepin-daemon group while denying it for unprivileged callers.
  • Refine RPM and build scripts to depend on deepin-security-loader, add hardware-control policy translations, and install loader wrappers for session-daemon and langselector without breaking libexec layout.
  • Add comprehensive unit tests for securityloader allow-caller registry, process group and ancestry checks, and security-loader handshake argument parsing and I/O validation.
  • Persist and restore authorized callers across daemon lifetimes with bus-ID scoping to avoid leaking authorizations across system bus restarts.

Build:

  • Extend policy translation targets to include new hardware-control polkit policy.
  • Adjust Makefile install paths to place dde-session-daemon and langselector binaries under /usr/libexec/deepin with loader wrapper scripts in the original daemon lib directory.

Tests:

  • Add tests covering allow-caller authorization logic, persistence, removal, concurrent registration, and process-ancestry validation.
  • Add tests validating security-loader handshake argument parsing, descriptor validation, and response size limits.

Chores:

  • Declare deepin-security-loader as a package dependency in RPM and wire system units to the new loader-aware binary layout.

@deepin-ci-robot

Copy link
Copy Markdown

[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 sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Sorry @fly602, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@sourcery-ai

sourcery-ai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Reviewer's Guide

Integrates deepin-security-loader into multiple daemons and hardware-control paths, introducing an allow-caller registry that enforces DBus caller authorization per scope with a Polkit fallback, wiring it through airplane mode, power, system-daemon, input devices, and langselector, plus packaging and DBus policy updates to run certain binaries via loader wrappers.

File-Level Changes

Change Details Files
Introduce securityloader allow-caller registry and handshake mechanism for security-loader integration.
  • Add AllowCallerRegistry type that persists authorized DBus unique names per scope and validates registrars based on uid, groups, and process ancestry.
  • Implement Authorize logic returning AuthOK/AuthDenied/AuthNotEnabled based on registry state and caller uid.
  • Implement Handshake helper that parses injected --fd1/--fd2 arguments, exchanges JSON over pipes with deepin-security-loader, and registers the process unique name for specified destinations.
  • Add comprehensive unit tests for allow-caller registry logic, process ancestry helpers, persistence, and handshake argument/IO validation.
securityloader/allowcaller.go
securityloader/allowcaller_test.go
securityloader/handshake.go
securityloader/handshake_test.go
Wire allow-caller authorization into airplane mode, power management, system-daemon power interface, and input devices touchpad control with Polkit fallback when not loader-started.
  • Extend Manager/Daemon/InputDevices/Touchpad structs with AllowCallerRegistry references and initialize registry from system-daemon main.
  • Add SetAllowCaller DBus methods on Daemon1, Power1, AirplaneMode1, and InputDevices1 to register allowed callers per scope via the registry.
  • Update Enable/EnableWifi/EnableBluetooth, SetIdleState/SetScreenState, SetTlpMode, and SetTouchpadEnable to first consult AllowCallerRegistry, deny on AuthDenied, and fallback to existing Polkit-based authorization when AuthNotEnabled.
  • Introduce checkDaemonAuth, checkPowerAuth, and checkTouchpadAuth helpers using Polkit Authority for fine-grained actions when loader is not in use.
system/airplane_mode1/manager.go
system/airplane_mode1/exported_methods_auto.go
bin/dde-system-daemon/power.go
system/inputdevices1/touchpad.go
system/inputdevices1/inputdevices.go
system/inputdevices1/inputdevices_ifc.go
system/inputdevices1/exported_methods_auto.go
system/power1/manager.go
system/power1/manager_ifc.go
system/power1/exported_methods_auto.go
bin/dde-system-daemon/exported_methods_auto.go
bin/dde-system-daemon/main.go
Integrate security-loader startup for session-daemon and langselector and extend langselector with per-user destination registration.
  • Modify dde-session-daemon main to perform securityloader.Handshake with a set of DDE system destinations and refuse startup on fatal handshake error when loaded by loader.
  • Add securityloader.DoSecurityLoader invocation in langselector main and provide langselector-specific Destinations including LocaleHelper1, Lastore1, and the current Accounts1.User path resolved via DBus.
  • Add langselector1/securityloader.go with helper to build loader destination list and resolve the current user’s accounts path.
  • Install loader-wrapper scripts for dde-session-daemon and langselector to run them via deepin-security-loader while keeping binaries under libexec.
bin/dde-session-daemon/main.go
bin/langselector/main.go
langselector1/securityloader.go
misc/scripts/dde-session-daemon-loader-wrapper
misc/scripts/langselector-loader-wrapper
Update DBus policy configs to restrict SetAllowCaller calls to root/deepin-daemon group and deny them for default context, ensuring only privileged components can register allowed callers.
  • Extend org.deepin.dde.AirplaneMode1.conf and org.deepin.dde.InputDevices1.conf to allow SetAllowCaller only for root and deepin-daemon group and explicitly deny it in default policy.
  • Update org.deepin.dde.Daemon1.conf and org.deepin.dde.Power1.conf to add deepin-daemon group policies allowing SetAllowCaller and deny this member for default context.
  • Ensure only the owning service and privileged group can call SetAllowCaller while all other methods remain broadly callable as before.
misc/conf/org.deepin.dde.AirplaneMode1.conf
misc/conf/org.deepin.dde.InputDevices1.conf
misc/conf/org.deepin.dde.Daemon1.conf
misc/conf/org.deepin.dde.Power1.conf
Adjust build, packaging, and systemd wiring to add hardware-control polkit policy, depend on deepin-security-loader, and route specific daemons through libexec/deepin wrappers.
  • Extend Makefile POLICIES list with hardware-control and ensure ts conversion and install steps copy dde-session-daemon and langselector into libexec/deepin with loader wrappers installed into lib/deepin-daemon.
  • Update RPM spec to require deepin-security-loader and to tweak Makefile lib vs libexec substitutions while preserving security-loader-target paths.
  • Modify dde-lockservice systemd unit ExecStart to reference both the existing libexecdir path and a deepin-specific libexec/dde path (line-wrapped).
  • Add hardware-control polkit policy template file and Debian packaging stubs/overrides for the new securities (files listed but content not shown in diff).
Makefile
rpm/dde-daemon.spec
misc/conf/org.deepin.dde.Power1.conf
misc/polkit-action/org.deepin.dde.hardware-control.policy.in
systemd/lockservice.service
debian/control
debian/dde-daemon.lintian-overrides
misc/polkit-action/org.deepin.dde.airplane.policy
misc/polkit-action/org.deepin.dde.power.policy

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

@fly602
fly602 force-pushed the fix-security branch 2 times, most recently from 0bb9d87 to e02c924 Compare August 11, 2026 09:21
fly602 added 6 commits August 11, 2026 17:35
1. 新增 securityloader 模块,实现与 deepin-security-loader 的文件描述符
通信握手机制,解析并清理注入的启动参数
2. 将 dde-session-daemon 二进制文件安装路径从 /usr/lib/deepin-daemon 迁
移至 /usr/libexec/deepin/,原路径替换为 loader-wrapper 脚本以实现安全
加载
3. 在 dde-system-daemon 和 system/power 模块中引入 AllowCallerRegistry,
新增 SetAllowCaller DBus 方法用于动态注册受信任的调用方唯一名称
4. 对 SetIdleState、SetScreenState 和 SetTlpMode 等敏感接口增加权限校
验,拦截非 root 且未在 AllowCallerRegistry 中注册的 DBus 调用
5. 实现 AllowCallerRegistry 状态的 JSON 持久化,通过比对系统总线 BusID
防止跨重启周期的无效授权,并监听 NameOwnerChanged 信号自动清理断开连接的
调用方
6. 更新 DBus 策略配置,严格限制 SetAllowCaller 方法仅允许 root 用户和
deepin-daemon 组调用,并在 default 策略中显式拒绝
7. 在 debian 和 rpm 打包规则中新增 deepin-security-loader 依赖,并添加相
关单元测试

Influence:
1. 验证 dde-session-daemon 能否通过 wrapper 脚本正常启动,并确认启动日志
中无 security-loader handshake failed 错误
2. 测试 dde-session-daemon 正常启动后

Task: https://pms.uniontech.com/task-view-393313.html
1. 在 InputDevices 和 Touchpad 模块中集成 securityloader 的 AllowCaller
机制以增强安全性
2. 为 SetTouchpadEnable 接口增加 DBus Sender 权限校验防止恶意调用
3. 新增并导出 SetAllowCaller 接口供受信任的系统服务进行调用者身份注册
4. 更新 DBus 策略配置限制仅 root 和 deepin-daemon 组可调用
SetAllowCaller 并在默认策略中拒绝其他未授权访问
5. 在 session-daemon 启动阶段注册 InputDevices 的安全作用域

Task: https://pms.uniontech.com/task-view-393313.html
1. 移除飞行模式模块中原有的基于 polkit 的同步鉴权逻辑及相关的依赖
2. 引入并集成 securityloader 的 AllowCallerRegistry 白名单鉴权机制,增加
AirplaneModeScope 常量定义
3. 导出 SetAllowCaller 接口,并在 dde-session-daemon 中添加该接口的 DBus
配置以完成权限注册
4. 修改 DBus 策略配置文件,严格限制 SetAllowCaller 方法仅允许 root 用户
和 deepin-daemon 组访问,并在默认策略中增加拒绝规则
5. 修改 Enable、EnableWifi、EnableBluetooth 三个核心方法的权限校验方式,
由原来的 polkit 交互式鉴权改为统一白名单校验,并补充鉴权失败时的日志记录

Task: https://pms.uniontech.com/task-view-393313.html
dde-session-daemon 启动时将 org.deepin.dde.Lastore1.Manager 加入
security-loader 握手目标,使当前进程的 system bus unique name 通过
lastore-daemon 的 SetAllowCaller 注册为受信任调用者。

lastore Agent 调用 RegisterAgent 和 UnRegisterAgent 时复用该 system bus
连接,从而走 allow-caller 鉴权,避免弹出 polkit 交互认证框。

Log: 为 lastore Agent 注册适配 security-loader

Influence: lastore Agent 注册、注销及更新通知功能

Task: https://pms.uniontech.com/task-view-393313.html
1. 在 securityloader.go 的 defaultDestList 中新增了 LocaleHelper 的 D-Bus
配置项
2. 包含其 DbusName、DbusPath 和 DbusInterface 的具体定义
3. 此改动是为了将 LocaleHelper 服务纳入安全握手机制的白名单中,确保系统语
言选择器能够正常与 LocaleHelper 进行安全通信,避免因权限校验导致的 D-Bus
调用失败

历史相关:迁移 v20 中 langselector securityloader 完整握手机制
(含 cfd01e630 控制中心切换语言弹鉴权窗、e29680ba3 修复切换语言不生效
两笔历史提交),D-Bus 接口名适配 v25 风格:
- com.deepin.api.LocaleHelper -> org.deepin.dde.LocaleHelper1
- com.deepin.daemon.Accounts -> org.deepin.dde.Accounts1
- com.deepin.lastore -> org.deepin.dde.Lastore1

Influence:
1. 测试系统语言或区域设置的切换功能是否正常生效
2. 验证语言选择器与LocaleHelper之间的D-Bus通信是否畅通无阻
3. 检查系统日志中是否还存在与LocaleHelper相关的D-Bus权限拒绝或安全握手失
败的报错
4. 回归测试语言选择器的其他基础功能,确保新增配置未对原有服务通信造成
干扰
Log: 切换语言仅允许dde-session-daemon调用

Task: https://pms.uniontech.com/task-view-393313.html
当服务未通过 deepin-security-loader 启动时,AllowCaller 白名单未启用,
SetTouchpadEnable、SetTlpMode、SetIdleState、SetScreenState 等接口
回退到 polkit 认证提权,保证非安全加载场景下功能可用。

新增 polkit 策略 org.deepin.dde.hardware-control:
- org.deepin.dde.inputdevices.set-touchpad: 触控板开关
- org.deepin.dde.daemon.set-idle-state: 设置空闲状态
- org.deepin.dde.daemon.set-screen-state: 设置屏幕状态

SetTlpMode 复用已有 org.deepin.dde.power.doAction 策略。

Task: https://pms.uniontech.com/task-view-393313.html
1. 为 dde-system-daemon 配置 /run/dde-daemon 运行目录及状态保留,
   使 AllowCaller 状态在 ProtectSystem=strict 下可写
2. 将 dde-session-daemon 用户服务改为 forking 模式,由 systemd
   接管 security-loader 启动的真实进程,并等待 D-Bus 名称就绪
3. wrapper 检查 loader 及 CAP_SETGID,不可用时直接启动真实进程,
   由原有 polkit 鉴权路径回退

Influence:
1. 验证 dde-system-daemon 启动及重启后 /run/dde-daemon 权限正确,
   AllowCaller 状态可写入和恢复
2. 验证 dde-session-daemon 通过 security-loader 启动后服务保持 active,
   MainPID 指向真实进程且 D-Bus 名称正常就绪
3. 验证 Daemon1、Lastore1、InputDevices1 和 AirplaneMode1 的调用方
   注册成功,日志中无 read-only file system 错误
4. 验证 loader 缺失或 CAP_SETGID 不可用时可直接启动,并使用原有
   polkit 鉴权路径
5. 验证服务停止、异常退出和自动重启时无残留进程

Task: https://pms.uniontech.com/task-view-393313.html
@deepin-ci-robot

Copy link
Copy Markdown

deepin pr auto review

★ 总体评分:35分

■ 【总体评价】

代码实现了 deepin-security-loader 鉴权机制,但存在高危权限绕过与不安全目录权限漏洞
逻辑基本正确但因安全模型存在缺陷及代码重复扣65分

■ 【详细分析】

  • 1.语法逻辑(基本正确)✓

代码结构清晰,并发控制使用了读写锁,isProcessDescendant 正确处理了进程树遍历与环检测。Authorize 方法中对 nil map 的读取在 Go 中是安全的,不会触发 panic。AddCaller 中先加锁后写入并在持久化失败时回滚的逻辑严密。
建议:langselector1/securityloader.gouser.Current() 返回值不可能为 nil,可移除冗余的 if currentUser == nil 判断。

  • 2.代码质量(一般)✕

power.gotouchpad.gomanager_ifc.go 中新增的 Polkit 回退鉴权函数 checkDaemonAuthcheckTouchpadAuthcheckPowerAuth 存在严重的代码重复,仅 actionId 不同。langselector1/securityloader.go 文件末尾缺少换行符。
潜在问题:重复代码增加维护成本,若 Polkit 调用逻辑变更需同步修改多处。
建议:提取公共函数 checkPolkitAuth(sysBusName, actionId string) (bool, error) 供各模块调用;补全文件末尾换行符。

  • 3.代码性能(无性能问题)✓

Authorize 使用 sync.RWMutex 保护读多写少的场景,开销极低。getProcessGroupsgetProcessParentPID 虽涉及 /proc 文件读取,但仅在 AddCaller 注册时触发,属于低频操作,不影响运行时性能。

  • 4.代码安全(存在 3 个安全漏洞)✕

漏洞对比统计:新增漏洞 3 个,减少漏洞 0 个,持平 0 个
引入了新的安全加载机制,但在目录权限控制、异常处理一致性及权限信任模型上存在缺陷,可能导致权限提升或防护机制被绕过。

  • 安全漏洞1(高危):[权限提升] 在 [securityloader/allowcaller.go] 的 [authorizeRegistrar] 函数中,当 senderUID == 0 时直接返回 nil 放行。该设计允许任何以 root 身份运行的进程(若被攻破)为任意非特权 D-Bus 调用者注册白名单,从而绕过后续所有 Polkit 鉴权,破坏了最小权限原则。 ——非常重要

  • 安全漏洞2(中危):[不安全权限] 在 [misc/systemd/services/system/dde-system-daemon.service] 中,新增 RuntimeDirectoryMode=0777。这导致 /run/dde-daemon 目录对所有用户可写,攻击者可在该目录下创建同名文件或目录导致 writeState 持久化失败(拒绝服务),或利用目录可写性进行其他潜在攻击。 ——非常重要

  • 安全漏洞3(中危):[防护绕过] 在 [langselector1/securityloader.go] 的 [DoSecurityLoader] 函数中,当 loaded 为 true 但 err != nil 时,仅打印 Warning 而未像 dde-session-daemon 那样调用 os.Exit(1) 终止进程。这导致进程在安全加载器握手失败的情况下继续运行,可能造成安全加载器状态不一致或失去预期保护。 ——非常重要

  • 建议:1. 在 authorizeRegistrar 中移除对 root 的无条件信任,要求 root 调用者也必须满足进程祖先校验或处于特定特权组;2. 将 RuntimeDirectoryMode 修改为 0755 或更严格的权限,并在 writeState 中使用 os.Chmod 强制修正目录权限;3. 在 langselectorDoSecurityLoader 中,当 loaded == true && err != nil 时直接 os.Exit(1)

■ 【改进建议代码示例】

// securityloader/allowcaller.go - 修复 authorizeRegistrar 中的 root 信任绕过
func (r *AllowCallerRegistry) authorizeRegistrar(sender dbus.Sender, uniqueName string) error {
	senderUID, err := r.service.GetConnUID(string(sender))
	if err != nil {
		return fmt.Errorf("get SetAllowCaller sender %s UID failed: %w", sender, err)
	}
	// 移除对 root 的无条件信任,统一执行进程祖先校验
	if r.privilegedGroupID == invalidGroupID {
		return fmt.Errorf("privileged group %s is unavailable", privilegedGroup)
	}

	groups, err := r.service.GetConnGroups(string(sender))
	if err != nil {
		return fmt.Errorf("get SetAllowCaller sender %s groups failed: %w", sender, err)
	}
	if !containsGroup(groups, r.privilegedGroupID) {
		return fmt.Errorf("D-Bus caller %s is not in privileged group %s", sender, privilegedGroup)
	}

	targetUID, err := r.service.GetConnUID(uniqueName)
	if err != nil {
		return fmt.Errorf("get target caller %s UID failed: %w", uniqueName, err)
	}
	if targetUID != senderUID {
		return fmt.Errorf("SetAllowCaller sender UID %d does not own target %s with UID %d", senderUID, uniqueName, targetUID)
	}

	senderPID, err := r.service.GetConnPID(string(sender))
	if err != nil {
		return fmt.Errorf("get SetAllowCaller sender %s PID failed: %w", sender, err)
	}
	targetPID, err := r.service.GetConnPID(uniqueName)
	if err != nil {
		return fmt.Errorf("get target caller %s PID failed: %w", uniqueName, err)
	}
	if r.processParent == nil {
		return errors.New("process ancestry resolver is unavailable")
	}
	isDescendant, err := isProcessDescendant(targetPID, senderPID, r.processParent)
	if err != nil {
		return fmt.Errorf("verify target caller %s process ancestry failed: %w", uniqueName, err)
	}
	if !isDescendant {
		return fmt.Errorf(
			"target caller %s PID %d is not a descendant of SetAllowCaller sender %s PID %d",
			uniqueName, targetPID, sender, senderPID,
		)
	}
	return nil
}

@deepin-ci-robot

Copy link
Copy Markdown

@fly602: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
github-pr-review-ci 6385415 link true /test github-pr-review-ci

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here.

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