use super::policy::{SandboxLevel, SandboxPolicy};
pub fn sandbox_child_main() -> ! {
let args: Vec<String> = std::env::args().collect();
if args.len() < 3 {
eprintln!("localgpt-sandbox: expected policy JSON and command arguments");
std::process::exit(1);
}
let policy: SandboxPolicy = match serde_json::from_str(&args[1]) {
Ok(p) => p,
Err(e) => {
eprintln!("localgpt-sandbox: failed to parse policy: {}", e);
std::process::exit(1);
}
};
let command = &args[2];
if let Err(e) = apply_rlimits(&policy) {
eprintln!("localgpt-sandbox: failed to apply rlimits: {}", e);
std::process::exit(1);
}
if policy.level > SandboxLevel::None
&& let Err(e) = apply_platform_sandbox(&policy)
{
eprintln!("localgpt-sandbox: failed to apply sandbox: {}", e);
std::process::exit(1);
}
exec_bash(command);
}
fn apply_rlimits(policy: &SandboxPolicy) -> Result<(), String> {
use nix::sys::resource::{Resource, setrlimit};
setrlimit(
Resource::RLIMIT_FSIZE,
policy.max_file_size_bytes,
policy.max_file_size_bytes,
)
.map_err(|e| format!("RLIMIT_FSIZE: {}", e))?;
#[cfg(target_os = "linux")]
{
let nproc = policy.max_processes as u64;
setrlimit(Resource::RLIMIT_NPROC, nproc, nproc)
.map_err(|e| format!("RLIMIT_NPROC: {}", e))?;
}
setrlimit(Resource::RLIMIT_NOFILE, 256, 256).map_err(|e| format!("RLIMIT_NOFILE: {}", e))?;
Ok(())
}
fn apply_platform_sandbox(policy: &SandboxPolicy) -> Result<(), String> {
#[cfg(target_os = "linux")]
{
super::linux::apply_sandbox(policy)
}
#[cfg(target_os = "macos")]
{
super::macos::apply_sandbox(policy)
}
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
{
let _ = policy;
Ok(())
}
}
fn exec_bash(command: &str) -> ! {
#[cfg(target_os = "macos")]
{
if std::env::var("_LOCALGPT_SBPL_PROFILE").is_ok() {
super::macos::exec_sandboxed(command);
}
}
use std::os::unix::process::CommandExt;
let err = std::process::Command::new("/bin/bash")
.arg("-c")
.arg(command)
.exec();
eprintln!("localgpt-sandbox: failed to exec bash: {}", err);
std::process::exit(1);
}