阅读: 13

Q:

Ubuntu 26,以root身份shutdown时,提示被拒

# 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

可通过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”

最后修改日期: 2026-07-27

作者