diff --git a/src/child.rs b/src/child.rs index 3df6afb..62087a9 100644 --- a/src/child.rs +++ b/src/child.rs @@ -15,7 +15,7 @@ use std::ffi::CString; const STACK_SIZE: usize = 1024 * 1024; fn setup_container_configurations(config: &ContainerOpts) -> Result<(), Errcode> { set_container_hostname(&config.hostname)?; - setmountpoint(&config.mount_dir)?; + setmountpoint(&config.mount_dir, &config.addpaths)?; userns(config.fd, config.uid)?; setcapabilities()?; setsyscalls()?; diff --git a/src/cli.rs b/src/cli.rs index 5ab2c0d..893d47b 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -22,6 +22,10 @@ pub struct Args { /// Directory to mount as root of the container #[structopt(parse(from_os_str), short = "m", long = "mount")] pub mount_dir: PathBuf, + + /// Mount a directory inside the container + #[structopt(parse(from_os_str), short = "a", long = "add")] + pub addpaths: Vec, } pub fn parse_args() -> Result { diff --git a/src/config.rs b/src/config.rs index c80bf1a..5ad9ff5 100644 --- a/src/config.rs +++ b/src/config.rs @@ -14,22 +14,23 @@ pub struct ContainerOpts{ pub fd: RawFd, pub uid: u32, pub mount_dir: PathBuf, + pub addpaths: Vec<(PathBuf, PathBuf)>, } impl ContainerOpts{ - pub fn new(command: String, uid: u32, mount_dir: PathBuf) + pub fn new(command: String, uid: u32, mount_dir: PathBuf, addpaths: Vec<(PathBuf, PathBuf)>) -> Result<(ContainerOpts, (RawFd, RawFd)), Errcode> { let sockets = generate_socketpair()?; let argv: Vec = command.split_ascii_whitespace() .map(|s| CString::new(s).expect("Cannot read arg")).collect(); let path = argv[0].clone(); - Ok(( ContainerOpts { path, argv, uid, + addpaths, mount_dir, hostname: generate_hostname()?, fd: sockets.1.clone(), diff --git a/src/container.rs b/src/container.rs index 6f88fab..034fb08 100644 --- a/src/container.rs +++ b/src/container.rs @@ -12,6 +12,7 @@ use nix::sys::wait::waitpid; use nix::sys::utsname::uname; use std::os::unix::io::RawFd; +use std::path::PathBuf; pub struct Container{ sockets: (RawFd, RawFd), @@ -21,10 +22,22 @@ pub struct Container{ impl Container { pub fn new(args: Args) -> Result { + let mut addpaths = vec![]; + for ap_pair in args.addpaths.iter(){ + let mut pair = ap_pair.to_str().unwrap().split(":"); + let frompath = PathBuf::from(pair.next().unwrap()) + .canonicalize().expect("Cannot canonicalize path") + .to_path_buf(); + let mntpath = PathBuf::from(pair.next().unwrap()) + .strip_prefix("/").expect("Cannot strip prefix from path") + .to_path_buf(); + addpaths.push((frompath, mntpath)); + } let (config, sockets) = ContainerOpts::new( args.command, args.uid, - args.mount_dir)?; + args.mount_dir, + addpaths)?; Ok(Container { sockets, diff --git a/src/mounts.rs b/src/mounts.rs index fc51eac..64bd89d 100644 --- a/src/mounts.rs +++ b/src/mounts.rs @@ -74,7 +74,7 @@ pub fn mount_directory(path: Option<&PathBuf>, mount_point: &PathBuf, flags: Vec use std::fs::remove_dir; use nix::unistd::{pivot_root, chdir}; use nix::mount::{mount, MsFlags, umount2, MntFlags}; -pub fn setmountpoint(mount_dir: &PathBuf) -> Result<(), Errcode> { +pub fn setmountpoint(mount_dir: &PathBuf, addpaths: &Vec<(PathBuf, PathBuf)>) -> Result<(), Errcode> { log::debug!("Setting mount points ..."); mount_directory(None, &PathBuf::from("/"), vec![MsFlags::MS_REC, MsFlags::MS_PRIVATE])?; @@ -83,6 +83,13 @@ pub fn setmountpoint(mount_dir: &PathBuf) -> Result<(), Errcode> { create_directory(&new_root)?; mount_directory(Some(&mount_dir), &new_root, vec![MsFlags::MS_BIND, MsFlags::MS_PRIVATE])?; + log::debug!("Mounting additionnal paths"); + for (inpath, mntpath) in addpaths.iter(){ + let outpath = new_root.join(mntpath); + create_directory(&outpath)?; + mount_directory(Some(inpath), &outpath, vec![MsFlags::MS_PRIVATE, MsFlags::MS_BIND])?; + } + log::debug!("Pivoting root"); let old_root_tail = format!("oldroot.{}", random_string(6)); let put_old = new_root.join(PathBuf::from(old_root_tail.clone())); diff --git a/test.sh b/test.sh index 2367598..e9071d1 100755 --- a/test.sh +++ b/test.sh @@ -3,10 +3,7 @@ set -e mkdir -p mountdir -cd testbin -RUSTFLAGS="-C target-feature=+crt-static" cargo build --release --target="x86_64-unknown-linux-gnu" -cp target/x86_64-unknown-linux-gnu/release/testbin ../mountdir/ -cd .. cargo build +cp /bin/bash ./mountdir/ clear -sudo ./target/debug/crabcan --debug -u 0 -m ./mountdir/ -c "/testbin" +sudo ./target/debug/crabcan --debug -u 0 -m ./mountdir/ -c "/bash" -a /lib64:/lib64 -a /lib:/lib diff --git a/testbin/.gitignore b/testbin/.gitignore deleted file mode 100644 index eb5a316..0000000 --- a/testbin/.gitignore +++ /dev/null @@ -1 +0,0 @@ -target diff --git a/testbin/Cargo.toml b/testbin/Cargo.toml deleted file mode 100644 index 50909fd..0000000 --- a/testbin/Cargo.toml +++ /dev/null @@ -1,4 +0,0 @@ -[package] -name = "testbin" -version = "0.1.0" -edition = "2021" diff --git a/testbin/src/main.rs b/testbin/src/main.rs deleted file mode 100644 index e7a11a9..0000000 --- a/testbin/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello, world!"); -}