namespace-util: introduce userns_acquire_self_root()

This is a simple helper for creating a userns that just maps the
callers user to UID 0 in the namespace. This can be acquired unpriv,
which makes it useful for various purposes, for example for the logic in
is_idmapping_supported(), hence port it over.

(is_idmapping_supported() used a different mapping before, with the
nobody users, but there's no real reason for that, and we'll use
userns_acquire_self_root() elsewhere soon, where the root mapping is
important).
This commit is contained in:
Lennart Poettering
2025-03-10 11:30:11 +01:00
parent 6431c34b8a
commit 783b40bd73
2 changed files with 17 additions and 10 deletions

View File

@@ -561,6 +561,21 @@ int userns_acquire(const char *uid_map, const char *gid_map, bool setgroups_deny
return pidref_namespace_open_by_type(&pid, NAMESPACE_USER);
}
int userns_acquire_self_root(void) {
/* Returns a user namespace with only our own uid/gid mapped to root, and everything else unmapped.
*
* Note: this can be acquired unprivileged! */
_cleanup_free_ char *uid_map = NULL, *gid_map = NULL;
if (asprintf(&uid_map, "0 " UID_FMT " 1", getuid()) < 0)
return -ENOMEM;
if (asprintf(&gid_map, "0 " GID_FMT " 1", getgid()) < 0)
return -ENOMEM;
return userns_acquire(uid_map, gid_map, /* setgroups_deny= */ true);
}
int userns_enter_and_pin(int userns_fd, pid_t *ret_pid) {
_cleanup_close_pair_ int pfd[2] = EBADF_PAIR;
_cleanup_(sigkill_waitp) pid_t pid = 0;
@@ -704,7 +719,6 @@ int process_is_owned_by_uid(const PidRef *pidref, uid_t uid) {
int is_idmapping_supported(const char *path) {
_cleanup_close_ int mount_fd = -EBADF, userns_fd = -EBADF, dir_fd = -EBADF;
_cleanup_free_ char *uid_map = NULL, *gid_map = NULL;
int r;
assert(path);
@@ -712,15 +726,7 @@ int is_idmapping_supported(const char *path) {
if (!mount_new_api_supported())
return false;
r = strextendf(&uid_map, UID_FMT " " UID_FMT " " UID_FMT "\n", UID_NOBODY, UID_NOBODY, 1u);
if (r < 0)
return r;
r = strextendf(&gid_map, GID_FMT " " GID_FMT " " GID_FMT "\n", GID_NOBODY, GID_NOBODY, 1u);
if (r < 0)
return r;
userns_fd = r = userns_acquire(uid_map, gid_map, /* setgroups_deny= */ true);
userns_fd = r = userns_acquire_self_root();
if (ERRNO_IS_NEG_NOT_SUPPORTED(r) || ERRNO_IS_NEG_PRIVILEGE(r) || r == -EINVAL)
return false;
if (r == -ENOSPC) {

View File

@@ -87,6 +87,7 @@ int parse_userns_uid_range(const char *s, uid_t *ret_uid_shift, uid_t *ret_uid_r
int userns_acquire_empty(void);
int userns_acquire(const char *uid_map, const char *gid_map, bool setgroups_deny);
int userns_acquire_self_root(void);
int userns_enter_and_pin(int userns_fd, pid_t *ret_pid);
int userns_get_base_uid(int userns_fd, uid_t *ret_uid, gid_t *ret_gid);