]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
manager: if we are reexecuting, do not invoke any fallbacks
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 27 Jan 2022 14:03:27 +0000 (15:03 +0100)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Tue, 15 Feb 2022 10:13:26 +0000 (11:13 +0100)
For https://bugzilla.redhat.com/show_bug.cgi?id=1986176:
if we are trying to reexecute, and this fails for any reason, we shouldn't
try to execute /sbin/init or /bin/sh. It is better to just freeze.
If we freeze it is easier to diagnose what happened, but if we execute
one of the fallbacks, we don't really know what will happen. In particular
the new init might just return, causing the machine to shut down. Or we
may successfully spawn /bin/sh, which could leave the machine open.

src/core/main.c

index ea2b9b7a52cb130449f31ccb05e374f9f4a2b86d..93cbf62769bafd451c21a08d70bb32ab39949e7a 100644 (file)
@@ -1824,7 +1824,8 @@ static void filter_args(
         }
 }
 
-static void do_reexecute(
+static int do_reexecute(
+                ManagerObjective objective,
                 int argc,
                 char* argv[],
                 const struct rlimit *saved_rlimit_nofile,
@@ -1838,6 +1839,7 @@ static void do_reexecute(
         const char **args;
         int r;
 
+        assert(IN_SET(objective, MANAGER_REEXECUTE, MANAGER_SWITCH_ROOT));
         assert(argc >= 0);
         assert(saved_rlimit_nofile);
         assert(saved_rlimit_memlock);
@@ -1901,6 +1903,12 @@ static void do_reexecute(
 
                 args[0] = SYSTEMD_BINARY_PATH;
                 (void) execv(args[0], (char* const*) args);
+
+                if (objective == MANAGER_REEXECUTE) {
+                        *ret_error_message = "Failed to execute our own binary";
+                        return log_error_errno(errno, "Failed to execute our own binary %s: %m", args[0]);
+                }
+
                 log_debug_errno(errno, "Failed to execute our own binary %s, trying fallback: %m", args[0]);
         }
 
@@ -1938,17 +1946,16 @@ static void do_reexecute(
                               ANSI_HIGHLIGHT_RED "  !!  " ANSI_NORMAL,
                               "Failed to execute /sbin/init");
 
+        *ret_error_message = "Failed to execute fallback shell";
         if (r == -ENOENT) {
                 log_warning("No /sbin/init, trying fallback");
 
                 args[0] = "/bin/sh";
                 args[1] = NULL;
                 (void) execve(args[0], (char* const*) args, saved_env);
-                log_error_errno(errno, "Failed to execute /bin/sh, giving up: %m");
+                return log_error_errno(errno, "Failed to execute /bin/sh, giving up: %m");
         } else
-                log_warning_errno(r, "Failed to execute /sbin/init, giving up: %m");
-
-        *ret_error_message = "Failed to execute fallback shell";
+                return log_warning_errno(r, "Failed to execute /sbin/init, giving up: %m");
 }
 
 static int invoke_main_loop(
@@ -3045,13 +3052,14 @@ finish:
         mac_selinux_finish();
 
         if (IN_SET(r, MANAGER_REEXECUTE, MANAGER_SWITCH_ROOT))
-                do_reexecute(argc, argv,
-                             &saved_rlimit_nofile,
-                             &saved_rlimit_memlock,
-                             fds,
-                             switch_root_dir,
-                             switch_root_init,
-                             &error_message); /* This only returns if reexecution failed */
+                r = do_reexecute(r,
+                                 argc, argv,
+                                 &saved_rlimit_nofile,
+                                 &saved_rlimit_memlock,
+                                 fds,
+                                 switch_root_dir,
+                                 switch_root_init,
+                                 &error_message); /* This only returns if reexecution failed */
 
         arg_serialization = safe_fclose(arg_serialization);
         fds = fdset_free(fds);