deck_sandbox/linux.rs
1//! Linux backend: seccompiler BPF + landlock ruleset.
2//!
3//! In Phase 1 we wire up profile -> ruleset translation and expose the
4//! [`Sandbox`] trait shape. Actual `exec(2)`-time application of the filter
5//! is staged in Phase 2 (it requires forking a helper process and applying
6//! the filter post-fork, pre-exec).
7
8use deck_core::Sandbox;
9
10use crate::profile::SandboxProfile;
11
12#[derive(Debug, Default)]
13pub struct LinuxSandbox {
14 _placeholder: (),
15}
16
17impl LinuxSandbox {
18 /// Translate a profile into a landlock ruleset (Phase 1: returns the
19 /// counts so we can unit-test the translation; actual ruleset object
20 /// is wired in Phase 2 when the child-spawn glue lands).
21 #[must_use]
22 pub fn plan(&self, profile: &SandboxProfile) -> SandboxPlan {
23 SandboxPlan {
24 read_paths: profile.allow_read.len(),
25 write_paths: profile.allow_write.len(),
26 allow_network: profile.allow_network,
27 }
28 }
29}
30
31impl Sandbox for LinuxSandbox {
32 fn availability(&self) -> &'static str {
33 "scaffolded (not enforcing in 0.1)"
34 }
35
36 fn enforces(&self) -> bool {
37 // 0.1 ships the policy types and the dependency wiring but does
38 // NOT yet apply the seccomp BPF filter or the landlock ruleset
39 // around `exec(2)`. Reporting `false` keeps `doctor` honest and
40 // gives `--sandbox-strict` the correct refusal behaviour. The
41 // fork+exec helper + `landlock_create_ruleset(NULL, 0, ...)`
42 // probe land in 0.2.
43 false
44 }
45}
46
47#[derive(Debug, Clone, Copy)]
48pub struct SandboxPlan {
49 pub read_paths: usize,
50 pub write_paths: usize,
51 pub allow_network: bool,
52}
53
54#[cfg(test)]
55mod tests {
56 use super::*;
57 use std::path::PathBuf;
58
59 #[test]
60 fn plan_counts_paths() {
61 let sb = LinuxSandbox::default();
62 let p = SandboxProfile {
63 allow_read: vec![PathBuf::from("/etc")],
64 allow_write: vec![PathBuf::from("/tmp")],
65 allow_network: false,
66 };
67 let plan = sb.plan(&p);
68 assert_eq!(plan.read_paths, 1);
69 assert_eq!(plan.write_paths, 1);
70 assert!(!plan.allow_network);
71 }
72}