From: Lennart Poettering Date: Thu, 27 Nov 2025 07:59:17 +0000 (+0100) Subject: exec-invoke: handle PRIVATE_USERS_SELF cases together X-Git-Tag: v260-rc1~318^2~1 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=c28aeab184a46a218dbe1fee55002a2d58f03b7e;p=thirdparty%2Fsystemd.git exec-invoke: handle PRIVATE_USERS_SELF cases together And moving things to a switch/case sttement. --- diff --git a/src/core/exec-invoke.c b/src/core/exec-invoke.c index b35f3fbf97e..6edc37dc459 100644 --- a/src/core/exec-invoke.c +++ b/src/core/exec-invoke.c @@ -2394,7 +2394,14 @@ static int setup_private_users_child(int unshare_ready_fd, const char *uid_map, return 0; } -static int setup_private_users(PrivateUsers private_users, uid_t ouid, gid_t ogid, uid_t uid, gid_t gid, bool allow_setgroups) { +static int setup_private_users( + PrivateUsers private_users, + uid_t ouid, + gid_t ogid, + uid_t uid, + gid_t gid, + bool allow_setgroups) { + _cleanup_free_ char *uid_map = NULL, *gid_map = NULL; _cleanup_close_pair_ int errno_pipe[2] = EBADF_PAIR; _cleanup_close_ int unshare_ready_fd = -EBADF; @@ -2413,63 +2420,80 @@ static int setup_private_users(PrivateUsers private_users, uid_t ouid, gid_t ogi * For unprivileged users (i.e. without capabilities), the root to root mapping is excluded. As such, it * does not need CAP_SETUID to write the single line mapping to itself. */ - if (private_users == PRIVATE_USERS_NO) - return 0; + switch (private_users) { /* Prepare the UID mappings */ + + case PRIVATE_USERS_NO: + return 0; /* Early exit */ - if (private_users == PRIVATE_USERS_IDENTITY) { + case PRIVATE_USERS_IDENTITY: uid_map = strdup("0 0 65536\n"); if (!uid_map) return -ENOMEM; - } else if (private_users == PRIVATE_USERS_FULL) { + break; + + case PRIVATE_USERS_FULL: /* Map all UID/GID from original to new user namespace. * * Note the kernel defines the UID range between 0 and UINT32_MAX so we map all UIDs even though * the UID range beyond INT32_MAX (e.g. i.e. the range above the signed 32-bit range) is * icky. For example, setfsuid() returns the old UID as signed integer. But units can decide to * use these UIDs/GIDs so we need to map them. */ - r = asprintf(&uid_map, "0 0 " UID_FMT "\n", (uid_t) UINT32_MAX); - if (r < 0) + if (asprintf(&uid_map, "0 0 " UID_FMT "\n", (uid_t) UINT32_MAX) < 0) return -ENOMEM; - /* Can only set up multiple mappings with CAP_SETUID. */ - } else if (have_effective_cap(CAP_SETUID) > 0 && uid != ouid && uid_is_valid(uid)) { - r = asprintf(&uid_map, - UID_FMT " " UID_FMT " 1\n" /* Map $OUID → $OUID */ - UID_FMT " " UID_FMT " 1\n", /* Map $UID → $UID */ - ouid, ouid, uid, uid); - if (r < 0) - return -ENOMEM; - } else { - r = asprintf(&uid_map, - UID_FMT " " UID_FMT " 1\n", /* Map $OUID → $OUID */ - ouid, ouid); + break; + + case PRIVATE_USERS_SELF: + /* Can only set up multiple mappings with CAP_SETUID. */ + if (uid_is_valid(uid) && uid != ouid && have_effective_cap(CAP_SETUID) > 0) + r = asprintf(&uid_map, + UID_FMT " " UID_FMT " 1\n" /* Map $OUID → $OUID */ + UID_FMT " " UID_FMT " 1\n", /* Map $UID → $UID */ + ouid, ouid, uid, uid); + else + r = asprintf(&uid_map, + UID_FMT " " UID_FMT " 1\n", /* Map $OUID → $OUID */ + ouid, ouid); if (r < 0) return -ENOMEM; + + break; + + default: + assert_not_reached(); } - if (private_users == PRIVATE_USERS_IDENTITY) { + switch (private_users) { /* Prepare the GID mappings */ + + case PRIVATE_USERS_IDENTITY: gid_map = strdup("0 0 65536\n"); if (!gid_map) return -ENOMEM; - } else if (private_users == PRIVATE_USERS_FULL) { - r = asprintf(&gid_map, "0 0 " GID_FMT "\n", (gid_t) UINT32_MAX); - if (r < 0) - return -ENOMEM; + break; - /* Can only set up multiple mappings with CAP_SETGID. */ - } else if (have_effective_cap(CAP_SETGID) > 0 && gid != ogid && gid_is_valid(gid)) { - r = asprintf(&gid_map, - GID_FMT " " GID_FMT " 1\n" /* Map $OGID → $OGID */ - GID_FMT " " GID_FMT " 1\n", /* Map $GID → $GID */ - ogid, ogid, gid, gid); - if (r < 0) + case PRIVATE_USERS_FULL: + if (asprintf(&gid_map, "0 0 " GID_FMT "\n", (gid_t) UINT32_MAX) < 0) return -ENOMEM; - } else { - r = asprintf(&gid_map, - GID_FMT " " GID_FMT " 1\n", /* Map $OGID -> $OGID */ - ogid, ogid); + + break; + + case PRIVATE_USERS_SELF: + /* Can only set up multiple mappings with CAP_SETGID. */ + if (gid_is_valid(gid) && gid != ogid && have_effective_cap(CAP_SETGID) > 0) + r = asprintf(&gid_map, + GID_FMT " " GID_FMT " 1\n" /* Map $OGID → $OGID */ + GID_FMT " " GID_FMT " 1\n", /* Map $GID → $GID */ + ogid, ogid, gid, gid); + else + r = asprintf(&gid_map, + GID_FMT " " GID_FMT " 1\n", /* Map $OGID -> $OGID */ + ogid, ogid); if (r < 0) return -ENOMEM; + break; + + default: + assert_not_reached(); } /* Create a communication channel so that the parent can tell the child when it finished creating the user