diff options
author | Matthias Schiffer <mschiffer@universe-factory.net> | 2021-10-11 22:42:39 +0200 |
---|---|---|
committer | Matthias Schiffer <mschiffer@universe-factory.net> | 2021-10-11 22:42:39 +0200 |
commit | 818bea32074136d787fe4edaa5472543604bb727 (patch) | |
tree | 303ef844adb2fc13ef0aa5336bb9894b08ab6eb6 | |
parent | e8796f338b921cf2aba7a73bc946c556791177e3 (diff) | |
download | rebel-818bea32074136d787fe4edaa5472543604bb727.tar rebel-818bea32074136d787fe4edaa5472543604bb727.zip |
Map single UID/GID, not full subid mapping
-rw-r--r-- | Cargo.lock | 11 | ||||
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | src/main.rs | 1 | ||||
-rw-r--r-- | src/runner/container/mod.rs | 42 | ||||
-rw-r--r-- | src/unshare.rs | 128 |
5 files changed, 18 insertions, 165 deletions
@@ -838,7 +838,6 @@ dependencies = [ "serde_yaml", "tar", "tee_readwrite", - "users", "walkdir", ] @@ -1117,16 +1116,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f14ee04d9415b52b3aeab06258a3f07093182b88ba0f9b8d203f211a7a7d41c7" [[package]] -name = "users" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24cc0f6d6f267b73e5a2cadf007ba8f9bc39c6a6f9666f8cf25ea809a153b032" -dependencies = [ - "libc", - "log", -] - -[[package]] name = "uuid" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -27,7 +27,6 @@ serde_json = "1.0.62" serde_yaml = "0.8" tar = "0.4.32" tee_readwrite = "0.1.0" -users = "0.11.0" walkdir = "2" [profile.dev.package."*"] diff --git a/src/main.rs b/src/main.rs index e36b743..9483702 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,7 +8,6 @@ mod runner; mod task; mod template; mod types; -mod unshare; mod util; use clap::Clap; diff --git a/src/runner/container/mod.rs b/src/runner/container/mod.rs index dbfa929..1c4c748 100644 --- a/src/runner/container/mod.rs +++ b/src/runner/container/mod.rs @@ -9,26 +9,28 @@ use ipc_channel::ipc; use nix::{ sched::CloneFlags, sys::{signal, stat}, - unistd, + unistd::{self, Gid, Uid}, }; use serde::{Deserialize, Serialize}; use crate::{ - runner, unshare, - util::{clone, error::*, ipc::CheckDisconnect}, + runner, + util::{clone, error::*}, }; #[derive(Debug, Deserialize, Serialize)] struct Request(runner::Task, ipc::IpcSender<Result<runner::TaskOutput>>); -fn runner(idmap_finished: ipc::IpcReceiver<()>, channel: ipc::IpcReceiver<Request>) -> ! { - idmap_finished - .recv() - .check_disconnect() - .expect("IPC recv() error") - .expect("Unexpected IPC message"); +fn setup_userns(uid: Uid, gid: Gid) { + std::fs::write("/proc/self/setgroups", "deny").expect("Failed to write /proc/self/setgroups"); + std::fs::write("/proc/self/uid_map", &format!("0 {} 1", uid)) + .expect("Failed to write /proc/self/uid_map"); + std::fs::write("/proc/self/gid_map", &format!("0 {} 1", gid)) + .expect("Failed to write /proc/self/gid_map"); +} - unistd::setgroups(&[]).expect("setgroups()"); +fn runner(uid: Uid, gid: Gid, channel: ipc::IpcReceiver<Request>) -> ! { + setup_userns(uid, gid); stat::umask(stat::Mode::from_bits_truncate(0o022)); @@ -65,30 +67,22 @@ impl ContainerRunner { pub unsafe fn new() -> Result<Self> { init::preinit_runner()?; + let uid = unistd::geteuid(); + let gid = unistd::getegid(); + let (tx, rx) = ipc::channel().expect("IPC channel creation failed"); - let (idmap_finished_tx, idmap_finished_rx) = - ipc::channel().expect("IPC channel creation failed"); - let pid = match clone::clone(CloneFlags::CLONE_NEWUSER | CloneFlags::CLONE_NEWNS) - .expect("clone()") - { - unistd::ForkResult::Parent { child } => { + match clone::clone(CloneFlags::CLONE_NEWUSER | CloneFlags::CLONE_NEWNS).expect("clone()") { + unistd::ForkResult::Parent { .. } => { drop(rx); - drop(idmap_finished_rx); - child } unistd::ForkResult::Child => { drop(tx); - drop(idmap_finished_tx); - runner(idmap_finished_rx, rx); + runner(uid, gid, rx); /* Not reached */ } }; - unshare::idmap(pid)?; - - drop(idmap_finished_tx); - Ok(ContainerRunner { channel: tx }) } } diff --git a/src/unshare.rs b/src/unshare.rs deleted file mode 100644 index 6264294..0000000 --- a/src/unshare.rs +++ /dev/null @@ -1,128 +0,0 @@ -use std::{ - ffi::{OsStr, OsString}, - fs::File, - io::{self, BufRead, Result}, - os::unix::ffi::*, - path::Path, - process, -}; - -use nix::unistd; - -use crate::util::Checkable; - -type ID = u32; - -#[derive(Debug, Eq, Ord, PartialEq, PartialOrd)] -struct SubIDRange { - start: ID, - count: ID, -} - -fn parse_uid(s: &OsStr) -> Option<ID> { - s.to_str().and_then(|s| s.parse().ok()) -} - -fn parse_id_range(line: Vec<u8>, uid: &OsStr, username: Option<&OsStr>) -> Option<SubIDRange> { - let parts: Vec<_> = line.split(|c| *c == b':').map(OsStr::from_bytes).collect(); - if parts.len() != 3 { - return None; - } - if parts[0] != uid && Some(parts[0]) != username { - return None; - } - - let start = parse_uid(parts[1])?; - let count = parse_uid(parts[2])?; - - Some(SubIDRange { start, count }) -} - -fn read_id_ranges<P: AsRef<Path>>(filename: P) -> Result<Vec<SubIDRange>> { - let uid = users::get_effective_uid(); - let username = users::get_user_by_uid(uid).map(|user| user.name().to_os_string()); - - let uidstr = OsString::from(uid.to_string()); - let usernamestr = username.as_deref(); - - let file = File::open(filename)?; - let lines = io::BufReader::new(file).split(b'\n'); - - lines - .map(|line| Ok(parse_id_range(line?, &uidstr, usernamestr))) - .filter_map(Result::transpose) - .collect() -} - -#[derive(Debug)] -struct SubIDMap { - lower: ID, - upper: ID, - count: ID, -} - -fn generate_idmap(id: ID, mapped_id: ID, mut ranges: Vec<SubIDRange>) -> Vec<SubIDMap> { - let mut map = vec![SubIDMap { - lower: mapped_id, - upper: id, - count: 1, - }]; - - let mut add_map = |lower, upper, count| { - if count > 0 { - map.push(SubIDMap { - lower, - upper, - count, - }); - } - count - }; - - let mut lower = 0; - - ranges.sort(); - for range in &ranges { - if mapped_id >= lower && mapped_id < lower + range.count { - let offset = mapped_id - lower; - lower += add_map(lower, range.start, offset) + 1; - lower += add_map(lower, range.start + offset, range.count - offset); - } else { - lower += add_map(lower, range.start, range.count); - } - } - - map -} - -fn get_uid_map() -> Result<Vec<SubIDMap>> { - let uid = users::get_effective_uid(); - let uid_ranges = read_id_ranges("/etc/subuid")?; - Ok(generate_idmap(uid, 0, uid_ranges)) -} - -fn get_gid_map() -> Result<Vec<SubIDMap>> { - let gid = users::get_effective_gid(); - let gid_ranges = read_id_ranges("/etc/subgid")?; - Ok(generate_idmap(gid, 0, gid_ranges)) -} - -fn run_idmap_cmd(cmd: &str, pid: &str, map: &[SubIDMap]) -> Result<()> { - let mut builder = process::Command::new(cmd); - builder.arg(pid); - for uids in map { - builder.arg(uids.lower.to_string()); - builder.arg(uids.upper.to_string()); - builder.arg(uids.count.to_string()); - } - builder.status().and_then(|status| status.check()) -} - -pub fn idmap(pid: unistd::Pid) -> Result<()> { - let pid_string = pid.to_string(); - - run_idmap_cmd("newuidmap", pid_string.as_str(), &get_uid_map()?)?; - run_idmap_cmd("newgidmap", pid_string.as_str(), &get_gid_map()?)?; - - Ok(()) -} |