]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
nspawn-bind-user: Write membership records
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Thu, 30 Oct 2025 21:20:59 +0000 (22:20 +0100)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Fri, 31 Oct 2025 07:57:38 +0000 (08:57 +0100)
src/nspawn/nspawn-bind-user.c
src/nspawn/nspawn.c
src/nspawn/nspawn.h

index d9a06e2c03753dfa9973d070d92010cfc8ffe189..0211cfe23c861bd23ef5737cf9be447cd5cb36a6 100644 (file)
@@ -5,12 +5,16 @@
 #include "sd-json.h"
 
 #include "alloc-util.h"
+#include "chase.h"
+#include "fd-util.h"
 #include "fileio.h"
 #include "format-util.h"
+#include "io-util.h"
 #include "log.h"
 #include "nspawn.h"
 #include "machine-bind-user.h"
 #include "nspawn-bind-user.h"
+#include "strv.h"
 #include "user-record.h"
 #include "group-record.h"
 #include "path-util.h"
@@ -67,6 +71,40 @@ static int write_and_symlink(
         return 0;
 }
 
+static int write_membership(const char *root, const char *user, const char *group) {
+        int r;
+
+        assert(user);
+        assert(group);
+
+        _cleanup_free_ char *membership = strjoin(user, ":", group, ".membership");
+        if (!membership)
+                return log_oom();
+
+        _cleanup_free_ char *p = path_join("/run/host/userdb/", membership);
+        if (!p)
+                return log_oom();
+
+        _cleanup_close_ int fd = chase_and_open(
+                        p,
+                        root,
+                        CHASE_PREFIX_ROOT|CHASE_NO_AUTOFS,
+                        O_WRONLY|O_CREAT|O_CLOEXEC,
+                        /* ret_path= */ NULL);
+        if (fd < 0)
+                return log_error_errno(errno, "Failed to create %s: %m", p);
+
+        r = userns_chown_at(fd, /* fname= */ NULL, /* uid= */ 0, /* gid= */ 0, /* flags= */ 0);
+        if (r < 0)
+                return log_error_errno(r, "Failed to adjust access mode of '%s': %m", p);
+
+        r = loop_write(fd, "{}\n", SIZE_MAX);
+        if (r < 0)
+                return log_error_errno(r, "Failed to write empty JSON object into %s: %m", p);
+
+        return 0;
+}
+
 int bind_user_setup(const MachineBindUserContext *c, const char *root) {
         static const UserRecordLoadFlags strip_flags = /* Removes privileged info */
                 USER_RECORD_LOAD_MASK_PRIVILEGED|
@@ -130,6 +168,12 @@ int bind_user_setup(const MachineBindUserContext *c, const char *root) {
                 if (r < 0)
                         return r;
 
+                STRV_FOREACH(u, stripped_group->members) {
+                        r = write_membership(root, *u, stripped_group->group_name);
+                        if (r < 0)
+                                return r;
+                }
+
                 /* Third, write out user shadow data. i.e. extract privileged info from user record */
                 r = user_record_clone(d->payload_user, shadow_flags, &shadow_user);
                 if (r < 0)
@@ -161,6 +205,12 @@ int bind_user_setup(const MachineBindUserContext *c, const char *root) {
                                 0);
                 if (r < 0)
                         return r;
+
+                STRV_FOREACH(g, stripped_user->member_of) {
+                        r = write_membership(root, stripped_user->user_name, *g);
+                        if (r < 0)
+                                return r;
+                }
         }
 
         return 1;
index 88d2346d0099c4c5b7a4a7da288acc0c40cbd6a6..814895b7818f630895f4cdeae2ad8a82a000c1b7 100644 (file)
@@ -1733,7 +1733,7 @@ static int in_child_chown(void) {
         return IN_SET(arg_userns_mode, USER_NAMESPACE_PICK, USER_NAMESPACE_FIXED);
 }
 
-static int userns_chown_at(int fd, const char *fname, uid_t uid, gid_t gid, int flags) {
+int userns_chown_at(int fd, const char *fname, uid_t uid, gid_t gid, int flags) {
         assert(fd >= 0 || fd == AT_FDCWD);
 
         if (!in_child_chown())
@@ -1756,6 +1756,9 @@ static int userns_chown_at(int fd, const char *fname, uid_t uid, gid_t gid, int
                         return -EOVERFLOW;
         }
 
+        if (isempty(fname))
+                flags |= AT_EMPTY_PATH;
+
         return RET_NERRNO(fchownat(fd, strempty(fname), uid, gid, flags));
 }
 
index 943b22db2d4d3dad465e5380e4eece4d7ed8329e..192110c4d4233d9a36c90e2f3bf2093abc96254e 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "shared-forward.h"
 
+int userns_chown_at(int fd, const char *fname, uid_t uid, gid_t gid, int flags);
 int userns_lchown(const char *p, uid_t uid, gid_t gid);
 int userns_mkdir(const char *root, const char *path, mode_t mode, uid_t uid, gid_t gid);
 int make_run_host(const char *root);