use std::process::Command;
use tracing::{debug, info, warn};
use crate::policy::{SandboxPolicy, NetworkPolicy};
use crate::error::SandboxError;
use crate::Sandbox;
pub struct LandlockSandbox {
policy: SandboxPolicy,
}
impl LandlockSandbox {
pub fn new(policy: SandboxPolicy) -> Result<Self, SandboxError> {
if !Self::is_available() {
return Err(SandboxError::NotAvailable(
"Landlock not supported on this kernel".into()
));
}
debug!("Created Landlock sandbox");
Ok(Self { policy })
}
}
impl Sandbox for LandlockSandbox {
fn wrap_command(&self, cmd: Command) -> Result<Command, SandboxError> {
warn!("Landlock sandbox wrapping not fully implemented - using passthrough");
Ok(cmd)
}
fn is_available() -> bool {
use std::fs;
if let Ok(contents) = fs::read_to_string("/sys/kernel/security/lsm") {
if contents.contains("landlock") {
return true;
}
}
false
}
fn sandbox_type(&self) -> &'static str {
"landlock"
}
}
#[cfg(target_os = "linux")]
pub fn apply_landlock_policy(policy: &SandboxPolicy) -> Result<(), SandboxError> {
use landlock::{
Access, AccessFs, PathBeneath, PathFd, Ruleset, RulesetAttr,
RulesetCreatedAttr, ABI,
};
let abi = ABI::V3;
let mut ruleset = Ruleset::default()
.handle_access(AccessFs::from_all(abi))
.map_err(|e| SandboxError::PolicyError(format!("Failed to create ruleset: {}", e)))?;
let ruleset = ruleset.create()
.map_err(|e| SandboxError::PolicyError(format!("Failed to create ruleset: {}", e)))?;
for perm in &policy.read_paths {
let path = &perm.path;
if path.exists() {
if let Ok(fd) = PathFd::new(path) {
let access = AccessFs::ReadFile | AccessFs::ReadDir;
let _ = ruleset.add_rule(PathBeneath::new(fd, access));
}
}
}
for perm in &policy.write_paths {
let path = &perm.path;
if path.exists() {
if let Ok(fd) = PathFd::new(path) {
let access = AccessFs::WriteFile | AccessFs::RemoveFile |
AccessFs::RemoveDir | AccessFs::MakeDir;
let _ = ruleset.add_rule(PathBeneath::new(fd, access));
}
}
}
for perm in &policy.exec_paths {
let path = &perm.path;
if path.exists() {
if let Ok(fd) = PathFd::new(path) {
let access = AccessFs::Execute;
let _ = ruleset.add_rule(PathBeneath::new(fd, access));
}
}
}
ruleset.restrict_self()
.map_err(|e| SandboxError::PolicyError(format!("Failed to restrict: {}", e)))?;
info!("Applied Landlock restrictions");
Ok(())
}
#[cfg(not(target_os = "linux"))]
pub fn apply_landlock_policy(_policy: &SandboxPolicy) -> Result<(), SandboxError> {
Err(SandboxError::NotAvailable("Landlock only available on Linux".into()))
}
#[cfg(test)]
mod tests {
use super::*;
use std::path::PathBuf;
#[test]
fn test_availability_check() {
let _ = LandlockSandbox::is_available();
}
}