use std::ffi::{OsStr, OsString}; use std::path::{Path, PathBuf}; use std::time::Duration; use ia_sandbox::config::{ Aslr, ClearUsage, Config, Environment, Interactive, Limits, Mount, ShareNet, SpaceUsage, SwapRedirects, }; use ia_sandbox::run_info::RunInfo; use ia_sandbox::{self, JailHandle, Result}; const CGROUPS_DEFAULT_PATH: &str = "/sys/fs/cgroup/ia-sandbox"; pub struct ConfigBuilder { command: PathBuf, args: Vec, new_root: Option, share_net: bool, redirect_stdin: Option, redirect_stdout: Option, redirect_stderr: Option, limits: Option, instance_name: OsString, mounts: Vec, swap_redirects: SwapRedirects, clear_usage: ClearUsage, environment: Environment, } impl ConfigBuilder { pub fn new>(command: T) -> ConfigBuilder { ConfigBuilder { command: command.as_ref().into(), args: Vec::new(), new_root: None, share_net: true, redirect_stdin: Some("/dev/null".into()), redirect_stdout: Some("/dev/null".into()), redirect_stderr: Some("/dev/null".into()), limits: None, instance_name: OsString::from("test"), mounts: Vec::new(), swap_redirects: SwapRedirects::default(), clear_usage: ClearUsage::default(), environment: Environment::default(), } } pub fn command>(&mut self, command: T) -> &mut ConfigBuilder { self.command = command.as_ref().into(); self } pub fn arg>(&mut self, arg: T) -> &mut ConfigBuilder { self.args.push(arg.as_ref().into()); self } pub fn args(&mut self, args: I) -> &mut ConfigBuilder where I: IntoIterator, T: AsRef, { for arg in args { self.arg(arg); } self } pub fn new_root>(&mut self, new_root: T) -> &mut ConfigBuilder { self.new_root = Some(new_root.as_ref().into()); self } pub fn share_net(&mut self, share_net: bool) -> &mut ConfigBuilder { self.share_net = share_net; self } pub fn stdin>(&mut self, redirect_stdin: T) -> &mut ConfigBuilder { self.redirect_stdin = Some(redirect_stdin.as_ref().into()); self } pub fn stdout>(&mut self, redirect_stdin: T) -> &mut ConfigBuilder { self.redirect_stdout = Some(redirect_stdin.as_ref().into()); self } pub fn stderr>(&mut self, redirect_stdin: T) -> &mut ConfigBuilder { self.redirect_stderr = Some(redirect_stdin.as_ref().into()); self } pub fn limits>(&mut self, limits: T) -> &mut ConfigBuilder { self.limits = Some(limits.into()); self } pub fn instance_name>(&mut self, instance_name: T) -> &mut ConfigBuilder { self.instance_name = instance_name.as_ref().into(); self } pub fn mount(&mut self, mount: Mount) -> &mut ConfigBuilder { self.mounts.push(mount); self } pub fn swap_redirects(&mut self, swap_redirects: SwapRedirects) -> &mut ConfigBuilder { self.swap_redirects = swap_redirects; self } pub fn clear_usage(&mut self, clear_usage: ClearUsage) -> &mut ConfigBuilder { self.clear_usage = clear_usage; self } pub fn environment(&mut self, environment: Environment) -> &mut ConfigBuilder { self.environment = environment; self } pub fn build_and_spawn(&mut self) -> Result { let config = Config { command: self.command.clone(), args: self.args.clone(), new_root: self.new_root.clone(), share_net: if self.share_net { ShareNet::Share } else { ShareNet::Unshare }, redirect_stdin: self.redirect_stdin.clone(), redirect_stdout: self.redirect_stdout.clone(), redirect_stderr: self.redirect_stderr.clone(), limits: self.limits.unwrap_or_default(), instance_name: self.instance_name.clone(), hierarchy_path: Some(CGROUPS_DEFAULT_PATH.into()), mounts: self.mounts.clone(), swap_redirects: self.swap_redirects, clear_usage: self.clear_usage, interactive: Interactive::default(), aslr: Aslr::default(), privileged: false, environment: self.environment.clone(), }; ia_sandbox::spawn_jail(&config) } pub fn build_and_run(&mut self) -> Result> { self.build_and_spawn()?.wait() } } #[derive(Clone, Copy, Default)] pub struct LimitsBuilder { wall_time: Option, user_time: Option, memory: Option, stack: Option, pids: Option, } impl LimitsBuilder { pub fn new() -> Self { LimitsBuilder { wall_time: None, user_time: None, memory: None, stack: None, pids: None, } } pub fn wall_time(&mut self, wall_time: Duration) -> &mut LimitsBuilder { self.wall_time = Some(wall_time); self } pub fn user_time(&mut self, user_time: Duration) -> &mut LimitsBuilder { self.user_time = Some(user_time); self } pub fn memory(&mut self, memory: SpaceUsage) -> &mut LimitsBuilder { self.memory = Some(memory); self } pub fn stack(&mut self, stack: SpaceUsage) -> &mut LimitsBuilder { self.stack = Some(stack); self } pub fn pids(&mut self, pids: usize) -> &mut LimitsBuilder { self.pids = Some(pids); self } } impl From for Limits { fn from(limits_builder: LimitsBuilder) -> Limits { Limits { wall_time: limits_builder.wall_time, user_time: limits_builder.user_time, memory: limits_builder.memory, stack: limits_builder.stack, pids: limits_builder.pids, } } }