Bug 2118593

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 9 Reporter: David Tardon <dtardon>
Component: systemdAssignee: systemd-maint
Status: CLOSED ERRATA QA Contact: Frantisek Sumsal <fsumsal>
Severity: unspecified Docs Contact:
Priority: unspecified    
Version: 9.0CC: dtardon, fhirtz, jamacku, systemd-maint-list, systemd-maint
Target Milestone: rcKeywords: FeatureBackport, Reproducer, TestOnly, Triaged
Target Release: ---   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: systemd-252-3.el9 Doc Type: If docs needed, set a value
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2023-05-09 08:21:58 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:
Bug Depends On: 2138081    
Bug Blocks:    

Description David Tardon 2022-08-16 08:27:54 UTC
This bug was initially created as a copy of Bug #2053273

I am copying this bug because: 
If we're doing this in RHEL-8, we need to do it in RHEL-9 as well to avoid a regression in behavior.


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 1 Frank Hirtz 2022-11-02 15:45:50 UTC
Good afternoon,

I wanted to check in on the thinking on this patch inclusion to see if we look to be possibly on track with getting it into a release? We have a client who, with this, will be able to greatly accelerate their patching cycle (removing a reboot from their process), so they're quite eager to get this. It's a fairly straightforward backport, and while the original reasoning behind the 'legacy' commands behavioral differences might have made sense, it's not clear that there's any need/benefit nowadays. Anyway, feedback or guidance welcome.

Thank you!

Frank.

Comment 5 errata-xmlrpc 2023-05-09 08:21:58 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:2531