diff options
Diffstat (limited to 'src/core/execute.c')
-rw-r--r-- | src/core/execute.c | 207 |
1 files changed, 151 insertions, 56 deletions
diff --git a/src/core/execute.c b/src/core/execute.c index 06a291fd39..4c2968f971 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -1643,6 +1643,9 @@ static bool exec_needs_mount_namespace( assert(context); assert(params); + if (context->root_image) + return true; + if (!strv_isempty(context->read_write_paths) || !strv_isempty(context->read_only_paths) || !strv_isempty(context->inaccessible_paths)) @@ -1665,6 +1668,9 @@ static bool exec_needs_mount_namespace( context->protect_control_groups) return true; + if (context->mount_apivfs) + return true; + return false; } @@ -1685,25 +1691,31 @@ static int setup_private_users(uid_t uid, gid_t gid) { * child then writes the UID mapping, under full privileges. The parent waits for the child to finish and * continues execution normally. */ - if (uid != 0 && uid_is_valid(uid)) - asprintf(&uid_map, - "0 0 1\n" /* Map root → root */ - UID_FMT " " UID_FMT " 1\n", /* Map $UID → $UID */ - uid, uid); - else + if (uid != 0 && uid_is_valid(uid)) { + r = asprintf(&uid_map, + "0 0 1\n" /* Map root → root */ + UID_FMT " " UID_FMT " 1\n", /* Map $UID → $UID */ + uid, uid); + if (r < 0) + return -ENOMEM; + } else { uid_map = strdup("0 0 1\n"); /* The case where the above is the same */ - if (!uid_map) - return -ENOMEM; + if (!uid_map) + return -ENOMEM; + } - if (gid != 0 && gid_is_valid(gid)) - asprintf(&gid_map, - "0 0 1\n" /* Map root → root */ - GID_FMT " " GID_FMT " 1\n", /* Map $GID → $GID */ - gid, gid); - else + if (gid != 0 && gid_is_valid(gid)) { + r = asprintf(&gid_map, + "0 0 1\n" /* Map root → root */ + GID_FMT " " GID_FMT " 1\n", /* Map $GID → $GID */ + gid, gid); + if (r < 0) + return -ENOMEM; + } else { gid_map = strdup("0 0 1\n"); /* The case where the above is the same */ - if (!gid_map) - return -ENOMEM; + if (!gid_map) + return -ENOMEM; + } /* Create a communication channel so that the parent can tell the child when it finished creating the user * namespace. */ @@ -1896,8 +1908,8 @@ static int compile_read_write_paths( _cleanup_strv_free_ char **l = NULL; char **rt; - /* Compile the list of writable paths. This is the combination of the explicitly configured paths, plus all - * runtime directories. */ + /* Compile the list of writable paths. This is the combination of + * the explicitly configured paths, plus all runtime directories. */ if (strv_isempty(context->read_write_paths) && strv_isempty(context->runtime_directory)) { @@ -1926,20 +1938,26 @@ static int compile_read_write_paths( return 0; } -static int apply_mount_namespace(Unit *u, const ExecContext *context, - const ExecParameters *params, - ExecRuntime *runtime) { - int r; - _cleanup_free_ char **rw = NULL; +static int apply_mount_namespace( + Unit *u, + ExecCommand *command, + const ExecContext *context, + const ExecParameters *params, + ExecRuntime *runtime) { + + _cleanup_strv_free_ char **rw = NULL; char *tmp = NULL, *var = NULL; - const char *root_dir = NULL; + const char *root_dir = NULL, *root_image = NULL; NameSpaceInfo ns_info = { .ignore_protect_paths = false, .private_dev = context->private_devices, .protect_control_groups = context->protect_control_groups, .protect_kernel_tunables = context->protect_kernel_tunables, .protect_kernel_modules = context->protect_kernel_modules, + .mount_apivfs = context->mount_apivfs, }; + bool apply_restrictions; + int r; assert(context); @@ -1958,8 +1976,12 @@ static int apply_mount_namespace(Unit *u, const ExecContext *context, if (r < 0) return r; - if (params->flags & EXEC_APPLY_CHROOT) - root_dir = context->root_directory; + if (params->flags & EXEC_APPLY_CHROOT) { + root_image = context->root_image; + + if (!root_image) + root_dir = context->root_directory; + } /* * If DynamicUser=no and RootDirectory= is set then lets pass a relaxed @@ -1969,16 +1991,20 @@ static int apply_mount_namespace(Unit *u, const ExecContext *context, if (!context->dynamic_user && root_dir) ns_info.ignore_protect_paths = true; - r = setup_namespace(root_dir, &ns_info, rw, - context->read_only_paths, - context->inaccessible_paths, + apply_restrictions = (params->flags & EXEC_APPLY_PERMISSIONS) && !command->privileged; + + r = setup_namespace(root_dir, root_image, + &ns_info, rw, + apply_restrictions ? context->read_only_paths : NULL, + apply_restrictions ? context->inaccessible_paths : NULL, context->bind_mounts, context->n_bind_mounts, tmp, var, - context->protect_home, - context->protect_system, - context->mount_flags); + apply_restrictions ? context->protect_home : PROTECT_HOME_NO, + apply_restrictions ? context->protect_system : PROTECT_SYSTEM_NO, + context->mount_flags, + DISSECT_IMAGE_DISCARD_ON_LOOP); /* If we couldn't set up the namespace this is probably due to a * missing capability. In this case, silently proceeed. */ @@ -1992,33 +2018,47 @@ static int apply_mount_namespace(Unit *u, const ExecContext *context, return r; } -static int apply_working_directory(const ExecContext *context, - const ExecParameters *params, - const char *home, - const bool needs_mount_ns) { - const char *d; - const char *wd; +static int apply_working_directory( + const ExecContext *context, + const ExecParameters *params, + const char *home, + const bool needs_mount_ns, + int *exit_status) { + + const char *d, *wd; assert(context); + assert(exit_status); + + if (context->working_directory_home) { + + if (!home) { + *exit_status = EXIT_CHDIR; + return -ENXIO; + } - if (context->working_directory_home) wd = home; - else if (context->working_directory) + + } else if (context->working_directory) wd = context->working_directory; else wd = "/"; if (params->flags & EXEC_APPLY_CHROOT) { if (!needs_mount_ns && context->root_directory) - if (chroot(context->root_directory) < 0) + if (chroot(context->root_directory) < 0) { + *exit_status = EXIT_CHROOT; return -errno; + } d = wd; } else - d = strjoina(strempty(context->root_directory), "/", strempty(wd)); + d = prefix_roota(context->root_directory, wd); - if (chdir(d) < 0 && !context->working_directory_missing_ok) + if (chdir(d) < 0 && !context->working_directory_missing_ok) { + *exit_status = EXIT_CHDIR; return -errno; + } return 0; } @@ -2160,6 +2200,35 @@ static int send_user_lookup( return 0; } +static int acquire_home(const ExecContext *c, uid_t uid, const char** home, char **buf) { + int r; + + assert(c); + assert(home); + assert(buf); + + /* If WorkingDirectory=~ is set, try to acquire a usable home directory. */ + + if (*home) + return 0; + + if (!c->working_directory_home) + return 0; + + if (uid == 0) { + /* Hardcode /root as home directory for UID 0 */ + *home = "/root"; + return 1; + } + + r = get_home_dir(buf); + if (r < 0) + return r; + + *home = *buf; + return 1; +} + static int exec_child( Unit *unit, ExecCommand *command, @@ -2177,7 +2246,7 @@ static int exec_child( char **error_message) { _cleanup_strv_free_ char **our_env = NULL, **pass_env = NULL, **accum_env = NULL, **final_argv = NULL; - _cleanup_free_ char *mac_selinux_context_net = NULL; + _cleanup_free_ char *mac_selinux_context_net = NULL, *home_buffer = NULL; _cleanup_free_ gid_t *supplementary_gids = NULL; const char *username = NULL, *groupname = NULL; const char *home = NULL, *shell = NULL; @@ -2330,6 +2399,13 @@ static int exec_child( user_lookup_fd = safe_close(user_lookup_fd); + r = acquire_home(context, uid, &home, &home_buffer); + if (r < 0) { + *exit_status = EXIT_CHDIR; + *error_message = strdup("Failed to determine $HOME for user"); + return r; + } + /* If a socket is connected to STDIN/STDOUT/STDERR, we * must sure to drop O_NONBLOCK */ if (socket_fd >= 0) @@ -2433,11 +2509,12 @@ static int exec_child( } if (context->utmp_id) - utmp_put_init_process(context->utmp_id, getpid(), getsid(0), context->tty_path, + utmp_put_init_process(context->utmp_id, getpid(), getsid(0), + context->tty_path, context->utmp_mode == EXEC_UTMP_INIT ? INIT_PROCESS : context->utmp_mode == EXEC_UTMP_LOGIN ? LOGIN_PROCESS : USER_PROCESS, - username ? "root" : context->user); + username); if (context->user) { r = chown_terminal(STDIN_FILENO, uid); @@ -2536,7 +2613,7 @@ static int exec_child( needs_mount_namespace = exec_needs_mount_namespace(context, params, runtime); if (needs_mount_namespace) { - r = apply_mount_namespace(unit, context, params, runtime); + r = apply_mount_namespace(unit, command, context, params, runtime); if (r < 0) { *exit_status = EXIT_NAMESPACE; return r; @@ -2544,11 +2621,9 @@ static int exec_child( } /* Apply just after mount namespace setup */ - r = apply_working_directory(context, params, home, needs_mount_namespace); - if (r < 0) { - *exit_status = EXIT_CHROOT; + r = apply_working_directory(context, params, home, needs_mount_namespace, exit_status); + if (r < 0) return r; - } /* Drop groups as early as possbile */ if ((params->flags & EXEC_APPLY_PERMISSIONS) && !command->privileged) { @@ -2975,6 +3050,7 @@ void exec_context_done(ExecContext *c) { c->working_directory = mfree(c->working_directory); c->root_directory = mfree(c->root_directory); + c->root_image = mfree(c->root_image); c->tty_path = mfree(c->tty_path); c->syslog_identifier = mfree(c->syslog_identifier); c->user = mfree(c->user); @@ -3096,7 +3172,7 @@ const char* exec_context_fdname(const ExecContext *c, int fd_index) { int exec_context_named_iofds(Unit *unit, const ExecContext *c, const ExecParameters *p, int named_iofds[3]) { unsigned i, targets; - const char *stdio_fdname[3]; + const char* stdio_fdname[3]; assert(c); assert(p); @@ -3109,18 +3185,32 @@ int exec_context_named_iofds(Unit *unit, const ExecContext *c, const ExecParamet stdio_fdname[i] = exec_context_fdname(c, i); for (i = 0; i < p->n_fds && targets > 0; i++) - if (named_iofds[STDIN_FILENO] < 0 && c->std_input == EXEC_INPUT_NAMED_FD && stdio_fdname[STDIN_FILENO] && streq(p->fd_names[i], stdio_fdname[STDIN_FILENO])) { + if (named_iofds[STDIN_FILENO] < 0 && + c->std_input == EXEC_INPUT_NAMED_FD && + stdio_fdname[STDIN_FILENO] && + streq(p->fd_names[i], stdio_fdname[STDIN_FILENO])) { + named_iofds[STDIN_FILENO] = p->fds[i]; targets--; - } else if (named_iofds[STDOUT_FILENO] < 0 && c->std_output == EXEC_OUTPUT_NAMED_FD && stdio_fdname[STDOUT_FILENO] && streq(p->fd_names[i], stdio_fdname[STDOUT_FILENO])) { + + } else if (named_iofds[STDOUT_FILENO] < 0 && + c->std_output == EXEC_OUTPUT_NAMED_FD && + stdio_fdname[STDOUT_FILENO] && + streq(p->fd_names[i], stdio_fdname[STDOUT_FILENO])) { + named_iofds[STDOUT_FILENO] = p->fds[i]; targets--; - } else if (named_iofds[STDERR_FILENO] < 0 && c->std_error == EXEC_OUTPUT_NAMED_FD && stdio_fdname[STDERR_FILENO] && streq(p->fd_names[i], stdio_fdname[STDERR_FILENO])) { + + } else if (named_iofds[STDERR_FILENO] < 0 && + c->std_error == EXEC_OUTPUT_NAMED_FD && + stdio_fdname[STDERR_FILENO] && + streq(p->fd_names[i], stdio_fdname[STDERR_FILENO])) { + named_iofds[STDERR_FILENO] = p->fds[i]; targets--; } - return (targets == 0 ? 0 : -ENOENT); + return targets == 0 ? 0 : -ENOENT; } int exec_context_load_environment(Unit *unit, const ExecContext *c, char ***l) { @@ -3276,6 +3366,7 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { "%sPrivateUsers: %s\n" "%sProtectHome: %s\n" "%sProtectSystem: %s\n" + "%sMountAPIVFS: %s\n" "%sIgnoreSIGPIPE: %s\n" "%sMemoryDenyWriteExecute: %s\n" "%sRestrictRealtime: %s\n", @@ -3292,10 +3383,14 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { prefix, yes_no(c->private_users), prefix, protect_home_to_string(c->protect_home), prefix, protect_system_to_string(c->protect_system), + prefix, yes_no(c->mount_apivfs), prefix, yes_no(c->ignore_sigpipe), prefix, yes_no(c->memory_deny_write_execute), prefix, yes_no(c->restrict_realtime)); + if (c->root_image) + fprintf(f, "%sRootImage: %s\n", prefix, c->root_image); + STRV_FOREACH(e, c->environment) fprintf(f, "%sEnvironment: %s\n", prefix, *e); |