From 6ccc7a39729e454bd323bb3794de09adca028362 Mon Sep 17 00:00:00 2001 From: valoq Date: Sun, 29 Jun 2025 15:48:53 +0200 Subject: [PATCH] allow multiple paths --- src/commands/decompress.rs | 12 +++- src/commands/list.rs | 2 +- src/utils/landlock.rs | 28 ++++---- src/utils/src_utils_landlock.rs | 109 ++++++++++++++++++++++++++++++++ 4 files changed, 133 insertions(+), 18 deletions(-) create mode 100644 src/utils/src_utils_landlock.rs diff --git a/src/commands/decompress.rs b/src/commands/decompress.rs index ef11dd7..b94e45f 100644 --- a/src/commands/decompress.rs +++ b/src/commands/decompress.rs @@ -321,9 +321,17 @@ fn execute_decompression( // init landlock sandbox to restrict file system write access to output_dir // The output directory iseither specified with the -d option or the current working directory is used // TODO: restrict acess to the current working directory to allow only creating new files - landlock::init_sandbox(Some(output_dir)); + + // TODO: move to unpack and smart_unpack to cover the differetn dirctories used for + // decompression - if is_smart_unpack { + //if !input_is_stdin && options.remove { + //permit write access to input_file_path + //} else { + landlock::init_sandbox(&[output_dir]); + //} + + if is_smart_unpack { return smart_unpack(unpack_fn, output_dir, output_file_path, question_policy); } diff --git a/src/commands/list.rs b/src/commands/list.rs index 91b03a7..df6494a 100644 --- a/src/commands/list.rs +++ b/src/commands/list.rs @@ -29,7 +29,7 @@ pub fn list_archive_contents( let mut temp_file = tempfile::NamedTempFile::new()?; // Initialize landlock sandbox with write access restricted to /tmp/ as required by some formats - landlock::init_sandbox(Some(temp_file.path())); + landlock::init_sandbox(&[temp_file.path()]); let reader = fs::File::open(archive_path)?; diff --git a/src/utils/landlock.rs b/src/utils/landlock.rs index e18a57f..f20b1d9 100644 --- a/src/utils/landlock.rs +++ b/src/utils/landlock.rs @@ -55,7 +55,6 @@ fn restrict_paths(hierarchies: &[&str]) -> Result Result) { - -// if std::env::var("CI").is_ok() { -// return; -// } - +/// Restricts the process to only access the given hierarchies using Landlock, if supported. +/// Accepts multiple allowed directories as &[&Path]. +pub fn init_sandbox(allowed_dirs: &[&Path]) { + // if std::env::var("CI").is_ok() { + // return; + // } if is_landlock_supported() { - let status = if let Some(allowed_dir) = allowed_dir { - let path_str = allowed_dir.to_str().expect("Cannot convert path"); - restrict_paths(&[path_str]) + let paths: Vec<&str> = allowed_dirs + .iter() + .map(|p| p.to_str().expect("Cannot convert path")) + .collect(); + + let status = if !paths.is_empty() { + restrict_paths(&paths) } else { restrict_paths(&[]) }; @@ -104,8 +106,4 @@ pub fn init_sandbox(allowed_dir: Option<&Path>) { } else { // warn!("Landlock is NOT supported on this platform or kernel (<5.19)."); } - - - } - diff --git a/src/utils/src_utils_landlock.rs b/src/utils/src_utils_landlock.rs new file mode 100644 index 0000000..0fa9d76 --- /dev/null +++ b/src/utils/src_utils_landlock.rs @@ -0,0 +1,109 @@ +// Landlock support and generic Landlock sandbox implementation. +// https://landlock.io/rust-landlock/landlock/struct.Ruleset.html + +use landlock::{ + Access, AccessFs, PathBeneath, PathFd, PathFdError, RestrictionStatus, Ruleset, + RulesetAttr, RulesetCreatedAttr, RulesetError, ABI, +}; +use thiserror::Error; + +use std::path::Path; + +/// The status code returned from `ouch` on error +pub const EXIT_FAILURE: i32 = libc::EXIT_FAILURE; + +/// Returns true if Landlock is supported by the running kernel (Linux kernel >= 5.19). +#[cfg(target_os = "linux")] +pub fn is_landlock_supported() -> bool { + use std::process::Command; + + if let Ok(output) = Command::new("uname").arg("-r").output() { + if let Ok(version_str) = String::from_utf8(output.stdout) { + // Version string is expected to be in "5.19.0-foo" or similar + let mut parts = version_str.trim().split('.'); + if let (Some(major), Some(minor)) = (parts.next(), parts.next()) { + if let (Ok(major), Ok(minor)) = (major.parse::(), minor.parse::()) { + return (major > 5) || (major == 5 && minor >= 19); + } + } + } + } + false +} + +#[cfg(not(target_os = "linux"))] +pub fn is_landlock_supported() -> bool { + false +} + +#[derive(Debug, Error)] +pub enum MyRestrictError { + #[error(transparent)] + Ruleset(#[from] RulesetError), + #[error(transparent)] + AddRule(#[from] PathFdError), +} + +/// Restricts the process to only access the given hierarchies using Landlock, if supported. +/// +/// The Landlock ABI is set to v2 for compatibility with Linux 5.19+. +/// All hierarchies are given full access, but root ("/") is read-only. +fn restrict_paths(hierarchies: &[&str]) -> Result { + // The Landlock ABI should be incremented (and tested) regularly. + // ABI set to 2 in compatibility with linux 5.19 and higher + let abi = ABI::V2; + let access_all = AccessFs::from_all(abi); + let access_read = AccessFs::from_read(abi); + + let mut ruleset = Ruleset::default() + .handle_access(access_all)? + .create()? + // Read-only access to / (entire filesystem). + .add_rules(landlock::path_beneath_rules(&["/"], access_read))?; + + // Add write permissions to specified directory of provided + if !hierarchies.is_empty() { + ruleset = ruleset.add_rules( + hierarchies + .iter() + .map::, _>(|p| { + Ok(PathBeneath::new(PathFd::new(p)?, access_all)) + }), + )?; + } + + Ok(ruleset.restrict_self()?) +} + +/// Restricts the process to only access the given hierarchies using Landlock, if supported. +/// Accepts multiple allowed directories as &[&Path]. +pub fn init_sandbox(allowed_dirs: &[&Path]) { + // if std::env::var("CI").is_ok() { + // return; + // } + + if is_landlock_supported() { + let paths: Vec<&str> = allowed_dirs + .iter() + .map(|p| p.to_str().expect("Cannot convert path")) + .collect(); + + let status = if !paths.is_empty() { + restrict_paths(&paths) + } else { + restrict_paths(&[]) + }; + + match status { + Ok(_status) => { + // check + } + Err(_e) => { + // log warning + std::process::exit(EXIT_FAILURE); + } + } + } else { + // warn!("Landlock is NOT supported on this platform or kernel (<5.19)."); + } +} \ No newline at end of file