mirror of
https://github.com/ouch-org/ouch.git
synced 2025-07-18 23:50:35 +00:00
add landlock
This commit is contained in:
parent
945ffde551
commit
61599dfa25
@ -20,6 +20,8 @@ Categories Used:
|
||||
|
||||
## [Unreleased](https://github.com/ouch-org/ouch/compare/0.6.1...HEAD)
|
||||
|
||||
- Add landlock support for linux filesystem isolation [\#723](https://github.com/ouch-org/ouch/pull/723) ([valoq](https://github.com/valoq))
|
||||
|
||||
### New Features
|
||||
|
||||
- Merge folders in decompression [\#798](https://github.com/ouch-org/ouch/pull/798) ([tommady](https://github.com/tommady))
|
||||
|
@ -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"
|
||||
|
@ -49,6 +49,8 @@ pub struct CliArgs {
|
||||
#[arg(short = 'c', long, global = true)]
|
||||
pub threads: Option<usize>,
|
||||
|
||||
pub output_dir: Option<PathBuf>,
|
||||
|
||||
// Ouch and claps subcommands
|
||||
#[command(subcommand)]
|
||||
pub cmd: Subcommand,
|
||||
@ -155,6 +157,7 @@ mod tests {
|
||||
// This is usually replaced in assertion tests
|
||||
password: None,
|
||||
threads: None,
|
||||
output_dir: None,
|
||||
cmd: Subcommand::Decompress {
|
||||
// Put a crazy value here so no test can assert it unintentionally
|
||||
files: vec!["\x00\x11\x22".into()],
|
||||
|
37
src/main.rs
37
src/main.rs
@ -7,8 +7,10 @@ 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;
|
||||
@ -43,5 +45,40 @@ fn main() {
|
||||
|
||||
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());
|
||||
|
||||
// restrict filesystem access to working_dir;
|
||||
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_support::is_landlock_supported() {
|
||||
|
||||
let path_str = allowed_dir.to_str().expect("Cannot convert path");
|
||||
match sandbox::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).");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
39
src/sandbox.rs
Normal file
39
src/sandbox.rs
Normal file
@ -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<RestrictionStatus, MyRestrictError> {
|
||||
// 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::<Result<_, MyRestrictError>, _>(|p| {
|
||||
Ok(PathBeneath::new(PathFd::new(p)?, access_all))
|
||||
}),
|
||||
)?
|
||||
.restrict_self()?)
|
||||
}
|
||||
|
||||
|
24
src/utils/landlock_support.rs
Normal file
24
src/utils/landlock_support.rs
Normal file
@ -0,0 +1,24 @@
|
||||
//Check Landlock kernel support (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::<u32>(), minor.parse::<u32>()) {
|
||||
return (major > 5) || (major == 5 && minor >= 19);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
pub fn is_landlock_supported() -> bool {
|
||||
false
|
||||
}
|
@ -10,6 +10,7 @@ mod fs;
|
||||
pub mod io;
|
||||
pub mod logger;
|
||||
mod question;
|
||||
pub mod landlock_support;
|
||||
|
||||
pub use self::{
|
||||
file_visibility::FileVisibilityPolicy,
|
||||
|
8
tests/landlock.rs
Normal file
8
tests/landlock.rs
Normal file
@ -0,0 +1,8 @@
|
||||
#[test]
|
||||
fn test_landlock_restriction() {
|
||||
if !cfg!(target_os = "linux") {
|
||||
eprintln!("Skipping Landlock test: not running on Linux.");
|
||||
return;
|
||||
}
|
||||
// TODO: Add test
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user