Skip to content

Commit

Permalink
Support containers launched with user namespace
Browse files Browse the repository at this point in the history
  • Loading branch information
nbdd0121 committed Oct 3, 2024
1 parent 0af2316 commit c6b8b21
Showing 1 changed file with 32 additions and 1 deletion.
33 changes: 32 additions & 1 deletion src/util/namespace.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use std::fs::File;
use std::os::fd::AsFd;
use std::os::unix::fs::MetadataExt;

use anyhow::Result;
use rustix::fs::{Gid, Uid};
use rustix::process::Pid;
use rustix::thread::{LinkNameSpaceType, UnshareFlags};
use rustix::thread::{CapabilitiesSecureBits, LinkNameSpaceType, UnshareFlags};

pub struct MntNamespace {
fd: File,
Expand Down Expand Up @@ -33,6 +35,35 @@ impl MntNamespace {
self.fd.as_fd(),
Some(LinkNameSpaceType::Mount),
)?;

// If user namespace is used, we must act like the root user *inside*
// namespace to be able to create files properly (otherwise EOVERFLOW
// will be returned when creating file).
//
// Entering the user namespace turns out to be problematic.
// The reason seems to be this line [1]:
// which means `CAP_MKNOD` capability of the *init* namespace is needed.
// However task's associated security context is all relative to its current
// user namespace [2], so once you enter a user namespace there's no way of getting
// back `CAP_MKNOD` of the init namespace anymore.
// (Yes this means that even if CAP_MKNOD is granted to the container, you canot
// create device nodes within it.)
//
// https://elixir.bootlin.com/linux/v6.11.1/source/fs/namei.c#L4073
// https://elixir.bootlin.com/linux/v6.11.1/source/include/linux/cred.h#L111
let metadata = std::fs::metadata("/")?;
let uid = metadata.uid();
let gid = metadata.gid();

// By default `setuid` will drop capabilities when transitioning from root
// to non-root user. This bit prevents it so our code still have superpower.
rustix::thread::set_capabilities_secure_bits(
CapabilitiesSecureBits::NO_SETUID_FIXUP,
)?;

rustix::thread::set_thread_uid(unsafe { Uid::from_raw(uid) })?;
rustix::thread::set_thread_gid(unsafe { Gid::from_raw(gid) })?;

Ok(f())
})
.join()
Expand Down

0 comments on commit c6b8b21

Please sign in to comment.