Files
agent-sandbox/src/lib.rs
Kristóf Tóth 12644ae31e Apply a seccomp-BPF syscall allowlist by default
Derived from Podman's default profile, stripped of capability-conditional
rules (we never grant capabilities), argument filters, and the explicit
EPERM block. Dangerous syscalls (mount, unshare, ptrace, bpf,
perf_event_open, io_uring_*, keyctl, kexec_*, ...) fall through to the
default ENOSYS action, which also keeps glibc's clone3 -> clone fallback
working. x86_64 and aarch64 are supported; other archs error out.

Toggle with --seccomp / --no-seccomp or seccomp = <bool> in config.
2026-04-08 08:34:34 +02:00

82 lines
1.9 KiB
Rust

mod agents;
mod blacklist;
pub mod cli;
pub mod config;
mod errors;
mod preflight;
mod sandbox;
mod seccomp;
pub use errors::SandboxError;
use std::env;
use std::ffi::OsString;
use std::fs;
use std::os::unix::process::CommandExt;
use std::path::PathBuf;
pub enum SandboxMode {
Blacklist,
Whitelist,
}
pub struct SandboxConfig {
pub mode: SandboxMode,
pub hardened: bool,
pub unshare_net: bool,
pub seccomp: bool,
pub extra_rw: Vec<PathBuf>,
pub extra_ro: Vec<PathBuf>,
pub mask: Vec<PathBuf>,
pub bwrap_args: Vec<String>,
pub command: PathBuf,
pub command_args: Vec<OsString>,
pub chdir: PathBuf,
pub dry_run: bool,
}
pub fn require_home() -> Result<String, SandboxError> {
env::var("HOME")
.ok()
.filter(|h| !h.is_empty())
.ok_or(SandboxError::HomeNotSet)
}
pub fn require_run_user() -> Result<String, SandboxError> {
env::var("XDG_RUNTIME_DIR")
.ok()
.or_else(resolve_run_user_from_proc)
.ok_or(SandboxError::RunUserNotFound)
}
fn resolve_run_user_from_proc() -> Option<String> {
let status = fs::read_to_string("/proc/self/status").ok()?;
for line in status.lines() {
if let Some(rest) = line.strip_prefix("Uid:") {
let uid = rest.split_whitespace().next()?;
return Some(format!("/run/user/{uid}"));
}
}
None
}
pub fn run(config: SandboxConfig) -> Result<(), SandboxError> {
preflight::check(&config)?;
let mut cmd = sandbox::build_command(&config)?;
if config.dry_run {
println!("{}", shell_quote_command(&cmd));
return Ok(());
}
Err(SandboxError::Io(cmd.exec()))
}
fn shell_quote_command(cmd: &std::process::Command) -> String {
let prog = cmd.get_program().to_string_lossy();
let args = cmd.get_args().map(|a| a.to_string_lossy());
let all: Vec<_> = std::iter::once(prog).chain(args).collect();
shlex::try_join(all.iter().map(|s| s.as_ref())).unwrap()
}