From c511d12a5a9fa0b3888db605b2e0630987295be9 Mon Sep 17 00:00:00 2001 From: Jake Hillion Date: Thu, 7 Apr 2022 21:57:11 +0100 Subject: [PATCH] added mount namespace separation --- README.md | 6 +++-- src/void.rs | 76 ++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 65 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index f8c5cf2..a545446 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,9 @@ The basic example instructs the shim to spawn two processes, each of which write To run this example: + cargo build cargo build --example basic - cargo run -- -s examples/basic/spec.json target/debug/examples/basic + sudo target/debug/clone-shim -s examples/basic/spec.json target/debug/examples/basic ### examples/pipes @@ -17,5 +18,6 @@ The pipes example shows some of the power of the shim by using pipes. The proces To run this example: + cargo build cargo build --example pipes - cargo run -- -s examples/pipes/spec.json target/debug/examples/pipes + sudo target/debug/clone-shim -s examples/pipes/spec.json target/debug/examples/pipes diff --git a/src/void.rs b/src/void.rs index cfee746..1f2712b 100644 --- a/src/void.rs +++ b/src/void.rs @@ -1,3 +1,5 @@ +use log::{debug, error}; + use crate::clone::{clone3, CloneArgs, CloneFlags}; use crate::{Error, Result}; @@ -5,7 +7,8 @@ use std::collections::HashMap; use std::fs; use std::path::PathBuf; -use nix::mount::{mount, umount, MsFlags}; +use nix::mount::{mount, umount2, MntFlags, MsFlags}; +use nix::sched::unshare; use nix::sys::signal::Signal; use nix::unistd::{pivot_root, Pid}; @@ -36,7 +39,6 @@ impl VoidBuilder { | CloneFlags::CLONE_NEWNET | CloneFlags::CLONE_NEWNS | CloneFlags::CLONE_NEWPID - | CloneFlags::CLONE_NEWUSER | CloneFlags::CLONE_NEWUTS, ); args.exit_signal = Some(Signal::SIGCHLD); @@ -47,11 +49,23 @@ impl VoidBuilder { })?; if child == Pid::from_raw(0) { - self.newns_post().unwrap(); + let result = { + self.void_mount_namespace()?; + self.void_user_namespace()?; // last to maintain permissions - std::process::exit(child_fn()) + Ok::<(), Error>(()) + }; + + if let Err(e) = result { + error!("error preparing void: {}", e); + std::process::exit(-1) + } else { + std::process::exit(child_fn()) + } } + debug!("cloned child: {}", child); + // Leak the child function's resources in the parent process. // This avoids closing files that have been "moved" into the child. // It is also an over-approximation, and may cause actual memory leaks. @@ -63,12 +77,26 @@ impl VoidBuilder { } // per-namespace void creation - fn newns_post(&self) -> Result<()> { - // consume the TempDir so it doesn't get deleted - let new_root = tempfile::tempdir()?.into_path(); - + fn void_mount_namespace(&self) -> Result<()> { + // change the propagation type of the old root to private mount( Option::<&str>::None, + "/", + Option::<&str>::None, + MsFlags::MS_PRIVATE, + Option::<&str>::None, + ) + .map_err(|e| Error::Nix { + msg: "mount", + src: e, + })?; + + // create and consume a tmpdir to mount a tmpfs into + let new_root = tempfile::tempdir()?.into_path(); + + // mount a tmpfs as the new root + mount( + Some("tmpfs"), &new_root, Some("tmpfs"), MsFlags::empty(), @@ -79,19 +107,37 @@ impl VoidBuilder { src: e, })?; - // TODO: Mount mounts + // prepare a subdirectory to pivot the old root into + let put_old = new_root.join("old_root/"); + debug!("new_root: {:?}; put_old: {:?}", &new_root, &put_old); + fs::create_dir(&put_old)?; - let old_root = new_root.join("old_root/"); - fs::create_dir(&old_root)?; - - pivot_root(&new_root, &old_root).map_err(|e| Error::Nix { + // pivot the old root into a subdirectory of the new root + pivot_root(&new_root, &put_old).map_err(|e| Error::Nix { msg: "pivot_root", src: e, })?; + + // chdir after std::env::set_current_dir("/")?; - umount("old_root/").map_err(|e| Error::Nix { - msg: "umount", + // TODO: mount requested mounts + + // unmount the old root + umount2("old_root/", MntFlags::MNT_DETACH).map_err(|e| Error::Nix { + msg: "umount2", + src: e, + })?; + + // delete the old root mount point + fs::remove_dir("old_root/")?; + + Ok(()) + } + + fn void_user_namespace(&self) -> Result<()> { + unshare(CloneFlags::CLONE_NEWUSER).map_err(|e| Error::Nix { + msg: "unshare", src: e, })?;