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");