]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
uid-range: add new uid_range_load_userns() for loading /proc/self/uid_map
authorLennart Poettering <lennart@poettering.net>
Thu, 31 Mar 2022 11:28:54 +0000 (13:28 +0200)
committerLennart Poettering <lennart@poettering.net>
Fri, 1 Apr 2022 09:20:12 +0000 (11:20 +0200)
src/shared/uid-range.c
src/shared/uid-range.h
src/test/test-uid-range.c

index 1adf4f62c231f6942012344af4dbf1a8b2b033f3..c6b4b9d79500453c4960cecac21c00abfde25b63 100644 (file)
@@ -5,8 +5,13 @@
 #include <string.h>
 
 #include "alloc-util.h"
+#include "errno-util.h"
+#include "fd-util.h"
+#include "format-util.h"
 #include "macro.h"
+#include "path-util.h"
 #include "sort-util.h"
+#include "stat-util.h"
 #include "uid-range.h"
 #include "user-util.h"
 
@@ -178,3 +183,47 @@ bool uid_range_contains(const UidRange *p, size_t n, uid_t uid) {
 
         return false;
 }
+
+int uid_range_load_userns(UidRange **p, size_t *n, const char *path) {
+        _cleanup_fclose_ FILE *f = NULL;
+        int r;
+
+        /* If 'path' is NULL loads the UID range of the userns namespace we run. Otherwise load the data from
+         * the specified file (which can be either uid_map or gid_map, in case caller needs to deal with GID
+         * maps).
+         *
+         * To simplify things this will modify the passed array in case of later failure. */
+
+        if (!path)
+                path = "/proc/self/uid_map";
+
+        f = fopen(path, "re");
+        if (!f) {
+                r = -errno;
+
+                if (r == -ENOENT && path_startswith(path, "/proc/") && proc_mounted() > 0)
+                        return -EOPNOTSUPP;
+
+                return r;
+        }
+
+        for (;;) {
+                uid_t uid_base, uid_shift, uid_range;
+                int k;
+
+                errno = 0;
+                k = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT "\n", &uid_base, &uid_shift, &uid_range);
+                if (k == EOF) {
+                        if (ferror(f))
+                                return errno_or_else(EIO);
+
+                        return 0;
+                }
+                if (k != 3)
+                        return -EBADMSG;
+
+                r = uid_range_add(p, n, uid_base, uid_range);
+                if (r < 0)
+                        return r;
+        }
+}
index 1e118ec42c8f8bf72070211f5f122424856cb154..d256a6eebba97e3c5ca523fb6e1ad89eb276e0f3 100644 (file)
@@ -13,3 +13,5 @@ int uid_range_add_str(UidRange **p, size_t *n, const char *s);
 
 int uid_range_next_lower(const UidRange *p, size_t n, uid_t *uid);
 bool uid_range_contains(const UidRange *p, size_t n, uid_t uid);
+
+int uid_range_load_userns(UidRange **p, size_t *n, const char *path);
index 2dcc2d04d5ad468b0bb67920150aed867af8ba58..2e39628cefe998f5baedc6bb7fac4e8cb492a660 100644 (file)
@@ -3,10 +3,16 @@
 #include <stddef.h>
 
 #include "alloc-util.h"
+#include "errno-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
 #include "tests.h"
+#include "tmpfile-util.h"
 #include "uid-range.h"
 #include "user-util.h"
 #include "util.h"
+#include "virt.h"
 
 TEST(uid_range) {
         _cleanup_free_ UidRange *p = NULL;
@@ -72,4 +78,45 @@ TEST(uid_range) {
         assert_se(p[0].nr == 1983);
 }
 
+TEST(load_userns) {
+        _cleanup_(unlink_and_freep) char *fn = NULL;
+        _cleanup_free_ UidRange *p = NULL;
+        _cleanup_fclose_ FILE *f = NULL;
+        size_t n = 0;
+        int r;
+
+        r = uid_range_load_userns(&p, &n, NULL);
+        if (ERRNO_IS_NOT_SUPPORTED(r))
+                return;
+
+        assert_se(r >= 0);
+        assert_se(uid_range_contains(p, n, getuid()));
+
+        r = running_in_userns();
+        if (r == 0) {
+                assert_se(n == 1);
+                assert_se(p[0].start == 0);
+                assert_se(p[0].nr == UINT32_MAX);
+        }
+
+        assert_se(fopen_temporary(NULL, &f, &fn) >= 0);
+        fputs("0 0 20\n"
+              "100 0 20\n", f);
+        assert_se(fflush_and_check(f) >= 0);
+
+        p = mfree(p);
+        n = 0;
+
+        assert_se(uid_range_load_userns(&p, &n, fn) >= 0);
+
+        assert_se(uid_range_contains(p, n, 0));
+        assert_se(uid_range_contains(p, n, 19));
+        assert_se(!uid_range_contains(p, n, 20));
+
+        assert_se(!uid_range_contains(p, n, 99));
+        assert_se(uid_range_contains(p, n, 100));
+        assert_se(uid_range_contains(p, n, 119));
+        assert_se(!uid_range_contains(p, n, 120));
+}
+
 DEFINE_TEST_MAIN(LOG_DEBUG);