fixed-spawners #36

Merged
JakeHillion merged 2 commits from fixed-spawners into main 2022-05-17 15:56:08 +01:00
3 changed files with 70 additions and 15 deletions

View File

@ -105,6 +105,8 @@ impl<'a> Spawner<'a> {
let pipe = self.pipes.get_mut(s).unwrap().take_read()?; let pipe = self.pipes.get_mut(s).unwrap().take_read()?;
builder.keep_fd(&pipe); builder.keep_fd(&pipe);
builder.mount("/proc", "/proc").remount_proc();
let closure = || match self.pipe_trigger(pipe, entrypoint, name) { let closure = || match self.pipe_trigger(pipe, entrypoint, name) {
Ok(()) => exitcode::OK, Ok(()) => exitcode::OK,
Err(e) => { Err(e) => {
@ -129,6 +131,8 @@ impl<'a> Spawner<'a> {
let socket = self.sockets.get_mut(s).unwrap().take_read()?; let socket = self.sockets.get_mut(s).unwrap().take_read()?;
builder.keep_fd(&socket); builder.keep_fd(&socket);
builder.mount("/proc", "/proc").remount_proc();
let closure = || match self.file_socket_trigger(socket, entrypoint, name) { let closure = || match self.file_socket_trigger(socket, entrypoint, name) {
Ok(()) => exitcode::OK, Ok(()) => exitcode::OK,
Err(e) => { Err(e) => {
@ -327,6 +331,10 @@ impl<'a> Spawner<'a> {
Environment::DomainName(name) => { Environment::DomainName(name) => {
builder.set_domain_name(name); builder.set_domain_name(name);
} }
Environment::Procfs => {
builder.mount("/proc", "/proc").remount_proc();
}
} }
} }
} }

View File

@ -117,6 +117,8 @@ pub enum Environment {
Hostname(String), Hostname(String),
DomainName(String), DomainName(String),
Procfs,
} }
#[derive(Serialize, Deserialize, PartialEq, Eq, Hash, Debug)] #[derive(Serialize, Deserialize, PartialEq, Eq, Hash, Debug)]

View File

@ -1,9 +1,10 @@
use log::{debug, error}; use log::{debug, error, info, trace};
use crate::clone::{clone3, CloneArgs, CloneFlags}; use crate::clone::{clone3, CloneArgs, CloneFlags};
use crate::{Error, Result}; use crate::{Error, Result};
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::env;
use std::fmt; use std::fmt;
use std::fs; use std::fs;
use std::io::Write; use std::io::Write;
@ -33,6 +34,8 @@ pub struct VoidBuilder {
mounts: HashMap<PathBuf, PathBuf>, mounts: HashMap<PathBuf, PathBuf>,
fds: HashSet<RawFd>, fds: HashSet<RawFd>,
remount_proc: bool,
} }
impl VoidBuilder { impl VoidBuilder {
@ -42,6 +45,7 @@ impl VoidBuilder {
domain_name: None, domain_name: None,
mounts: HashMap::new(), mounts: HashMap::new(),
fds: HashSet::new(), fds: HashSet::new(),
remount_proc: false,
} }
} }
@ -65,6 +69,11 @@ impl VoidBuilder {
self self
} }
pub fn remount_proc(&mut self) -> &mut Self {
self.remount_proc = true;
self
}
pub fn spawn(&mut self, child_fn: impl FnOnce() -> i32) -> Result<VoidHandle> { pub fn spawn(&mut self, child_fn: impl FnOnce() -> i32) -> Result<VoidHandle> {
let mut args = CloneArgs::new( let mut args = CloneArgs::new(
CloneFlags::CLONE_NEWCGROUP CloneFlags::CLONE_NEWCGROUP
@ -94,15 +103,23 @@ impl VoidBuilder {
})?; })?;
let result = { let result = {
debug!("voiding user namespace...");
self.void_user_namespace(parent_uid, parent_gid)?; // first to regain full capabilities self.void_user_namespace(parent_uid, parent_gid)?; // first to regain full capabilities
debug!("voiding file descriptors...");
self.void_file_descriptors()?; self.void_file_descriptors()?;
debug!("voiding ipc namespace...");
self.void_ipc_namespace()?; self.void_ipc_namespace()?;
debug!("voiding uts namespace...");
self.void_uts_namespace()?; self.void_uts_namespace()?;
debug!("voiding network namespace...");
self.void_network_namespace()?; self.void_network_namespace()?;
debug!("voiding pid namespace...");
self.void_pid_namespace()?; self.void_pid_namespace()?;
debug!("voiding mount namespace...");
self.void_mount_namespace()?; self.void_mount_namespace()?;
debug!("voiding cgroup namespace...");
self.void_cgroup_namespace()?; self.void_cgroup_namespace()?;
Ok::<(), Error>(()) Ok::<(), Error>(())
@ -112,6 +129,7 @@ impl VoidBuilder {
error!("error preparing void: {}", e); error!("error preparing void: {}", e);
std::process::exit(-1) std::process::exit(-1)
} else { } else {
info!("successfully prepared void");
std::process::exit(child_fn()) std::process::exit(child_fn())
} }
} }
@ -180,7 +198,7 @@ impl VoidBuilder {
* unavailable after unmounting the old root. * unavailable after unmounting the old root.
*/ */
fn void_mount_namespace(&self) -> Result<()> { fn void_mount_namespace(&self) -> Result<()> {
// change the propagation type of the old root to private trace!("changing the propagation type of the old root to private");
mount( mount(
Option::<&str>::None, Option::<&str>::None,
"/", "/",
@ -193,10 +211,21 @@ impl VoidBuilder {
src: e, src: e,
})?; })?;
// create and consume a tmpdir to mount a tmpfs into trace!("creating tmpdir for new root");
let new_root = tempfile::tempdir()?.into_path(); let tmp_base = {
let env_dir = env::temp_dir();
if env_dir.exists() {
env_dir
} else {
debug!("env_dir does not exist, assuming `/` as the base");
"/".into()
}
};
// mount a tmpfs as the new root // consume so it does not attempt to delete a folder which no longer exists
let new_root = tempfile::tempdir_in(tmp_base)?.into_path();
trace!("mounting a new root tmpfs at `{:?}`", &new_root);
mount( mount(
Some("tmpfs"), Some("tmpfs"),
&new_root, &new_root,
@ -209,13 +238,12 @@ impl VoidBuilder {
src: e, src: e,
})?; })?;
// prepare a subdirectory to pivot the old root into let put_old = new_root.join("old_root/");
let old_root = new_root.join("old_root/"); debug!("new_root: {:?}; put_old: {:?}", &new_root, &put_old);
debug!("new_root: {:?}; put_old: {:?}", &new_root, &old_root); fs::create_dir_all(&put_old)?;
fs::create_dir(&old_root)?;
// pivot the old root into a subdirectory of the new root trace!("pivoting old root into a subdirectory of new root");
pivot_root(&new_root, &old_root).map_err(|e| Error::Nix { pivot_root(&new_root, &put_old).map_err(|e| Error::Nix {
msg: "pivot_root", msg: "pivot_root",
src: e, src: e,
})?; })?;
@ -223,10 +251,10 @@ impl VoidBuilder {
let new_root = PathBuf::from("/"); let new_root = PathBuf::from("/");
let old_root = PathBuf::from("/old_root/"); let old_root = PathBuf::from("/old_root/");
// chdir after trace!("changing root directory to new root");
std::env::set_current_dir(&new_root)?; std::env::set_current_dir(&new_root)?;
// mount paths before unmounting old_root trace!("creating bind mounts before unmounting");
for (src, dst) in &self.mounts { for (src, dst) in &self.mounts {
let mut src = old_root.join(src.strip_prefix("/").unwrap_or(src)); let mut src = old_root.join(src.strip_prefix("/").unwrap_or(src));
let dst = new_root.join(dst.strip_prefix("/").unwrap_or(dst)); let dst = new_root.join(dst.strip_prefix("/").unwrap_or(dst));
@ -252,12 +280,29 @@ impl VoidBuilder {
fs::write(&dst, b"")?; fs::write(&dst, b"")?;
} }
// bind mount // rbind mount
mount( mount(
Some(&src), Some(&src),
&dst, &dst,
Option::<&str>::None, Option::<&str>::None,
MsFlags::MS_BIND, MsFlags::MS_BIND | MsFlags::MS_REC,
Option::<&str>::None,
)
.map_err(|e| Error::Nix {
msg: "mount",
src: e,
})?;
}
// remount proc
if self.remount_proc {
debug!("remounting /proc`");
mount(
Some("proc"),
"/proc",
Some("proc"),
MsFlags::empty(),
Option::<&str>::None, Option::<&str>::None,
) )
.map_err(|e| Error::Nix { .map_err(|e| Error::Nix {