summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2021-10-11 22:42:39 +0200
committerMatthias Schiffer <mschiffer@universe-factory.net>2021-10-11 22:42:39 +0200
commit818bea32074136d787fe4edaa5472543604bb727 (patch)
tree303ef844adb2fc13ef0aa5336bb9894b08ab6eb6
parente8796f338b921cf2aba7a73bc946c556791177e3 (diff)
downloadrebel-818bea32074136d787fe4edaa5472543604bb727.tar
rebel-818bea32074136d787fe4edaa5472543604bb727.zip
Map single UID/GID, not full subid mapping
-rw-r--r--Cargo.lock11
-rw-r--r--Cargo.toml1
-rw-r--r--src/main.rs1
-rw-r--r--src/runner/container/mod.rs42
-rw-r--r--src/unshare.rs128
5 files changed, 18 insertions, 165 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 35d4077..f6bb6ee 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -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"
diff --git a/Cargo.toml b/Cargo.toml
index 3b982d1..100cfc0 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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(())
-}