pub mod envfilter;
pub mod handle;
#[cfg(target_os = "linux")]
pub mod linux;
#[cfg(target_os = "macos")]
pub mod macos;
#[cfg(target_os = "macos")]
#[path = "macos/net_proxy.rs"]
pub mod macos_net_proxy;
#[cfg(target_os = "windows")]
pub mod windows;
pub use handle::{SandboxHandle, SpawnOptions, StdioMode};
#[cfg(unix)]
use std::os::fd::OwnedFd;
use crate::config::NetMode;
use crate::policy::{Policy, Tier};
pub struct Spawned {
pub handle: SandboxHandle,
#[cfg(unix)]
pub broker_ctrl_fd: Option<OwnedFd>,
#[cfg(unix)]
pub relay_port: Option<u16>,
#[cfg(unix)]
pub notif_listener: Option<OwnedFd>,
}
pub enum Backend {
#[cfg(target_os = "linux")]
Linux(Box<linux::LinuxSandbox>),
#[cfg(target_os = "macos")]
Macos(Box<macos::MacosSandbox>),
#[cfg(target_os = "windows")]
Windows(Box<windows::WindowsSandbox>),
}
impl Backend {
pub fn detect(net: NetMode, observe_seccomp: bool) -> anyhow::Result<Self> {
Self::detect_with_backend(net, observe_seccomp, None)
}
pub fn detect_with_backend(
net: NetMode,
observe_seccomp: bool,
backend_name: Option<&str>,
) -> anyhow::Result<Self> {
if let Some(name) = backend_name {
match name {
"auto" | "default" => {}
"process" => {}
"win-sandbox" | "windows-sandbox" => {
#[cfg(target_os = "windows")]
{
let caps = windows::windows_sandbox::capabilities();
if !caps.launcher_present
|| !caps.virtualization_firmware_enabled
|| !caps.feature_enabled
{
anyhow::bail!(
"Windows Sandbox feature is not enabled or virtualization firmware is disabled: {}\n\
action: enable Hyper-V / Windows Sandbox in Windows Features and virtualization in BIOS; run `vetto doctor` for the full capability picture",
caps.note
);
}
return Ok(Backend::Windows(Box::new(windows::WindowsSandbox::new(
net,
)?)));
}
#[cfg(not(target_os = "windows"))]
{
anyhow::bail!(
"--backend win-sandbox is only available on Windows\n\
action: use `--backend auto` or `--backend process` on this operating system; run `vetto doctor` for supported backends"
);
}
}
other => {
anyhow::bail!(
"unknown backend '{other}'; valid backends: auto, process, win-sandbox\n\
action: select a valid backend or omit the flag; run `vetto doctor` for the full capability picture"
);
}
}
}
#[cfg(target_os = "linux")]
{
let probe = linux::probe();
let tier = linux::pick_tier(&probe)?;
Ok(Backend::Linux(Box::new(linux::LinuxSandbox {
probe,
tier,
net,
observe_seccomp,
})))
}
#[cfg(target_os = "macos")]
{
let _ = observe_seccomp;
Ok(Backend::Macos(Box::new(macos::MacosSandbox::new(net))))
}
#[cfg(target_os = "windows")]
{
let _ = observe_seccomp;
Ok(Backend::Windows(Box::new(windows::WindowsSandbox::new(
net,
)?)))
}
#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
{
let _ = (net, observe_seccomp);
Err(anyhow::anyhow!(
crate::error::VettoError::UnsupportedPlatform("this platform")
))
}
}
pub fn tier(&self) -> Option<Tier> {
match self {
#[cfg(target_os = "linux")]
Backend::Linux(s) => Some(s.tier),
#[cfg(target_os = "macos")]
Backend::Macos(_) => None,
#[cfg(target_os = "windows")]
Backend::Windows(_) => None,
}
}
pub fn describe(&self) -> String {
match self {
#[cfg(target_os = "linux")]
Backend::Linux(s) => format!(
"linux tier={} (landlock ABI {:?}, userns={}, full-stack={}, seccomp-notify={}, audit-feed={})",
s.tier.label(),
s.probe.landlock_abi,
s.probe.userns_available,
s.probe.full_tier_available,
s.probe.seccomp_notify_available,
s.probe.audit_feed_readable,
),
#[cfg(target_os = "macos")]
Backend::Macos(_) => "macos seatbelt (deprecated sandbox-exec, works today)".into(),
#[cfg(target_os = "windows")]
Backend::Windows(s) => format!("windows process sandbox ({})", s.capabilities.summary()),
}
}
pub fn spawn(self, policy: &Policy, opts: SpawnOptions) -> anyhow::Result<Spawned> {
match self {
#[cfg(target_os = "linux")]
Backend::Linux(s) => s.spawn(policy, opts),
#[cfg(target_os = "macos")]
Backend::Macos(s) => s.spawn(policy, opts),
#[cfg(target_os = "windows")]
Backend::Windows(s) => s.spawn(policy, opts),
}
}
}