From a6b3e96df57bd055d1a98a28484bdd5be4ed30de Mon Sep 17 00:00:00 2001 From: valoq Date: Sun, 29 Jun 2025 12:10:20 +0200 Subject: [PATCH] improve code structure --- src/commands/decompress.rs | 5 ++++ src/commands/list.rs | 6 +++++ src/main.rs | 36 +++----------------------- src/utils/landlock.rs | 53 +++++++++++++++++++++++++++++++++----- 4 files changed, 61 insertions(+), 39 deletions(-) diff --git a/src/commands/decompress.rs b/src/commands/decompress.rs index 6c254ad..0885f8c 100644 --- a/src/commands/decompress.rs +++ b/src/commands/decompress.rs @@ -5,6 +5,7 @@ use std::{ }; use fs_err as fs; +use crate::utils::landlock; #[cfg(not(feature = "bzip3"))] use crate::archive; @@ -316,6 +317,10 @@ fn execute_decompression( is_output_dir_provided: bool, is_smart_unpack: bool, ) -> crate::Result> { + + // init landlock sandbox to restrict file system write access to output_dir + 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 4a344a7..4fafec7 100644 --- a/src/commands/list.rs +++ b/src/commands/list.rs @@ -4,6 +4,7 @@ use std::{ }; use fs_err as fs; +use crate::utils::landlock; use crate::{ archive, @@ -23,6 +24,11 @@ pub fn list_archive_contents( question_policy: QuestionPolicy, password: Option<&[u8]>, ) -> crate::Result<()> { + + // Initialize landlock sandbox with empty write path + // This allows only read access to the filesystem + //landlock::init_sandbox(None); + let reader = fs::File::open(archive_path)?; // Zip archives are special, because they require io::Seek, so it requires it's logic separated diff --git a/src/main.rs b/src/main.rs index 1e1466a..4375188 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,10 +7,8 @@ pub mod error; pub mod extension; pub mod list; pub mod utils; -//pub mod sandbox; use std::{env, path::PathBuf}; -use std::path::Path; use cli::CliArgs; use once_cell::sync::Lazy; @@ -50,9 +48,9 @@ fn run() -> Result<()> { let (args, skip_questions_positively, file_visibility_policy) = CliArgs::parse_and_validate_args()?; // Get the output dir if specified, else use current dir - let working_dir = args.output_dir - .clone() - .unwrap_or_else(|| env::current_dir().unwrap_or_default()); + //let working_dir = args.output_dir + // .clone() + // .unwrap_or_else(|| env::current_dir().unwrap_or_default()); // restrict filesystem access to working_dir; // 1. working_dir is either the output_dir specified by the -d option or @@ -68,33 +66,7 @@ fn run() -> Result<()> { // directory requires LANDLOCK_ACCESS_FS_MAKE_DIR // expects either the .tmp-ouch-XXXXXX path or the specified output directory (-d option) - init_sandbox(&working_dir); + //utils::landlock::init_sandbox(&working_dir); commands::run(args, skip_questions_positively, file_visibility_policy) } - -fn init_sandbox(allowed_dir: &Path) { - - if std::env::var("CI").is_ok() { - return; - } - - - if utils::landlock::is_landlock_supported() { - - let path_str = allowed_dir.to_str().expect("Cannot convert path"); - match utils::landlock::restrict_paths(&[path_str]) { - 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)."); - } - -} - diff --git a/src/utils/landlock.rs b/src/utils/landlock.rs index 8ab67a9..e7f256c 100644 --- a/src/utils/landlock.rs +++ b/src/utils/landlock.rs @@ -7,6 +7,11 @@ use landlock::{ }; 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 { @@ -43,24 +48,58 @@ pub enum MyRestrictError { /// /// The Landlock ABI is set to v2 for compatibility with Linux 5.19+. /// All hierarchies are given full access, but root ("/") is read-only. -pub fn restrict_paths(hierarchies: &[&str]) -> Result { +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); - Ok(Ruleset::default() + + 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_rules( + .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)) }), - )? - .restrict_self()?) -} \ No newline at end of file + )?; + } + + Ok(ruleset.restrict_self()?) +} + + +pub fn init_sandbox(allowed_dir: &Path) { + + if std::env::var("CI").is_ok() { + return; + } + + + if is_landlock_supported() { + + let path_str = allowed_dir.to_str().expect("Cannot convert path"); + + match restrict_paths(&[path_str]) { + 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)."); + } + +} +