From 8b5e3be88eeb1bdba50c87cb24d9e6b31e825f38 Mon Sep 17 00:00:00 2001 From: Michal Sekletar Date: Fri, 7 Feb 2025 20:18:49 +0100 Subject: [PATCH] basic/namespace-util: obtain uid and gid before unsharing user namespace Getting user and group after unsharing user namespace is too late because without any mapping, i.e. just after unshare(), we are mapped to nobody. --- src/basic/namespace-util.c | 9 +++++++-- src/test/test-namespace.c | 26 ++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/basic/namespace-util.c b/src/basic/namespace-util.c index a026ae7d05..e110001716 100644 --- a/src/basic/namespace-util.c +++ b/src/basic/namespace-util.c @@ -412,6 +412,8 @@ int detach_mount_namespace(void) { } int detach_mount_namespace_harder(uid_t target_uid, gid_t target_gid) { + uid_t from_uid; + gid_t from_gid; int r; /* Tried detach_mount_namespace() first. If that doesn't work due to permissions, opens up an @@ -439,11 +441,14 @@ int detach_mount_namespace_harder(uid_t target_uid, gid_t target_gid) { if (r != -EPERM) return r; + from_uid = getuid(); + from_gid = getgid(); + if (unshare(CLONE_NEWUSER) < 0) return log_debug_errno(errno, "Failed to acquire user namespace: %m"); r = write_string_filef("/proc/self/uid_map", 0, - UID_FMT " " UID_FMT " 1\n", target_uid, getuid()); + UID_FMT " " UID_FMT " 1\n", target_uid, from_uid); if (r < 0) return log_debug_errno(r, "Failed to write uid map: %m"); @@ -452,7 +457,7 @@ int detach_mount_namespace_harder(uid_t target_uid, gid_t target_gid) { return log_debug_errno(r, "Failed to write setgroups file: %m"); r = write_string_filef("/proc/self/gid_map", 0, - GID_FMT " " GID_FMT " 1\n", target_gid, getgid()); + GID_FMT " " GID_FMT " 1\n", target_gid, from_gid); if (r < 0) return log_debug_errno(r, "Failed to write gid map: %m"); diff --git a/src/test/test-namespace.c b/src/test/test-namespace.c index 52049efdb8..9d30b08c5e 100644 --- a/src/test/test-namespace.c +++ b/src/test/test-namespace.c @@ -414,6 +414,32 @@ TEST(namespace_get_leader) { } } +TEST(detach_mount_namespace_harder) { + _cleanup_(pidref_done) PidRef pid = PIDREF_NULL; + _cleanup_close_pair_ int p[2] = EBADF_PAIR; + char x = 0; + int r; + + ASSERT_OK_ERRNO(pipe2(p, O_CLOEXEC)); + + ASSERT_OK(r = pidref_safe_fork("(child)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGKILL|FORK_LOG, &pid)); + if (r == 0) { + p[0] = safe_close(p[0]); + + ASSERT_OK(detach_mount_namespace_harder(0, 0)); + + ASSERT_OK_EQ_ERRNO(write(p[1], &(const char[]) { 'x' }, 1), 1); + freeze(); + } + + p[1] = safe_close(p[1]); + ASSERT_OK_EQ_ERRNO(read(p[0], &x, 1), 1); + ASSERT_EQ(x, 'x'); + + ASSERT_OK_POSITIVE(pidref_in_same_namespace(NULL, &pid, NAMESPACE_USER)); + ASSERT_OK_ZERO(pidref_in_same_namespace(NULL, &pid, NAMESPACE_MOUNT)); +} + static int intro(void) { if (!have_namespaces()) return log_tests_skipped("Don't have namespace support or lacking privileges");