#![cfg(all(
feature = "backend-linux",
feature = "dangerous-test-hooks",
target_os = "linux"
))]
use bvisor::linux::launch::report_confinement_unavailable;
use bvisor::{
Backend, BackendId, BackendRegistry, BoundaryPlanner, BoundaryReportBody, BoundaryRunner,
BoundarySpec, BudgetFinding, BudgetRequirements, Capability, EvidenceRequirements, FsAccess,
FsConfinement, GuaranteeProfile, HostControl, LinuxBackend, MinGuarantee, Outcome, PathSet,
StdStreams, Workload,
};
use std::path::{Path, PathBuf};
use std::sync::Arc;
fn test_launcher_path() -> PathBuf {
PathBuf::from(env!("CARGO_BIN_EXE_bvisor-linux-launcher"))
}
const LANDLOCK_ABI_FLOOR: i64 = 1;
fn live_landlock_abi() -> i64 {
const LANDLOCK_CREATE_RULESET_VERSION: libc::c_uint = 1;
let raw = unsafe {
libc::syscall(
libc::SYS_landlock_create_ruleset,
std::ptr::null::<libc::c_void>(),
0usize,
LANDLOCK_CREATE_RULESET_VERSION,
)
};
if raw < 0 {
0
} else {
raw
}
}
fn landlock_available() -> bool {
live_landlock_abi() >= LANDLOCK_ABI_FLOOR
}
fn skip(test: &str) {
use std::io::Write;
let mut sink = std::io::stderr();
let _ = writeln!(
sink,
"SKIP {test}: live landlock ABI {} < floor {LANDLOCK_ABI_FLOOR} \
(kernel lacks landlock or the sandbox blocks it)",
live_landlock_abi()
);
}
fn skip_confinement_unavailable(test: &str) {
use std::io::Write;
let mut sink = std::io::stderr();
let _ = writeln!(
sink,
"SKIP {test}: kernel/container lacks landlock/userns/seccomp (ENOSYS); confinement \
cannot install here — exercised on capable kernels + the bvisor-linux CI lane"
);
}
struct Scratch {
root: PathBuf,
}
impl Scratch {
fn new(tag: &str) -> Self {
let pid = std::process::id();
let nanos = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.as_nanos())
.unwrap_or(0);
let root = std::env::temp_dir().join(format!("bvisor-fs-{tag}-{pid}-{nanos}"));
std::fs::create_dir_all(&root).expect("scratch root");
Self { root }
}
fn path(&self, name: &str) -> PathBuf {
self.root.join(name)
}
}
impl Drop for Scratch {
fn drop(&mut self) {
let _ = std::fs::remove_dir_all(&self.root);
}
}
struct FsGroundTruth {
marker: String,
witness_path: PathBuf,
}
impl FsGroundTruth {
fn danger_occurred(&self) -> bool {
match std::fs::read(&self.witness_path) {
Ok(bytes) => String::from_utf8_lossy(&bytes).contains(&self.marker),
Err(_) => false,
}
}
}
fn fs_spec(args: Vec<String>, access: FsAccess, root: &Path) -> BoundarySpec {
BoundarySpec {
workload: Workload::Process {
exe: "/bin/sh".to_string(),
args,
},
capabilities: vec![Capability::Filesystem {
access,
scope: PathSet {
roots: vec![root.to_string_lossy().into_owned()],
},
recursive: true,
confinement: FsConfinement::DeclaredRootsOnly,
}],
controls: vec![
HostControl::LaunchWorkload,
HostControl::CaptureStreams {
streams: StdStreams::capture_out_err(),
},
],
budgets: BudgetRequirements::uniform(8, MinGuarantee::Mediated),
evidence: EvidenceRequirements::default(),
}
}
fn run(spec: &BoundarySpec) -> BoundaryReportBody {
let backend = Arc::new(LinuxBackend::with_launcher_path(test_launcher_path()));
let id: BackendId = backend.id();
let mut registry = BackendRegistry::new();
registry.register(Arc::clone(&backend) as Arc<dyn Backend>);
let plan = BoundaryPlanner::new(®istry)
.plan(spec, &id)
.expect("LinuxBackend admits a declared-roots FS spec");
BoundaryRunner::new(®istry)
.run(&plan)
.expect("the confined run seals a terminal report")
.body
}
fn report_records_confinement_installed(body: &BoundaryReportBody) -> bool {
let named = body
.observed
.iter()
.any(|f| f.kind == "filesystem_confined" && f.detail.contains("launcher restrict_self"));
let attested = body
.observed
.iter()
.any(|f| f.kind == "launcher_note" && f.detail.contains("installed=true"));
let not_under_claimed = !body
.observed
.iter()
.any(|f| f.kind == "confinement_not_installed");
named && attested && not_under_claimed
}
#[test]
fn g1_landlock_denies_secret_read_outside_declared_root() {
if !landlock_available() {
skip("g1");
return;
}
let scratch = Scratch::new("g1");
let root = scratch.path("quarantine");
std::fs::create_dir_all(&root).expect("quarantine dir");
let secret = scratch.path("secret.key");
let marker = "TOPSECRET-G1-MARKER".to_string();
std::fs::write(&secret, &marker).expect("plant secret");
let exfil = root.join("exfil.txt");
let cmd = format!(
"cat {secret} > {exfil}",
secret = secret.to_string_lossy(),
exfil = exfil.to_string_lossy()
);
let body = run(&fs_spec(vec!["-c".into(), cmd], FsAccess::ReadWrite, &root));
if report_confinement_unavailable(&body.observed) {
skip_confinement_unavailable("g1");
return;
}
let gt = FsGroundTruth {
marker,
witness_path: exfil,
};
assert!(
!gt.danger_occurred(),
"GROUNDTRUTH: landlock (launcher restrict_self) must block the out-of-root \
secret read; the secret leaked into the in-root exfil sink on disk. report:\n{:?}",
body.observed
);
assert!(
report_records_confinement_installed(&body),
"report must HONESTLY attest the launcher installed the confinement it ran \
under: {:?}",
body.observed
);
assert_eq!(
body.outcome,
Outcome::Completed,
"a confined run that exec'd is an honest Completed: {:?}",
body.observed
);
}
#[test]
fn g3_landlock_denies_write_outside_quarantine() {
if !landlock_available() {
skip("g3");
return;
}
let scratch = Scratch::new("g3");
let root = scratch.path("quarantine");
std::fs::create_dir_all(&root).expect("quarantine dir");
let escape = scratch.path("escape.txt");
let marker = "ESCAPED-G3-MARKER".to_string();
let cmd = format!(
"echo {marker} > {escape}",
escape = escape.to_string_lossy()
);
let body = run(&fs_spec(vec!["-c".into(), cmd], FsAccess::Write, &root));
if report_confinement_unavailable(&body.observed) {
skip_confinement_unavailable("g3");
return;
}
let gt = FsGroundTruth {
marker,
witness_path: escape,
};
assert!(
!gt.danger_occurred(),
"GROUNDTRUTH: landlock (launcher restrict_self) must block the \
out-of-quarantine write; the escape file exists on disk. report:\n{:?}",
body.observed
);
assert!(
report_records_confinement_installed(&body),
"report must HONESTLY attest the launcher installed the confinement: {:?}",
body.observed
);
}
#[test]
fn control_in_root_write_is_allowed_and_completes() {
if !landlock_available() {
skip("control");
return;
}
let scratch = Scratch::new("ctl");
let root = scratch.path("quarantine");
std::fs::create_dir_all(&root).expect("quarantine dir");
let inside = root.join("allowed.txt");
let marker = "ALLOWED-MARKER".to_string();
let cmd = format!(
"echo {marker} > {inside}",
inside = inside.to_string_lossy()
);
let body = run(&fs_spec(vec!["-c".into(), cmd], FsAccess::Write, &root));
if report_confinement_unavailable(&body.observed) {
skip_confinement_unavailable("control");
return;
}
let landed = std::fs::read(&inside)
.map(|b| String::from_utf8_lossy(&b).contains(&marker))
.unwrap_or(false);
assert!(
landed,
"an in-root write must be allowed through landlock (launcher restrict_self). \
report:\n{:?}",
body.observed
);
assert_eq!(
body.outcome,
Outcome::Completed,
"an allowed in-root write completes cleanly: {:?}",
body.observed
);
assert!(
report_records_confinement_installed(&body),
"the launcher installed the confinement the allowed write ran under: {:?}",
body.observed
);
}
#[test]
fn cgroup_leaf_is_created_and_reported_through_execute() {
if !landlock_available() {
skip("cgroup_leaf (landlock unavailable, the FS spec cannot admit)");
return;
}
if bvisor::linux::cgroup::probe_controller_base(&["pids"]).is_none() {
skip("cgroup_leaf (no pids-delegating cgroup base on this host)");
return;
}
let scratch = Scratch::new("cgroup-run");
let root = scratch.path("quarantine");
std::fs::create_dir_all(&root).expect("quarantine dir");
let body = run(&fs_spec(
vec!["-c".into(), "true".into()],
FsAccess::Write,
&root,
));
if report_confinement_unavailable(&body.observed) {
skip_confinement_unavailable("cgroup_leaf");
return;
}
assert_eq!(
body.outcome,
Outcome::Completed,
"the workload runs to success in the cgroup leaf: {:?}",
body.observed
);
assert!(
body.observed
.iter()
.any(|f| f.kind == "cgroup_leaf_prepared"),
"execute() must report preparing the cgroup leaf: {:?}",
body.observed
);
assert!(
body.observed.iter().any(|f| f.kind == "launcher_note"
&& f.detail.contains("cgroup_placement=clone_into_cgroup")),
"the launcher must note CLONE_INTO_CGROUP placement: {:?}",
body.observed
);
let pc = &body.budget.process_count;
assert_eq!(
pc.supplied_guarantee,
GuaranteeProfile::Hard,
"process_count is a HARD cgroup pids.max cap (not sampled): {pc:?}"
);
assert_eq!(
pc.finding,
BudgetFinding::WithinLimit,
"the workload's peak pid count stayed within the cap: {pc:?}"
);
assert!(
pc.observed_usage >= 1,
"the witnessed peak is a REAL measurement of at least the workload itself: {pc:?}"
);
assert!(
body.observed
.iter()
.any(|f| f.kind == "process_count_witnessed"),
"execute() must surface the pids.peak witness as honest evidence: {:?}",
body.observed
);
assert_eq!(
body.budget.cpu_micros.finding,
BudgetFinding::ObservationUnavailable,
"CPU is NOT witnessed this step (no over-claim): {:?}",
body.budget.cpu_micros
);
}
#[test]
fn launcher_identity_is_attested_by_its_content_digest() {
if !landlock_available() {
skip("launcher_identity");
return;
}
let scratch = Scratch::new("ident");
let root = scratch.path("quarantine");
std::fs::create_dir_all(&root).expect("quarantine dir");
let body = run(&fs_spec(
vec!["-c".into(), "true".into()],
FsAccess::Write,
&root,
));
if report_confinement_unavailable(&body.observed) {
skip_confinement_unavailable("launcher_identity");
return;
}
let bytes = std::fs::read(test_launcher_path()).expect("read launcher bin");
let expected: String = batpak::event::hash::compute_hash(&bytes)
.iter()
.map(|b| format!("{b:02x}"))
.collect();
let attested = body
.observed
.iter()
.find(|f| f.kind == "launcher_identity")
.expect("execute() must attest a launcher_identity fact");
assert!(
attested.detail.contains(&format!("blake3={expected}")),
"the attested launcher digest must equal an INDEPENDENT blake3 of the binary: \
{attested:?}"
);
}
#[cfg(gauntlet_red_fixture)]
#[test]
fn g3_red_fixture_unconfined_backend_is_caught() {
let scratch = Scratch::new("g3-red");
let escape = scratch.path("escape.txt");
let marker = "ESCAPED-RED-MARKER".to_string();
let cmd = format!(
"echo {marker} > {escape}",
escape = escape.to_string_lossy()
);
let _ = std::process::Command::new("/bin/sh")
.args(["-c", &cmd])
.output()
.expect("unconfined spawn");
let gt = FsGroundTruth {
marker,
witness_path: escape,
};
assert!(
!gt.danger_occurred(),
"RED FIXTURE: an unconfined backend lets the write ESCAPE; GroundTruth \
catches it, so this assertion must fail"
);
}