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..2a3ac38 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -343,4 +343,21 @@ 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("/")?, AccessFs::Execute))? + .try_clone()? + .restrict_self()?) + }, + false, + ); + } } diff --git a/src/ruleset.rs b/src/ruleset.rs index f802c3c..466f3b3 100644 --- a/src/ruleset.rs +++ b/src/ruleset.rs @@ -653,6 +653,25 @@ impl RulesetCreated { }; Ok(body()?) } + + /// Creates a new `RulesetCreated` instance by duplicating the underlying file descriptor. + /// Rule modification will affect both `RulesetCreated` instances simultaneously. + /// + /// On error, returns [`std::io::Error`]. + pub fn try_clone(&self) -> std::io::Result { + Ok(RulesetCreated { + fd: match self.fd { + -1 => -1, + self_fd => match unsafe { libc::fcntl(self_fd, libc::F_DUPFD_CLOEXEC, 0) } { + dup_fd if dup_fd >= 0 => dup_fd, + _ => return Err(Error::last_os_error()), + }, + }, + no_new_privs: self.no_new_privs, + requested_handled_fs: self.requested_handled_fs, + compat: self.compat, + }) + } } impl Drop for RulesetCreated {