diff options
author | Mike Yuan <me@yhndnzj.com> | 2025-01-08 12:43:05 +0100 |
---|---|---|
committer | Mike Yuan <me@yhndnzj.com> | 2025-01-11 15:53:14 +0100 |
commit | 8c2c8235a64be93e9e8d18927ad997efda156a95 (patch) | |
tree | 9b4f88aa9dead4b847d6de02d902dd4172a05450 | |
parent | namespace-util: group userns functions together (diff) | |
download | systemd-8c2c8235a64be93e9e8d18927ad997efda156a95.tar.xz systemd-8c2c8235a64be93e9e8d18927ad997efda156a95.zip |
namespace-util: introduce userns_enter_and_pin() helper
which generalizes forking a process into userns and freeze()
Addresses https://github.com/systemd/systemd/pull/35833/files#r1905508153
-rw-r--r-- | src/basic/namespace-util.c | 23 | ||||
-rw-r--r-- | src/basic/namespace-util.h | 1 | ||||
-rw-r--r-- | src/basic/uid-range.c | 43 |
3 files changed, 22 insertions, 45 deletions
diff --git a/src/basic/namespace-util.c b/src/basic/namespace-util.c index 2ae5003459..6ece5108df 100644 --- a/src/basic/namespace-util.c +++ b/src/basic/namespace-util.c @@ -558,7 +558,7 @@ int userns_acquire(const char *uid_map, const char *gid_map) { return TAKE_FD(userns_fd); } -int userns_get_base_uid(int userns_fd, uid_t *ret_uid, gid_t *ret_gid) { +int userns_enter_and_pin(int userns_fd, pid_t *ret_pid) { _cleanup_(close_pairp) int pfd[2] = EBADF_PAIR; _cleanup_(sigkill_waitp) pid_t pid = 0; ssize_t n; @@ -566,12 +566,13 @@ int userns_get_base_uid(int userns_fd, uid_t *ret_uid, gid_t *ret_gid) { int r; assert(userns_fd >= 0); + assert(ret_pid); if (pipe2(pfd, O_CLOEXEC) < 0) return -errno; r = safe_fork_full( - "(sd-baseuns)", + "(sd-pinuserns)", /* stdio_fds= */ NULL, (int[]) { pfd[1], userns_fd }, 2, FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGKILL, @@ -608,6 +609,20 @@ int userns_get_base_uid(int userns_fd, uid_t *ret_uid, gid_t *ret_gid) { assert(n == 1); assert(x == 'x'); + *ret_pid = TAKE_PID(pid); + return 0; +} + +int userns_get_base_uid(int userns_fd, uid_t *ret_uid, gid_t *ret_gid) { + _cleanup_(sigkill_waitp) pid_t pid = 0; + int r; + + assert(userns_fd >= 0); + + r = userns_enter_and_pin(userns_fd, &pid); + if (r < 0) + return r; + uid_t uid; r = uid_map_search_root(pid, "uid_map", &uid); if (r < 0) @@ -630,13 +645,13 @@ int userns_get_base_uid(int userns_fd, uid_t *ret_uid, gid_t *ret_gid) { } int process_is_owned_by_uid(const PidRef *pidref, uid_t uid) { - assert(uid_is_valid(uid)); - int r; /* Checks if the specified process either is owned directly by the specified user, or if it is inside * a user namespace owned by it. */ + assert(uid_is_valid(uid)); + uid_t process_uid; r = pidref_get_uid(pidref, &process_uid); if (r < 0) diff --git a/src/basic/namespace-util.h b/src/basic/namespace-util.h index 58347cbf88..49e2de3bb3 100644 --- a/src/basic/namespace-util.h +++ b/src/basic/namespace-util.h @@ -87,6 +87,7 @@ int parse_userns_uid_range(const char *s, uid_t *ret_uid_shift, uid_t *ret_uid_r int userns_acquire_empty(void); int userns_acquire(const char *uid_map, const char *gid_map); +int userns_enter_and_pin(int userns_fd, pid_t *ret_pid); int userns_get_base_uid(int userns_fd, uid_t *ret_uid, gid_t *ret_gid); diff --git a/src/basic/uid-range.c b/src/basic/uid-range.c index 687ddacc57..cbae1bbf78 100644 --- a/src/basic/uid-range.c +++ b/src/basic/uid-range.c @@ -9,6 +9,7 @@ #include "fd-util.h" #include "format-util.h" #include "macro.h" +#include "namespace-util.h" #include "path-util.h" #include "process-util.h" #include "sort-util.h" @@ -264,10 +265,7 @@ int uid_range_load_userns(const char *path, UIDRangeUsernsMode mode, UIDRange ** } int uid_range_load_userns_by_fd(int userns_fd, UIDRangeUsernsMode mode, UIDRange **ret) { - _cleanup_(close_pairp) int pfd[2] = EBADF_PAIR; _cleanup_(sigkill_waitp) pid_t pid = 0; - ssize_t n; - char x; int r; assert(userns_fd >= 0); @@ -275,46 +273,9 @@ int uid_range_load_userns_by_fd(int userns_fd, UIDRangeUsernsMode mode, UIDRange assert(mode < _UID_RANGE_USERNS_MODE_MAX); assert(ret); - if (pipe2(pfd, O_CLOEXEC) < 0) - return -errno; - - r = safe_fork_full( - "(sd-mkuserns)", - /* stdio_fds= */ NULL, - (int[]) { pfd[1], userns_fd }, 2, - FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGKILL, - &pid); + r = userns_enter_and_pin(userns_fd, &pid); if (r < 0) return r; - if (r == 0) { - /* Child. */ - - if (setns(userns_fd, CLONE_NEWUSER) < 0) { - log_debug_errno(errno, "Failed to join userns: %m"); - _exit(EXIT_FAILURE); - } - - userns_fd = safe_close(userns_fd); - - n = write(pfd[1], &(const char) { 'x' }, 1); - if (n < 0) { - log_debug_errno(errno, "Failed to write to fifo: %m"); - _exit(EXIT_FAILURE); - } - assert(n == 1); - - freeze(); - } - - pfd[1] = safe_close(pfd[1]); - - n = read(pfd[0], &x, 1); - if (n < 0) - return -errno; - if (n == 0) - return -EPROTO; - assert(n == 1); - assert(x == 'x'); const char *p = procfs_file_alloca( pid, |