From c5687aa182c6c5f862d6a4f8f9d49cacee05e891 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Sala=C3=BCn?= Date: Tue, 13 Dec 2022 17:38:57 +0100 Subject: [PATCH] compat: Implement Compatible for references too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This enables to change the compatibility for builder objects or their references like it is done for RulesetAttr and RulesetCreatedAttr. Make Compatibility a requirement for RulesetAttr and RulesetCreatedAttr traits to ensure consistency. This change makes it possible to read the CompatLevel tied to an object. It may be superfluous but should not harm. Signed-off-by: Mickaël Salaün --- src/compat.rs | 7 +++++-- src/fs.rs | 30 +++++++++++++++++++++++------- src/ruleset.rs | 38 ++++++++++++++++++++++++-------------- 3 files changed, 52 insertions(+), 23 deletions(-) diff --git a/src/compat.rs b/src/compat.rs index a0a6bfc8..727b6eb5 100644 --- a/src/compat.rs +++ b/src/compat.rs @@ -273,7 +273,7 @@ impl Compatibility { /// (e.g. applications carefully designed to only be run with a specific set of kernel features), /// it may be required to error out if some of these features are not available /// and will then not be enforced. -pub trait Compatible { +pub trait Compatible: Sized + AsMut { /// To enable a best-effort security approach, /// Landlock features that are not supported by the running system /// are silently ignored by default, @@ -349,7 +349,10 @@ pub trait Compatible { /// .create()?) /// } /// ``` - fn set_compatibility(self, level: CompatLevel) -> Self; + fn set_compatibility(mut self, level: CompatLevel) -> Self { + *self.as_mut() = level; + self + } } /// See the [`Compatible`] documentation. diff --git a/src/fs.rs b/src/fs.rs index abed03ac..95db5496 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -262,13 +262,6 @@ where } } -impl Compatible for PathBeneath { - fn set_compatibility(mut self, level: CompatLevel) -> Self { - self.compat_level = level; - self - } -} - #[test] fn path_beneath_try_compat() { use crate::*; @@ -317,6 +310,29 @@ fn path_beneath_try_compat() { } } +impl AsMut for PathBeneath { + fn as_mut(&mut self) -> &mut CompatLevel { + &mut self.compat_level + } +} + +impl Compatible for PathBeneath {} + +impl Compatible for &mut PathBeneath {} + +#[test] +fn path_beneath_compatibility() { + let mut path = PathBeneath::new(PathFd::new("/").unwrap(), AccessFs::from_all(ABI::V1)); + let path_ref = &mut path; + + assert_eq!(path_ref.as_mut(), &CompatLevel::BestEffort); + + path_ref.set_compatibility(CompatLevel::SoftRequirement); + assert_eq!(path_ref.as_mut(), &CompatLevel::SoftRequirement); + + path.set_compatibility(CompatLevel::HardRequirement); +} + // It is useful for documentation generation to explicitely implement Rule for every types, instead // of doing it generically. impl Rule for PathBeneath where F: AsRawFd {} diff --git a/src/ruleset.rs b/src/ruleset.rs index c349e73d..7eea6906 100644 --- a/src/ruleset.rs +++ b/src/ruleset.rs @@ -254,13 +254,23 @@ impl Ruleset { } } +impl AsMut for Ruleset { + fn as_mut(&mut self) -> &mut CompatLevel { + &mut self.compat.level + } +} + +impl Compatible for Ruleset {} + +impl Compatible for &mut Ruleset {} + impl AsMut for Ruleset { fn as_mut(&mut self) -> &mut Ruleset { self } } -pub trait RulesetAttr: Sized + AsMut { +pub trait RulesetAttr: Sized + AsMut + Compatible { /// Attempts to add a set of access rights that will be supported by this ruleset. /// By default, all actions requiring these access rights will be denied. /// Consecutive calls to `handle_access()` will be interpreted as logical ORs @@ -289,6 +299,7 @@ fn ruleset_attr() { // Can pass this reference to prepare the ruleset... ruleset_ref + .set_compatibility(CompatLevel::BestEffort) .handle_access(AccessFs::Execute) .unwrap() .handle_access(AccessFs::ReadFile) @@ -296,6 +307,7 @@ fn ruleset_attr() { // ...and finally create the ruleset (thanks to non-lexical lifetimes). ruleset + .set_compatibility(CompatLevel::BestEffort) .handle_access(AccessFs::Execute) .unwrap() .handle_access(AccessFs::WriteFile) @@ -330,14 +342,17 @@ fn ruleset_created_handle_access_or() { )); } -impl Compatible for Ruleset { - fn set_compatibility(mut self, level: CompatLevel) -> Self { - self.compat.level = level; - self +impl AsMut for RulesetCreated { + fn as_mut(&mut self) -> &mut CompatLevel { + &mut self.compat.level } } -pub trait RulesetCreatedAttr: Sized + AsMut { +impl Compatible for RulesetCreated {} + +impl Compatible for &mut RulesetCreated {} + +pub trait RulesetCreatedAttr: Sized + AsMut + Compatible { /// Attempts to add a new rule to the ruleset. /// /// On error, returns a wrapped [`AddRulesError`]. @@ -476,7 +491,7 @@ pub trait RulesetCreatedAttr: Sized + AsMut { /// call while [`CompatLevel::SoftRequirement`] was set (with /// [`set_compatibility()`](Compatible::set_compatibility)). fn set_no_new_privs(mut self, no_new_privs: bool) -> Self { - self.as_mut().no_new_privs = no_new_privs; + >::as_mut(&mut self).no_new_privs = no_new_privs; self } } @@ -607,6 +622,7 @@ fn ruleset_created_attr() { // Can pass this reference to populate the ruleset... ruleset_created_ref + .set_compatibility(CompatLevel::BestEffort) .add_rule(PathBeneath::new( PathFd::new("/usr").unwrap(), AccessFs::Execute, @@ -620,6 +636,7 @@ fn ruleset_created_attr() { // ...and finally restrict with the last rules (thanks to non-lexical lifetimes). ruleset_created + .set_compatibility(CompatLevel::BestEffort) .add_rule(PathBeneath::new( PathFd::new("/tmp").unwrap(), AccessFs::Execute, @@ -634,13 +651,6 @@ fn ruleset_created_attr() { .unwrap(); } -impl Compatible for RulesetCreated { - fn set_compatibility(mut self, level: CompatLevel) -> Self { - self.compat.level = level; - self - } -} - #[test] fn ruleset_unsupported() { assert_eq!(