Skip to content

Commit 93c58cf

Browse files
committed
fix(sandbox): probe Landlock before build, skip on unsupported kernels
On kernels without Landlock (e.g. gVisor's sentry returns ENOSYS for syscall 444), the previous best_effort path still logged "Applying Landlock" + "Landlock ruleset built" events even though no enforcement was happening. Probe at the top of `landlock::prepare` and short-circuit with a single High-severity "Sandbox Unavailable" finding. Signed-off-by: Davanum Srinivas <dsrinivas@nvidia.com>
1 parent 2e03faf commit 93c58cf

1 file changed

Lines changed: 39 additions & 2 deletions

File tree

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

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,45 @@ pub fn prepare(policy: &SandboxPolicy, workdir: Option<&str>) -> Result<Option<P
119119
return Ok(None);
120120
}
121121

122+
let compatibility = &policy.landlock.compatibility;
123+
124+
// Probe first: kernels without Landlock (e.g. gVisor's sentry returns
125+
// ENOSYS) would otherwise log misleading "Applying"+"Built" events.
126+
let availability = probe_availability();
127+
if !matches!(availability, LandlockAvailability::Available { .. }) {
128+
match compatibility {
129+
LandlockCompatibility::BestEffort => {
130+
openshell_ocsf::ocsf_emit!(
131+
openshell_ocsf::DetectionFindingBuilder::new(crate::ocsf_ctx())
132+
.activity(openshell_ocsf::ActivityId::Open)
133+
.severity(openshell_ocsf::SeverityId::High)
134+
.confidence(openshell_ocsf::ConfidenceId::High)
135+
.is_alert(true)
136+
.finding_info(
137+
openshell_ocsf::FindingInfo::new(
138+
"landlock-unavailable",
139+
"Landlock Filesystem Sandbox Unavailable",
140+
)
141+
.with_desc(&format!(
142+
"Running WITHOUT filesystem restrictions: Landlock is {availability}. \
143+
Set landlock.compatibility to 'hard_requirement' to make this fatal."
144+
)),
145+
)
146+
.message(format!(
147+
"Landlock filesystem sandbox unavailable: {availability}"
148+
))
149+
.build()
150+
);
151+
return Ok(None);
152+
}
153+
LandlockCompatibility::HardRequirement => {
154+
return Err(miette::miette!(
155+
"Landlock unavailable in hard_requirement mode: {availability}"
156+
));
157+
}
158+
}
159+
}
160+
122161
let total_paths = read_only.len() + read_write.len();
123162
let abi = ABI::V2;
124163
openshell_ocsf::ocsf_emit!(
@@ -135,8 +174,6 @@ pub fn prepare(policy: &SandboxPolicy, workdir: Option<&str>) -> Result<Option<P
135174
.build()
136175
);
137176

138-
let compatibility = &policy.landlock.compatibility;
139-
140177
let result: Result<PreparedRuleset> = (|| {
141178
let access_all = AccessFs::from_all(abi);
142179
let access_read = AccessFs::from_read(abi);

0 commit comments

Comments
 (0)