From 768bf95f73a46cfc0377c2f1d5537358efe95fae Mon Sep 17 00:00:00 2001 From: Carl Petty Date: Wed, 20 Mar 2024 21:29:25 -0600 Subject: [PATCH] Initial ruleset duplication --- src/compat.rs | 2 +- src/ruleset.rs | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/src/compat.rs b/src/compat.rs index e08ceead..a61f24e7 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/ruleset.rs b/src/ruleset.rs index f802c3cc..60bce317 100644 --- a/src/ruleset.rs +++ b/src/ruleset.rs @@ -653,6 +653,32 @@ 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 a wrapped [`RulesetError::NewRef`]. + pub fn new_ref(&self) -> Result { + let 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 { @@ -719,6 +745,29 @@ fn ruleset_created_attr() { ); } +#[test] +fn ruleset_created_new_ref() { + Ruleset::from(ABI::V1) + .handle_access(AccessFs::Execute) + .unwrap() + .create() + .unwrap() + .add_rule(PathBeneath::new( + PathFd::new("/usr").unwrap(), + AccessFs::Execute, + )) + .unwrap() + .add_rule(PathBeneath::new( + PathFd::new("/etc").unwrap(), + AccessFs::Execute, + )) + .unwrap() + .new_ref() + .unwrap() + .restrict_self() + .unwrap(); +} + #[test] fn ruleset_unsupported() { assert_eq!(