fixed-spawners #36
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)]
|
||||||
|
75
src/void.rs
75
src/void.rs
@ -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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user