Skip to content

fix(auth): unify caller authentication to isTrustedSender and remove binary path identification#428

Open
Fire-dtx wants to merge 1 commit into
linuxdeepin:masterfrom
Fire-dtx:master
Open

fix(auth): unify caller authentication to isTrustedSender and remove binary path identification#428
Fire-dtx wants to merge 1 commit into
linuxdeepin:masterfrom
Fire-dtx:master

Conversation

@Fire-dtx
Copy link
Copy Markdown
Contributor

Replace binary path-based caller identification (getExecutablePathAndCmdline, mapMethodCaller, checkInvokePermission) with isTrustedSender + polkit authentication for DistUpgradePartly and PrepareDistUpgradePartly interfaces. Remove caller authentication from RemovePackage interface. Add appstore_intranet.list to trusted source list. Remove deprecated deny-exec-whitelist and install-package-support-auth config items.

Introduce manager_auth.go with allow-caller registration, lightdm trusted UID support, and persistent runtime state under /run/lastore. Export SetAllowCaller D-Bus method for deepin-security-loader integration. Add D-Bus access rules for SetAllowCaller deny and deepin-daemon group policy. Configure RuntimeDirectory with 0700 mode and preserve semantics.

@deepin-ci-robot
Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: Fire-dtx

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

Comment thread lib/systemd/system/lastore-daemon.service
Comment thread src/lastore-daemon/common.go Outdated
@Fire-dtx Fire-dtx force-pushed the master branch 5 times, most recently from cb2d794 to e4fe428 Compare May 26, 2026 07:11
…binary path identification

Replace binary path-based caller identification (getExecutablePathAndCmdline,
mapMethodCaller, checkInvokePermission, checkSenderNsMntValid) with
isTrustedSender + polkit authentication across all protected interfaces
(InstallPackage, RemovePackage, DistUpgradePartly, PrepareDistUpgradePartly,
PrepareFullScreenUpgrade, PowerOff, SetUpdateSources, UpdateMode,
CheckUpdateModeWrite). Remove hardcoded executable path constants and
whitelists (allowInstallPackageExecPaths, allowRemovePackageExecPaths).

Consolidate duplicated isTrustedSender + polkit check blocks into the
existing checkInvokePermission method, eliminating inline authentication
logic in InstallPackage, RemovePackage, DistUpgradePartly,
PrepareFullScreenUpgrade and PrepareDistUpgradePartly.

Introduce manager_auth.go with allow-caller registration, lightdm trusted
UID support, and persistent runtime state under /run/lastore. Export
SetAllowCaller D-Bus method for deepin-security-loader integration.
Add D-Bus access rules: deny SetAllowCaller/PowerOff for default policy,
allow deepin-daemon and lightdm groups. Configure RuntimeDirectoryMode
to 0700 with RuntimeDirectoryPreserve=yes. Add appstore_intranet.list
to trusted source list. Remove deprecated deny-exec-whitelist and
install-package-support-auth config items. Add isInstallLikeJobType
helper. Refactor PrepareFullScreenUpgrade to use terminate() closure
and remove dead lastore-upgrader.service fallback path.

Add unit tests for manager_auth (isTrustedSender, SetAllowCaller
persistence, runtime state load/remove, bus restart cleanup) and
isInstallLikeJobType. Fix appinfo_test to use t.TempDir() instead
of hardcoded /tmp path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@deepin-ci-robot
Copy link
Copy Markdown

deepin pr auto review

这是一次非常出色且重构力度较大的代码审查。本次提交的核心是将 lastore-daemon 的鉴权模型从**“基于可执行文件路径的白名单”迁移到了“基于 DBus UniqueName 的动态白名单 + 可信 UID + Polkit”**的组合鉴权模型。这大大提升了架构的灵活性和安全性。

以下是我对本次 diff 的详细审查意见,分为语法逻辑、代码质量、代码性能和代码安全四个方面:

一、 语法与逻辑

  1. manager_auth.go 中的锁粒度与 IPC 死锁风险

    • 问题:在 loadAllowCaller 方法中,先释放了 allowCallerStateMu,然后在 for 循环中通过 m.sysDBusDaemon.GetNameOwner 进行 DBus IPC 调用,随后又在 if !validCallers.Equal(callersToCheck) 代码块中重新获取 allowCallerStateMu。虽然释放锁进行 IPC 是避免死锁的正确做法,但在这期间如果有 SetAllowCaller 请求并发执行,可能会导致磁盘上的状态文件被并发写入,产生数据覆盖或文件损坏。
    • 建议:将最终写回磁盘的操作提取为一个独立方法,采用“比较并交换”的思想:在释放状态锁前保存旧快照,IPC 结束后重新获取锁,对比当前状态与旧快照是否一致,若不一致则说明期间有并发修改,此时应放弃写盘或合并变更,直接返回。
  2. manager_ifc.goPrepareFullScreenUpgrade 的逻辑重构

    • 问题:原代码使用 for { ... break } 模拟 do-whilegoto,重构后提取为 terminate 内部函数,逻辑更清晰。但原逻辑中,只要 for 循环内任何一步出错 break,最终都会执行 RestartUnit。而重构后的逻辑中,如果 terminate() 返回 error,会进入 RestartUnit 分支;但如果 terminate() 成功执行了 seat.Terminate(0) 并返回 nil,则外部的 errnil,不会触发 RestartUnit,这与原逻辑一致。
    • 隐患:如果 seat.Terminate(0) 成功,但随后因为某些异步原因未能成功注销图形会话,现在的逻辑无法像原来那样“兜底”重启 display-manager。建议确认 seat.Terminate 是否为同步阻塞且绝对可靠,否则建议在 terminate 成功返回前增加适当的心跳检查,或在注释中明确说明为何不再需要 fallback 逻辑。
  3. job_manager.goisInstallLikeJobType 缺少类型

    • 问题:新增了 isInstallLikeJobType 函数,其中包含了 system.InstallJobType, system.OnlyInstallJobType 等,但缺少了 system.DistUpgradeJobType(全量升级)。而在 manager_upgrade.godistUpgrade 函数里,原本是有 job.caller = caller 赋值的,现在被删除了。
    • 建议:请确认 DistUpgradeJobType 是否属于 "Install Like" 类型?如果属于,请在 switch-case 中补充。同时,确认删除 job.caller 赋值后,下游逻辑是否不再依赖 caller 字段进行差异化处理(如 inhibtor 逻辑)。

