From: Matteo Croce Date: Tue, 26 Nov 2024 10:54:29 +0000 (+0100) Subject: core: split out setup_private_users_child() X-Git-Tag: v258-rc1~134^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2c7dabff5008d1a82edde8c300435cf46991c2f7;p=thirdparty%2Fsystemd.git core: split out setup_private_users_child() Drop support for kernels older than 3.19, as this is where /proc//setgroups was added. https://github.com/torvalds/linux/commit/9cc46516ddf497ea16e8d7cb986ae03a0f6b92f8 --- diff --git a/src/core/exec-invoke.c b/src/core/exec-invoke.c index 0f428685466..09deb0f5c11 100644 --- a/src/core/exec-invoke.c +++ b/src/core/exec-invoke.c @@ -2234,6 +2234,42 @@ static int build_pass_environment(const ExecContext *c, char ***ret) { return 0; } +static int setup_private_users_child(int unshare_ready_fd, const char *uid_map, const char *gid_map, bool allow_setgroups) { + int r; + + /* Child process, running in the original user namespace. Let's update the parent's UID/GID map from + * here, after the parent opened its own user namespace. */ + + pid_t ppid = getppid(); + + /* Wait until the parent unshared the user namespace */ + uint64_t c; + if (read(unshare_ready_fd, &c, sizeof(c)) < 0) + return log_debug_errno(errno, "Failed to read from signaling eventfd: %m"); + + /* Disable the setgroups() system call in the child user namespace, for good, unless PrivateUsers=full + * and using the system service manager. */ + const char *a = procfs_file_alloca(ppid, "setgroups"); + const char *setgroups = allow_setgroups ? "allow" : "deny"; + r = write_string_file(a, setgroups, WRITE_STRING_FILE_DISABLE_BUFFER); + if (r < 0) + return log_debug_errno(r, "Failed to write '%s' to %s: %m", setgroups, a); + + /* First write the GID map */ + a = procfs_file_alloca(ppid, "gid_map"); + r = write_string_file(a, gid_map, WRITE_STRING_FILE_DISABLE_BUFFER); + if (r < 0) + return log_debug_errno(r, "Failed to write GID map to %s: %m", a); + + /* Then write the UID map */ + a = procfs_file_alloca(ppid, "uid_map"); + r = write_string_file(a, uid_map, WRITE_STRING_FILE_DISABLE_BUFFER); + if (r < 0) + return log_debug_errno(r, "Failed to write UID map to %s: %m", a); + + return 0; +} + static int setup_private_users(PrivateUsers private_users, uid_t ouid, gid_t ogid, uid_t uid, gid_t gid, bool allow_setgroups) { _cleanup_free_ char *uid_map = NULL, *gid_map = NULL; _cleanup_close_pair_ int errno_pipe[2] = EBADF_PAIR; @@ -2339,69 +2375,10 @@ static int setup_private_users(PrivateUsers private_users, uid_t ouid, gid_t ogi if (r < 0) return r; if (r == 0) { - _cleanup_close_ int fd = -EBADF; - const char *a; - pid_t ppid; - - /* Child process, running in the original user namespace. Let's update the parent's UID/GID map from - * here, after the parent opened its own user namespace. */ - - ppid = getppid(); errno_pipe[0] = safe_close(errno_pipe[0]); - - /* Wait until the parent unshared the user namespace */ - if (read(unshare_ready_fd, &c, sizeof(c)) < 0) - report_errno_and_exit(errno_pipe[1], -errno); - - /* Disable the setgroups() system call in the child user namespace, for good, unless PrivateUsers=full - * and using the system service manager. */ - a = procfs_file_alloca(ppid, "setgroups"); - fd = open(a, O_WRONLY|O_CLOEXEC); - if (fd < 0) { - if (errno != ENOENT) { - r = log_debug_errno(errno, "Failed to open %s: %m", a); - report_errno_and_exit(errno_pipe[1], r); - } - - /* If the file is missing the kernel is too old, let's continue anyway. */ - } else { - const char *setgroups = allow_setgroups ? "allow\n" : "deny\n"; - if (write(fd, setgroups, strlen(setgroups)) < 0) { - r = log_debug_errno(errno, "Failed to write '%s' to %s: %m", setgroups, a); - report_errno_and_exit(errno_pipe[1], r); - } - - fd = safe_close(fd); - } - - /* First write the GID map */ - a = procfs_file_alloca(ppid, "gid_map"); - fd = open(a, O_WRONLY|O_CLOEXEC); - if (fd < 0) { - r = log_debug_errno(errno, "Failed to open %s: %m", a); - report_errno_and_exit(errno_pipe[1], r); - } - - if (write(fd, gid_map, strlen(gid_map)) < 0) { - r = log_debug_errno(errno, "Failed to write GID map to %s: %m", a); - report_errno_and_exit(errno_pipe[1], r); - } - - fd = safe_close(fd); - - /* The write the UID map */ - a = procfs_file_alloca(ppid, "uid_map"); - fd = open(a, O_WRONLY|O_CLOEXEC); - if (fd < 0) { - r = log_debug_errno(errno, "Failed to open %s: %m", a); - report_errno_and_exit(errno_pipe[1], r); - } - - if (write(fd, uid_map, strlen(uid_map)) < 0) { - r = log_debug_errno(errno, "Failed to write UID map to %s: %m", a); + r = setup_private_users_child(unshare_ready_fd, uid_map, gid_map, allow_setgroups); + if (r < 0) report_errno_and_exit(errno_pipe[1], r); - } - _exit(EXIT_SUCCESS); }