use super::{run_capped, Backend, RunSpec, Sandbox, SandboxOutcome};
use crate::error::Result;
pub struct LinuxSandbox;
impl Sandbox for LinuxSandbox {
async fn run(&self, spec: RunSpec<'_>) -> Result<SandboxOutcome> {
let wrapped = unshare_argv(spec.argv, spec.allow_network);
let wspec = RunSpec {
argv: &wrapped,
workdir: spec.workdir,
limits: spec.limits,
allow_network: spec.allow_network,
};
run_capped(Backend::LinuxNamespaces, wspec, |_cmd| {}).await
}
fn backend(&self) -> Backend {
Backend::LinuxNamespaces
}
}
pub(crate) fn unshare_argv(inner: &[String], allow_network: bool) -> Vec<String> {
let mut v: Vec<String> = vec![
"unshare".into(),
"--user".into(),
"--map-root-user".into(),
"--mount".into(),
"--pid".into(),
"--fork".into(),
];
if !allow_network {
v.push("--net".into());
}
v.push("--".into());
v.extend(inner.iter().cloned());
v
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn denies_network_with_a_new_net_namespace() {
let argv = unshare_argv(&["echo".into(), "hi".into()], false);
assert!(argv.contains(&"--net".into()), "net namespace must isolate network by default");
assert!(argv.windows(2).any(|w| w == ["--".to_string(), "echo".to_string()]));
}
#[test]
fn allows_network_when_asked() {
let argv = unshare_argv(&["echo".into()], true);
assert!(!argv.contains(&"--net".into()), "no net namespace when network is allowed");
}
}