From 18ce04d193ecf883199923ab4564f3560b255f17 Mon Sep 17 00:00:00 2001 From: Carl Petty Date: Thu, 21 Mar 2024 10:33:55 -0600 Subject: [PATCH] Added try_clone to RulsetCreated. This enables the sharing of a parent ruleset that can be passed to multiple/threads without the need to reconstruct the a ruleset. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mickaël Salaün --- src/compat.rs | 2 +- src/lib.rs | 20 ++++++++++++++++++++ src/ruleset.rs | 30 ++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/compat.rs b/src/compat.rs index e08ceea..a61f24e 100644 --- a/src/compat.rs +++ b/src/compat.rs @@ -255,7 +255,7 @@ fn compat_state_update_2() { } #[cfg_attr(test, derive(Debug, PartialEq))] -#[derive(Clone)] +#[derive(Copy, Clone)] pub(crate) struct Compatibility { abi: ABI, pub(crate) level: Option, diff --git a/src/lib.rs b/src/lib.rs index 3c26100..8e6590c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -343,4 +343,24 @@ mod tests { false, ); } + + #[test] + fn ruleset_created_try_clone() { + check_ruleset_support( + ABI::V1, + Some(ABI::V1), + move |ruleset: Ruleset| -> _ { + Ok(ruleset + .handle_access(AccessFs::Execute)? + .create()? + .add_rule(PathBeneath::new( + PathFd::new("/usr").unwrap(), + AccessFs::Execute, + ))? + .try_clone()? + .restrict_self()?) + }, + false, + ); + } } diff --git a/src/ruleset.rs b/src/ruleset.rs index f802c3c..d8c703f 100644 --- a/src/ruleset.rs +++ b/src/ruleset.rs @@ -653,6 +653,36 @@ impl RulesetCreated { }; Ok(body()?) } + + /// Creates a copy of this object and duplicates the file descriptor with + /// CLOEXEC set. The `RulesetCreated` object that is produced is intended + /// to be a readonly copy of the original object, however this + /// is not currently supported by the landlock kernel module. The intention + /// behind this method is to provide a way to keep a parent ruleset intact so + /// it can be applied to any number of new processes or threads without + /// creating the object over and over. + /// + /// Any modification of the underlying ruleset changes will alter both + /// the new RulesetCreated and the original. + /// + /// On error, returns [`std::io::Error`]. + pub fn try_clone(&self) -> Result { + let mut dup_fd = -1; + + if self.fd != -1 { + dup_fd = unsafe { libc::fcntl(self.fd, libc::F_DUPFD_CLOEXEC, 0) }; + if dup_fd == -1 { + return Err(Error::last_os_error()); + } + } + + Ok(RulesetCreated { + fd: dup_fd, + no_new_privs: self.no_new_privs, + requested_handled_fs: self.requested_handled_fs, + compat: self.compat, + }) + } } impl Drop for RulesetCreated {