Bug 2053273

Summary: [PATCH] backport - System V Compatbility Shutdown/Reboot Commands Should Honor Inhibitors and Send PrepareForShutdown DBus Signal When Run As Root
Product: Red Hat Enterprise Linux 8 Reporter: Frank Hirtz <fhirtz>
Component: systemdAssignee: David Tardon <dtardon>
Status: CLOSED ERRATA QA Contact: Frantisek Sumsal <fsumsal>
Severity: medium Docs Contact:
Priority: unspecified    
Version: 8.5CC: dtardon, jamacku, jwesterd, systemd-maint-list
Target Milestone: rcKeywords: Improvement, Reproducer, Triaged
Target Release: ---Flags: pm-rhel: mirror+
Hardware: All   
OS: Linux   
Whiteboard:
Fixed In Version: systemd-239-72.el8 Doc Type: If docs needed, set a value
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2023-05-16 09:07:15 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

Description Frank Hirtz 2022-02-10 20:11:15 UTC
Description of problem:

Client would like to request a backport of the upstream commit to address the issue detailed here.  

Description/details copied from:
https://github.com/systemd/systemd/issues/22058

---
System V compatibility shutdown/reboot/halt commands (ie via /usr/sbin/{shutdown,reboot}) do not exhibit the same behavior as a systemctl {reboot,halt} when run as root.

---
Most notable is that inhibitors appear to be skipped and a PrepareForShutdown DBus signal is not emitted when immediate action via /usr/sbin/{reboot,shutdown,halt,poweroff} are executed.

This behavior changes when using /usr/sbin/shutdown in a scheduled manner - i.e. /usr/sbin/shutdown -r +1 . In this case, delay inhibitors are honored and the DBus signal goes out, giving an inconsistent behavior in shutdown, reboot and poweroff operations between systemctl and the System V compatibility commands.

Example Test Case
Install required python depedencies:
~~~
apt install libdbus-1-dev libglib2.0-dev python3-gi pip
pip3 install dbus-python
Use the following sample script:

#!/usr/bin/python3

import time, os, sys
import dbus
from gi.repository import GLib
from dbus.mainloop.glib import DBusGMainLoop

def handle_shutdown(*args):
    # Note: Default maximum inhibit delay time is 5 seconds.
    # This can be raised in /etc/systemd/login.conf by
    # setting InhibitDelayMaxSec .
    print("Inhibit the shutdown for 30 seconds...")
    time.sleep(30)
    print("Letting go of inhibit lock")
    os.close(inhibitor_fd)

DBusGMainLoop(set_as_default=True)
bus = dbus.SystemBus()

login = bus.get_object("org.freedesktop.login1", "/org/freedesktop/login1")
manager = dbus.Interface(login, dbus_interface='org.freedesktop.login1.Manager')
inhibitor = manager.Inhibit("shutdown", "Shutdown Handler", "Handle events on shutdown notification", "delay")

inhibitor_fd = inhibitor.take()

bus.add_signal_receiver(handle_shutdown, dbus_interface="org.freedesktop.login1.Manager", signal_name="PrepareForShutdown")

loop = GLib.MainLoop()
loop.run()
~~~

Run the above script.

As root, issue a systemctl reboot command. The inhibitor is honored, the PrepareForShutdown signal is sent and the inhibitor actions the signal.

Repeat the test, this time issuing a /usr/sbin/reboot or /usr/sbin/halt command. The inhibitor will not be triggered and the system will immediately go down.

Again repeat the test, running /usr/sbin/shutdown -r +1 . After one minute, the inhibitor will be honored, the PrepareForShutdown signal is sent and the inhibitor actions the signal.

Expected behavior:

~~~
root@image:~# ./inhibitor.py &
[1] 64
root@image:~# systemctl reboot
Inhibit the shutdown for 30 seconds...
root@image:~# 
         Stopping Session 262 of User root...
[  OK  ] Removed slice Slice /system/getty.
[  OK  ] Removed slice Slice /system/modprobe.
[  OK  ] Stopped target Graphical Interface.
[  OK  ] Stopped target Multi-User System.
[  OK  ] Stopped target Login Prompts.
[  OK  ] Stopped target Host and Network Name Lookups.
[....]
~~~
Describe the solution you'd like:

Legacy shutdown, halt and poweroff commands should be able to take advantage of the inhibitors, as well as the PepareForShutdown signal, even when run as root - as they are for systemctl reboot/halt commands.

This looks to be due to logind_reboot() not being called in halt_main() if the reboot was executed by root.

systemd/src/systemctl/systemctl-compat-halt.c
~~~
Lines 156 to 175 in 3989bdc

         if (geteuid() != 0) { 
                 if (arg_dry_run || arg_force > 0) { 
                         (void) must_be_root(); 
                         return -EPERM; 
                 } 
  
                 /* Try logind if we are a normal user and no special mode applies. Maybe polkit allows us to 
                  * shutdown the machine. */ 
                 if (IN_SET(arg_action, ACTION_POWEROFF, ACTION_REBOOT, ACTION_KEXEC, ACTION_HALT)) { 
                         r = logind_reboot(arg_action); 
                         if (r >= 0) 
                                 return r; 
                         if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS)) 
                                 /* Requested operation is not supported on the local system or already in 
                                  * progress */ 
                                 return r; 
  
                         /* on all other errors, try low-level operation */ 
                 } 
         } 
~~~

Bypassing the check and calling logind_reboot() yields the expected behavior.


Additional info:

Patch commit:
https://github.com/systemd/systemd/commit/adefc8789b63225662e50ceaa282f9553b5c64eb

Comment 5 John Westerdale 2022-10-20 13:56:35 UTC
Is it likely that this (or similar) backport might occur for RHEL8?  Getting legacy actions (reboot/shutdown) to assume behavior of the systemd equivalents seems like a step in the right direction, that is - compliance with the new behavior.  Likely code simplification as well.

Comment 8 Plumber Bot 2023-02-16 10:40:49 UTC
fix merged to github main branch -> https://github.com/redhat-plumbers/systemd-rhel8/pull/355

Comment 15 errata-xmlrpc 2023-05-16 09:07:15 UTC
Since the problem described in this bug report should be
resolved in a recent advisory, it has been closed with a
resolution of ERRATA.

For information on the advisory (systemd bug fix and enhancement update), and where to find the updated
files, follow the link below.

If the solution does not work for you, open a new bug report.

https://access.redhat.com/errata/RHBA-2023:2985