Special cased rules for ownership for now.

Fortune for rng's current commit: Blessing − 吉
plugin
Avril 2 years ago
parent 430bc78072
commit 0a7e4286b3
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -47,6 +47,8 @@ pub mod locations {
const ROOT_OWNED_ONLY = 1 << 4; const ROOT_OWNED_ONLY = 1 << 4;
/// Only qualify user-owned files (can be unioned with other `_OWNED_ONLY` constants) /// Only qualify user-owned files (can be unioned with other `_OWNED_ONLY` constants)
const USER_OWNED_ONLY = 1 << 5; const USER_OWNED_ONLY = 1 << 5;
/// Owned by user or by root.
const USER_OR_ROOT_OWNED = Self::ROOT_OWNED_ONLY.bits | Self::USER_OWNED_ONLY.bits;
/// Disqualify files that are accessible at all by anyone other than the current user (or root, which can accesss everything.) /// Disqualify files that are accessible at all by anyone other than the current user (or root, which can accesss everything.)
const USER_ACCESSIBLE_ONLY = 1 << 6; const USER_ACCESSIBLE_ONLY = 1 << 6;
/// Disallow *all* untrusted files. /// Disallow *all* untrusted files.
@ -124,11 +126,60 @@ pub mod locations {
} }
set!($name => |_, _| _panic_with_msg()) set!($name => |_, _| _panic_with_msg())
}; };
($name:ident: $($func_body:tt)+) => { /*FUCK THIS, I HATE ITERATON IN MACROS< WHY DOES IT HAVE TO BE SO RECURSIVELY LEAKILY RETARDED AAAA(@ compose ($f_name:ident, $f_file:ident) via $operator:tt $ignore:tt; $first:ident, $second:ident $($rest:tt)*)
set!($name => |path, filename| { $($func_body)+}) => (table[Self::$first.bits() as usize]($f_name, $f_file) $operator set!(@ compose ($f_name, $f_file) via $operator &&; Self::$second.bits(), $($rest)*));
(@ compose ($f_name:ident, $f_file:ident) $(via $operator:tt)?; $($first:ident)? $(,)?)
=> ($(table[Self::$first.bits() as usize])?);
($name:ident $(; use $operator:tt)? => $($other:ident),+) => {
set!($name => |path, filename| {
set!(@ compose (path, filename) via $($operator)? &&; $($other),+)
});
}*/
}
/// In lookups, use process EUID instead of UID.
const USE_EFFECTIVE_UID: bool = true;
/// Get UID or **E**UID.
#[inline(always)]
fn get_uid<const E: bool>() -> u32
{
extern "C" {
fn getuid() -> u32; // uid_t
//XXX: Should we use process's UID or EUID? It seems we should use EUID.
fn geteuid() -> u32; // uid_t
}
// SAFETY: These are effectively pure.
unsafe {
if E {
geteuid()
} else {
getuid()
}
}
}
#[inline(always)]
fn check_uid<const CACHED: bool>(against: impl PartialEq<u32>) -> bool
{
//TODO: Allow these to be reset, somehow? Idk... Make them regular static atomics?
lazy_static! {
static ref USER_UID_CACHED: u32 = get_uid::<false>();
static ref USER_EUID_CACHED: u32 = get_uid::<true>();
}
against == if CACHED {
if USE_EFFECTIVE_UID {
*USER_EUID_CACHED
} else {
*USER_UID_CACHED
}
} else {
get_uid::<USE_EFFECTIVE_UID>()
} }
} }
set!(NAME_MATCH as ! "This should already have been checked"); set!(NAME_MATCH as ! "This should already have been checked");
set!(NON_SYMLINK => |path: &Path, _| !path.is_symlink()); set!(NON_SYMLINK => |path: &Path, _| !path.is_symlink());
set!(NON_EXEC => |path, _| { set!(NON_EXEC => |path, _| {
@ -163,15 +214,10 @@ pub mod locations {
}); });
set!(USER_OWNED_ONLY => |path, _| { set!(USER_OWNED_ONLY => |path, _| {
use std::os::unix::fs::MetadataExt as _; use std::os::unix::fs::MetadataExt as _;
extern "C" {
fn getuid() -> u32; // uid_t //let user_id = get_uid::<USE_EFFECTIVE_UID>();
//XXX: Should we use process's UID or EUID? It seems we should use EUID.
fn geteuid() -> u32; // uid_t
}
// SAFETY: This is a pure function for all that matters.
let user_id = unsafe { geteuid() };
path.metadata() path.metadata()
.map(move |meta| meta.uid() == user_id) .map(move |meta| check_uid::<true>(meta.uid()))
.unwrap_or(false) .unwrap_or(false)
}); });
set!(USER_ACCESSIBLE_ONLY => |path, _| { set!(USER_ACCESSIBLE_ONLY => |path, _| {
@ -192,6 +238,19 @@ pub mod locations {
.map(|meta| !meta.permissions().mode() & OTHER_ACCESSORS == 0) //XXX: Test this .map(|meta| !meta.permissions().mode() & OTHER_ACCESSORS == 0) //XXX: Test this
.unwrap_or(false) .unwrap_or(false)
}); });
set!(USER_OR_ROOT_OWNED => |path, _| {
use std::os::unix::fs::MetadataExt as _;
//let user_id = get_uid::<USE_EFFECTIVE_UID>();
path.metadata()
.map(move |meta| match meta.uid() {
0 => true,
uid if check_uid::<true>(uid) => true,
_ => false
})
.unwrap_or(false)
});
//set!(USER_OR_ROOT_OWNED; use || => USER_OWNED_ONLY, ROOT_OWNED_ONLY);
//TODO: Composition of functions should be done via OR, how to insert all possible compositions into table? We get confusing error messages when we try inside `set!()` //TODO: Composition of functions should be done via OR, how to insert all possible compositions into table? We get confusing error messages when we try inside `set!()`
table table
} }
@ -398,16 +457,36 @@ impl PathLookup
return true; return true;
} }
macro_rules! check {
($name:ident) => {
if RULES.contains(Rule::$name) {
Rule::RULE_FUNCTION_CHECK_TABLE[Rule::$name.bits() as usize](path, filename)
} else {
true
}
};
(try $($op:tt)? $name:ident) => {
if $($op)? check!($name) {
return false;
}
}
}
// XXX: Ugh, for now, this shit must be checked independently.
check!(try ! USER_OR_ROOT_OWNED);
// Check rest of rules in sequence. Hopefully this will be unrolled since the first `if` statement is all const-fn on a static constant.
while bit > 0 while bit > 0
{ {
// SAFETY: We know `INACCESSIBLE` is the largest // SAFETY: We know `INACCESSIBLE` is the largest
if RULES.contains(unsafe { Rule::from_bits_unchecked(bit) }) { if RULES.contains(unsafe { Rule::from_bits_unchecked(bit) }) {
if !Rule::RULE_FUNCTION_CHECK_TABLE[bit as usize](path, filename) {
return false;
}
} }
bit >>= 1; bit >>= 1;
} }
true
todo!("TODO: extra Untrusted lookup rules checked on `path` here.")
} }
lazy_static! { lazy_static! {
static ref TRUSTED_EXT_REGEX_MAP: Vec<Regex> = static ref TRUSTED_EXT_REGEX_MAP: Vec<Regex> =

Loading…
Cancel
Save