diff --git a/CHANGELOG.md b/CHANGELOG.md index e0f569f..6d95a43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ Categories Used: - Merge folders in decompression [\#798](https://github.com/ouch-org/ouch/pull/798) ([tommady](https://github.com/tommady)) - Add `--no-smart-unpack` flag to decompression command to disable smart unpack [\#809](https://github.com/ouch-org/ouch/pull/809) ([talis-fb](https://github.com/talis-fb)) +- Add landlock support for linux filesystem isolation [\#723](https://github.com/ouch-org/ouch/pull/723) ([valoq](https://github.com/valoq)) ### Improvements diff --git a/Cargo.toml b/Cargo.toml index fc692b6..b6866e7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,7 @@ gzp = { version = "0.11.3", default-features = false, features = [ "snappy_default", ] } ignore = "0.4.23" +landlock = "0.4.2" libc = "0.2.155" linked-hash-map = "0.5.6" lz4_flex = "0.11.3" @@ -39,6 +40,7 @@ sevenz-rust2 = { version = "0.13.1", features = ["compress", "aes256"] } snap = "1.1.1" tar = "0.4.42" tempfile = "3.10.1" +thiserror = "2.0.12" time = { version = "0.3.36", default-features = false } unrar = { version = "0.5.7", optional = true } xz2 = "0.1.7" diff --git a/src/main.rs b/src/main.rs index 3f1f7dd..fe781f5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,7 @@ pub mod error; pub mod extension; pub mod list; pub mod utils; +pub mod sandbox; use std::{env, path::PathBuf}; @@ -43,5 +44,41 @@ fn main() { fn run() -> Result<()> { let (args, skip_questions_positively, file_visibility_policy) = CliArgs::parse_and_validate_args()?; + + // check args if case A: "decompress -d " or case B: "decompress -r" is used + //if true + //Case A: + // write_dirs = outputdir + //Case B: + // write_dir = inputdir + + //init_sandbox( write_dirs ); + init_sandbox(); + commands::run(args, skip_questions_positively, file_visibility_policy) } + +// init_sandbox( write_dirs +fn init_sandbox() { + + //if empty write_dirs + //{ + //restrict write permissions to the current workign directory + let working_dir = get_current_working_dir().expect("Cannot get current working dir"); + let path_str = working_dir.to_str().expect("Cannot convert path"); + + //} + //else + //path_str = write_dirs; + let status = sandbox::restrict_paths(&[path_str]).expect("failed to build the ruleset"); + //} + + // todos: + // check status and report error or warning if landlock restriction failed + // add os detection to encapsulate this feature to be executed on linux only + // add implementation for other OS +} + +fn get_current_working_dir() -> std::io::Result { + env::current_dir() +} diff --git a/src/sandbox.rs b/src/sandbox.rs new file mode 100644 index 0000000..9c555f7 --- /dev/null +++ b/src/sandbox.rs @@ -0,0 +1,39 @@ +// generic landlock 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; + +#[derive(Debug, Error)] +pub enum MyRestrictError { + #[error(transparent)] + Ruleset(#[from] RulesetError), + #[error(transparent)] + AddRule(#[from] PathFdError), +} + +pub 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() + .handle_access(access_all)? + .create()? + // Read-only access to / (entire filesystem). + .add_rules(landlock::path_beneath_rules(&["/"], access_read))? + .add_rules( + hierarchies + .iter() + .map::, _>(|p| { + Ok(PathBeneath::new(PathFd::new(p)?, access_all)) + }), + )? + .restrict_self()?) +} + +