Skip to content

Commit 80e94a2

Browse files
committed
Support containers launched with user namespace
1 parent 75e472d commit 80e94a2

File tree

1 file changed

+32
-1
lines changed

1 file changed

+32
-1
lines changed

src/util/namespace.rs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
use std::fs::File;
22
use std::os::fd::AsFd;
3+
use std::os::unix::fs::MetadataExt;
34

45
use anyhow::Result;
6+
use rustix::fs::{Gid, Uid};
57
use rustix::process::Pid;
6-
use rustix::thread::{LinkNameSpaceType, UnshareFlags};
8+
use rustix::thread::{CapabilitiesSecureBits, LinkNameSpaceType, UnshareFlags};
79

810
pub struct Namespace {
911
mnt_fd: File,
@@ -32,6 +34,35 @@ impl Namespace {
3234
self.mnt_fd.as_fd(),
3335
Some(LinkNameSpaceType::Mount),
3436
)?;
37+
38+
// If user namespace is used, we must act like the root user *inside*
39+
// namespace to be able to create files properly (otherwise EOVERFLOW
40+
// will be returned when creating file).
41+
//
42+
// Entering the user namespace turns out to be problematic.
43+
// The reason seems to be this line [1]:
44+
// which means `CAP_MKNOD` capability of the *init* namespace is needed.
45+
// However task's associated security context is all relative to its current
46+
// user namespace [2], so once you enter a user namespace there's no way of getting
47+
// back `CAP_MKNOD` of the init namespace anymore.
48+
// (Yes this means that even if CAP_MKNOD is granted to the container, you canot
49+
// create device nodes within it.)
50+
//
51+
// https://elixir.bootlin.com/linux/v6.11.1/source/fs/namei.c#L4073
52+
// https://elixir.bootlin.com/linux/v6.11.1/source/include/linux/cred.h#L111
53+
let metadata = std::fs::metadata("/")?;
54+
let uid = metadata.uid();
55+
let gid = metadata.gid();
56+
57+
// By default `setuid` will drop capabilities when transitioning from root
58+
// to non-root user. This bit prevents it so our code still have superpower.
59+
rustix::thread::set_capabilities_secure_bits(
60+
CapabilitiesSecureBits::NO_SETUID_FIXUP,
61+
)?;
62+
63+
rustix::thread::set_thread_uid(unsafe { Uid::from_raw(uid) })?;
64+
rustix::thread::set_thread_gid(unsafe { Gid::from_raw(gid) })?;
65+
3566
Ok(f()?)
3667
})
3768
.join()

0 commit comments

Comments
 (0)