### Allow Starting New UDP Servers Source: https://docs.rs/extrasafe/latest/extrasafe/builtins/network/struct.Networking.html Enables starting new UDP sockets. Use with caution, as it allows new socket creation. Consider using `allow_running_udp_sockets` after initial setup. ```rust pub fn allow_start_udp_servers(self) -> YesReally ``` -------------------------------- ### Allow Starting New Unix Servers Source: https://docs.rs/extrasafe/latest/extrasafe/builtins/network/struct.Networking.html Enables the creation of new Unix domain server sockets. Generally, it's recommended to use `allow_running_unix_servers` after initial setup. ```rust pub fn allow_start_unix_servers(self) -> YesReally ``` -------------------------------- ### Allow Starting UDP Servers (IPv4/IPv6) Source: https://docs.rs/extrasafe/latest/src/extrasafe/builtins/network.rs.html Configures seccomp rules to allow starting new UDP sockets for both IPv4 and IPv6. This includes allowing the `socket` and `bind` syscalls, along with general network I/O, read, and write operations. Use with caution as it permits new socket creation. ```rust pub fn allow_start_udp_servers(mut self) -> YesReally { const AF_INET: u64 = libc::AF_INET as u64; const AF_INET6: u64 = libc::AF_INET6 as u64; const SOCK_DGRAM: u64 = libc::SOCK_DGRAM as u64; // IPv4 let rule = SeccompRule::new(Sysno::socket) .and_condition(seccomp_arg_filter!(arg0 & AF_INET == AF_INET)) .and_condition(seccomp_arg_filter!(arg1 & SOCK_DGRAM == SOCK_DGRAM)); self.custom.entry(Sysno::socket) .or_insert_with(Vec::new) .push(rule); // IPv6 let rule = SeccompRule::new(Sysno::socket) .and_condition(seccomp_arg_filter!(arg0 & AF_INET6 == AF_INET6)) .and_condition(seccomp_arg_filter!(arg1 & SOCK_DGRAM == SOCK_DGRAM)); self.custom.entry(Sysno::socket) .or_insert_with(Vec::new) .push(rule); self.allowed.extend(&[Sysno::bind]); self.allowed.extend(NET_IO_SYSCALLS); self.allowed.extend(NET_READ_SYSCALLS); self.allowed.extend(NET_WRITE_SYSCALLS); YesReally::new(self) } ``` -------------------------------- ### Allow Starting New TCP Servers Source: https://docs.rs/extrasafe/latest/extrasafe/builtins/network/struct.Networking.html Enables starting new TCP servers. Use with caution, as it allows new socket creation. Consider using `allow_running_tcp_servers` after initial setup. ```rust pub fn allow_start_tcp_servers(self) -> YesReally ``` -------------------------------- ### SeccompArgumentFilter Examples Source: https://docs.rs/extrasafe/latest/extrasafe/struct.SeccompArgumentFilter.html Examples demonstrating how to use the `seccomp_arg_filter!` macro to create syscall argument filters. These examples show how to allow reading from stdin, filter for IPv4 sockets, and filter for TCP sockets. ```rust seccomp_arg_filter!(arg0 == 1); ``` ```rust seccomp_arg_filter!(arg0 & AF_INET == AF_INET); ``` ```rust seccomp_arg_filter!(arg0 & SOCK_STREAM == SOCK_STREAM); ``` -------------------------------- ### Initialize Isolate Environment Source: https://docs.rs/extrasafe/latest/src/extrasafe/isolate/mod.rs.html Call this function at the start of your program to check if it's running as an isolate subprocess. If so, it sets up the user namespace and executes the provided function. Panics if isolate setup fails. ```rust pub fn main_hook Isolate>(isolate_name: &'static str, builder: F) { /// drop wrapper for the tempdir so that even if there's a panic it should get cleaned up struct TempDirCleanup(pub PathBuf); impl Drop for TempDirCleanup { fn drop(&mut self) { std::fs::remove_dir(&self.0) .expect("tmpfs dir was not empty"); } } let mut args = std::env::args(); // Check if we're supposed to be running as the specified isolate if let Some(arg0) = args.next() { if arg0 == isolate_name { let isolate = builder(isolate_name); let tempdir = system::make_tempdir(isolate_name); let tempdir_clean = TempDirCleanup(tempdir.clone()); let mut child_stack = Vec::with_capacity(system::CHILD_STACK_SIZE); let (_child_pid, child_pidfd) = isolate.isolate_and_run(&mut child_stack, tempdir.clone()); let child_ret = system::wait_for_child(child_pidfd); drop(tempdir_clean); std::process::exit(child_ret); } } // If we're not, just continue with the rest of the program } ``` -------------------------------- ### Networking::allow_start_unix_servers Source: https://docs.rs/extrasafe/latest/extrasafe/builtins/network/struct.Networking.html Allows the starting of new Unix domain servers, with security considerations for its use. ```APIDOC ## Networking::allow_start_unix_servers ### Description Allow starting new Unix domain servers ### Security Notes You probably don’t need to use this. In most cases you can just run your server and then use `allow_running_unix_servers`. ### Returns A `YesReally` that allows starting new Unix domain servers. ``` -------------------------------- ### allow_start_udp_servers Source: https://docs.rs/extrasafe/latest/src/extrasafe/builtins/network.rs.html Allows starting new UDP sockets. This is generally not needed as `allow_running_udp_sockets` is sufficient for most use cases. ```APIDOC ## allow_start_udp_servers ### Description Allows starting new UDP sockets. In most cases, you can just run your server and then use [`allow_running_udp_sockets`](Self::allow_running_udp_sockets). ### Method `allow_start_udp_servers` ### Parameters None ### Returns `YesReally` object ``` -------------------------------- ### Isolate Main Hook Setup Source: https://docs.rs/extrasafe/latest/extrasafe/isolate/struct.Isolate.html This function should be called at the start of the program to check if the current process is an isolate subprocess. If so, it sets up the user namespace and runs the configured function. ```rust pub fn main_hook Isolate>( isolate_name: &'static str, builder: F, ) ``` -------------------------------- ### Networking::allow_start_tcp_clients Source: https://docs.rs/extrasafe/latest/extrasafe/builtins/network/struct.Networking.html Allows starting new TCP clients, permitting socket creation but not binding. ```APIDOC ## Networking::allow_start_tcp_clients ### Description Allow starting new TCP clients. ### Security Notes In some cases you can create the socket ahead of time, but that isn’t possible with e.g. reqwest, so we allow socket but not bind here. ### Returns A `Networking` ruleset that allows starting new TCP clients. ``` -------------------------------- ### Networking::allow_start_tcp_servers Source: https://docs.rs/extrasafe/latest/extrasafe/builtins/network/struct.Networking.html Allows the starting of new TCP servers, with security considerations for its use. ```APIDOC ## Networking::allow_start_tcp_servers ### Description Allow starting new TCP servers. ### Security Notes You probably don’t need to use this. In most cases you can just run your server and then use `allow_running_tcp_servers`. See `examples/network_server.rs` for an example with warp. ### Returns A `YesReally` that allows starting new TCP servers. ``` -------------------------------- ### Networking::allow_start_udp_servers Source: https://docs.rs/extrasafe/latest/extrasafe/builtins/network/struct.Networking.html Allows the starting of new UDP sockets, with security considerations for its use. ```APIDOC ## Networking::allow_start_udp_servers ### Description Allow starting new UDP sockets. ### Security Notes You probably don’t need to use this. In most cases you can just run your server and then use `allow_running_udp_sockets`. ### Returns A `YesReally` that allows starting new UDP sockets. ``` -------------------------------- ### Allow Starting TCP Clients (IPv4/IPv6) Source: https://docs.rs/extrasafe/latest/src/extrasafe/builtins/network.rs.html Configures seccomp rules to allow starting new TCP client sockets for both IPv4 and IPv6. This permits the `socket` syscall with `SOCK_STREAM` and the `connect` syscall, along with general network I/O, read, and write operations. It does not allow `bind` to prevent new server socket creation. ```rust pub fn allow_start_tcp_clients(mut self) -> Networking { const AF_INET: u64 = libc::AF_INET as u64; const AF_INET6: u64 = libc::AF_INET6 as u64; const SOCK_STREAM: u64 = libc::SOCK_STREAM as u64; // IPv4 let rule = SeccompRule::new(Sysno::socket) .and_condition(seccomp_arg_filter!(arg0 & AF_INET == AF_INET)) .and_condition(seccomp_arg_filter!(arg1 & SOCK_STREAM == SOCK_STREAM)); self.custom.entry(Sysno::socket) .or_insert_with(Vec::new) .push(rule); // IPv6 let rule = SeccompRule::new(Sysno::socket) .and_condition(seccomp_arg_filter!(arg0 & AF_INET6 == AF_INET6)) .and_condition(seccomp_arg_filter!(arg1 & SOCK_STREAM == SOCK_STREAM)); self.custom.entry(Sysno::socket) .or_insert_with(Vec::new) .push(rule); self.allowed.extend(&[Sysno::connect]); self.allowed.extend(NET_IO_SYSCALLS); self.allowed.extend(NET_READ_SYSCALLS); self.allowed.extend(NET_WRITE_SYSCALLS); self } ``` -------------------------------- ### allow_start_tcp_clients Source: https://docs.rs/extrasafe/latest/src/extrasafe/builtins/network.rs.html Allows starting new TCP clients by enabling the `socket` syscall for TCP connections. ```APIDOC ## allow_start_tcp_clients ### Description Allows starting new TCP clients. This enables the `socket` syscall for TCP connections (SOCK_STREAM) for both IPv4 and IPv6. It also allows `connect` and general network I/O. ### Method `allow_start_tcp_clients` ### Parameters None ### Returns `Networking` object ``` -------------------------------- ### main_hook Source: https://docs.rs/extrasafe/latest/src/extrasafe/isolate/mod.rs.html At the start of the program, call this function to check whether we are in an isolate subprocess and should run `func` after setting up the user namespace. Panics if there is an error with starting the isolate. ```APIDOC pub fn main_hook Isolate>(isolate_name: &'static str, builder: F) ``` -------------------------------- ### Initialize SystemIO with no IO syscalls allowed Source: https://docs.rs/extrasafe/latest/src/extrasafe/builtins/systemio.rs.html Use `SystemIO::nothing()` to create a ruleset that denies all IO operations by default. This is a safe starting point for building a custom IO policy. ```rust pub(crate) fn nothing() -> SystemIO { SystemIO { allowed: HashSet::new(), custom: HashMap::new(), #[cfg(feature = "landlock")] landlock_rules: HashMap::new() } } ``` -------------------------------- ### allow_start_unix_servers Source: https://docs.rs/extrasafe/latest/src/extrasafe/builtins/network.rs.html Allows the creation of both stream and datagram Unix domain sockets, along with bind, and general network I/O, read, and write system calls. This is useful for starting new Unix servers. ```APIDOC ## allow_start_unix_servers ### Description Allows the creation of both stream and datagram Unix domain sockets, along with bind, and general network I/O, read, and write system calls. This is useful for starting new Unix servers. ### Method `self.allow_start_unix_servers()` ### Parameters None ### Returns `YesReally` - A configuration object allowing further customization or finalization. ``` -------------------------------- ### Initialize Networking Rules Source: https://docs.rs/extrasafe/latest/src/extrasafe/builtins/network.rs.html Starts with a `Networking` struct that allows no network syscalls by default. This is the base for building more specific network rule sets. ```rust pub fn nothing() -> Networking { Networking { allowed: HashSet::new(), custom: HashMap::new(), } } ``` -------------------------------- ### Example: SoftRequirement for Renaming Files Source: https://docs.rs/extrasafe/latest/extrasafe/trait.Compatible.html Demonstrates using `set_compatibility(CompatLevel::SoftRequirement)` to handle Landlock features that might not be supported, ensuring the application functions correctly if renaming is not explicitly supported by the kernel. It also shows switching to `CompatLevel::BestEffort` for subsequent operations. ```rust use landlock::* fn ruleset_handling_renames() -> Result { Ok(Ruleset::default() // This ruleset must either handle the AccessFs::Refer right, // or it must silently ignore the whole sandboxing. .set_compatibility(CompatLevel::SoftRequirement) .handle_access(AccessFs::Refer)? // However, this ruleset may also handle other (future) access rights // if they are supported by the running kernel. .set_compatibility(CompatLevel::BestEffort) .handle_access(AccessFs::from_all(ABI::V3))? .create()?) } ``` -------------------------------- ### Example: Adding Rules from Environment Variable Source: https://docs.rs/extrasafe/latest/extrasafe/trait.RulesetCreatedAttr.html Demonstrates how to create a custom iterator to read paths from an environment variable and add them as rules to a ruleset. This is useful for dynamically configuring access restrictions. ```rust use landlock::{ Access, AccessFs, ABI, BitFlags, PathBeneath, PathFd, PathFdError, RestrictionStatus, Ruleset, RulesetAttr, RulesetCreatedAttr, RulesetError, }; use std::env; use std::ffi::OsStr; use std::os::unix::ffi::{OsStrExt, OsStringExt}; use thiserror::Error; #[derive(Debug, Error)] enum PathEnvError<'a> { #[error(transparent)] Ruleset(#[from] RulesetError), #[error(transparent)] AddRuleIter(#[from] PathFdError), #[error("missing environment variable {0}")] MissingVar(&'a str), } struct PathEnv { paths: Vec, access: BitFlags, } impl PathEnv { // env_var is the name of an environment variable // containing paths requested to be allowed. // Paths are separated with ":", e.g. "/bin:/lib:/usr:/proc". // In case an empty string is provided, // no restrictions are applied. // `access` is the set of access rights allowed for each of the parsed paths. fn new<'a>(env_var: &'a str, access: BitFlags) -> Result> { Ok(Self { paths: env::var_os(env_var) .ok_or(PathEnvError::MissingVar(env_var))? .into_vec(), access, }) } fn iter( &self, ) -> impl Iterator, PathEnvError<'static>>> + '_ { let is_empty = self.paths.is_empty(); self.paths .split(|b| *b == b':') // Skips the first empty element from of an empty string. .skip_while(move |_| is_empty) .map(OsStr::from_bytes) .map(move |path| Ok(PathBeneath::new(PathFd::new(path)?, self.access))) } } fn restrict_env() -> Result> { Ok(Ruleset::default() .handle_access(AccessFs::from_all(ABI::V1))? .create()? // In the shell: export EXECUTABLE_PATH="/usr:/bin:/sbin" .add_rules(PathEnv::new("EXECUTABLE_PATH", AccessFs::Execute.into())?.iter())? .restrict_self()?) } ``` -------------------------------- ### fn from_all Source: https://docs.rs/extrasafe/latest/extrasafe/trait.Access.html Gets the access rights defined by a specific `ABI`. Union of `from_read()` and `from_write()`. ```APIDOC ## fn from_all(abi: ABI) -> BitFlags ### Description Gets the access rights defined by a specific `ABI`. Union of `from_read()` and `from_write()`. ### Parameters #### Path Parameters - **abi** (ABI) - Required - Description of the ABI parameter. ### Response #### Success Response (BitFlags) - Returns a BitFlags representing all access rights. ``` -------------------------------- ### from_all Method Source: https://docs.rs/extrasafe/latest/extrasafe/trait.Access.html Gets all access rights defined by a specific ABI. This is a union of from_read() and from_write(). ```rust fn from_all(abi: ABI) -> BitFlags { ... } ``` -------------------------------- ### Isolate::run Source: https://docs.rs/extrasafe/latest/extrasafe/isolate/struct.Isolate.html Starts a subprocess that activates an Isolate with the given name and environment variables. Only the provided environment variables will be present in the subprocess. ```APIDOC ## pub fn run(isolate_name: &'static str, envs: &HashMap) -> Result ### Description Start a subprocess that will activate an Isolate with the given `isolate_name` and environment variables. Only the provided environment variables will be present in the subprocess and nothing else from the current process. The subprocess’s `argv` will only contain `isolate_name`. ### Parameters * `isolate_name`: &'static str - The name of the isolate to activate. * `envs`: &HashMap - A map of environment variables to set in the subprocess. ### Returns A `Result` containing the `Output` of the subprocess if successful, or an `IsolateError` if starting the Command fails. ``` -------------------------------- ### Create Threads Ruleset with Nothing Allowed Source: https://docs.rs/extrasafe/latest/src/extrasafe/builtins/danger_zone.rs.html Initializes a `Threads` ruleset with no syscalls allowed by default. Use this as a starting point before adding specific permissions. ```rust pub fn nothing() -> Threads { Threads { allowed: HashSet::new(), } } ``` -------------------------------- ### Run an Isolate subprocess with environment variables Source: https://docs.rs/extrasafe/latest/src/extrasafe/isolate/mod.rs.html Starts a subprocess that activates an Isolate. It clears existing environment variables and sets only the provided ones. The subprocess's `argv[0]` is set to the isolate name. ```rust pub fn run(isolate_name: &'static str, envs: &HashMap) -> Result { let memfd = system::create_memfd_from_self_exe()?; std::process::Command::new(format!("/proc/self/fd/{}", memfd.as_raw_fd())) .arg0(isolate_name) .env_clear() ``` -------------------------------- ### Construct a new SeccompRule Source: https://docs.rs/extrasafe/latest/extrasafe/struct.SeccompRule.html Creates a new SeccompRule that unconditionally allows the specified syscall. Use this as a starting point before adding specific argument conditions. ```rust pub fn new(syscall: Sysno) -> SeccompRule ``` -------------------------------- ### Run Isolate Subprocess Source: https://docs.rs/extrasafe/latest/extrasafe/isolate/struct.Isolate.html Starts a subprocess that activates an Isolate with the specified name and environment variables. Only the provided environment variables are present in the subprocess. ```rust pub fn run( isolate_name: &'static str, envs: &HashMap, ) -> Result ``` -------------------------------- ### Allow Starting New TCP Servers (IPv4/IPv6) Source: https://docs.rs/extrasafe/latest/src/extrasafe/builtins/network.rs.html Configures `Networking` rules to allow the creation of new TCP sockets for both IPv4 and IPv6. This is typically used when a server needs to bind to a new port. ```rust pub fn allow_start_tcp_servers(mut self) -> YesReally { const AF_INET: u64 = libc::AF_INET as u64; const AF_INET6: u64 = libc::AF_INET6 as u64; const SOCK_STREAM: u64 = libc::SOCK_STREAM as u64; // IPv4 let rule = SeccompRule::new(Sysno::socket) .and_condition(seccomp_arg_filter!(arg0 & AF_INET == AF_INET)) .and_condition(seccomp_arg_filter!(arg1 & SOCK_STREAM == SOCK_STREAM)); self.custom.entry(Sysno::socket) .or_insert_with(Vec::new) .push(rule); // IPv6 let rule = SeccompRule::new(Sysno::socket) .and_condition(seccomp_arg_filter!(arg0 & AF_INET6 == AF_INET6)) .and_condition(seccomp_arg_filter!(arg1 & SOCK_STREAM == SOCK_STREAM)); self.custom.entry(Sysno::socket) ``` -------------------------------- ### Allow Starting New TCP Clients Source: https://docs.rs/extrasafe/latest/extrasafe/builtins/network/struct.Networking.html Enables the creation of new TCP client sockets. This allows the `socket` syscall but not `bind`, accommodating libraries like reqwest that create sockets ahead of time. ```rust pub fn allow_start_tcp_clients(self) -> Networking ``` -------------------------------- ### Create Time RuleSet with Nothing Allowed Source: https://docs.rs/extrasafe/latest/src/extrasafe/builtins/time.rs.html Initializes a new Time RuleSet where no time-related syscalls are permitted by default. Use this as a starting point before selectively allowing specific syscalls. ```rust pub fn nothing() -> Time { Time { allowed: HashSet::new(), } } ``` -------------------------------- ### Create a new Threads ruleset Source: https://docs.rs/extrasafe/latest/extrasafe/builtins/danger_zone/struct.Threads.html Initializes a new Threads ruleset with default settings where no operations are allowed. This is the starting point for configuring thread-related syscall permissions. ```rust pub fn nothing() -> Threads ``` -------------------------------- ### Initialize SystemIO to allow all IO syscalls Source: https://docs.rs/extrasafe/latest/src/extrasafe/builtins/systemio.rs.html Use `SystemIO::everything()` to create a ruleset that permits all standard IO syscalls. This is a convenient shortcut for enabling a broad range of file operations. ```rust pub fn everything() -> SystemIO { SystemIO::nothing() .allow_read() .allow_write() .allow_open().yes_really() .allow_metadata() .allow_unlink() .allow_close() } ``` -------------------------------- ### isolate_and_run Source: https://docs.rs/extrasafe/latest/src/extrasafe/isolate/mod.rs.html `clone`s into a new namespace, creates a tmpfs at `tempdir`, bindmounts the relevant directories into it, `pivot_root`s into the tmpfs, and runs `self.func`. ```APIDOC fn isolate_and_run(&self, child_stack: &mut [u8], tempdir: PathBuf) -> (libc::pid_t, libc::id_t) ``` -------------------------------- ### SystemIO::everything Source: https://docs.rs/extrasafe/latest/extrasafe/builtins/systemio/struct.SystemIO.html Creates a SystemIO configuration that allows all IO syscalls. ```APIDOC ## SystemIO::everything ### Description Allow all IO syscalls. ### Method `SystemIO::everything()` ### Returns A `SystemIO` struct with all IO syscalls allowed. ``` -------------------------------- ### SystemIO: Allow Directory Creation (Landlock) Source: https://docs.rs/extrasafe/latest/extrasafe/builtins/systemio/struct.SystemIO.html Uses Landlock to permit the creation of directories. Multiple directories can be allowed by chaining calls. ```rust pub fn allow_create_dir>(self, path: P) -> SystemIO ``` -------------------------------- ### Any::type_id Source: https://docs.rs/extrasafe/latest/extrasafe/enum.AccessFs.html Gets the TypeId of the AccessFs value. ```APIDOC ## fn type_id(&self) -> TypeId ### Description Gets the `TypeId` of `self`. ### Method type_id ### Returns - TypeId: The unique identifier for the type of `self`. ``` -------------------------------- ### SystemIO: Allow All IO Source: https://docs.rs/extrasafe/latest/extrasafe/builtins/systemio/struct.SystemIO.html Initializes SystemIO to permit all IO syscalls. Use with caution as it grants broad access. ```rust pub fn everything() -> SystemIO ``` -------------------------------- ### SystemIO::allow_create_dir Source: https://docs.rs/extrasafe/latest/extrasafe/builtins/systemio/struct.SystemIO.html Uses Landlock to allow the creation of directories. ```APIDOC ## SystemIO::allow_create_dir ### Description Use Landlock to allow creating directories. If this function is called multiple times, all directories passed will be allowed. ### Method `SystemIO::allow_create_dir>(self, path: P) -> SystemIO` ### Parameters * `path` (P: AsRef) - The path where directories can be created. ### Returns A modified `SystemIO` struct that allows directory creation. ``` -------------------------------- ### Using BitFlags with AccessFs Source: https://docs.rs/extrasafe/latest/extrasafe/enum.AccessFs.html Demonstrates how to create and manipulate sets of file system access rights using BitFlags and the AccessFs enum. Includes creating flags from individual variants, combining them, and using ABI-specific constructors. ```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)); ``` -------------------------------- ### Perform Bind Mount with mount Source: https://docs.rs/extrasafe/latest/src/extrasafe/isolate/isolate_sys.rs.html Sets up a bind mount from a source path to a destination path within the new root. It handles creating parent directories for files and directories, and ensures the destination exists. ```rust let dst = if dst.is_absolute() { dst.strip_prefix("/").unwrap() } else { dst }; let dst = root.join(dst); // if directory, create all directories // else if file, socket, etc., create all parent directories and make empty file to bindmount on to. if src.is_dir() { std::fs::create_dir_all(&dst) .unwrap_or_else(|_| panic!("failed to create dst directory (or parent directories) when bindmounting {}", dst.display())); } else { if let Some(parent) = dst.parent() { std::fs::create_dir_all(parent) .unwrap_or_else(|_| panic!("failed to create parent directories when bindmounting {}", dst.display())); } drop(File::create(&dst) .unwrap_or_else(|_| panic!("failed to create empty file when bindmounting {}", dst.display()))); } let src_dircstr = CString::new(src.as_os_str().as_encoded_bytes()).unwrap(); let dst_dircstr = CString::new(dst.as_os_str().as_encoded_bytes()).unwrap(); let bind_cstr = CString::new("bind").unwrap(); let rc = unsafe { libc::mount(src_dircstr.as_ptr(), dst_dircstr.as_ptr(), bind_cstr.as_ptr(), libc::MS_REC | libc::MS_BIND, std::ptr::null()) }; fail_negative!(rc, format!("failed to bindmount. do you have permissions for the src directory? dst must also exist! (it should be an empty file or directory)\nsrc: {:?}, dst: {:?}", src, dst)); ``` -------------------------------- ### AccessFs::from_file Source: https://docs.rs/extrasafe/latest/extrasafe/enum.AccessFs.html Gets the access rights legitimate for non-directory files based on the provided ABI. ```APIDOC ## impl AccessFs ### pub fn from_file(abi: ABI) -> BitFlags Gets the access rights legitimate for non-directory files. ``` -------------------------------- ### fn from_write Source: https://docs.rs/extrasafe/latest/extrasafe/trait.Access.html Gets the access rights identified as write-only according to a specific ABI. Exclusive with `from_read()`. ```APIDOC ## fn from_write(abi: ABI) -> BitFlags ### Description Gets the access rights identified as write-only according to a specific ABI. Exclusive with `from_read()`. ### Parameters #### Path Parameters - **abi** (ABI) - Required - Description of the ABI parameter. ### Response #### Success Response (BitFlags) - Returns a BitFlags representing write-only access rights. ``` -------------------------------- ### Create a PathBeneath rule Source: https://docs.rs/extrasafe/latest/extrasafe/struct.PathBeneath.html Demonstrates how to create a PathBeneath rule for the home directory with read directory access. This is useful for setting up file system access controls. ```rust use landlock::{AccessFs, PathBeneath, PathFd, PathFdError}; fn home_dir() -> Result, PathFdError> { Ok(PathBeneath::new(PathFd::new("/home")?, AccessFs::ReadDir)) } ``` -------------------------------- ### fn from_read Source: https://docs.rs/extrasafe/latest/extrasafe/trait.Access.html Gets the access rights identified as read-only according to a specific ABI. Exclusive with `from_write()`. ```APIDOC ## fn from_read(abi: ABI) -> BitFlags ### Description Gets the access rights identified as read-only according to a specific ABI. Exclusive with `from_write()`. ### Parameters #### Path Parameters - **abi** (ABI) - Required - Description of the ABI parameter. ### Response #### Success Response (BitFlags) - Returns a BitFlags representing read-only access rights. ``` -------------------------------- ### from_write Method Source: https://docs.rs/extrasafe/latest/extrasafe/trait.Access.html Gets write-only access rights based on a specific ABI. This method is exclusive with from_read(). ```rust fn from_write(abi: ABI) -> BitFlags; ``` -------------------------------- ### from_read Method Source: https://docs.rs/extrasafe/latest/extrasafe/trait.Access.html Gets read-only access rights based on a specific ABI. This method is exclusive with from_write(). ```rust fn from_read(abi: ABI) -> BitFlags; ``` -------------------------------- ### Default Networking Rules Source: https://docs.rs/extrasafe/latest/extrasafe/builtins/network/struct.Networking.html Initializes a Networking RuleSet that allows no network syscalls by default. This is the most restrictive starting point. ```rust pub fn nothing() -> Networking ``` -------------------------------- ### Using seccomp_arg_filter for Basic Filtering Source: https://docs.rs/extrasafe/latest/extrasafe/macro.seccomp_arg_filter.html Demonstrates how to use the seccomp_arg_filter macro for basic argument comparisons. Ensure `extrasafe::*` is imported. ```rust use extrasafe::*; // usage: `seccomp_arg_filter!( );` // or `seccomp_arg_filter!( & == );` // arg0 through arg5 are supported // operations <=, <, >=, >, ==, != are supported let argfilter = seccomp_arg_filter!(arg0 < 5); ``` -------------------------------- ### SystemIO::allow_open Source: https://docs.rs/extrasafe/latest/extrasafe/builtins/systemio/struct.SystemIO.html Configures SystemIO to allow `open` syscalls. Returns a `YesReally` wrapper due to security implications. ```APIDOC ## SystemIO::allow_open ### Description Allow `open` syscalls. ### Method `SystemIO::allow_open(self) -> YesReally` ### Security The reason this function returns a `YesReally` is because it’s easy to accidentally combine it with another ruleset that allows `write` - for example the Network ruleset - even if you only want to read files. Consider using `allow_open_directory()` or `allow_open_file()`. ### Returns A `YesReally` wrapper containing a modified `SystemIO` struct that allows opening files. ``` -------------------------------- ### ForkAndExec Struct Definition Source: https://docs.rs/extrasafe/latest/extrasafe/builtins/danger_zone/struct.ForkAndExec.html Defines the ForkAndExec struct, which is part of the 'danger zone' due to its ability to start new processes. ```APIDOC ## Struct ForkAndExec ```rust pub struct ForkAndExec; ``` `ForkAndExec` is in the danger zone because it can be used to start another process, including more privileged ones. That process will still be under seccomp’s restrictions (see `tests/inherit_filters.rs`) but depending on your filter it could still do bad things. Note that this also allows the `clone` syscall. ``` -------------------------------- ### Getting Underlying Bits (Const) Source: https://docs.rs/extrasafe/latest/extrasafe/struct.BitFlags.html Returns the underlying bitwise value of a BitFlags instance. This is the const-compatible variant of the `bits` method. ```rust pub const fn bits_c(self) -> u8 ``` -------------------------------- ### ForkAndExec RuleSet Source: https://docs.rs/extrasafe/latest/src/extrasafe/builtins/danger_zone.rs.html Allows syscalls related to forking, executing, and waiting for processes. This can be used to start new processes, including more privileged ones. ```APIDOC ## ForkAndExec ### Description Allows syscalls for forking, executing, and waiting for processes. This is in the danger zone because it can be used to start another process, including more privileged ones. That process will still be under seccomp's restrictions, but depending on your filter it could still do bad things. Note that this also allows the `clone` syscall. ### RuleSet Implementation Implements `RuleSet` for `ForkAndExec`. * `simple_rules()`: Returns a vector of allowed syscalls including `fork`, `vfork`, `execve`, `execveat`, `wait4`, `waitid`, `clone`, `clone3`. If the target environment is `musl`, it also includes `pipe` and `pipe2`. * `conditional_rules()`: Returns a HashMap of syscalls with conditional rules (currently empty). * `name()`: Returns the name of the ruleset, "ForkAndExec". ``` -------------------------------- ### Create PathFd for Root Directory Source: https://docs.rs/extrasafe/latest/extrasafe/struct.PathFd.html Demonstrates how to create a PathFd for the root directory and use it with AccessFs to create a PathBeneath object. This is useful for setting up access controls. ```rust use landlock::{AccessFs, PathBeneath, PathFd, PathFdError}; fn allowed_root_dir(access: AccessFs) -> Result, PathFdError> { let fd = PathFd::new("/")?; Ok(PathBeneath::new(fd, access)) } ``` -------------------------------- ### SystemIO: Allow File Creation in Directory (Landlock) Source: https://docs.rs/extrasafe/latest/extrasafe/builtins/systemio/struct.SystemIO.html Uses Landlock to permit file creation within specified directories. Multiple directories can be allowed by chaining calls. Note potential failures when combined with `allow_open_readonly`. ```rust pub fn allow_create_in_dir>(self, path: P) -> SystemIO ``` -------------------------------- ### Allow open syscalls with extra confirmation Source: https://docs.rs/extrasafe/latest/src/extrasafe/builtins/systemio.rs.html Use `allow_open()` to permit syscalls for opening files. It returns a `YesReally` wrapper to ensure the user is aware of the security implications, as opening files can be combined with other rulesets like network access. ```rust pub fn allow_open(mut self) -> YesReally { self.allowed.extend(IO_OPEN_SYSCALLS); YesReally::new(self) } ``` -------------------------------- ### Get the underlying bitwise value Source: https://docs.rs/extrasafe/latest/extrasafe/struct.BitFlags.html Retrieves the raw numeric representation of the BitFlags instance. This is useful for interoperation with systems that expect raw bitmasks. ```rust #[bitflags] #[repr(u8)] #[derive(Clone, Copy)] enum Flags { Foo = 1 << 0, Bar = 1 << 1, } let both_flags = Flags::Foo | Flags::Bar; assert_eq!(both_flags.bits(), 0b11); ``` -------------------------------- ### BasicCapabilities Source: https://docs.rs/extrasafe/latest/src/extrasafe/builtins/mod.rs.html Provides a RuleSet for basic system capabilities. ```APIDOC pub mod basic; pub use basic::BasicCapabilities; ``` -------------------------------- ### Networking RuleSet Source: https://docs.rs/extrasafe/latest/src/extrasafe/builtins/network.rs.html A RuleSet representing syscalls that perform network operations. It can be configured to allow running servers, starting new servers, or acting as a client. ```APIDOC ## Networking ### Description A [`RuleSet`] representing syscalls that perform network operations - accept/listen/bind/connect etc. ### How to use 1. Select TCP or UDP (or both) with `enable_tcp()`, `enable_udp()` 2a. If you are a server of some sort, **strongly** consider first binding to your ports and then not allowing further binds by using `running_tcp_server()` or `running_udp_server()`. Otherwise, 2b. If you are a client, use `tcp_client()` and/or `udp_client()`, which does not allow `accept` or `listen` syscalls. The most common use-case: select TCP or UDP (or both) with `.enable_tcp()` or `.enable_udp()`, and then decide if you're going to allow binding to new ports ### Security considerations If you enable writing (on either tcp or udp), this enables the `write` syscall which will therefore also enable writing to stdout/stderr and any open files. Therefore you should take care to consider whether you can split up your program (e.g. across separate threads) into a part that opens and writes to files and a part that speaks to the network. This is a good security practice in general. ### Methods * `Networking::nothing()`: By default, allow no networking syscalls. * `Networking::allow_running_tcp_servers()`: Allow a running TCP server to continue running. Does not allow `socket` or `bind`, preventing new sockets from being created. * `Networking::allow_start_tcp_servers()`: Allow starting new TCP servers. You probably don't need to use this. In most cases you can just run your server and then use [`allow_running_tcp_servers`](Self::allow_running_tcp_servers). ### Syscalls Allowed by Default * `NET_IO_SYSCALLS`: `epoll_create`, `epoll_create1`, `epoll_ctl`, `epoll_wait`, `epoll_pwait`, `epoll_pwait2`, `select`, `pselect6`, `poll`, `ppoll`, `accept`, `accept4`, `eventfd`, `eventfd2`, `fcntl`, `ioctl`, `getsockopt`, `setsockopt`, `getpeername`, `getsockname`. * `NET_READ_SYSCALLS`: `listen`, `recvfrom`, `recvmsg`, `recvmmsg`, `read`, `readv`, `preadv`, `preadv2`. * `NET_WRITE_SYSCALLS`: `sendto`, `sendmsg`, `sendmmsg`, `sendfile`, `write`, `writev`, `pwritev`, `pwritev2`. ### Custom Rules * `Sysno::socket`: Allows creating new TCP sockets for IPv4 and IPv6. ``` -------------------------------- ### Allow Connecting Source: https://docs.rs/extrasafe/latest/extrasafe/builtins/network/struct.Networking.html Permits the `connect` syscall, enabling clients to establish connections to network resources. Exercise caution as this allows connections to potentially dangerous resources. ```rust pub fn allow_connect(self) -> YesReally ``` -------------------------------- ### Create an empty BitFlags set Source: https://docs.rs/extrasafe/latest/extrasafe/struct.BitFlags.html Initializes a BitFlags instance with no flags set, equivalent to a numeric value of 0. This is useful for starting with a clean 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::empty(); assert!(empty.is_empty()); assert_eq!(empty.contains(MyFlag::One), false); assert_eq!(empty.contains(MyFlag::Two), false); assert_eq!(empty.contains(MyFlag::Three), false); ``` -------------------------------- ### SystemIO: Allow Open Syscalls (with Security Warning) Source: https://docs.rs/extrasafe/latest/extrasafe/builtins/systemio/struct.SystemIO.html Configures SystemIO to permit `open` syscalls. Returns a `YesReally` type due to the potential for accidental combination with write permissions. Consider using `allow_open_directory()` or `allow_open_file()` for more specific control. ```rust pub fn allow_open(self) -> YesReally ``` -------------------------------- ### Create a new Isolate instance Source: https://docs.rs/extrasafe/latest/src/extrasafe/isolate/mod.rs.html Initializes a new Isolate with a specified name and function to execute. Default settings for network and filesystem size are applied. ```rust pub fn new(isolate_name: &'static str, func: fn() -> ()) -> Isolate { Isolate { isolate_name, func, new_network: true, root_fs_size: 10, bindmounts: HashMap::new(), } } ``` -------------------------------- ### allow_connect Source: https://docs.rs/extrasafe/latest/src/extrasafe/builtins/network.rs.html Allows the `connect` syscall, enabling connections to network resources. ```APIDOC ## allow_connect ### Description Allows the `connect` syscall. This enables connecting to network resources, but consider the security implications as it allows connections to potentially dangerous network resources. ### Method `allow_connect` ### Parameters None ### Returns `YesReally` object ``` -------------------------------- ### allow_dns_files Source: https://docs.rs/extrasafe/latest/extrasafe/builtins/systemio/struct.SystemIO.html Configures SystemIO to allow access to DNS-related files, such as /etc/resolv.conf, using Landlock. ```APIDOC ## allow_dns_files ### Description Use Landlock to allow access to DNS files, like /etc/resolv.conf. ### Method `self.allow_dns_files()` ### Parameters None ### Returns `SystemIO` - The modified SystemIO object. ``` -------------------------------- ### Close file descriptors >= 3 Source: https://docs.rs/extrasafe/latest/src/extrasafe/isolate/isolate_sys.rs.html This function closes all file descriptors starting from 3 up to the maximum, leaving stdin, stdout, and stderr open. It uses `SYS_close_range` for efficient closing, typically called after `pivot_root`. ```rust let flags: i32 = libc::CLOSE_RANGE_UNSHARE.try_into().unwrap(); let rc = unsafe { libc::syscall(libc::SYS_close_range, 3, u32::MAX, flags) }; fail_negative!(rc, "failed to close fds > 3 after pivot_root"); ``` -------------------------------- ### allow_dns_files Source: https://docs.rs/extrasafe/latest/src/extrasafe/builtins/systemio.rs.html Use Landlock to allow access to DNS files, like /etc/resolv.conf. This also allows relevant syscalls like close, read, metadata, and open. ```APIDOC ## allow_dns_files ### Description Use Landlock to allow access to DNS files, like /etc/resolv.conf. This function configures read access to common DNS configuration files. ### Method `SystemIO.allow_dns_files()` ### Parameters None ### Request Example ```rust let mut rules = SystemIO::new(); rules = rules.allow_dns_files(); ``` ### Response Returns the modified SystemIO object with DNS file access rules applied. ### Additional Allowed Syscalls - `allow_close()` - `allow_read()` - `allow_metadata()` - `allow_open().yes_really()` ``` -------------------------------- ### SystemIO: Allow Listing Directory Contents (Landlock) Source: https://docs.rs/extrasafe/latest/extrasafe/builtins/systemio/struct.SystemIO.html Uses Landlock to permit listing the contents of specified directories. Multiple directories can be allowed by chaining calls. ```rust pub fn allow_list_dir>(self, path: P) -> SystemIO ``` -------------------------------- ### SystemIO::nothing Source: https://docs.rs/extrasafe/latest/extrasafe/builtins/systemio/struct.SystemIO.html Creates a SystemIO configuration that allows no IO syscalls by default. ```APIDOC ## SystemIO::nothing ### Description By default, allow no IO syscalls. ### Method `SystemIO::nothing()` ### Returns A `SystemIO` struct with no IO syscalls allowed. ``` -------------------------------- ### allow_create_dir Source: https://docs.rs/extrasafe/latest/src/extrasafe/builtins/systemio.rs.html Use Landlock to allow creating directories. If this function is called multiple times, all directories passed will be allowed. ```APIDOC ## allow_create_dir ### Description Allows the creation of directories using Landlock. ### Method `allow_create_dir>(mut self, path: P) -> SystemIO` ### Parameters #### Path Parameters - **path** (P): A path where directories can be created. `P` must implement `AsRef`. ### Request Example ```rust // Assuming 'sys_io' is an instance of SystemIO sys_io.allow_create_dir("/path/to/parent_directory"); ``` ### Response Returns the modified `SystemIO` instance. ``` -------------------------------- ### SystemIO::allow_create_in_dir Source: https://docs.rs/extrasafe/latest/extrasafe/builtins/systemio/struct.SystemIO.html Uses Landlock to allow files to be created within a specified directory. ```APIDOC ## SystemIO::allow_create_in_dir ### Description Use Landlock to allow files to be created in the given directory. If this function is called multiple times, all directories passed will be allowed. ### Method `SystemIO::allow_create_in_dir>(self, path: P) -> SystemIO` ### Note Note that if this is used with [`allow_open_readonly`] or other syscall-argument restricting methods, applying the `SafetyContext` will fail. ### Parameters * `path` (P: AsRef) - The path to the directory where files can be created. ### Returns A modified `SystemIO` struct that allows file creation in the specified directory. ``` -------------------------------- ### create_dir Source: https://docs.rs/extrasafe/latest/extrasafe/access/fn.create_dir.html This function provides a convenient way to set up Landlock access rights for creating directories. ```APIDOC ## Function create_dir extrasafe::access ### Summary ```rust pub fn create_dir() -> BitFlags ``` ### Description Convenience function for landlock create dir access right ``` -------------------------------- ### allow_ssl_files Source: https://docs.rs/extrasafe/latest/extrasafe/builtins/systemio/struct.SystemIO.html Configures SystemIO to allow access to SSL certificate files using Landlock. This is often unnecessary for crates using rustls and webpki-roots as certificates are embedded. ```APIDOC ## allow_ssl_files ### Description Use Landlock to allow access to SSL certificates in /etc/ssl, /etc/ca-certificates, etc. Note that crates using rustls and webpki-roots you actually don’t need these because the certificates are embedded in the output binary. ### Method `self.allow_ssl_files()` ### Parameters None ### Returns `SystemIO` - The modified SystemIO object. ``` -------------------------------- ### SystemIO: Default (No IO) Source: https://docs.rs/extrasafe/latest/extrasafe/builtins/systemio/struct.SystemIO.html Initializes SystemIO to disallow all IO syscalls by default. This is the most restrictive setting. ```rust pub fn nothing() -> SystemIO ``` -------------------------------- ### SystemIO Source: https://docs.rs/extrasafe/latest/src/extrasafe/builtins/mod.rs.html Provides a RuleSet for system input/output operations. ```APIDOC pub mod systemio; pub use systemio::SystemIO; ``` -------------------------------- ### Allow Connect Syscall Source: https://docs.rs/extrasafe/latest/src/extrasafe/builtins/network.rs.html Enables the `connect` syscall, allowing the process to initiate connections to network resources. Be aware that this permits connections to potentially dangerous network endpoints. ```rust pub fn allow_connect(mut self) -> YesReally { self.allowed.extend(&[Sysno::connect]); YesReally::new(self) } ``` -------------------------------- ### Allow Open/Openat with WriteCreate Flags Source: https://docs.rs/extrasafe/latest/src/extrasafe/builtins/systemio.rs.html Configures seccomp rules to allow `open` and `openat` syscalls when specific write-related flags are used. This is crucial for file creation and modification operations. ```rust const WRITECREATE: u64 = O_WRONLY | O_RDWR | O_APPEND | O_CREAT | O_EXCL;// | O_TMPFILE; // flags are the second argument for open but the third for openat let rule = SeccompRule::new(Sysno::open) .and_condition(seccomp_arg_filter!(arg1 & WRITECREATE == 0)); self.custom.entry(Sysno::open) .or_insert_with(Vec::new) .push(rule); let rule = SeccompRule::new(Sysno::openat) .and_condition(seccomp_arg_filter!(arg2 & WRITECREATE == 0)); self.custom.entry(Sysno::openat) .or_insert_with(Vec::new) .push(rule); ``` -------------------------------- ### SeccompRule::new Source: https://docs.rs/extrasafe/latest/extrasafe/struct.SeccompRule.html Constructs a new SeccompRule that unconditionally allows the given syscall. ```APIDOC ### impl SeccompRule #### pub fn new(syscall: Sysno) -> SeccompRule Constructs a new `SeccompRule` that unconditionally allows the given syscall. ``` -------------------------------- ### Ordering Source: https://docs.rs/extrasafe/latest/extrasafe/struct.BitFlags.html Implementations for ordering BitFlags. ```APIDOC ## Ordering ### `impl Ord for BitFlags` #### `fn cmp(&self, other: &BitFlags) -> Ordering` Compares `self` and `other` and returns an `Ordering`. #### `fn max(self, other: Self) -> Self` Compares and returns the maximum of two values. #### `fn min(self, other: Self) -> Self` Compares and returns the minimum of two values. #### `fn clamp(self, min: Self, max: Self) -> Self` Restricts a value to a certain interval. ``` -------------------------------- ### Perform pivot_root and unmount old root Source: https://docs.rs/extrasafe/latest/src/extrasafe/isolate/isolate_sys.rs.html This snippet demonstrates how to use `pivot_root` to change the root directory and then unmount the old root using `MNT_DETACH`. It's crucial for setting up isolated filesystems. ```rust let curdir_ptr = curdir_cstr.as_ptr(); let rc = unsafe { libc::syscall(libc::SYS_pivot_root, curdir_ptr, curdir_ptr) }; fail_negative!(rc, format!("failed to pivot_root . . into {}", tmpfs.display())); // now unmount old / with MNT_DETACH let rc = unsafe { libc::umount2(curdir_ptr, libc::MNT_DETACH) }; fail_negative!(rc, "failed to unmount old /"); ```