machined: pass user as positional argument in machine_default_shell_args()

Instead of interpolating the user name directly into the sh -c script
body via asprintf %s, pass it as a positional parameter ($1) in a
separate argv entry. This avoids the user string being parsed as part
of the shell script syntax.

Also validate the user name in bus_machine_method_open_shell() with
valid_user_group_name(), matching the validation already done on the
Varlink path via json_dispatch_const_user_group_name().

Follow-up for 49af9e1368
This commit is contained in:
Luca Boccassi
2026-04-13 22:11:50 +01:00
parent 4bf9db7314
commit a9e9288288
2 changed files with 17 additions and 9 deletions
+4
View File
@@ -26,6 +26,7 @@
#include "signal-util.h"
#include "string-util.h"
#include "strv.h"
#include "user-util.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, machine_class, MachineClass);
static BUS_DEFINE_PROPERTY_GET2(property_get_state, "s", Machine, machine_get_state, machine_state_to_string);
@@ -366,6 +367,9 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu
return r;
user = isempty(user) ? "root" : user;
if (!valid_user_group_name(user, VALID_USER_RELAX))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user name '%s'", user);
/* Ensure only root can shell into the root namespace. This is to avoid unprivileged users registering
* a process they own in the root user namespace, and then shelling in as root or another user. Note that
* the shell operation is privileged and requires 'auth_admin', so we do not need to check the caller's uid,
+13 -9
View File
@@ -1103,11 +1103,10 @@ int machine_start_shell(
char** machine_default_shell_args(const char *user) {
_cleanup_strv_free_ char **args = NULL;
int r;
assert(user);
args = new0(char*, 3 + 1);
args = new0(char*, 5 + 1);
if (!args)
return NULL;
@@ -1119,14 +1118,19 @@ char** machine_default_shell_args(const char *user) {
if (!args[1])
return NULL;
r = asprintf(&args[2],
"shell=$(getent passwd %s 2>/dev/null | { IFS=: read _ _ _ _ _ _ x; echo \"$x\"; })\n"\
"exec \"${shell:-/bin/sh}\" -l", /* -l is means --login */
user);
if (r < 0) {
args[2] = NULL;
args[2] = strdup(
"shell=$(getent passwd \"$1\" 2>/dev/null | { IFS=: read _ _ _ _ _ _ x; echo \"$x\"; })\n"
"exec \"${shell:-/bin/sh}\" -l"); /* -l means --login */
if (!args[2])
return NULL;
args[3] = strdup("sh"); /* $0 placeholder for sh -c */
if (!args[3])
return NULL;
args[4] = strdup(user); /* becomes $1 in the script */
if (!args[4])
return NULL;
}
return TAKE_PTR(args);
}