]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core/exec-invoke: suppress placeholder home only in build_environment()
authorMike Yuan <me@yhndnzj.com>
Mon, 18 Nov 2024 18:41:07 +0000 (19:41 +0100)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 28 Nov 2024 14:08:36 +0000 (15:08 +0100)
Currently, get_fixed_user() employs USER_CREDS_SUPPRESS_PLACEHOLDER,
meaning home path is set to NULL if it's empty or root. However,
the path is also used for applying WorkingDirectory=~, and we'd
spuriously use the invoking user's home as fallback even if
User= is changed in that case.

Let's instead delegate such suppression to build_environment(),
so that home is proper initialized for usage at other steps.
shell doesn't actually suffer from such problem, but it's changed
too for consistency.

Alternative to #34789

(cherry picked from commit b718b86e1b8477f58461f3c456c944abb1428c0f)

src/core/exec-invoke.c
test/units/TEST-07-PID1.working-directory.sh [new file with mode: 0755]

index b9b896c355d3ea6858651d50508a8dc09e3f7f65..9b52ab7dba0286a1ef5dbc5a098a57691e1fada3 100644 (file)
@@ -858,10 +858,7 @@ static int get_fixed_user(
         assert(user_or_uid);
         assert(ret_username);
 
-        /* Note that we don't set $HOME or $SHELL if they are not particularly enlightening anyway
-         * (i.e. are "/" or "/bin/nologin"). */
-
-        r = get_user_creds(&user_or_uid, ret_uid, ret_gid, ret_home, ret_shell, USER_CREDS_CLEAN|USER_CREDS_SUPPRESS_PLACEHOLDER);
+        r = get_user_creds(&user_or_uid, ret_uid, ret_gid, ret_home, ret_shell, USER_CREDS_CLEAN);
         if (r < 0)
                 return r;
 
@@ -1886,7 +1883,10 @@ static int build_environment(
                 }
         }
 
-        if (home && set_user_login_env) {
+        /* Note that we don't set $HOME or $SHELL if they are not particularly enlightening anyway
+         * (i.e. are "/" or "/bin/nologin"). */
+
+        if (home && set_user_login_env && !empty_or_root(home)) {
                 x = strjoin("HOME=", home);
                 if (!x)
                         return -ENOMEM;
@@ -1895,7 +1895,7 @@ static int build_environment(
                 our_env[n_env++] = x;
         }
 
-        if (shell && set_user_login_env) {
+        if (shell && set_user_login_env && !shell_is_placeholder(shell)) {
                 x = strjoin("SHELL=", shell);
                 if (!x)
                         return -ENOMEM;
@@ -3599,7 +3599,7 @@ static int acquire_home(const ExecContext *c, const char **home, char **ret_buf)
         if (!c->working_directory_home)
                 return 0;
 
-        if (c->dynamic_user)
+        if (c->dynamic_user || (c->user && is_this_me(c->user) <= 0))
                 return -EADDRNOTAVAIL;
 
         r = get_home_dir(ret_buf);
@@ -4311,7 +4311,7 @@ int exec_invoke(
         r = acquire_home(context, &home, &home_buffer);
         if (r < 0) {
                 *exit_status = EXIT_CHDIR;
-                return log_exec_error_errno(context, params, r, "Failed to determine $HOME for user: %m");
+                return log_exec_error_errno(context, params, r, "Failed to determine $HOME for the invoking user: %m");
         }
 
         /* If a socket is connected to STDIN/STDOUT/STDERR, we must drop O_NONBLOCK */
diff --git a/test/units/TEST-07-PID1.working-directory.sh b/test/units/TEST-07-PID1.working-directory.sh
new file mode 100755 (executable)
index 0000000..1cff3e0
--- /dev/null
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+set -eux
+set -o pipefail
+
+# shellcheck source=test/units/util.sh
+. "$(dirname "$0")"/util.sh
+
+(! systemd-run --wait -p DynamicUser=yes \
+                      -p EnvironmentFile=-/usr/lib/systemd/systemd-asan-env \
+                      -p WorkingDirectory='~' true)
+
+assert_eq "$(systemd-run --pipe --uid=root -p WorkingDirectory='~' pwd)" "/root"
+assert_eq "$(systemd-run --pipe --uid=nobody -p WorkingDirectory='~' pwd)" "/"
+assert_eq "$(systemd-run --pipe --uid=testuser -p WorkingDirectory='~' pwd)" "/home/testuser"
+
+(! systemd-run --wait -p DynamicUser=yes -p User=testuser \
+                      -p EnvironmentFile=-/usr/lib/systemd/systemd-asan-env \
+                      -p WorkingDirectory='~' true)