Skip to content

Commit

Permalink
compat: Implement Compatible for references too
Browse files Browse the repository at this point in the history
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 <mic@digikod.net>
  • Loading branch information
l0kod committed Dec 16, 2022
1 parent fb22d7a commit c5687aa
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 23 deletions.
7 changes: 5 additions & 2 deletions src/compat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<CompatLevel> {
/// To enable a best-effort security approach,
/// Landlock features that are not supported by the running system
/// are silently ignored by default,
Expand Down Expand Up @@ -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.
Expand Down
30 changes: 23 additions & 7 deletions src/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,13 +262,6 @@ where
}
}

impl<F> Compatible for PathBeneath<F> {
fn set_compatibility(mut self, level: CompatLevel) -> Self {
self.compat_level = level;
self
}
}

#[test]
fn path_beneath_try_compat() {
use crate::*;
Expand Down Expand Up @@ -317,6 +310,29 @@ fn path_beneath_try_compat() {
}
}

impl<F> AsMut<CompatLevel> for PathBeneath<F> {
fn as_mut(&mut self) -> &mut CompatLevel {
&mut self.compat_level
}
}

impl<F> Compatible for PathBeneath<F> {}

impl<F> Compatible for &mut PathBeneath<F> {}

#[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<F> Rule<AccessFs> for PathBeneath<F> where F: AsRawFd {}
Expand Down
38 changes: 24 additions & 14 deletions src/ruleset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,13 +254,23 @@ impl Ruleset {
}
}

impl AsMut<CompatLevel> for Ruleset {
fn as_mut(&mut self) -> &mut CompatLevel {
&mut self.compat.level
}
}

impl Compatible for Ruleset {}

impl Compatible for &mut Ruleset {}

impl AsMut<Ruleset> for Ruleset {
fn as_mut(&mut self) -> &mut Ruleset {
self
}
}

pub trait RulesetAttr: Sized + AsMut<Ruleset> {
pub trait RulesetAttr: Sized + AsMut<Ruleset> + 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
Expand Down Expand Up @@ -289,13 +299,15 @@ 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)
.unwrap();

// ...and finally create the ruleset (thanks to non-lexical lifetimes).
ruleset
.set_compatibility(CompatLevel::BestEffort)
.handle_access(AccessFs::Execute)
.unwrap()
.handle_access(AccessFs::WriteFile)
Expand Down Expand Up @@ -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<CompatLevel> for RulesetCreated {
fn as_mut(&mut self) -> &mut CompatLevel {
&mut self.compat.level
}
}

pub trait RulesetCreatedAttr: Sized + AsMut<RulesetCreated> {
impl Compatible for RulesetCreated {}

impl Compatible for &mut RulesetCreated {}

pub trait RulesetCreatedAttr: Sized + AsMut<RulesetCreated> + Compatible {
/// Attempts to add a new rule to the ruleset.
///
/// On error, returns a wrapped [`AddRulesError`].
Expand Down Expand Up @@ -476,7 +491,7 @@ pub trait RulesetCreatedAttr: Sized + AsMut<RulesetCreated> {
/// 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;
<Self as AsMut<RulesetCreated>>::as_mut(&mut self).no_new_privs = no_new_privs;
self
}
}
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -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!(
Expand Down

0 comments on commit c5687aa

Please sign in to comment.