improve code structure

This commit is contained in:
valoq 2025-06-29 12:10:20 +02:00
parent 1aa6bad460
commit a6b3e96df5
No known key found for this signature in database
GPG Key ID: 19F09A0FB865CBD8
4 changed files with 61 additions and 39 deletions

View File

@ -5,6 +5,7 @@ use std::{
}; };
use fs_err as fs; use fs_err as fs;
use crate::utils::landlock;
#[cfg(not(feature = "bzip3"))] #[cfg(not(feature = "bzip3"))]
use crate::archive; use crate::archive;
@ -316,6 +317,10 @@ fn execute_decompression(
is_output_dir_provided: bool, is_output_dir_provided: bool,
is_smart_unpack: bool, is_smart_unpack: bool,
) -> crate::Result<ControlFlow<(), usize>> { ) -> crate::Result<ControlFlow<(), usize>> {
// init landlock sandbox to restrict file system write access to output_dir
landlock::init_sandbox(output_dir);
if is_smart_unpack { if is_smart_unpack {
return smart_unpack(unpack_fn, output_dir, output_file_path, question_policy); return smart_unpack(unpack_fn, output_dir, output_file_path, question_policy);
} }

View File

@ -4,6 +4,7 @@ use std::{
}; };
use fs_err as fs; use fs_err as fs;
use crate::utils::landlock;
use crate::{ use crate::{
archive, archive,
@ -23,6 +24,11 @@ pub fn list_archive_contents(
question_policy: QuestionPolicy, question_policy: QuestionPolicy,
password: Option<&[u8]>, password: Option<&[u8]>,
) -> crate::Result<()> { ) -> 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)?; let reader = fs::File::open(archive_path)?;
// Zip archives are special, because they require io::Seek, so it requires it's logic separated // Zip archives are special, because they require io::Seek, so it requires it's logic separated

View File

@ -7,10 +7,8 @@ pub mod error;
pub mod extension; pub mod extension;
pub mod list; pub mod list;
pub mod utils; pub mod utils;
//pub mod sandbox;
use std::{env, path::PathBuf}; use std::{env, path::PathBuf};
use std::path::Path;
use cli::CliArgs; use cli::CliArgs;
use once_cell::sync::Lazy; 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()?; let (args, skip_questions_positively, file_visibility_policy) = CliArgs::parse_and_validate_args()?;
// Get the output dir if specified, else use current dir // Get the output dir if specified, else use current dir
let working_dir = args.output_dir //let working_dir = args.output_dir
.clone() // .clone()
.unwrap_or_else(|| env::current_dir().unwrap_or_default()); // .unwrap_or_else(|| env::current_dir().unwrap_or_default());
// restrict filesystem access to working_dir; // restrict filesystem access to working_dir;
// 1. working_dir is either the output_dir specified by the -d option or // 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 // directory requires LANDLOCK_ACCESS_FS_MAKE_DIR
// expects either the .tmp-ouch-XXXXXX path or the specified output directory (-d option) // 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) 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).");
}
}

View File

@ -7,6 +7,11 @@ use landlock::{
}; };
use thiserror::Error; 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). /// Returns true if Landlock is supported by the running kernel (Linux kernel >= 5.19).
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
pub fn is_landlock_supported() -> bool { 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+. /// The Landlock ABI is set to v2 for compatibility with Linux 5.19+.
/// All hierarchies are given full access, but root ("/") is read-only. /// All hierarchies are given full access, but root ("/") is read-only.
pub fn restrict_paths(hierarchies: &[&str]) -> Result<RestrictionStatus, MyRestrictError> { fn restrict_paths(hierarchies: &[&str]) -> Result<RestrictionStatus, MyRestrictError> {
// The Landlock ABI should be incremented (and tested) regularly. // The Landlock ABI should be incremented (and tested) regularly.
// ABI set to 2 in compatibility with linux 5.19 and higher // ABI set to 2 in compatibility with linux 5.19 and higher
let abi = ABI::V2; let abi = ABI::V2;
let access_all = AccessFs::from_all(abi); let access_all = AccessFs::from_all(abi);
let access_read = AccessFs::from_read(abi); let access_read = AccessFs::from_read(abi);
Ok(Ruleset::default()
let mut ruleset = Ruleset::default()
.handle_access(access_all)? .handle_access(access_all)?
.create()? .create()?
// Read-only access to / (entire filesystem). // Read-only access to / (entire filesystem).
.add_rules(landlock::path_beneath_rules(&["/"], access_read))? .add_rules(landlock::path_beneath_rules(&["/"], access_read))?;
.add_rules(
// Add write permissions to specified directory of provided
if !hierarchies.is_empty() {
ruleset = ruleset.add_rules(
hierarchies hierarchies
.iter() .iter()
.map::<Result<_, MyRestrictError>, _>(|p| { .map::<Result<_, MyRestrictError>, _>(|p| {
Ok(PathBeneath::new(PathFd::new(p)?, access_all)) Ok(PathBeneath::new(PathFd::new(p)?, access_all))
}), }),
)? )?;
.restrict_self()?) }
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).");
}
}