diff options
author | Lennart Poettering <lennart@poettering.net> | 2023-04-20 18:51:55 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2024-04-06 16:08:23 +0200 |
commit | 20ba086e775838112e777f8f6dc3c03af4f3d772 (patch) | |
tree | 2ff2d3caba36ea73494bbb7a678cc5d5fb93ed8b /src/basic | |
parent | uid-range: optionally load outside view of UID range from uid_map procfs file (diff) | |
download | systemd-20ba086e775838112e777f8f6dc3c03af4f3d772.tar.xz systemd-20ba086e775838112e777f8f6dc3c03af4f3d772.zip |
uid-range: add new uid_range_load_userns_by_fd() helper
This is similar to uid_range_load_userns() but instead of reading the
uid_map off a process it reads it off a userns fd.
(Of course the kernel has no API for this right now, hence we fork off a
throw-away process which joins the user namespace, and then read off the
data from there.)
Diffstat (limited to 'src/basic')
-rw-r--r-- | src/basic/uid-range.c | 61 | ||||
-rw-r--r-- | src/basic/uid-range.h | 1 |
2 files changed, 62 insertions, 0 deletions
diff --git a/src/basic/uid-range.c b/src/basic/uid-range.c index 4c35df5ea8..f1b086711d 100644 --- a/src/basic/uid-range.c +++ b/src/basic/uid-range.c @@ -10,6 +10,7 @@ #include "format-util.h" #include "macro.h" #include "path-util.h" +#include "process-util.h" #include "sort-util.h" #include "stat-util.h" #include "uid-range.h" @@ -260,6 +261,66 @@ int uid_range_load_userns(UIDRange **ret, const char *path, UIDRangeUsernsMode m return 0; } +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); + assert(mode >= 0); + 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); + 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, + IN_SET(mode, UID_RANGE_USERNS_INSIDE, UID_RANGE_USERNS_OUTSIDE) ? "uid_map" : "gid_map"); + + return uid_range_load_userns(ret, p, mode); +} + bool uid_range_overlaps(const UIDRange *range, uid_t start, uid_t nr) { if (!range) diff --git a/src/basic/uid-range.h b/src/basic/uid-range.h index d6b62f2365..f4d3d41db5 100644 --- a/src/basic/uid-range.h +++ b/src/basic/uid-range.h @@ -43,5 +43,6 @@ typedef enum UIDRangeUsernsMode { } UIDRangeUsernsMode; int uid_range_load_userns(UIDRange **ret, const char *path, UIDRangeUsernsMode mode); +int uid_range_load_userns_by_fd(int userns_fd, UIDRangeUsernsMode mode, UIDRange **ret); bool uid_range_overlaps(const UIDRange *range, uid_t start, uid_t nr); |