### Example: restrict_paths Source: https://landlock.io/rust-landlock/src/landlock/ruleset.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E A complete example showing how to build a ruleset with file hierarchies and apply restrictions, handling multiple error types. ```APIDOC ## Example: restrict_paths ### Description A complete example demonstrating how to create a ruleset, add rules for file hierarchies, and restrict the current process. ### Code ```rust use landlock::{ Access, AccessFs, PathBeneath, PathFd, PathFdError, RestrictionStatus, Ruleset, RulesetAttr, RulesetCreatedAttr, RulesetError, ABI, }; use thiserror::Error; #[derive(Debug, Error)] enum MyRestrictError { #[error(transparent)] Ruleset(#[from] RulesetError), #[error(transparent)] AddRule(#[from] PathFdError), } fn restrict_paths(hierarchies: &[&str]) -> Result { // The Landlock ABI should be incremented (and tested) regularly. let abi = ABI::V1; let access_all = AccessFs::from_all(abi); n let access_read = AccessFs::from_read(abi); n Ok(Ruleset::default() n .handle_access(access_all)? n .create()? .add_rules( hierarchies n .iter() n .map::, _>(|p| { Ok(PathBeneath::new(PathFd::new(p)?, access_read)) }), )? .restrict_self()?) } let status = restrict_paths(&["/usr", "/home"]).expect("failed to build the ruleset"); ``` ``` -------------------------------- ### AccessFs Usage Example Source: https://landlock.io/rust-landlock/landlock/enum.AccessFs.html Demonstrates how to create and manipulate sets of AccessFs rights using BitFlags and the make_bitflags macro. ```rust use landlock::{ABI, Access, AccessFs, BitFlags, make_bitflags}; let exec = AccessFs::Execute; let exec_set: BitFlags = exec.into(); let file_content = make_bitflags!(AccessFs::{Execute | WriteFile | ReadFile}); let fs_v1 = AccessFs::from_all(ABI::V1); let without_exec = fs_v1 & !AccessFs::Execute; assert_eq!(fs_v1 | AccessFs::Refer, AccessFs::from_all(ABI::V2)); ``` -------------------------------- ### Using make_bitflags Source: https://landlock.io/rust-landlock/landlock/macro.make_bitflags.html?search= Examples showing how to use the macro for creating bitflag instances and its usage in const contexts. ```rust let x = make_bitflags!(Test::{A | C}); assert_eq!(x, Test::A | Test::C); // Also works in const contexts: const X: BitFlags = make_bitflags!(Test::A); ``` -------------------------------- ### Example: restrict_thread using path_beneath_rules Source: https://landlock.io/rust-landlock/landlock/fn.path_beneath_rules.html Example usage of `path_beneath_rules` to create read-only rules for /usr, /etc, /dev and read-write rules for /home, /tmp, then restrict the current thread. It prints the enforcement status and warns if not enforced. ```rust use landlock::{ ABI, Access, AccessFs, Ruleset, RulesetAttr, RulesetCreatedAttr, RulesetStatus, RulesetError, path_beneath_rules, }; fn restrict_thread() -> Result<(), RulesetError> { let abi = ABI::V1; let status = Ruleset::default() .handle_access(AccessFs::from_all(abi))? .create()? // Read-only access to /usr, /etc and /dev. .add_rules(path_beneath_rules(&["/usr", "/etc", "/dev"], AccessFs::from_read(abi)))? // Read-write access to /home and /tmp. .add_rules(path_beneath_rules(&["/home", "/tmp"], AccessFs::from_all(abi)))? .restrict_self()?; match status.ruleset { // The FullyEnforced case must be tested by the developer. RulesetStatus::FullyEnforced => println!("Fully sandboxed."), RulesetStatus::PartiallyEnforced => println!("Partially sandboxed."), // Users should be warned that they are not protected. RulesetStatus::NotEnforced => println!("Not sandboxed! Please update your kernel."), } Ok(()) } ``` -------------------------------- ### Create a NetPort rule Source: https://landlock.io/rust-landlock/landlock/struct.NetPort.html Example showing how to create a new NetPort rule for binding to port 80. ```rust use landlock::{AccessNet, NetPort}; fn bind_http() -> NetPort { NetPort::new(80, AccessNet::BindTcp) } ``` -------------------------------- ### Example: creating a PathBeneath with PathFd Source: https://landlock.io/rust-landlock/landlock/struct.PathFd.html Shows how to use PathFd::new to open a root directory and create a PathBeneath with a given access rights set. Returns a Result with PathFdError. ```rust use landlock::{AccessFs, PathBeneath, PathFd, PathFdError}; fn allowed_root_dir(access: AccessFs) -> Result, PathFdError> { let fd = PathFd::new("/")?; Ok(PathBeneath::new(fd, access)) } ``` -------------------------------- ### RestrictSelf usage example Source: https://landlock.io/rust-landlock/src/landlock/restrict_self.rs.html Example showing how to use the RestrictSelf builder to configure log_subdomains and apply the restriction. ```APIDOC ## RestrictSelf usage example ### Description Example demonstrating how to use the RestrictSelf builder to configure log_subdomains and apply the restriction. ### Example ```rust use landlock::*; let status = RestrictSelf::default() .log_subdomains(false)? .apply()?; println!("Landlock status: {:?}", status.landlock); # Ok::<(), RulesetError>(()) ``` ### Notes - The apply() method returns a RestrictSelfStatus with the Landlock support status and effective flag states. - Use set_compatibility() to control how unsupported flags are handled. ``` -------------------------------- ### ruleset.rs module source with Ruleset builder example Source: https://landlock.io/rust-landlock/src/landlock/ruleset.rs.html This is the full source of the `ruleset.rs` module, including the `Rule` and `PrivateRule` traits, the `RulesetStatus` enum, the `RestrictionStatus` struct, and the `Ruleset` builder documentation with a simple example. The example shows how to create a ruleset using `Ruleset::default()`, handle access, create the ruleset, add a rule with `PathBeneath`, and call `restrict_self()`. It uses `ABI::V1` and `AccessFs::from_all` and `from_read` to define access rights. ```rust // SPDX-License-Identifier: Apache-2.0 OR MIT use crate::compat::private::OptionCompatLevelMut; use crate::flags::{RestrictSelfFlag, SyscallFlagExt}; use crate::prctl::try_set_no_new_privs; use crate::restrict_self::private::RestrictSelfFlagsState; use crate::{ uapi, AccessFs, AccessNet, AddRuleError, AddRulesError, BitFlags, CompatLevel, CompatState, Compatibility, Compatible, CreateRulesetError, HandledAccess, LandlockStatus, PrivateHandledAccess, RestrictSelfAttr, RestrictSelfError, RulesetError, Scope, ScopeError, TryCompat, }; use std::io::Error; use std::mem::size_of_val; use std::os::unix::io::{AsRawFd, FromRawFd, OwnedFd}; #[cfg(test)] use crate::*; // Public interface without methods and which is impossible to implement outside this crate. pub trait Rule: PrivateRule where T: HandledAccess, { } // PrivateRule is not public outside this crate. pub trait PrivateRule where Self: TryCompat + Compatible, T: HandledAccess, { const TYPE_ID: uapi::landlock_rule_type; /// Returns a raw pointer to the rule's inner attribute. /// /// The caller must ensure that the rule outlives the pointer this function returns, or else it /// will end up pointing to garbage. fn as_ptr(&mut self) -> *const libc::c_void; fn check_consistency(&self, ruleset: &RulesetCreated) -> Result<(), AddRulesError>; } /// Enforcement status of a ruleset. #[derive(Debug, PartialEq, Eq)] pub enum RulesetStatus { /// All requested restrictions are enforced. FullyEnforced, /// Some requested restrictions are enforced, /// following a best-effort approach. PartiallyEnforced, /// The running system doesn't support Landlock /// or a subset of the requested Landlock features. NotEnforced, } impl From for RulesetStatus { fn from(state: CompatState) -> Self { match state { CompatState::Init | CompatState::No | CompatState::Dummy => RulesetStatus::NotEnforced, CompatState::Full => RulesetStatus::FullyEnforced, CompatState::Partial => RulesetStatus::PartiallyEnforced, } } } // The Debug, PartialEq and Eq implementations are useful for crate users to debug and check the // result of a Landlock ruleset enforcement. /// Status of a [`RulesetCreated`] /// after calling [`restrict_self()`](RulesetCreated::restrict_self). #[derive(Debug, PartialEq, Eq)] #[non_exhaustive] pub struct RestrictionStatus { /// Status of the Landlock ruleset enforcement. pub ruleset: RulesetStatus, /// Status of `prctl(2)`'s `PR_SET_NO_NEW_PRIVS` enforcement. pub no_new_privs: bool, /// Status of Landlock for the running kernel. pub landlock: LandlockStatus, /// Same-exec logging is enabled (default: true). pub log_same_exec: bool, /// New-exec logging is enabled (default: false). pub log_new_exec: bool, /// Subdomain logging is enabled (default: true). pub log_subdomains: bool, /// The ruleset was applied to all threads of the process (default: false). pub all_threads: bool, } /// Landlock ruleset builder. /// /// `Ruleset` enables to create a Landlock ruleset in a flexible way /// following the builder pattern. /// Most build steps return a [`Result`] with [`RulesetError`]. /// /// You should probably not create more than one ruleset per application. /// Creating multiple rulesets is only useful when gradually restricting an application /// (e.g., a first set of generic restrictions before reading any file, /// then a second set of tailored restrictions after reading the configuration). /// /// # Simple example /// /// Simple helper handling only Landlock-related errors. /// /// ``` /// use landlock::{ /// Access, AccessFs, PathBeneath, PathFd, RestrictionStatus, Ruleset, RulesetAttr, /// RulesetCreatedAttr, RulesetError, ABI, /// }; /// use std::os::unix::io::AsFd; /// /// fn restrict_fd(hierarchy: T) -> Result /// where /// T: AsFd, /// { /// // The Landlock ABI should be incremented (and tested) regularly. /// let abi = ABI::V1; /// let access_all = AccessFs::from_all(abi); /// let access_read = AccessFs::from_read(abi); /// Ok(Ruleset::default() /// .handle_access(access_all)? /// .create()? /// .add_rule(PathBeneath::new(hierarchy, access_read))? /// .restrict_self()?) /// } /// /// let fd = PathFd::new("/home").expect("failed to open /home"); /// let status = restrict_fd(fd).expect("failed to build the ruleset"); /// ``` /// /// # Generic example /// ``` -------------------------------- ### Define PathFd struct with example Source: https://landlock.io/rust-landlock/src/landlock/fs.rs.html?search= Defines the PathFd struct with documentation and an example showing how to create a PathBeneath from a PathFd for a root directory. ```rust /// Simple helper to open a file or a directory with the `O_PATH` flag. /// /// This is the recommended way to identify a path /// and manage the lifetime of the underlying opened file descriptor. /// Indeed, using other [`AsFd`] implementations such as [`File`] brings more complexity /// and may lead to unexpected errors (e.g., denied access). /// /// [`File`]: std::fs::File /// /// # Example /// /// ``` /// use landlock::{AccessFs, PathBeneath, PathFd, PathFdError}; /// /// fn allowed_root_dir(access: AccessFs) -> Result, PathFdError> { /// let fd = PathFd::new("/")?; /// Ok(PathBeneath::new(fd, access)) /// } /// ``` #[derive(Debug)] pub struct PathFd { fd: OwnedFd, } ``` -------------------------------- ### Go library usage with landlock.V2.RestrictPaths and WithRefer Source: https://landlock.io/news/2 Usage example for the Go library go-landlock, showing how to restrict paths with read-write access and the refer flag. Requires Landlock ABI v2 support. ```go err := landlock.V2.RestrictPaths( landlock.RWDirs("/src", "/dest").WithRefer(), ) ``` -------------------------------- ### Example: BindTcp and ConnectTcp usage with landlock::AccessNet Source: https://landlock.io/rust-landlock/landlock/enum.AccessNet.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Shows how to create a `BitFlags` set using `AccessNet::BindTcp`, the `make_bitflags!` macro, and `AccessNet::from_all(ABI::V4)`. The assert verifies that `bind_connect` equals the network access rights for ABI V4. ```rust use landlock::{ABI, Access, AccessNet, BitFlags, make_bitflags}; let bind = AccessNet::BindTcp; let bind_set: BitFlags = bind.into(); let bind_connect = make_bitflags!(AccessNet::{BindTcp | ConnectTcp}); let net_v4 = AccessNet::from_all(ABI::V4); assert_eq!(bind_connect, net_v4); ``` -------------------------------- ### restrict_self_log_subdomains test setup Source: https://landlock.io/rust-landlock/src/landlock/restrict_self.rs.html?search= Partial test setup for verifying log_subdomains flag with mocked ABI V7. ```rust #[test] fn restrict_self_log_subdomains() { // With mocked V7: flag should be set. // TODO: Add real kernel test with audit parsing for end-to-end validation. let rs = RestrictSelf { requested_flags: 0, actual_flags: 0, no_new_privs: true, compat: ABI::V7.into(), ``` -------------------------------- ### Ruleset compatibility dummy test Source: https://landlock.io/rust-landlock/src/landlock/ruleset.rs.html?search= Iterates through compatibility levels to verify basic setup. ```rust #[test] fn ruleset_compat_dummy() { for level in [CompatLevel::BestEffort, CompatLevel::SoftRequirement] { println!("level: {:?}", level); ``` -------------------------------- ### Rust library usage with Ruleset and path_beneath_rules Source: https://landlock.io/news/2 Usage example for the Rust library, demonstrating how to create a ruleset, add rules for read-only and read-write access, and restrict the current process. Uses ABI::V1 and handles errors with the ? operator. ```rust let abi = ABI::V1; let status = Ruleset::new() .handle_access(AccessFs::from_all(abi))? .create()? // Read-only access to /usr, /etc and /dev. .add_rules(path_beneath_rules(&["/usr", "/etc", "/dev"], AccessFs::from_read(abi)))? // Read-write access to /home and /tmp. .add_rules(path_beneath_rules(&["/home", "/tmp"], AccessFs::from_all(abi)))? .restrict_self()?; ``` -------------------------------- ### Creating and combining Scope bit flags Source: https://landlock.io/rust-landlock/landlock/enum.Scope.html Shows how to create a BitFlags from a single scope, combine scopes with make_bitflags!, and obtain all scopes for a given ABI. The example asserts that the combined signal and abstract Unix socket scopes equal the set from ABI::V6. ```rust use landlock::{ABI, Access, Scope, BitFlags, make_bitflags}; let signal = Scope::Signal; let signal_set: BitFlags = signal.into(); let signal_uds = make_bitflags!(Scope::{Signal | AbstractUnixSocket}); let scope_v6 = Scope::from_all(ABI::V6); assert_eq!(signal_uds, scope_v6); ``` -------------------------------- ### Apply Landlock restrictions with RestrictSelf Source: https://landlock.io/rust-landlock/landlock/struct.RestrictSelf.html Example showing how to use the RestrictSelf builder to apply Landlock restrictions. ```rust use landlock::*; let status = RestrictSelf::default() .log_subdomains(false)? .apply()?; println!("Landlock status: {:?}", status.landlock); ``` -------------------------------- ### Create PathBeneath for /home with ReadDir access Source: https://landlock.io/rust-landlock/landlock/struct.PathBeneath.html?search= Example usage of PathBeneath::new to create a rule for the /home directory with ReadDir access. It returns a Result and uses the ? operator to propagate PathFdError. ```rust use landlock::{AccessFs, PathBeneath, PathFd, PathFdError}; fn home_dir() -> Result, PathFdError> { Ok(PathBeneath::new(PathFd::new("/home")?, AccessFs::ReadDir)) } ``` -------------------------------- ### Test ruleset compatibility dummy loop Source: https://landlock.io/rust-landlock/src/landlock/ruleset.rs.html?search=u32+-%3E+bool Starts a test that iterates over compatibility levels `BestEffort` and `SoftRequirement`, printing each level. The test body is incomplete in the source. ```rust 1124#[test] 1125fn ruleset_compat_dummy() { 1126 for level in [CompatLevel::BestEffort, CompatLevel::SoftRequirement] { 1127 println!("level: {:?}", level); 1128 ``` -------------------------------- ### PathBeneath compatibility and rule implementation in Rust Source: https://landlock.io/rust-landlock/src/landlock/fs.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E These Rust snippets from the landlock crate's fs module illustrate PathBeneath compatibility handling, rule implementation, and tests. The first snippet iterates over compatibility levels and verifies that the inner attribute buffer is synchronized only after calling as_ptr(). The second implements OptionCompatLevelMut and Compatible for PathBeneath and its mutable reference. The third tests default and explicit compatibility levels. The fourth implements PrivateRule for PathBeneath, checking that requested access rights are a subset of the ruleset's handled rights. The fifth test verifies that adding a rule with unhandled access returns an UnhandledAccess error. The final snippet is a doc example showing how to create a PathBeneath for the root directory using PathFd::new("/"). ```rust let full_access = AccessFs::from_all(ABI::V1); for compat_level in &[ CompatLevel::BestEffort, CompatLevel::SoftRequirement, CompatLevel::HardRequirement, ] { let mut compat_state = CompatState::Init; let mut path_beneath = PathBeneath::new(PathFd::new("/").unwrap(), full_access) .try_compat(abi, *compat_level, &mut compat_state) .unwrap() .unwrap(); assert_eq!(compat_state, CompatState::Full); // Without synchronization. let raw_access = path_beneath.attr.allowed_access; assert_eq!(raw_access, 0); // Synchronize the inner attribute buffer. let _ = path_beneath.as_ptr(); let raw_access = path_beneath.attr.allowed_access; assert_eq!(raw_access, full_access.bits()); } ``` ```rust impl OptionCompatLevelMut for PathBeneath { fn as_option_compat_level_mut(&mut self) -> &mut Option { &mut self.compat_level } } impl OptionCompatLevelMut for &mut PathBeneath { fn as_option_compat_level_mut(&mut self) -> &mut Option { &mut self.compat_level } } impl Compatible for PathBeneath {} impl Compatible for &mut PathBeneath {} ``` ```rust #[test] fn path_beneath_compatibility() { let mut path = PathBeneath::new(PathFd::new("/").unwrap(), AccessFs::from_all(ABI::V1)); let path_ref = &mut path; let level = path_ref.as_option_compat_level_mut(); assert_eq!(level, &None); assert_eq!( as Into>::into(*level), CompatLevel::BestEffort ); path_ref.set_compatibility(CompatLevel::SoftRequirement); assert_eq!( path_ref.as_option_compat_level_mut(), &Some(CompatLevel::SoftRequirement) ); path.set_compatibility(CompatLevel::HardRequirement); } ``` ```rust impl PrivateRule for PathBeneath where F: AsFd, { const TYPE_ID: uapi::landlock_rule_type = uapi::landlock_rule_type_LANDLOCK_RULE_PATH_BENEATH; fn as_ptr(&mut self) -> *const libc::c_void { self.attr.parent_fd = self.parent_fd.as_fd().as_raw_fd(); self.attr.allowed_access = self.allowed_access.bits(); &self.attr as *const _ as _ } fn check_consistency(&self, ruleset: &RulesetCreated) -> Result<(), AddRulesError> { // Checks that this rule doesn't contain a superset of the access-rights handled by the // ruleset. This check is about requested access-rights but not actual access-rights. // Indeed, we want to get a deterministic behavior, i.e. not based on the running kernel // (which is handled by Ruleset and RulesetCreated). if ruleset.requested_handled_fs.contains(self.allowed_access) { Ok(()) } else { Err(AddRuleError::UnhandledAccess { access: self.allowed_access, incompatible: self.allowed_access & !ruleset.requested_handled_fs, } .into()) } } } ``` ```rust #[test] fn path_beneath_check_consistency() { use crate::*; let ro_access = AccessFs::ReadDir | AccessFs::ReadFile; let rx_access = AccessFs::Execute | AccessFs::ReadFile; assert!(matches!( Ruleset::from(ABI::Unsupported) .handle_access(ro_access) .unwrap() .create() .unwrap() .add_rule(PathBeneath::new(PathFd::new("/").unwrap(), rx_access)) .unwrap_err(), RulesetError::AddRules(AddRulesError::Fs(AddRuleError::UnhandledAccess { access, incompatible })) if access == rx_access && incompatible == AccessFs::Execute )); } ``` ```rust use landlock::{AccessFs, PathBeneath, PathFd, PathFdError}; fn allowed_root_dir(access: AccessFs) -> Result, PathFdError> { let fd = PathFd::new("/")?; Ok(PathBeneath::new(fd, access)) } ``` -------------------------------- ### Configure and apply RestrictSelf with log_subdomains(false) Source: https://landlock.io/rust-landlock/src/landlock/restrict_self.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Use when configuring a RestrictSelf builder without creating a Landlock domain. The example disables subdomain logging and applies the restriction, then prints the resulting Landlock status. Requires Landlock ABI v7 or later; no_new_privs is enforced by default unless opted out via no_new_privs(false). ```rust use landlock::*; let status = RestrictSelf::default() .log_subdomains(false)? .apply()?; println!("Landlock status: {:?}", status.landlock); # Ok::<(), RulesetError>(()) ``` -------------------------------- ### Get File Access Rights Source: https://landlock.io/rust-landlock/src/landlock/fs.rs.html?search=std%3A%3Avec Gets the access rights legitimate for non-directory files. ```rust pub fn from_file(abi: ABI) -> BitFlags { Self::from_all(abi) & ACCESS_FILE } ``` -------------------------------- ### Errno Source: https://landlock.io/rust-landlock/landlock/index.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Get the underlying errno value. ```APIDOC ## Struct: Errno ### Description Get the underlying errno value. ``` -------------------------------- ### Create a full BitFlags set Source: https://landlock.io/rust-landlock/landlock/struct.BitFlags.html?search=u32+-%3E+bool Demonstrates creating a BitFlags instance with all flags set using BitFlags::all() and verifying its state. ```rust #[bitflags] #[repr(u8)] #[derive(Clone, Copy, PartialEq, Eq)] enum MyFlag { One = 1 << 0, Two = 1 << 1, Three = 1 << 2, } let empty: BitFlags = BitFlags::all(); assert!(empty.is_all()); assert_eq!(empty.contains(MyFlag::One), true); assert_eq!(empty.contains(MyFlag::Two), true); assert_eq!(empty.contains(MyFlag::Three), true); ``` -------------------------------- ### Compatibility methods including try_compat_binary Source: https://landlock.io/rust-landlock/src/landlock/compat.rs.html?search=std%3A%3Avec Provides the `Compatibility` implementation with methods `new`, `update`, `abi`, `status`, and `try_compat_binary`. The `try_compat_binary` method is documented to return `Ok(true)` for supported, `Ok(false)` for unsupported with `BestEffort` or `SoftRequirement`, and `Err` for unsupported with `HardRequirement`. ```rust impl Compatibility { // Compatibility is a semi-opaque struct. #[allow(clippy::new_without_default)] pub(crate) fn new() -> Self { LandlockStatus::current().into() } pub(crate) fn update(&mut self, state: CompatState) { self.state.update(state); } pub(crate) fn abi(&self) -> ABI { self.status.into() } pub(crate) fn status(&self) -> LandlockStatus { self.status } /// Handles the compat dispatch for a binary supported/not-supported check. /// /// This is factored out from the No branch of /// [`TryCompat::try_compat()`](crate::TryCompat::try_compat) for use by /// [`SyscallFlagExt::try_compat()`](crate::flags::SyscallFlagExt::try_compat), /// where a single flag is either fully supported or not (no Partial case). /// /// Returns `Ok(true)` if supported (caller should apply the flag), /// `Ok(false)` if unsupported but acceptable /// ([`BestEffort`](crate::CompatLevel::BestEffort) / /// [`SoftRequirement`](crate::CompatLevel::SoftRequirement)), or `Err` if /// unsupported with [`HardRequirement`](crate::CompatLevel::HardRequirement). pub(crate) fn try_compat_binary( &mut self, supported: bool, make_error: F, ) -> Result where F: FnOnce() -> E, { if supported { ``` -------------------------------- ### Simple example: restrict_fd function Source: https://landlock.io/rust-landlock/landlock/struct.Ruleset.html A helper function that builds a Landlock ruleset to restrict access to a file hierarchy. It uses ABI::V1, handles all access rights, and adds a read-only rule for the given path. The example opens /home and calls restrict_fd. ```rust use landlock::{ Access, AccessFs, PathBeneath, PathFd, RestrictionStatus, Ruleset, RulesetAttr, RulesetCreatedAttr, RulesetError, ABI, }; use std::os::unix::io::AsFd; fn restrict_fd(hierarchy: T) -> Result where T: AsFd, { // The Landlock ABI should be incremented (and tested) regularly. let abi = ABI::V1; let access_all = AccessFs::from_all(abi); let access_read = AccessFs::from_read(abi); Ok(Ruleset::default() .handle_access(access_all)? .create()? .add_rule(PathBeneath::new(hierarchy, access_read))? .restrict_self()?) } let fd = PathFd::new("/home").expect("failed to open /home"); let status = restrict_fd(fd).expect("failed to build the ruleset"); ``` -------------------------------- ### Test ruleset composition with filesystem and network scopes Source: https://landlock.io/rust-landlock/src/landlock/ruleset.rs.html?search= Demonstrates how handled filesystem and network accesses are composed using binary OR operations across different ABI versions. ```rust #[test] fn ruleset_created_fs_net_scope() { let access_fs = make_bitflags!(AccessFs::{Execute | ReadDir}); let access_net = make_bitflags!(AccessNet::{BindTcp | ConnectTcp}); let scopes = make_bitflags!(Scope::{AbstractUnixSocket | Signal}); // Tests composition (binary OR) of handled accesses. let ruleset = Ruleset::from(ABI::V5) .handle_access(access_fs) .unwrap() .scope(scopes) .unwrap() .handle_access(access_net) .unwrap(); assert_eq!(ruleset.requested_handled_fs, access_fs); assert_eq!(ruleset.actual_handled_fs, access_fs); assert_eq!(ruleset.requested_handled_net, access_net); assert_eq!(ruleset.actual_handled_net, access_net); assert_eq!(ruleset.requested_scoped, scopes); assert_eq!(ruleset.actual_scoped, BitFlags::::EMPTY); // Tests composition (binary OR) of handled accesses and scopes. let ruleset = Ruleset::from(ABI::V6) .handle_access(access_fs) .unwrap() .scope(scopes) .unwrap() .handle_access(access_net) .unwrap(); assert_eq!(ruleset.requested_handled_fs, access_fs); assert_eq!(ruleset.actual_handled_fs, access_fs); assert_eq!(ruleset.requested_handled_net, access_net); assert_eq!(ruleset.actual_handled_net, access_net); assert_eq!(ruleset.requested_scoped, scopes); assert_eq!(ruleset.actual_scoped, scopes); } ``` -------------------------------- ### AccessFs::from_file Source: https://landlock.io/rust-landlock/landlock/enum.AccessFs.html Gets the access rights legitimate for non-directory files. ```APIDOC ## AccessFs::from_file ### Description Gets the access rights legitimate for non-directory files. ### Method `pub fn from_file(abi: ABI) -> BitFlags` ### Parameters - **abi** (ABI) - Required - The ABI version to determine file access rights. ### Returns - **BitFlags** - The file access rights as a bitflags set. ``` -------------------------------- ### Test allow_root_compat Source: https://landlock.io/rust-landlock/src/landlock/lib.rs.html?search= Demonstrates creating a ruleset that allows all filesystem access rights at the root path. ```rust #[test] fn allow_root_compat() { let abi = ABI::V1; check_ruleset_support( abi, Some(abi), move |ruleset: Ruleset| -> _ { Ok(ruleset .handle_access(AccessFs::from_all(abi))? .create()? .add_rule(PathBeneath::new(PathFd::new("/")?, AccessFs::from_all(abi)))? .restrict_self()?) }, false, ); } ``` -------------------------------- ### AccessFs::from_file Source: https://landlock.io/rust-landlock/landlock/enum.AccessFs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Gets the access rights legitimate for non-directory files. ```APIDOC ## AccessFs::from_file ### Description Gets the access rights legitimate for non-directory files. ### Method `pub fn from_file(abi: ABI) -> BitFlags` ### Parameters - **abi** (ABI) - Required - The ABI version to use for determining file access rights. ### Returns - **BitFlags** - A BitFlags value containing the access rights legitimate for non-directory files. ``` -------------------------------- ### PathBeneath struct definition with doc example Source: https://landlock.io/rust-landlock/src/landlock/fs.rs.html Defines the `PathBeneath` struct, a Landlock rule for a file hierarchy, with a doc example showing how to create a rule for the `/home` directory with `AccessFs::ReadDir`. The struct holds a `landlock_path_beneath_attr`, a parent file descriptor, allowed access flags, and an optional compatibility level. ```rust /// Landlock rule for a file hierarchy. /// /// # Example /// /// ``` /// use landlock::{AccessFs, PathBeneath, PathFd, PathFdError}; /// /// fn home_dir() -> Result, PathFdError> { /// Ok(PathBeneath::new(PathFd::new("/home")?, AccessFs::ReadDir)) /// } /// ``` #[derive(Debug)] pub struct PathBeneath { attr: uapi::landlock_path_beneath_attr, // Ties the lifetime of a file descriptor to this object. parent_fd: F, allowed_access: BitFlags, compat_level: Option, } ``` -------------------------------- ### Test PathBeneath try_compat with ABI::V1 Source: https://landlock.io/rust-landlock/src/landlock/fs.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Tests `PathBeneath::try_compat` with `ABI::V1`. Verifies that `AccessFs::ReadDir | AccessFs::ReadFile` on a file path yields a `DirectoryAccess` error with `AccessFs::Refer` as incompatible, and that empty access yields an `AccessError::Empty` error. ```rust #[test] fn path_beneath_try_compat() { use crate::*; let abi = ABI::V1; for file in &["/etc/passwd", "/dev/null"] { let mut compat_state = CompatState::Init; let ro_access = AccessFs::ReadDir | AccessFs::ReadFile; assert!(matches!( PathBeneath::new(PathFd::new(file).unwrap(), ro_access) .try_compat(abi, CompatLevel::HardRequirement, &mut compat_state) .unwrap_err(), CompatError::PathBeneath(PathBeneathError::DirectoryAccess { access, incompatible }) if access == ro_access && incompatible == AccessFs::Refer )); let mut compat_state = CompatState::Init; assert!(matches!( PathBeneath::new(PathFd::new(file).unwrap(), BitFlags::EMPTY) .try_compat(abi, CompatLevel::BestEffort, &mut compat_state) .unwrap_err(), CompatError::Access(AccessError::Empty) )); } } ``` -------------------------------- ### CompatLevel Source: https://landlock.io/rust-landlock/landlock/index.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E See the Compatible documentation. ```APIDOC ## Enum: CompatLevel ### Description See the `Compatible` documentation. ``` -------------------------------- ### AccessFs::from_write Source: https://landlock.io/rust-landlock/landlock/enum.AccessFs.html Gets the access rights identified as write-only according to a specific ABI. Exclusive with `from_read()`. ```APIDOC ## AccessFs::from_write ### Description Gets the access rights identified as write-only according to a specific ABI. Exclusive with `from_read()`. ### Method `pub fn from_write(abi: ABI) -> BitFlags` ### Parameters - **abi** (ABI) - Required - The ABI version to determine write-only access rights. ### Returns - **BitFlags** - The write-only access rights as a bitflags set. ``` -------------------------------- ### PathBeneath::new, TryCompat impl, and path_beneath_try_compat_children test Source: https://landlock.io/rust-landlock/src/landlock/fs.rs.html?search= These Rust code blocks from the `PathBeneath` implementation and its tests show how to construct a `PathBeneath` with `new`, implement `TryCompat` for compatibility checks, and test error handling with `try_compat_children`. The test verifies that `AccessFs::Refer` is incompatible with `ABI::V1` and that `ABI::V2` produces a `DirectoryAccess` error. It uses `CompatState::Dummy` to avoid actual syscalls and asserts specific error variants. ```rust pub fn new(parent: F, access: A) -> Self where A: Into>, { PathBeneath { // Invalid access rights until as_ptr() is called. attr: unsafe { zeroed() }, parent_fd: parent, allowed_access: access.into(), compat_level: None, } } ``` ```rust impl TryCompat for PathBeneath where F: AsFd, { fn try_compat_children( mut self, abi: ABI, parent_level: L, compat_state: &mut CompatState, ) -> Result, CompatError> where L: Into, { // Checks with our own compatibility level, if any. self.allowed_access = match self.allowed_access.try_compat( abi, self.tailored_compat_level(parent_level), compat_state, )? { Some(a) => a, None => return Ok(None), }; Ok(Some(self)) } fn try_compat_inner( &mut self, _abi: ABI, ) -> Result, CompatError> { // Gets subset of valid accesses according the FD type. let valid_access = if is_file(&self.parent_fd).map_err(|e| PathBeneathError::StatCall { source: e })? { self.allowed_access & ACCESS_FILE } else { self.allowed_access }; if self.allowed_access != valid_access { let error = PathBeneathError::DirectoryAccess { access: self.allowed_access, incompatible: self.allowed_access ^ valid_access, } .into(); self.allowed_access = valid_access; // Linux would return EINVAL. Ok(CompatResult::Partial(error)) } else { Ok(CompatResult::Full) } } } ``` ```rust #[test] fn path_beneath_try_compat_children() { use crate::*; // AccessFs::Refer is not handled by ABI::V1 and only for directories. let access_file = AccessFs::ReadFile | AccessFs::Refer; // Test error ordering with ABI::V1 let mut ruleset = Ruleset::from(ABI::V1).handle_access(access_file).unwrap(); // Do not actually perform any syscall. ruleset.compat.state = CompatState::Dummy; assert!(matches!( RulesetCreated::new(ruleset, None) .set_compatibility(CompatLevel::HardRequirement) .add_rule(PathBeneath::new(PathFd::new("/dev/null").unwrap(), access_file)) .unwrap_err(), RulesetError::AddRules(AddRulesError::Fs(AddRuleError::Compat( CompatError::PathBeneath(PathBeneathError::DirectoryAccess { access, incompatible }) ))) if access == access_file && incompatible == AccessFs::Refer )); // Test error ordering with ABI::V2 let mut ruleset = Ruleset::from(ABI::V2).handle_access(access_file).unwrap(); // Do not actually perform any syscall. ruleset.compat.state = CompatState::Dummy; assert!(matches!( RulesetCreated::new(ruleset, None) .set_compatibility(CompatLevel::HardRequirement) .add_rule(PathBeneath::new(PathFd::new("/dev/null").unwrap(), access_file)) .unwrap_err(), RulesetError::AddRules(AddRulesError::Fs(AddRuleError::Compat( CompatError::PathBeneath(PathBeneathError::DirectoryAccess { access, incompatible }) ))) if access == access_file && incompatible == AccessFs::Refer )); } ``` -------------------------------- ### all Source: https://landlock.io/rust-landlock/landlock/struct.BitFlags.html?search=u32+-%3E+bool Creates a BitFlags with all flags set. Also available as BitFlags::ALL constant. ```APIDOC ## all ### Description Create a `BitFlags` with all flags set. ### Method all ### Signature pub fn all() -> BitFlags ### Returns - **BitFlags** - A BitFlags instance with all flags set. ### Example ```rust #[bitflags] #[repr(u8)] #[derive(Clone, Copy, PartialEq, Eq)] enum MyFlag { One = 1 << 0, Two = 1 << 1, Three = 1 << 2, } let empty: BitFlags = BitFlags::all(); assert!(empty.is_all()); assert_eq!(empty.contains(MyFlag::One), true); assert_eq!(empty.contains(MyFlag::Two), true); assert_eq!(empty.contains(MyFlag::Three), true); ``` ``` -------------------------------- ### AccessFs::from_read Source: https://landlock.io/rust-landlock/landlock/enum.AccessFs.html Gets the access rights identified as read-only according to a specific ABI. This method is exclusive with from_write(). ```APIDOC ## AccessFs::from_read ### Description Gets the access rights identified as read-only according to a specific ABI. Exclusive with `from_write()`. ### Method `pub fn from_read(abi: ABI) -> BitFlags` ### Parameters - **abi** (ABI) - Required - The ABI version to determine read-only access rights. ### Returns - **BitFlags** - The read-only access rights as a bitflags set. ``` -------------------------------- ### AccessFs::from_all Source: https://landlock.io/rust-landlock/src/landlock/fs.rs.html?search=std%3A%3Avec Creates a set of all file system access rights supported by a given ABI version, combining read and write access rights. ```APIDOC ## AccessFs::from_all ### Description Creates a BitFlags set containing all file system access rights supported by the specified ABI version. This is the union of from_read() and from_write(). ### Method from_all(abi: ABI) -> BitFlags ### Parameters - **abi** (ABI) - Required - The Landlock ABI version to determine which access rights are available. ### Returns - **BitFlags** - A set of all file system access rights for the given ABI. ### Example ```rust let fs_v1 = AccessFs::from_all(ABI::V1); ``` ``` -------------------------------- ### AccessFs::from_write Source: https://landlock.io/rust-landlock/landlock/enum.AccessFs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Gets the access rights identified as write-only according to a specific ABI. This method is exclusive with from_read(). ```APIDOC ## AccessFs::from_write ### Description Gets the access rights identified as write-only according to a specific ABI. Exclusive with `from_read()`. ### Method `pub fn from_write(abi: ABI) -> BitFlags` ### Parameters - **abi** (ABI) - Required - The ABI version to use for determining write-only access rights. ### Returns - **BitFlags** - A BitFlags value containing the write-only access rights. ``` -------------------------------- ### Implement TryCompat for NetPort Source: https://landlock.io/rust-landlock/src/landlock/net.rs.html?search= Implements TryCompat for NetPort, adjusting allowed access rights based on ABI compatibility and returning None if the rule becomes incompatible. ```rust impl TryCompat for NetPort { fn try_compat_children( mut self, abi: ABI, parent_level: L, compat_state: &mut CompatState, ) -> Result, CompatError> where L: Into, { // Checks with our own compatibility level, if any. self.allowed_access = match self.allowed_access.try_compat( abi, self.tailored_compat_level(parent_level), compat_state, )? { Some(a) => a, None => return Ok(None), }; Ok(Some(self)) } fn try_compat_inner( &mut self, _abi: ABI, ) -> Result, CompatError> { Ok(CompatResult::Full) } } ``` -------------------------------- ### AccessFs::from_read Source: https://landlock.io/rust-landlock/landlock/enum.AccessFs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Gets the access rights identified as read-only according to a specific ABI. This method is exclusive with from_write(). ```APIDOC ## AccessFs::from_read ### Description Gets the access rights identified as read-only according to a specific ABI. Exclusive with `from_write()`. ### Method `pub fn from_read(abi: ABI) -> BitFlags` ### Parameters - **abi** (ABI) - Required - The ABI version to use for determining read-only access rights. ### Returns - **BitFlags** - A BitFlags value containing the read-only access rights. ``` -------------------------------- ### PathBeneath::new and TryCompat implementation Source: https://landlock.io/rust-landlock/src/landlock/fs.rs.html Defines the PathBeneath constructor and its TryCompat implementation. The constructor stores the parent file descriptor and allowed access, deferring attribute initialization until as_ptr() is called. The compatibility methods adjust allowed access based on the file descriptor type and ABI, returning Partial with a DirectoryAccess error when directory-specific accesses are incompatible. ```rust pub fn new(parent: F, access: A) -> Self where A: Into>, { PathBeneath { // Invalid access rights until as_ptr() is called. attr: unsafe { zeroed() }, parent_fd: parent, allowed_access: access.into(), compat_level: None, } } ``` ```rust impl TryCompat for PathBeneath where F: AsFd, { fn try_compat_children( mut self, abi: ABI, parent_level: L, compat_state: &mut CompatState, ) -> Result, CompatError> where L: Into, { // Checks with our own compatibility level, if any. self.allowed_access = match self.allowed_access.try_compat( abi, self.tailored_compat_level(parent_level), compat_state, )? { Some(a) => a, None => return Ok(None), }; Ok(Some(self)) } fn try_compat_inner( &mut self, _abi: ABI, ) -> Result, CompatError> { // Gets subset of valid accesses according the FD type. let valid_access = if is_file(&self.parent_fd).map_err(|e| PathBeneathError::StatCall { source: e })? { self.allowed_access & ACCESS_FILE } else { self.allowed_access }; if self.allowed_access != valid_access { let error = PathBeneathError::DirectoryAccess { access: self.allowed_access, incompatible: self.allowed_access ^ valid_access, } .into(); self.allowed_access = valid_access; // Linux would return EINVAL. Ok(CompatResult::Partial(error)) } else { Ok(CompatResult::Full) } } } ``` -------------------------------- ### Test abi_v2_exec_refer Source: https://landlock.io/rust-landlock/src/landlock/lib.rs.html?search= Checks support for filesystem access rights across different ABI versions. ```rust #[test] fn abi_v2_exec_refer() { check_ruleset_support( ABI::V1, Some(ABI::V2), move |ruleset: Ruleset| -> _ { Ok(ruleset .handle_access(AccessFs::Execute)? // AccessFs::Refer is not supported by ABI::V1 (best-effort). .handle_access(AccessFs::Refer)? .create()? .restrict_self()?) }, false, ); ```