二、 代码质量

  1. manager_auth.go 中的 allowCallerStateFile 硬编码

    • 问题allowCallerStateFile 被硬编码为 /run/lastore/allow-callers.ini。而在 systemd service 文件中,配置了 RuntimeDirectory=lastoreRuntimeDirectoryPreserve=yes,这意味着运行时目录是 /run/lastore/
    • 建议:为了保持一致性和可维护性,建议通过 os.Getenv("RUNTIME_DIRECTORY") 或在代码中定义常量来动态获取路径,而不是硬编码绝对路径。这样可以防止未来修改 systemd 配置时导致代码与配置脱节。
  2. 废弃代码的清理

    • 亮点:删除了大量如 appStoreDaemonPath, mapMethodCaller, checkSenderNsMntValid 等废弃代码,代码库变得更加精简,值得肯定。
    • 建议common.go 中删除了 errors 包的导入,请确认整个项目中是否还有其他地方使用了该包(Go 1.18+ 虽然将 errorsfmt 标准库化,但确认无编译错误是必要的)。
  3. 单元测试的规范性

    • 亮点:新增了 manager_auth_test.go,使用了 testify/mock 和 testify/assert,覆盖了核心的鉴权状态流转逻辑,非常棒。
    • 建议appinfo_test.go 中将 /tmp/appinfo.json 改为 t.TempDir() 是极佳的改进,符合测试隔离原则。

三、 代码性能

  1. DBus IPC 调用开销

    • 问题:在 loadAllowCaller 中,启动时会对文件中残留的每个 UniqueName 调用一次 GetNameOwner 进行验证。如果白名单较大,这会导致启动时产生大量的 DBus 请求。
    • 建议:通常白名单数量不会太多(几个到十几个),当前实现可接受。但如果未来白名单规模增长,可以考虑监听 DBus 的 NameOwnerChanged 信号来被动维护白名单状态,而不是启动时主动轮询。
  2. 文件 I/O 频率

    • 问题:每次 addAllowCallerremoveAllowCaller 都会触发一次磁盘写文件操作(persistAllowCallerState)。
    • 建议:对于运行时状态,如果写操作频繁,可以考虑使用定时器(如每 5 秒)进行脏数据刷盘,而不是实时刷盘。但考虑到当前场景是鉴权操作,频率极低,实时刷盘保证了一致性,目前的做法是合理的。

四、 代码安全

  1. SetAllowCaller 的提权与越权风险(严重)

    • 问题:新增的 SetAllowCaller(uniqueName string) 方法允许将某个 DBus 连接加入高权限白名单。在 org.deepin.dde.Lastore1.conf 中,虽然通过 <deny> 拒绝了普通用户调用 SetAllowCaller,但允许了 group="deepin-daemon"user="root" 调用。
    • 隐患:如果属于 deepin-daemon 组的某个服务(如 dde-session-daemon)被攻破,攻击者可以通过调用 SetAllowCaller 将自己的恶意 DBus 连接名加入白名单,从而绕过 Polkit 鉴权执行系统级包安装和卸载。
    • 建议
      • addAllowCaller 内部增加调用者 UID 校验:确保只有 root 或特定的系统 UID(如 lightdm)才能调用此方法,即便同属 deepin-daemon 组的普通服务进程也不应具有授权他人的能力。
      • 考虑增加双向验证:不仅验证 uniqueName 是否真实存在,还应验证该 uniqueName 对应的 UID 是否属于受信任的范畴,防止高权限服务误将低权限恶意进程的连接拉白。
  2. RuntimeDirectoryMode 权限降级

    • 问题RuntimeDirectoryMode0750 改为 0700
    • 评价:这是一个非常好的安全加固/run/lastore/ 目录下现在存放了 allow-callers.ini,虽然文件本身不包含敏感密钥,但防止同组用户篡改该文件以注入恶意 DBus Name 是至关重要的。0700 确保只有 daemon 自身(root)可以读写该目录。
  3. Polkit 兜底鉴权

    • 问题:新逻辑中,非白名单、非受信 UID 的调用者统一走 polkit.CheckAuth
    • 评价:这是安全的兜底策略。但需确认 polkitActionChangeOwnData 这个 Action 在系统 Polkit 规则中的默认策略是什么。如果是 auth_admin,则普通用户需要输入管理员密码,这是安全的;如果是 auth_selfyes,则可能存在风险。建议在提交说明或注释中明确该 Polkit Action 的预期默认行为。

总结

本次重构方向正确,显著提升了鉴权模型的扩展性(适配 deepin-security-loader 场景),清理了大量历史技术债。最需要关注的是 SetAllowCaller 的越权风险,建议增加更严格的调用者身份校验,防止该接口成为提权跳板。此外,loadAllowCaller 中的并发状态一致性也需稍加防护。其余均为优秀或合理的改进。

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.

3 participants