From a5cede8c24fddda9b73f142e09b18b49adde1b9c Mon Sep 17 00:00:00 2001 From: Franck Bui Date: Tue, 1 Oct 2019 14:31:14 +0200 Subject: [PATCH] pid1: restore the original environment passed by the kernel when switching to a new system manager 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 | 8 ++++++++ src/basic/util.h | 3 +++ src/core/main.c | 8 ++++++-- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/basic/util.c b/src/basic/util.c index 93d610bc989..4989b8aa775 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -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" @@ -49,8 +50,11 @@ 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); +} diff --git a/src/basic/util.h b/src/basic/util.h index 6fc7480fcbd..15444b2e5c5 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -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_; diff --git a/src/core/main.c b/src/core/main.c index 425e958fe8c..b3a665b1196 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -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);