]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
namespace-util: introduce userns_acquire() as helper for allocating new unbound userns
authorLennart Poettering <lennart@poettering.net>
Wed, 20 Oct 2021 11:15:27 +0000 (13:15 +0200)
committerLennart Poettering <lennart@poettering.net>
Fri, 22 Oct 2021 14:34:30 +0000 (16:34 +0200)
This returns a namespace fd, and takes a uidmap/gidmap as string. This
is split out out mount-util.c's remount_idmap() logic, so that we can
allocate a userns independently.

src/basic/namespace-util.c
src/basic/namespace-util.h
src/shared/mount-util.c

index d1fee952458e5349c5e261e09bf737a00c13bffd..9d2e59e886305f95e6275b405fc435b1f339eb08 100644 (file)
@@ -5,6 +5,7 @@
 #include <sys/mount.h>
 
 #include "fd-util.h"
+#include "fileio.h"
 #include "missing_fs.h"
 #include "missing_magic.h"
 #include "namespace-util.h"
@@ -181,3 +182,41 @@ int detach_mount_namespace(void) {
 
         return 0;
 }
+
+int userns_acquire(const char *uid_map, const char *gid_map) {
+        char path[STRLEN("/proc//uid_map") + DECIMAL_STR_MAX(pid_t) + 1];
+        _cleanup_(sigkill_waitp) pid_t pid = 0;
+        _cleanup_close_ int userns_fd = -1;
+        int r;
+
+        assert(uid_map);
+        assert(gid_map);
+
+        /* Forks off a process in a new userns, configures the specified uidmap/gidmap, acquires an fd to it,
+         * and then kills the process again. This way we have a userns fd that is not bound to any
+         * process. We can use that for file system mounts and similar. */
+
+        r = safe_fork("(sd-mkuserns)", FORK_CLOSE_ALL_FDS|FORK_DEATHSIG|FORK_NEW_USERNS, &pid);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                /* Child. We do nothing here, just freeze until somebody kills us. */
+                freeze();
+
+        xsprintf(path, "/proc/" PID_FMT "/uid_map", pid);
+        r = write_string_file(path, uid_map, WRITE_STRING_FILE_DISABLE_BUFFER);
+        if (r < 0)
+                return log_error_errno(r, "Failed to write UID map: %m");
+
+        xsprintf(path, "/proc/" PID_FMT "/gid_map", pid);
+        r = write_string_file(path, gid_map, WRITE_STRING_FILE_DISABLE_BUFFER);
+        if (r < 0)
+                return log_error_errno(r, "Failed to write GID map: %m");
+
+        r = namespace_open(pid, NULL, NULL, NULL, &userns_fd, NULL);
+        if (r < 0)
+                return log_error_errno(r, "Failed to open netns fd: %m");
+
+        return TAKE_FD(userns_fd);
+
+}
index 39a6a46d1f99f42b9c3b3610f8ba90e382d3421b..24dce0939ec695bc655c746f9fb1a377f6abb01b 100644 (file)
@@ -24,3 +24,5 @@ static inline bool userns_shift_range_valid(uid_t shift, uid_t range) {
 
         return true;
 }
+
+int userns_acquire(const char *uid_map, const char *gid_map);
index e6b6a7e89a1d2e82edf4f9f41af7b537fb80ea0d..a7217adfa1a23647252be648702061fcdc854dad 100644 (file)
@@ -995,37 +995,18 @@ int make_mount_point(const char *path) {
 }
 
 static int make_userns(uid_t uid_shift, uid_t uid_range) {
-        char uid_map[STRLEN("/proc//uid_map") + DECIMAL_STR_MAX(uid_t) + 1], line[DECIMAL_STR_MAX(uid_t)*3+3+1];
-        _cleanup_(sigkill_waitp) pid_t pid = 0;
+        char line[DECIMAL_STR_MAX(uid_t)*3+3+1];
         _cleanup_close_ int userns_fd = -1;
-        int r;
 
         /* Allocates a userns file descriptor with the mapping we need. For this we'll fork off a child
          * process whose only purpose is to give us a new user namespace. It's killed when we got it. */
 
-        r = safe_fork("(sd-mkuserns)", FORK_CLOSE_ALL_FDS|FORK_DEATHSIG|FORK_NEW_USERNS, &pid);
-        if (r < 0)
-                return r;
-        if (r == 0)
-                /* Child. We do nothing here, just freeze until somebody kills us. */
-                freeze();
-
         xsprintf(line, UID_FMT " " UID_FMT " " UID_FMT "\n", 0, uid_shift, uid_range);
 
-        xsprintf(uid_map, "/proc/" PID_FMT "/uid_map", pid);
-        r = write_string_file(uid_map, line, WRITE_STRING_FILE_DISABLE_BUFFER);
-        if (r < 0)
-                return log_error_errno(r, "Failed to write UID map: %m");
-
         /* We always assign the same UID and GID ranges */
-        xsprintf(uid_map, "/proc/" PID_FMT "/gid_map", pid);
-        r = write_string_file(uid_map, line, WRITE_STRING_FILE_DISABLE_BUFFER);
-        if (r < 0)
-                return log_error_errno(r, "Failed to write GID map: %m");
-
-        r = namespace_open(pid, NULL, NULL, NULL, &userns_fd, NULL);
-        if (r < 0)
-                return r;
+        userns_fd = userns_acquire(line, line);
+        if (userns_fd < 0)
+                return log_debug_errno(userns_fd, "Failed to acquire new userns: %m");
 
         return TAKE_FD(userns_fd);
 }