Skip to content

Commit 99a9302

Browse files
committed
feat(sandbox): Landlock TCP port restriction in Platform mode
When Platform mode is active, apply Landlock ABI v4 network rules to restrict TCP connect to only the proxy port (default 3128). This makes the loopback CONNECT proxy mandatory at the kernel level -- a process calling connect() to any other port gets EACCES. This closes the cooperative proxy gap identified in the enforcement analysis: without this, processes ignoring HTTP_PROXY could bypass the proxy and connect directly (caught only by Tier 3 NetworkPolicy). With this, enforcement is at Tier 1 (kernel LSM). Graceful degradation: if the kernel does not support Landlock ABI v4 (e.g. RHEL 9.5 or earlier), the network rules are silently skipped and enforcement falls back to the cooperative proxy + NetworkPolicy (same as Issue NVIDIA#899 base behavior). Ref: NVIDIA#899
1 parent a7ad2cd commit 99a9302

1 file changed

Lines changed: 43 additions & 2 deletions

File tree

crates/openshell-sandbox/src/sandbox/linux/landlock.rs

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44
//! Landlock filesystem sandboxing.
55
66
use crate::policy::{LandlockCompatibility, SandboxPolicy};
7+
use crate::policy::NetworkMode;
78
use landlock::{
8-
ABI, Access, AccessFs, CompatLevel, Compatible, PathBeneath, PathFd, PathFdError, Ruleset,
9-
RulesetAttr, RulesetCreatedAttr,
9+
ABI, Access, AccessFs, AccessNet, CompatLevel, Compatible, NetPort, PathBeneath, PathFd,
10+
PathFdError, Ruleset, RulesetAttr, RulesetCreatedAttr,
1011
};
1112
use miette::{IntoDiagnostic, Result};
1213
use std::path::{Path, PathBuf};
@@ -184,6 +185,15 @@ pub fn prepare(policy: &SandboxPolicy, workdir: Option<&str>) -> Result<Option<P
184185
.handle_access(access_all)
185186
.into_diagnostic()?;
186187

188+
// Platform mode: also handle TCP connect access so Landlock can
189+
// restrict which ports the agent connects to. This requires ABI v4.
190+
// The compat_level handles graceful degradation on older kernels.
191+
if matches!(policy.network.mode, NetworkMode::Platform) {
192+
ruleset = ruleset
193+
.handle_access(AccessNet::ConnectTcp)
194+
.into_diagnostic()?;
195+
}
196+
187197
let mut ruleset = ruleset.create().into_diagnostic()?;
188198
let mut rules_applied: usize = 0;
189199

@@ -207,6 +217,37 @@ pub fn prepare(policy: &SandboxPolicy, workdir: Option<&str>) -> Result<Option<P
207217
}
208218
}
209219

220+
// Platform mode: restrict TCP connect to the proxy port only.
221+
// Uses Landlock ABI v4 (LANDLOCK_ACCESS_NET_CONNECT_TCP). If the
222+
// kernel doesn't support ABI v4, the network rules are silently
223+
// skipped (best_effort) and enforcement falls back to NetworkPolicy.
224+
if matches!(policy.network.mode, NetworkMode::Platform) {
225+
let proxy_port = policy
226+
.network
227+
.proxy
228+
.as_ref()
229+
.and_then(|p| p.http_addr)
230+
.map_or(3128_u16, |addr| addr.port());
231+
232+
match ruleset.add_rule(NetPort::new(proxy_port, AccessNet::ConnectTcp)) {
233+
Ok(r) => {
234+
ruleset = r;
235+
debug!(
236+
port = proxy_port,
237+
"Landlock allow TCP connect (proxy port only)"
238+
);
239+
rules_applied += 1;
240+
}
241+
Err(e) => {
242+
debug!(
243+
error = %e,
244+
"Landlock TCP port restriction unavailable (ABI v4 required), \
245+
falling back to cooperative proxy enforcement"
246+
);
247+
}
248+
}
249+
}
250+
210251
if rules_applied == 0 {
211252
return Err(miette::miette!(
212253
"Landlock ruleset has zero valid paths — all {} path(s) failed to open. \

0 commit comments

Comments
 (0)