Simplify proc scheme security.
This commit is contained in:
+1
-1
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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})",
|
||||
|
||||
Reference in New Issue
Block a user