标题: Ubuntu 26 root shutdown时被拒 创建: 2026-07-24 16:35 更新: 链接: https://scz.617.cn/unix/202607241635.txt https://mp.weixin.qq.com/s/h7Zr6rFi77gMC_gxsnATqA Q: Ubuntu 26,以root身份shutdown时,提示被拒 # TERM=dumb shutdown -P now Operation inhibited by "scz" (PID 3423 "gnome-session-s", user scz), reason is "user session inhibited". User scz is logged in on tty2. Please retry operation after closing inhibitors and logging out other users. 'systemd-inhibit' can be used to list active inhibitors. Alternatively, ignore inhibitors and users with 'systemctl poweroff -i'. 这是什么情况? A: 精确复现方案,在X用scz登录,开Terminal,执行 python3 此时root已无法shutdown,出现前述提示。一定在X的Terminal中执行python3进行测 试,在SSH Shell中执行python3,无此效果。 Ubuntu 26中init是到systemd的符号链接,shutdown是到systemctl的符号链接。 $ readlink -f $(which init) /usr/lib/systemd/systemd $ readlink -f $(which shutdown) /usr/bin/systemctl 这种系统"init 0"不对应关机。"shutdown -P"实际执行"systemctl poweroff"。 systemctl通过systemd、systemd-logind完成关机、重启等操作,这套机制遵循一种 名为"Inhibitor Locks"的东西,参看: https://systemd.io/INHIBITOR_LOCKS 普通进程可通过D-Bus向systemd-logind注册指定类型的inhibitor,比如说,我正在 升级,请勿关机。之后的"systemctl poweroff"会通过systemd询问systemd-logind, 发现有个shutdown inhibitor,systemd将拒绝关机。 可用如下命令查看当前注册生效中的inhibitor systemd-inhibit --list systemd-inhibit --no-pager --no-legend --list 或者更底层、更直接的命令 gdbus call \ --system \ --dest org.freedesktop.login1 \ --object-path /org/freedesktop/login1 \ --method org.freedesktop.login1.Manager.ListInhibitors 可用systemd-inhibit注册shutdown inhibitor,同时执行一个长期驻留的子进程, 在子进程存活期间,inhibitor对应的fd(文件句柄)不会自动关闭,inhibitor不会自 动注销。比如 systemd-inhibit \ --what=shutdown \ --who="any" \ --why="some" \ --mode=block \ bash bash可换成"pauseme sleep 0"之类的,只要子进程能长期驻留即可。上述操作对系 统有潜在影响,普通用户执行时要求输入root密码。 若遭遇root shutdown被拒,提示信息中已给出解决方案之一 systemctl poweroff -i "-i"是忽略inhibitor的意思。但这样过于简单粗暴,更好的解决之道是,找出那个 注册了shutdown inhibitor的进程,正常结束它,再关机。 D: D-Bus是个较大的攻击面,但我从未研究过,这次稍微多做点实验。 gdbus introspect \ --system \ --dest org.freedesktop.login1 \ --object-path /org/freedesktop/login1 上述命令向systemd-logind查询「你这个D-Bus服务提供哪些接口」,部分输出如下 -------------------------------------------------------------------------- interface org.freedesktop.login1.Manager { methods: ... ListSessions(out a(susso) sessions); ListSessionsEx(out a(sussussbto) sessions); ListUsers(out a(uso) users); ... ListInhibitors(out a(ssssuu) inhibitors); ... LockSessions(); UnlockSessions(); ... PowerOff(in b interactive); ... Reboot(in b interactive); ... -------------------------------------------------------------------------- gdbus可直接调用这些API。 gdbus call \ --system \ --dest org.freedesktop.login1 \ --object-path /org/freedesktop/login1 \ --method org.freedesktop.login1.Manager.LockSessions 在SSH Shell中以root身份执行LockSessions,将在主控台产生锁屏的效果,简单类 比成Windows cmd中执行: rundll32.exe user32.dll,LockWorkStation 针对LockSessions,可用gdbus取消锁屏: gdbus call \ --system \ --dest org.freedesktop.login1 \ --object-path /org/freedesktop/login1 \ --method org.freedesktop.login1.Manager.UnlockSessions 若在主控台交互式取消锁屏,需输入密码,gdbus取消锁屏则不需要,有趣。不过, 若主控台处于登录界面,UnlockSessions无法取消录登界面。 gdbus call \ --system \ --dest org.freedesktop.login1 \ --object-path /org/freedesktop/login1 \ --method org.freedesktop.login1.Manager.ListSessions TERM=dumb loginctl list-sessions TERM=dumb loginctl list-users 可通过D-Bus关机,以root身份执行: gdbus call \ --system \ --dest org.freedesktop.login1 \ --object-path /org/freedesktop/login1 \ --method org.freedesktop.login1.Manager.PowerOff \ true 对于root,无论PowerOff的参数是false还是true,均不会交互式授权,因为已经是 root。对于普通用户,上述命令过于底层,无法进入交互式授权环节,因为这是由其 他组件配合提供的,gdbus无此能力,只会报错: Error: GDBus.Error:org.freedesktop.DBus.Error.InteractiveAuthorizationRequired: Access denied as the requested operation requires interactive authentication. However, interactive authentication has not been enabled by the calling program. 可监控D-Bus消息,比如 dbus-monitor --system --monitor \ type=method_call,interface=org.freedesktop.login1.Manager,member=Inhibit 在X Terminal中执行python3,在dbus-monitor中将看到 method call ... path=/org/freedesktop/login1; interface=org.freedesktop.login1.Manager; member=Inhibit string "shutdown" string "scz" string "user session inhibited" string "block" 在root shell中执行 gdbus call \ --system \ --dest org.freedesktop.login1 \ --object-path /org/freedesktop/login1 \ --method org.freedesktop.login1.Manager.Inhibit \ shutdown \ any \ some \ block 在dbus-monitor中将看到 method call ... string "shutdown" string "any" string "some" string "block"