From 57cacf6603fac72003a93a8855bf72e06aeadd79 Mon Sep 17 00:00:00 2001 From: fuleyi Date: Fri, 7 Aug 2026 15:10:51 +0800 Subject: [PATCH] feat: add polkit auth to system dbus interfaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Port the v20 security hardening to v25 by adding polkit authorization (sender first param + checkAuthorization/checkAuth + .policy action with allow_active:yes/allow_inactive:no/ allow_any:no) to the system-level D-Bus methods that previously lacked authentication, mirroring the existing system/airplane_mode1. 2. system/power1 (org.deepin.dde.Power1): SetShortIdleState and SetTlpMode gain a sender + checkAuthorization guard; add org.deepin.dde.power.set-short-idle-state and set-tlp-mode actions to misc/polkit-action/org.deepin.dde.power.policy. 3. system/inputdevices1 (org.deepin.dde.InputDevices1.Touchpad): SetTouchpadEnable gains sender + checkAuthorization (helper added to inputdevices_ifc.go); add a new misc/polkit-action/org.deepin.dde.inputdevices.policy with the set-touchpad-enable action. 4. bin/dde-system-daemon (org.deepin.dde.Daemon1): SetIdleState and SetScreenState gain sender + the existing checkAuth helper; add org.deepin.dde.daemon.set-idle-state and set-screen-state actions to org.deepin.dde.daemon.system.policy.in (regenerated by the build via ts_to_policy). 5. Add misc/polkit-rules/org.deepin.dde.power.rules and org.deepin.dde.inputdevices.rules to allowlist root internal callers (subject.user === "root"), because root has no active local session and the new .policy defaults would otherwise silently deny dde-system-daemon->Power1.SetShortIdleState and keyevent1->InputDevices1.SetTouchpadEnable, breaking short-idle power management and the keyboard touchpad toggle. 6. system/airplane_mode1 is already compliant, no change. Adding sender does not change the on-wire signature (dbusutil-gen and the runtime dispatcher skip dbus.Sender), so exported_methods_auto.go and the go-dbus-factory bindings are unchanged; active local user callers stay covered by allow_active:yes with no new dialog. Log: Harden previously unauthenticated system-level D-Bus interfaces with polkit authorization. Influence: 1. Verify short-idle power management (wifi on/off, power mode switching) still works from the session UI with no polkit dialog. 2. Verify the keyboard touchpad on/off shortcut still toggles the touchpad enable state. 3. Verify setting TLP/power-save mode from the UI works with no polkit prompt. 4. Confirm root internal callers (dde-system-daemon -> SetShortIdleState, keyevent1 -> SetTouchpadEnable) are allowed by the new .rules and not silently denied. 5. Confirm a non-session external caller is now denied by polkit on SetShortIdleState, SetTlpMode, SetTouchpadEnable, SetIdleState and SetScreenState. feat: 加固未鉴权的 system 级 dbus 接口 1. 将 v20 安全整改合入 v25:为原先未鉴权的 system 级 D-Bus 方法补齐 polkit 鉴权(sender 首参 + checkAuthorization/checkAuth + .policy 动作,allow_active:yes/allow_inactive:no/allow_any:no),参照仓内 system/airplane_mode1 既有做法。 2. system/power1(org.deepin.dde.Power1):SetShortIdleState、 SetTlpMode 增加 sender + checkAuthorization;在 misc/polkit-action/org.deepin.dde.power.policy 新增 org.deepin.dde.power.set-short-idle-state 与 set-tlp-mode 动作。 3. system/inputdevices1(org.deepin.dde.InputDevices1.Touchpad): SetTouchpadEnable 增加 sender + checkAuthorization(helper 加到 inputdevices_ifc.go);新增 misc/polkit-action/org.deepin.dde.inputdevices.policy,含 set-touchpad-enable 动作。 4. bin/dde-system-daemon(org.deepin.dde.Daemon1):SetIdleState、 SetScreenState 增加 sender 并复用本仓既有 checkAuth;在 org.deepin.dde.daemon.system.policy.in 新增 org.deepin.dde.daemon.set-idle-state 与 set-screen-state 动作 (构建期 ts_to_policy 重新生成 .policy)。 5. 新增 misc/polkit-rules/org.deepin.dde.power.rules 与 org.deepin.dde.inputdevices.rules,对 root 内部调用方 (subject.user === "root")放行,避免 root 无活跃本地会话时被新 .policy 默认值静默拒绝,导致短 idle 电源管理 (dde-system-daemon->Power1.SetShortIdleState)与键盘触摸板开关 (keyevent1->InputDevices1.SetTouchpadEnable)失效。 6. system/airplane_mode1 已合规,无改动。新增 sender 不改变线上签名 (dbusutil-gen 与运行时派发均跳过 dbus.Sender),故 exported_methods_auto.go 与 go-dbus-factory 绑定不变;活跃本地 用户调用方仍由 allow_active:yes 静默放行,不新增用户侧鉴权弹窗。 Log: 加固原先未鉴权的 system 级 D-Bus 接口,补齐 polkit 鉴权。 Influence: 1. 验证从会话 UI 触发的短 idle 电源管理(wifi 开关、电源模式切换)仍正常,无 polkit 弹窗。 2. 验证键盘触摸板开/关快捷键仍能切换触摸板使能状态。 3. 验证从 UI 设置 TLP/节能模式不弹 polkit 提示。 4. 确认 root 内部调用方(dde-system-daemon->SetShortIdleState、 keyevent1->SetTouchpadEnable)被新 .rules 放行,不被静默拒绝。 5. 确认非会话的外部调用方在 SetShortIdleState、SetTlpMode、 SetTouchpadEnable、SetIdleState、SetScreenState 上被 polkit 拒绝。 PMS: TASK-393313 --- bin/dde-system-daemon/power.go | 16 ++++++- .../org.deepin.dde.daemon.system.policy.in | 18 ++++++++ .../org.deepin.dde.inputdevices.policy | 19 ++++++++ .../polkit-action/org.deepin.dde.power.policy | 18 ++++++++ .../org.deepin.dde.inputdevices.rules | 12 ++++++ misc/polkit-rules/org.deepin.dde.power.rules | 11 +++++ system/inputdevices1/daemon.go | 5 ++- system/inputdevices1/inputdevices_ifc.go | 29 ++++++++++++- system/inputdevices1/touchpad.go | 9 +++- system/power1/manager_ifc.go | 43 ++++++++++++++++++- 10 files changed, 172 insertions(+), 8 deletions(-) create mode 100644 misc/polkit-action/org.deepin.dde.inputdevices.policy create mode 100644 misc/polkit-rules/org.deepin.dde.inputdevices.rules create mode 100644 misc/polkit-rules/org.deepin.dde.power.rules diff --git a/bin/dde-system-daemon/power.go b/bin/dde-system-daemon/power.go index 528697af6..47d940218 100644 --- a/bin/dde-system-daemon/power.go +++ b/bin/dde-system-daemon/power.go @@ -28,6 +28,10 @@ const ( dsettingsPowerName = "org.deepin.dde.daemon.power" dsettingsIdleStatePath = "idleStatePath" dsettingsIdleScreenStatePath = "idleScreenStatePath" + + // polkit action ids used by checkAuth for SetIdleState / SetScreenState + actionSetIdleState = "org.deepin.dde.daemon.set-idle-state" + actionSetScreenState = "org.deepin.dde.daemon.set-screen-state" ) func isStrInList(item string, items []string) bool { @@ -172,12 +176,20 @@ func (d *Daemon) setState(file string, state bool) error { return nil } -func (d *Daemon) SetIdleState(state bool) *dbus.Error { +func (d *Daemon) SetIdleState(sender dbus.Sender, state bool) *dbus.Error { + err := checkAuth(actionSetIdleState, string(sender)) + if err != nil { + return dbusutil.ToError(err) + } logger.Infof("SetIdleState %s try set state: %v", d.idleStatePath, state) return dbusutil.ToError(d.setState(d.idleStatePath, state)) } -func (d *Daemon) SetScreenState(state bool) *dbus.Error { +func (d *Daemon) SetScreenState(sender dbus.Sender, state bool) *dbus.Error { + err := checkAuth(actionSetScreenState, string(sender)) + if err != nil { + return dbusutil.ToError(err) + } logger.Infof("SetScreenState %s try set state: %v", d.idleScreenStatePath, state) return dbusutil.ToError(d.setState(d.idleScreenStatePath, state)) } diff --git a/misc/polkit-action/org.deepin.dde.daemon.system.policy.in b/misc/polkit-action/org.deepin.dde.daemon.system.policy.in index e12eecb97..bda2ac11b 100644 --- a/misc/polkit-action/org.deepin.dde.daemon.system.policy.in +++ b/misc/polkit-action/org.deepin.dde.daemon.system.policy.in @@ -24,5 +24,23 @@ auth_admin + + Set short idle state + Authentication is required to set the short idle state + + no + no + yes + + + + Set screen idle state + Authentication is required to set the screen idle state + + no + no + yes + + diff --git a/misc/polkit-action/org.deepin.dde.inputdevices.policy b/misc/polkit-action/org.deepin.dde.inputdevices.policy new file mode 100644 index 000000000..e8523c759 --- /dev/null +++ b/misc/polkit-action/org.deepin.dde.inputdevices.policy @@ -0,0 +1,19 @@ + + + + LinuxDeepin + https://www.deepin.com/ + + + Enable or disable the touchpad + Authentication is required to enable or disable the touchpad + + no + no + yes + + + + diff --git a/misc/polkit-action/org.deepin.dde.power.policy b/misc/polkit-action/org.deepin.dde.power.policy index 418e0aff4..5ecaf5b12 100644 --- a/misc/polkit-action/org.deepin.dde.power.policy +++ b/misc/polkit-action/org.deepin.dde.power.policy @@ -27,4 +27,22 @@ Check Authentication Tämän toiminnon suorittaminen edellyttää todennusta + + Set short idle state + Authentication is required to set the short idle state + + no + no + yes + + + + Set TLP power mode + Authentication is required to set the TLP power mode + + no + no + yes + + diff --git a/misc/polkit-rules/org.deepin.dde.inputdevices.rules b/misc/polkit-rules/org.deepin.dde.inputdevices.rules new file mode 100644 index 000000000..a026c88b1 --- /dev/null +++ b/misc/polkit-rules/org.deepin.dde.inputdevices.rules @@ -0,0 +1,12 @@ +polkit.addRule(function(action, subject) { + // Allow root internal callers (e.g. keyevent1 running inside + // dde-system-daemon invoking org.deepin.dde.InputDevices1.Touchpad + // .SetTouchpadEnable over the system bus) to toggle the touchpad. + // Root has no active local session, so the allow_active:yes default in + // the .policy does not match and would otherwise fall back to + // allow_any:no and silently deny the call. + if (action.id === "org.deepin.dde.inputdevices.set-touchpad-enable" && + subject.user === "root") { + return polkit.Result.YES; + } +}); diff --git a/misc/polkit-rules/org.deepin.dde.power.rules b/misc/polkit-rules/org.deepin.dde.power.rules new file mode 100644 index 000000000..44e620ea6 --- /dev/null +++ b/misc/polkit-rules/org.deepin.dde.power.rules @@ -0,0 +1,11 @@ +polkit.addRule(function(action, subject) { + // Allow root internal callers (e.g. dde-system-daemon invoking + // org.deepin.dde.Power1.SetShortIdleState over the system bus) to set + // the short idle state. Root has no active local session, so the + // allow_active:yes default in the .policy does not match and would + // otherwise fall back to allow_any:no and silently deny the call. + if (action.id === "org.deepin.dde.power.set-short-idle-state" && + subject.user === "root") { + return polkit.Result.YES; + } +}); diff --git a/system/inputdevices1/daemon.go b/system/inputdevices1/daemon.go index 364e4f47f..2edb7d451 100644 --- a/system/inputdevices1/daemon.go +++ b/system/inputdevices1/daemon.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2018 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -16,6 +16,9 @@ const ( dbusServiceName = "org.deepin.dde.InputDevices1" dbusPath = "/org/deepin/dde/InputDevices1" dbusInterface = dbusServiceName + + // polkit action id used by checkAuthorization for SetTouchpadEnable + actionSetTouchpadEnable = "org.deepin.dde.inputdevices.set-touchpad-enable" ) func init() { diff --git a/system/inputdevices1/inputdevices_ifc.go b/system/inputdevices1/inputdevices_ifc.go index 2e13291fb..6d4e96372 100644 --- a/system/inputdevices1/inputdevices_ifc.go +++ b/system/inputdevices1/inputdevices_ifc.go @@ -1,11 +1,14 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2018 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later package inputdevices1 import ( + "errors" + "github.com/godbus/dbus/v5" + polkit "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.policykit1" "github.com/linuxdeepin/go-lib/dbusutil" ) @@ -13,3 +16,27 @@ func (m *InputDevices) SetWakeupDevices(sender dbus.Sender, path string, value s err := m.setWakeupDevices(path, value) return dbusutil.ToError(err) } + +// checkAuthorization verifies that the caller identified by sysBusName is +// allowed to perform the polkit action identified by actionId. It mirrors +// the pattern used by system/airplane_mode1 so that active local users are +// allowed without an authentication dialog (allow_active: yes). +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) + + 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 +} diff --git a/system/inputdevices1/touchpad.go b/system/inputdevices1/touchpad.go index 6f1a77993..5d4329522 100644 --- a/system/inputdevices1/touchpad.go +++ b/system/inputdevices1/touchpad.go @@ -79,8 +79,13 @@ func (t *Touchpad) handleDeviceChange(devices []string) { logger.Infof("touchpad devices updated: %d device(s)", len(devices)) } -func (t *Touchpad) SetTouchpadEnable(enabled bool) *dbus.Error { - err := t.setTouchpadEnable(enabled) +func (t *Touchpad) SetTouchpadEnable(sender dbus.Sender, enabled bool) *dbus.Error { + err := checkAuthorization(actionSetTouchpadEnable, string(sender)) + if err != nil { + logger.Warningf("checkAuthorization failed, err: %v, actionId=%v", err, actionSetTouchpadEnable) + return dbusutil.ToError(err) + } + err = t.setTouchpadEnable(enabled) return dbusutil.ToError(err) } diff --git a/system/power1/manager_ifc.go b/system/power1/manager_ifc.go index 4e663d136..9ff425ee7 100644 --- a/system/power1/manager_ifc.go +++ b/system/power1/manager_ifc.go @@ -9,6 +9,7 @@ import ( "fmt" dbus "github.com/godbus/dbus/v5" + polkit "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.policykit1" "github.com/linuxdeepin/go-lib/dbusutil" ) @@ -16,6 +17,10 @@ const ( dbusServiceName = "org.deepin.dde.Power1" dbusPath = "/org/deepin/dde/Power1" dbusInterface = dbusServiceName + + // polkit action ids used by checkAuthorization for the Power1 setters + actionSetTlpMode = "org.deepin.dde.power.set-tlp-mode" + actionSetShortIdleState = "org.deepin.dde.power.set-short-idle-state" ) func (*Manager) GetInterfaceName() string { @@ -106,13 +111,23 @@ func (m *Manager) SetMode(mode string) *dbus.Error { return nil } -func (m *Manager) SetTlpMode(mode string) *dbus.Error { +func (m *Manager) SetTlpMode(sender dbus.Sender, mode string) *dbus.Error { logger.Info("SetTlpMode : ", mode) + err := checkAuthorization(actionSetTlpMode, string(sender)) + if err != nil { + logger.Warningf("checkAuthorization failed, err: %v, actionId=%v", err, actionSetTlpMode) + return dbusutil.ToError(err) + } return dbusutil.ToError(m.setTlpMode(mode)) } -func (m *Manager) SetShortIdleState(state bool) *dbus.Error { +func (m *Manager) SetShortIdleState(sender dbus.Sender, state bool) *dbus.Error { logger.Info(" SetShortIdleState : ", state) + err := checkAuthorization(actionSetShortIdleState, string(sender)) + if err != nil { + logger.Warningf("checkAuthorization failed, err: %v, actionId=%v", err, actionSetShortIdleState) + return dbusutil.ToError(err) + } m.setShortIdleState(state) return nil } @@ -141,3 +156,27 @@ func (m *Manager) LockCpuFreq(governor string, lockTime int32) *dbus.Error { return nil } + +// checkAuthorization verifies that the caller identified by sysBusName is +// allowed to perform the polkit action identified by actionId. It mirrors +// the pattern used by system/airplane_mode1 so that active local users are +// allowed without an authentication dialog (allow_active: yes). +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) + + 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 +}