From: Daan De Meyer Date: Thu, 30 Oct 2025 21:20:59 +0000 (+0100) Subject: nspawn-bind-user: Write membership records X-Git-Tag: v259-rc1~209^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b430f2bc94922b313296ef0112ab582b96bdefa4;p=thirdparty%2Fsystemd.git nspawn-bind-user: Write membership records --- diff --git a/src/nspawn/nspawn-bind-user.c b/src/nspawn/nspawn-bind-user.c index d9a06e2c037..0211cfe23c8 100644 --- a/src/nspawn/nspawn-bind-user.c +++ b/src/nspawn/nspawn-bind-user.c @@ -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; diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 88d2346d009..814895b7818 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -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)); } diff --git a/src/nspawn/nspawn.h b/src/nspawn/nspawn.h index 943b22db2d4..192110c4d42 100644 --- a/src/nspawn/nspawn.h +++ b/src/nspawn/nspawn.h @@ -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);