嵌入式设备非root调用DBus Suspend方法报Permission Denied如何解决?
问题描述
我刚接触DBus,正在使用sdbus-cpp库在自研C++应用中调用org.freedesktop.login1.Manager.Suspend方法,目标是控制设备进入休眠模式。
应用以root用户运行时功能完全正常,但出于安全考虑需要以非root用户(用户名为embuser)运行。
我查阅资料后在/etc/dbus-1/system.d/目录下创建了suspend.conf配置文件,内容如下:
root@colibri:/etc/dbus-1/system.d$ cat suspend.conf <!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> <busconfig> <!-- Only root or user embuser can own the login1 service --> <policy user="embuser"> <allow own="org.freedesktop.login1"/> </policy> <policy user="root"> <allow own="org.freedesktop.login1"/> </policy> <!-- Allow anyone to invoke methods on login1 server --> <policy context="default"> <allow send_destination="org.freedesktop.login1"/> <allow receive_sender="org.freedesktop.login1"/> </policy> </busconfig>
我执行systemctl restart dbus重启DBus守护进程后,以embuser用户启动应用,程序输出如下信息后终止:
terminate called after throwing an instance of 'sdbus::Error'
what(): [org.freedesktop.DBus.Error.AccessDenied] Permission denied
Aborted
应用以root用户启动时可正常触发设备休眠,因此排除C++应用本身的问题。
请问我该如何配置才能让非root用户正常调用该DBus方法?现有配置文件是否存在遗漏?还有其他可行的解决路径吗?
我的设备运行在搭载ARM iMX7d处理器的Colibri嵌入式Linux模块上,内核和systemd版本信息如下:
$ uname -r 5.4.91-5.2.0-devel+git.c59b3c2da1e9 $ systemctl --version systemd 244 (244.5+) +PAM -AUDIT -SELINUX +IMA -APPARMOR -SMACK +SYSVINIT +UTMP -LIBCRYPTSETUP -GCRYPT -GNUTLS +ACL +XZ -LZ4 -SECCOMP +BLKID -ELFUTILS +KMOD -IDN2 -IDN -PCRE2 default-hierarchy=hybrid
解决方案
问题根因
现有配置存在两个核心问题:
- 多余的服务所有权配置:
<allow own="org.freedesktop.login1"/>是允许用户注册该DBus服务的权限,但org.freedesktop.login1本身由systemd-logind服务以root身份持有,你的应用仅作为调用方不需要该权限,属于无效配置。 - 遗漏PolicyKit校验:systemd-logind默认会通过Polkit做二次权限校验,即使DBus层面放行了调用请求,普通用户默认也没有休眠操作的Polkit权限,这是触发
AccessDenied报错的核心原因。
解决方法
方案1:配置Polkit规则(推荐,安全性最高)
该方案仅开放embuser用户的休眠权限,不影响其他用户和服务的权限配置:
- 在
/etc/polkit-1/rules.d/目录下创建规则文件50-allow-embuser-suspend.rules,内容如下:
polkit.addRule(function(action, subject) { if (action.id == "org.freedesktop.login1.suspend" && subject.user == "embuser") { return polkit.Result.YES; } });
- 设置规则文件权限:
chmod 644 /etc/polkit-1/rules.d/50-allow-embuser-suspend.rules - 重启Polkit服务生效:
systemctl restart polkit
方案2:调整DBus配置(适配无Polkit的精简嵌入式环境)
如果你的嵌入式系统裁剪了Polkit组件,可以直接修正DBus配置实现权限开放:
- 把你原来的
suspend.conf替换为如下内容,删除多余的服务所有权配置,仅放开Suspend方法的调用权限:
<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> <busconfig> <policy user="embuser"> <allow send_destination="org.freedesktop.login1" send_interface="org.freedesktop.login1.Manager" send_member="Suspend"/> </policy> </busconfig>
- 重启DBus服务生效:
systemctl restart dbus - 确认
/etc/systemd/logind.conf中AllowSuspend=yes,如果修改了该配置需要重启systemd-logind服务:systemctl restart systemd-logind
方案3:快速适配方案
绝大多数Linux发行版默认power用户组拥有休眠、关机等电源操作权限,直接把embuser加入该组即可:usermod -aG power embuser
执行后重新登录embuser用户即可生效。
内容的提问来源于stack exchange,提问作者Rob123

