]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: Check if any init exists before switching root
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Mon, 8 May 2023 11:48:25 +0000 (13:48 +0200)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Fri, 12 May 2023 05:48:50 +0000 (07:48 +0200)
If we switch root and can't execute an init program afterwards, we're
completely stuck as we can't go back to the initramfs to start
emergency.service as it will have been completely removed by the switch
root operation.

To prevent leaving users with a completely undebuggable system, let's
at least check before we switch root whether at least one of the init
programs we might want to execute actually exist, and fail early if
none of them exists.

src/core/main.c

index e86e0d941ec82048fb3f36853c79471426fc883c..5347372c817a298d4f038138053b455b6afc1cef 100644 (file)
@@ -31,6 +31,7 @@
 #include "bus-util.h"
 #include "capability-util.h"
 #include "cgroup-util.h"
+#include "chase.h"
 #include "clock-util.h"
 #include "conf-parser.h"
 #include "cpu-set-util.h"
@@ -1774,6 +1775,24 @@ static int do_reexecute(
         assert(saved_rlimit_memlock);
         assert(ret_error_message);
 
+        if (switch_root_init) {
+                r = chase(switch_root_init, switch_root_dir, CHASE_PREFIX_ROOT, NULL, NULL);
+                if (r < 0)
+                        log_warning_errno(r, "Failed to chase configured init %s/%s: %m",
+                                          strempty(switch_root_dir), switch_root_init);
+        } else {
+                r = chase(SYSTEMD_BINARY_PATH, switch_root_dir, CHASE_PREFIX_ROOT, NULL, NULL);
+                if (r < 0)
+                        log_debug_errno(r, "Failed to chase our own binary %s/%s: %m",
+                                        strempty(switch_root_dir), SYSTEMD_BINARY_PATH);
+        }
+
+        if (r < 0) {
+                r = chase("/sbin/init", switch_root_dir, CHASE_PREFIX_ROOT, NULL, NULL);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to chase %s/sbin/init", strempty(switch_root_dir));
+        }
+
         /* Close and disarm the watchdog, so that the new instance can reinitialize it, but doesn't get
          * rebooted while we do that */
         watchdog_close(true);