summaryrefslogtreecommitdiffstats
path: root/src/basic
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2023-04-20 18:51:55 +0200
committerLennart Poettering <lennart@poettering.net>2024-04-06 16:08:23 +0200
commit20ba086e775838112e777f8f6dc3c03af4f3d772 (patch)
tree2ff2d3caba36ea73494bbb7a678cc5d5fb93ed8b /src/basic
parentuid-range: optionally load outside view of UID range from uid_map procfs file (diff)
downloadsystemd-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.c61
-rw-r--r--src/basic/uid-range.h1
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);