Add support for trusted group IDs.
This commit is contained in:
parent
c4a6c6d82e
commit
712b46174d
|
@ -114,7 +114,7 @@ impl<'a> super::Verifier<'a> {
|
|||
if uid != 0 && Some(uid) != self.mistrust.trust_uid {
|
||||
errors.push(Error::BadOwner(path.into(), uid));
|
||||
}
|
||||
let forbidden_bits = if !self.readable_okay && path_type == PathType::Final {
|
||||
let mut forbidden_bits = if !self.readable_okay && path_type == PathType::Final {
|
||||
// If this is the target object, and it must not be readable,
|
||||
// then we forbid it to be group-rwx and all-rwx.
|
||||
0o077
|
||||
|
@ -139,6 +139,10 @@ impl<'a> super::Verifier<'a> {
|
|||
0o022
|
||||
}
|
||||
};
|
||||
// If we trust the GID, then we allow even more bits to be set.
|
||||
if self.mistrust.trust_gid == Some(meta.gid()) {
|
||||
forbidden_bits &= !0o070;
|
||||
}
|
||||
let bad_bits = meta.mode() & forbidden_bits;
|
||||
if bad_bits != 0 {
|
||||
errors.push(Error::BadPermission(path.into(), bad_bits));
|
||||
|
|
|
@ -87,8 +87,6 @@
|
|||
|
||||
// TODO: Stuff to add before this crate is ready....
|
||||
// - Ability to create directory if it doesn't exist.
|
||||
// - Get more flexible about group permissions. (diziet had an idea.)
|
||||
// - Stop-at-homedir support.
|
||||
// - Test the absolute heck out of it.
|
||||
|
||||
// POSSIBLY TODO:
|
||||
|
@ -168,6 +166,10 @@ pub struct Mistrust {
|
|||
/// What user ID do we trust by default (if any?)
|
||||
#[cfg(target_family = "unix")]
|
||||
trust_uid: Option<u32>,
|
||||
|
||||
/// What group ID do we trust by default (if any?)
|
||||
#[cfg(target_family = "unix")]
|
||||
trust_gid: Option<u32>,
|
||||
}
|
||||
|
||||
impl Default for Mistrust {
|
||||
|
@ -176,6 +178,8 @@ impl Default for Mistrust {
|
|||
ignore_prefix: None,
|
||||
#[cfg(target_family = "unix")]
|
||||
trust_uid: Some(unsafe { libc::getuid() }),
|
||||
#[cfg(target_family = "unix")]
|
||||
trust_gid: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -249,6 +253,23 @@ impl Mistrust {
|
|||
self
|
||||
}
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
/// Configure a trusted group ID for this `Mistrust`.
|
||||
///
|
||||
/// If a group ID is considered "trusted", then any file or directory we
|
||||
/// inspect is allowed to be readable and writable by that group.
|
||||
///
|
||||
/// By default, no group ID is trusted, and any group-readable or
|
||||
/// group-writable objects are treated the same as world-readable and
|
||||
/// world-writable objects respectively.
|
||||
///
|
||||
/// Anybody who is a member (or becomes a member) of the provided group will
|
||||
/// be allowed to read and modify the verified files.
|
||||
pub fn trust_group_id(&mut self, gid: u32) -> &mut Self {
|
||||
self.trust_gid = Some(gid);
|
||||
self
|
||||
}
|
||||
|
||||
/// Create a new [`Verifier`] with this configuration, to perform a single check.
|
||||
pub fn verifier(&self) -> Verifier<'_> {
|
||||
Verifier {
|
||||
|
@ -525,6 +546,36 @@ mod test {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
#[test]
|
||||
fn trust_gid() {
|
||||
use std::os::unix::prelude::MetadataExt;
|
||||
let d = Dir::new();
|
||||
d.dir("a/b");
|
||||
d.chmod("a", 0o770);
|
||||
d.chmod("a/b", 0o770);
|
||||
|
||||
let mut m = Mistrust::new();
|
||||
m.ignore_prefix(d.canonical_root()).unwrap();
|
||||
|
||||
// By default, we shouldn't be accept this directory, since it is
|
||||
// group-writable.
|
||||
let e = m.check_directory(d.path("a/b")).unwrap_err();
|
||||
assert!(matches!(e, Error::BadPermission(_, _)));
|
||||
|
||||
// But we can make the group trusted, which will make it okay for the
|
||||
// directory to be group-writable.
|
||||
let gid = d.path("a/b").metadata().unwrap().gid();
|
||||
m.trust_group_id(gid);
|
||||
m.check_directory(d.path("a/b")).unwrap();
|
||||
|
||||
// OTOH, if we made a _different_ group trusted, it'll fail.
|
||||
|
||||
m.trust_group_id(gid ^ 1);
|
||||
let e = m.check_directory(d.path("a/b")).unwrap_err();
|
||||
assert!(matches!(e, Error::BadPermission(_, _)));
|
||||
}
|
||||
|
||||
// TODO: Write far more tests.
|
||||
// * Can there be a test for a failed readlink()? I can't see an easy way
|
||||
// to provoke that without trying to make a time-of-check/time-of-use race
|
||||
|
|
Loading…
Reference in New Issue