]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
pid1: restore the original environment passed by the kernel when switching to a new...
authorFranck Bui <fbui@suse.com>
Tue, 1 Oct 2019 12:31:14 +0000 (14:31 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 3 Oct 2019 20:08:13 +0000 (22:08 +0200)
PID1 may modified the environment passed by the kernel when it starts
running. Commit 9d48671c62de133a2b9fe7c31e70c0ff8e68f2db unset $HOME for
example.

In case PID1 is going to switch to a new root and execute a new system manager
which is not systemd, we should restore the original environment as the new
manager might expect some variables to be set by default (more specifically
$HOME).

src/basic/util.c
src/basic/util.h
src/core/main.c

index 93d610bc9890b629d6e5ac16be22f2e96f3ff71c..4989b8aa77584cc5762c66d3552ff062653fd378 100644 (file)
@@ -39,6 +39,7 @@
 #include "set.h"
 #include "signal-util.h"
 #include "stat-util.h"
+#include "static-destruct.h"
 #include "string-util.h"
 #include "strv.h"
 #include "time-util.h"
 
 int saved_argc = 0;
 char **saved_argv = NULL;
+char **saved_env = NULL;
 static int saved_in_initrd = -1;
 
+STATIC_DESTRUCTOR_REGISTER(saved_env, strv_freep);
+
 bool kexec_loaded(void) {
        _cleanup_free_ char *s = NULL;
 
@@ -298,3 +302,7 @@ void disable_coredumps(void) {
         if (r < 0)
                 log_debug_errno(r, "Failed to turn off coredumps, ignoring: %m");
 }
+
+void save_env(void) {
+        saved_env = strv_copy(environ);
+}
index 6fc7480fcbd7697b6101832f301a766f78dbd03d..15444b2e5c576c9d524cb2258521c1a460cc0201 100644 (file)
@@ -13,6 +13,9 @@ static inline void save_argc_argv(int argc, char **argv) {
         saved_argv = argv;
 }
 
+extern char **saved_env;
+void save_env(void);
+
 bool kexec_loaded(void);
 
 int prot_from_flags(int flags) _const_;
index 425e958fe8c4c2e9ec9e01fa3cc1ff119f1e0d7e..b3a665b119644da38cd4cc0056af347287609f84 100644 (file)
@@ -1648,7 +1648,7 @@ static void do_reexecute(
 
         if (switch_root_init) {
                 args[0] = switch_root_init;
-                (void) execv(args[0], (char* const*) args);
+                (void) execve(args[0], (char* const*) args, saved_env);
                 log_warning_errno(errno, "Failed to execute configured init, trying fallback: %m");
         }
 
@@ -1665,7 +1665,7 @@ static void do_reexecute(
 
                 args[0] = "/bin/sh";
                 args[1] = NULL;
-                (void) execv(args[0], (char* const*) args);
+                (void) execve(args[0], (char* const*) args, saved_env);
                 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");
@@ -2392,6 +2392,10 @@ int main(int argc, char *argv[]) {
         /* Save the original command line */
         save_argc_argv(argc, argv);
 
+        /* Save the original environment as we might need to restore it if we're requested to
+         * execute another system manager later. */
+        save_env();
+
         /* Make sure that if the user says "syslog" we actually log to the journal. */
         log_set_upgrade_syslog_to_journal(true);