Simplify proc scheme security.

This commit is contained in:
4lDO2
2024-12-26 20:06:59 +01:00
parent 0ccc825bfb
commit a9fb2dcb93
4 changed files with 61 additions and 74 deletions
+1 -1
View File
@@ -124,7 +124,7 @@ pub fn close_tracee(session: &Session) {
/// Trigger a notification to the event: scheme
fn proc_trigger_event(file_id: usize, flags: EventFlags) {
event::trigger(GlobalSchemes::ProcFull.scheme_id(), file_id, flags);
event::trigger(GlobalSchemes::Proc.scheme_id(), file_id, flags);
}
/// Dispatch an event to any tracer tracing `self`. This will cause
+4 -11
View File
@@ -137,8 +137,7 @@ impl SchemeList {
Irq,
Time,
Sys,
ProcFull,
ProcRestricted,
Proc,
]);
#[cfg(feature = "acpi")]
@@ -163,8 +162,6 @@ impl SchemeList {
//anonymous mmap's are implemented
self.insert_global(ns, "memory", GlobalSchemes::Memory)
.unwrap();
self.insert_global(ns, "thisproc", GlobalSchemes::ProcRestricted)
.unwrap();
self.insert_global(ns, "pipe", GlobalSchemes::Pipe).unwrap();
}
@@ -209,9 +206,7 @@ impl SchemeList {
self.insert_global(ns, "debug", GlobalSchemes::Debug)
.unwrap();
self.insert_global(ns, "irq", GlobalSchemes::Irq).unwrap();
self.insert_global(ns, "proc", GlobalSchemes::ProcFull)
.unwrap();
self.insert_global(ns, "thisproc", GlobalSchemes::ProcRestricted)
self.insert_global(ns, "kernel.proc", GlobalSchemes::Proc)
.unwrap();
self.insert_global(ns, "serio", GlobalSchemes::Serio)
.unwrap();
@@ -538,8 +533,7 @@ pub enum GlobalSchemes {
Irq,
Time,
Sys,
ProcFull,
ProcRestricted,
Proc,
#[cfg(feature = "acpi")]
Acpi,
@@ -578,8 +572,7 @@ impl core::ops::Deref for GlobalSchemes {
Self::Irq => &IrqScheme,
Self::Time => &TimeScheme,
Self::Sys => &SysScheme,
Self::ProcFull => &ProcScheme::<true>,
Self::ProcRestricted => &ProcScheme::<false>,
Self::Proc => &ProcScheme,
#[cfg(feature = "acpi")]
Self::Acpi => &AcpiScheme,
#[cfg(dtb)]
+56 -47
View File
@@ -21,7 +21,7 @@ use crate::{
};
use super::{CallerCtx, GlobalSchemes, KernelSchemes, OpenResult};
use ::syscall::{SigProcControl, Sigcontrol};
use ::syscall::{ProcSchemeAttrs, SigProcControl, Sigcontrol};
use alloc::{
boxed::Box,
collections::{btree_map::Entry, BTreeMap},
@@ -30,10 +30,10 @@ use alloc::{
vec::Vec,
};
use core::{
mem,
mem::{self, size_of},
num::NonZeroUsize,
slice, str,
sync::atomic::{AtomicUsize, Ordering},
sync::atomic::{AtomicBool, AtomicUsize, Ordering},
};
use spin::RwLock;
use spinning_top::RwSpinlock;
@@ -95,13 +95,12 @@ enum RegsKind {
Env,
}
#[derive(Clone)]
enum ProcHandle {
Static { ty: &'static str, bytes: Box<[u8]> },
SessionId,
Attr { attr: Attr },
}
#[derive(Clone)]
enum ContextHandle {
// Opened by the process manager, after which it is locked. This capability is used to open
// Attr handles, to set ens/euid/egid/pid.
Authority,
Attr,
Status, // writing usize::MAX causes exit
Signal, // writing sends signal
@@ -152,7 +151,7 @@ enum Attr {
Gid,
// TODO: namespace, tid, etc.
}
pub struct ProcScheme<const FULL: bool>;
pub struct ProcScheme;
static NEXT_ID: AtomicUsize = AtomicUsize::new(1);
// Using BTreeMap as hashbrown doesn't have a const constructor.
@@ -181,9 +180,10 @@ fn new_handle((handle, fl): (Handle, InternalFlags)) -> Result<(usize, InternalF
enum OpenTy {
Ctxt(Arc<RwSpinlock<Context>>),
Auth,
}
impl<const FULL: bool> ProcScheme<FULL> {
impl ProcScheme {
fn openat_context(
&self,
path: &str,
@@ -239,15 +239,27 @@ impl<const FULL: bool> ProcScheme<FULL> {
flags: usize,
) -> Result<(usize, InternalFlags)> {
let operation_name = operation_str.ok_or(Error::new(EINVAL))?;
let (mut handle, positioned) = {
let OpenTy::Ctxt(context) = ty;
if let Some((kind, positioned)) =
let (mut handle, positioned) = match ty {
OpenTy::Ctxt(context) => if let Some((kind, positioned)) =
self.openat_context(operation_name, Arc::clone(&context))?
{
(Handle { context, kind }, positioned)
} else {
return Err(Error::new(EINVAL));
}
OpenTy::Auth => {
extern "C" fn ret() {}
let context = match operation_str.ok_or(Error::new(ENOENT))? {
"new-context" => context::spawn(true, ret)?,
"cur-context" => context::current(),
_ => return Err(Error::new(ENOENT)),
};
(Handle {
context,
kind: ContextHandle::OpenViaDup,
}, false)
}
};
{
@@ -301,34 +313,22 @@ impl<const FULL: bool> ProcScheme<FULL> {
}
}
fn new_context() -> Result<Arc<RwSpinlock<Context>>> {
let (euid, egid, ens) = match context::current().read() {
ref cur => (cur.euid, cur.egid, cur.ens),
};
let context = context::spawn(true, clone_handler)?;
{
let mut guard = context.write();
guard.euid = euid;
guard.egid = egid;
guard.ens = ens;
}
Ok(context)
}
impl<const FULL: bool> KernelScheme for ProcScheme<FULL> {
impl KernelScheme for ProcScheme {
fn kopen(&self, path: &str, _flags: usize, _ctx: CallerCtx) -> Result<OpenResult> {
let context = match path {
"new" => new_context()?,
"current" => context::current(),
_ => return Err(Error::new(ENOENT)),
};
if path != "authority" {
return Err(Error::new(ENOENT));
}
static LOCK: AtomicBool = AtomicBool::new(false);
if LOCK.swap(true, Ordering::Relaxed) {
return Err(Error::new(EEXIST));
}
let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
HANDLES.write().insert(
id,
Handle {
context,
kind: ContextHandle::OpenViaDup,
// TODO: placeholder
context: context::current(),
kind: ContextHandle::Authority,
},
);
Ok(OpenResult::SchemeLocal(id, InternalFlags::empty()))
@@ -545,6 +545,11 @@ impl<const FULL: bool> KernelScheme for ProcScheme<FULL> {
let buf = &array[..raw_buf.len()];
new_handle(match info {
Handle { kind: ContextHandle::Authority, .. } => return self.open_inner(OpenTy::Auth,
Some(core::str::from_utf8(buf).map_err(|_| Error::new(EINVAL))?)
.filter(|s| !s.is_empty()),
O_RDWR | O_CLOEXEC,
).map(|(r, fl)| OpenResult::SchemeLocal(r, fl)),
Handle {
kind: ContextHandle::OpenViaDup,
context,
@@ -643,11 +648,6 @@ impl<const FULL: bool> KernelScheme for ProcScheme<FULL> {
.map(|(r, fl)| OpenResult::SchemeLocal(r, fl))
}
}
extern "C" fn clone_handler() {
// This function will return to the syscall return assembly, and subsequently transition to
// usermode.
}
fn extract_scheme_number(fd: usize) -> Result<(KernelSchemes, usize)> {
let (scheme_id, number) = match &*context::current()
.read()
@@ -668,7 +668,7 @@ fn extract_scheme_number(fd: usize) -> Result<(KernelSchemes, usize)> {
fn verify_scheme(scheme: KernelSchemes) -> Result<()> {
if !matches!(
scheme,
KernelSchemes::Global(GlobalSchemes::ProcFull | GlobalSchemes::ProcRestricted)
KernelSchemes::Global(GlobalSchemes::Proc)
) {
return Err(Error::new(EBADF));
}
@@ -1002,9 +1002,7 @@ impl ContextHandle {
*/
Err(Error::new(EOPNOTSUPP))
}
Self::OpenViaDup
| Self::AwaitingAddrSpaceChange { .. }
| Self::AwaitingFiletableChange { .. } => Err(Error::new(EBADF)),
_ => Err(Error::new(EBADF)),
}
}
fn kreadoff(
@@ -1111,7 +1109,18 @@ impl ContextHandle {
buf.copy_exactly(crate::cpu_set::mask_as_bytes(&mask))?;
Ok(mem::size_of_val(&mask))
} // TODO: Replace write() with SYS_DUP_FORWARD.
} // TODO: Replace write() with SYS_SENDFD?
ContextHandle::Attr => {
let (euid, egid, ens, pid) = match context.read() {
ref c => (c.euid, c.egid, c.ens.get() as u32, c.pid as u32),
};
buf.copy_common_bytes_from_slice(&ProcSchemeAttrs {
pid,
euid,
egid,
ens,
})
}
// TODO: Find a better way to switch address spaces, since they also require switching
// the instruction and stack pointer. Maybe remove `<pid>/regs` altogether and replace it
-15
View File
@@ -156,7 +156,6 @@ pub fn format_call(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -
SYS_CLOCK_GETTIME => format!("clock_gettime({}, {:?})", b, unsafe {
read_struct::<TimeSpec>(c)
}),
SYS_EXIT => format!("exit({})", b),
SYS_FUTEX => format!(
"futex({:#X} [{:?}], {}, {}, {}, {})",
b,
@@ -166,17 +165,7 @@ pub fn format_call(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -
e,
f
),
SYS_GETEGID => format!("getegid()"),
SYS_GETENS => format!("getens()"),
SYS_GETEUID => format!("geteuid()"),
SYS_GETGID => format!("getgid()"),
SYS_GETNS => format!("getns()"),
SYS_GETPGID => format!("getpgid()"),
SYS_GETPID => format!("getpid()"),
SYS_GETPPID => format!("getppid()"),
SYS_GETUID => format!("getuid()"),
SYS_IOPL => format!("iopl({})", b),
SYS_KILL => format!("kill({}, {})", b, c),
SYS_MKNS => format!(
"mkns({:p} len: {})",
// TODO: Print out all scheme names?
@@ -194,10 +183,6 @@ pub fn format_call(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -
d
),
SYS_VIRTTOPHYS => format!("virttophys({:#X})", b),
SYS_SETREGID => format!("setregid({}, {})", b, c),
SYS_SETRENS => format!("setrens({}, {})", b, c),
SYS_SETREUID => format!("setreuid({}, {})", b, c),
SYS_WAITPID => format!("waitpid({}, {:#X}, {:?})", b, c, WaitFlags::from_bits(d)),
SYS_YIELD => format!("yield()"),
_ => format!(
"UNKNOWN{} {:#X}({:#X}, {:#X}, {:#X}, {:#X}, {:#X})",