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.
This commit is contained in:
Michal Sekletar
2025-02-07 20:18:49 +01:00
committed by Yu Watanabe
parent 278d5bfd7e
commit 8b5e3be88e
2 changed files with 33 additions and 2 deletions

View File

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

View File

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