]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
uid-range: add new uid_range_load_userns_by_fd() helper
authorLennart Poettering <lennart@poettering.net>
Thu, 20 Apr 2023 16:51:55 +0000 (18:51 +0200)
committerLennart Poettering <lennart@poettering.net>
Sat, 6 Apr 2024 14:08:23 +0000 (16:08 +0200)
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.)

src/basic/uid-range.c
src/basic/uid-range.h

index 4c35df5ea882c1ce61a3308863eb0c44cda94bd5..f1b086711d8c5960264fd300f1abf206c5809084 100644 (file)
@@ -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)
index d6b62f23651f2ed880c9a22c3cc9e5aafdeadb2d..f4d3d41db514ff1d018e53833270ce0c59f34fa9 100644 (file)
@@ -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);