From 1d5f8fd46d71bcf923d22711882acba99cb91b3c Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Tue, 17 Dec 2024 00:20:42 +0100 Subject: [PATCH] Move proc code to userspace. --- src/context/context.rs | 23 +- src/context/mod.rs | 25 +- src/context/process.rs | 124 --------- src/context/signal.rs | 3 +- src/context/switch.rs | 7 +- src/main.rs | 28 +- src/ptrace.rs | 2 +- src/scheme/proc.rs | 510 ++--------------------------------- src/scheme/sys/scheme_num.rs | 5 +- src/syscall/mod.rs | 22 -- src/syscall/process.rs | 491 +-------------------------------- 11 files changed, 44 insertions(+), 1196 deletions(-) delete mode 100644 src/context/process.rs diff --git a/src/context/context.rs b/src/context/context.rs index 57de1ca4d7..f46fc41ce5 100644 --- a/src/context/context.rs +++ b/src/context/context.rs @@ -18,7 +18,7 @@ use crate::{ memory::{allocate_p2frame, deallocate_p2frame, Enomem, Frame, RaiiFrame}, paging::{RmmA, RmmArch}, percpu::PercpuBlock, - scheme::FileHandle, + scheme::{FileHandle, SchemeNamespace}, }; use crate::syscall::error::{Error, Result, EAGAIN, ESRCH}; @@ -26,11 +26,9 @@ use crate::syscall::error::{Error, Result, EAGAIN, ESRCH}; use super::{ empty_cr3, memory::{AddrSpaceWrapper, GrantFileRef}, - process::{Process, ProcessId}, }; /// The status of a context - used for scheduling -/// See `syscall::process::waitpid` and the `sync` module for examples of usage #[derive(Clone, Debug)] pub enum Status { Runnable, @@ -124,13 +122,9 @@ impl PartialEq for WaitpidKey { impl Eq for WaitpidKey {} -/// A context, which identifies either a process or a thread +/// A context, which is typically mapped to a userspace thread #[derive(Debug)] pub struct Context { - /// The process ID of this context - pub pid: ProcessId, - /// Process state shared with other threads - pub process: Arc>, /// Signal handler pub sig: Option, /// Status of context @@ -183,6 +177,11 @@ pub struct Context { pub userspace: bool, pub being_sigkilled: bool, pub fmap_ret: Option, + + // TODO: Temporary replacement for existing kernel logic, replace with capabilities! + pub is_privileged: bool, + pub ens: SchemeNamespace, + pub rns: SchemeNamespace, } #[derive(Debug)] @@ -203,10 +202,8 @@ pub struct SignalState { } impl Context { - pub fn new(pid: ProcessId, process: Arc>) -> Result { + pub fn new() -> Result { let this = Context { - pid, - process, sig: None, status: Status::HardBlocked { reason: HardBlockedReason::NotYetStarted, @@ -231,6 +228,10 @@ impl Context { fmap_ret: None, being_sigkilled: false, + is_privileged: false, + ens: 0.into(), + rns: 0.into(), + #[cfg(feature = "syscall_debug")] syscall_debug_info: crate::syscall::debug::SyscallDebugInfo::default(), }; diff --git a/src/context/mod.rs b/src/context/mod.rs index cc40c63094..7e048cb155 100644 --- a/src/context/mod.rs +++ b/src/context/mod.rs @@ -17,10 +17,7 @@ use crate::{ syscall::error::{Error, Result}, }; -use self::{ - context::Kstack, - process::{Process, ProcessId, ProcessInfo}, -}; +use self::context::Kstack; pub use self::{ context::{BorrowedHtBuf, Context, Status, WaitpidKey}, switch::switch, @@ -54,9 +51,6 @@ pub mod file; /// Memory struct - contains a set of pages for a context pub mod memory; -/// Process handling - TODO move to userspace -pub mod process; - /// Signal handling pub mod signal; @@ -70,23 +64,11 @@ pub const CONTEXT_MAX_FILES: usize = 65_536; pub use self::arch::empty_cr3; -static KMAIN_PROCESS: Once>> = Once::new(); - // Set of weak references to all contexts available for scheduling. The only strong references are // the context file descriptors. static CONTEXTS: RwLock> = RwLock::new(BTreeSet::new()); pub fn init() { - let pid = ProcessId::new(0); - let process = KMAIN_PROCESS.call_once(|| { - Arc::new(RwLock::new(Process { - info: ProcessInfo::default(), - waitpid: Arc::new(WaitMap::new()), - threads: Vec::new(), - status: process::ProcessStatus::PossiblyRunnable, - })) - }); - let mut context = Context::new(pid, Arc::clone(process)).expect("failed to create kmain context"); context.sched_affinity = LogicalCpuSet::empty(); @@ -135,10 +117,6 @@ pub fn is_current(context: &Arc>) -> bool { .with_context(|current| Arc::ptr_eq(context, current)) } -pub fn current_pid() -> Result { - Ok(current().read().pid) -} - pub struct ContextRef(pub Arc>); impl ContextRef { pub fn upgrade(&self) -> Option>> { @@ -166,7 +144,6 @@ impl Eq for ContextRef {} /// Spawn a context from a function. pub fn spawn( userspace_allowed: bool, - process: Arc>, func: extern "C" fn(), ) -> Result>> { let stack = Kstack::new()?; diff --git a/src/context/process.rs b/src/context/process.rs deleted file mode 100644 index e31c06d0d1..0000000000 --- a/src/context/process.rs +++ /dev/null @@ -1,124 +0,0 @@ -use core::{ - ops::{Deref, DerefMut}, - sync::atomic::{AtomicUsize, Ordering}, -}; - -// TODO: move all this code to userspace -use alloc::{ - collections::BTreeMap, - sync::{Arc, Weak}, - vec::Vec, -}; - -use spin::RwLock; -use spinning_top::RwSpinlock; - -use syscall::{Error, Result, ENOMEM, ESRCH}; - -use crate::{ - scheme::{CallerCtx, SchemeNamespace}, - sync::WaitMap, -}; - -use crate::context::{self, Context, WaitpidKey}; - -int_like!(ProcessId, AtomicProcessId, usize, AtomicUsize); - -#[derive(Debug)] -pub struct Process { - pub info: ProcessInfo, - /// Context is being waited on - pub waitpid: Arc>, - pub status: ProcessStatus, - pub threads: Vec>>, -} -#[derive(Debug, Clone, Copy, Default)] -pub struct ProcessInfo { - /// The process ID of this process - pub pid: ProcessId, - /// The group ID of this process - pub pgid: ProcessId, - /// The ID of the parent process - pub ppid: ProcessId, - /// The ID of the session - pub session_id: ProcessId, - /// The real user id - pub ruid: u32, - /// The real group id - pub rgid: u32, - /// The real namespace id - pub rns: SchemeNamespace, - /// The effective user id - pub euid: u32, - /// The effective group id - pub egid: u32, - /// The effective namespace id - pub ens: SchemeNamespace, -} -impl Deref for Process { - type Target = ProcessInfo; - - fn deref(&self) -> &Self::Target { - &self.info - } -} -impl DerefMut for Process { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.info - } -} -#[derive(Debug, Clone, Copy)] -pub enum ProcessStatus { - PossiblyRunnable, - Stopped(usize), - Exiting, - Exited(usize), -} - -pub const INIT: ProcessId = ProcessId::new(1); -static NEXT_PID: AtomicProcessId = AtomicProcessId::new(INIT); -pub static PROCESSES: RwLock>>> = - RwLock::new(BTreeMap::new()); - -/// Get an iterator of all parents -pub fn ancestors( - list: &BTreeMap>>, - id: ProcessId, -) -> impl Iterator>)> + '_ { - core::iter::successors( - list.get(&id).map(|process| (id, process)), - move |(_id, process)| { - let process = process.read(); - let id = process.ppid; - list.get(&id).map(|process| (id, process)) - }, - ) -} - -pub fn current() -> Result>> { - let pid = context::current().read().pid; - Ok(Arc::clone( - PROCESSES.read().get(&pid).ok_or(Error::new(ESRCH))?, - )) -} -impl Process { - pub fn caller_ctx(&self) -> CallerCtx { - CallerCtx { - pid: self.pid.into(), - uid: self.euid, - gid: self.egid, - } - } -} -pub fn new_process(info: impl FnOnce(ProcessId) -> ProcessInfo) -> Result>> { - let pid = NEXT_PID.fetch_add(ProcessId::new(1), Ordering::Relaxed); - let proc = Arc::try_new(RwLock::new(Process { - waitpid: Arc::try_new(WaitMap::new()).map_err(|_| Error::new(ENOMEM))?, - threads: Vec::new(), - status: ProcessStatus::PossiblyRunnable, - info: info(pid), - })) - .map_err(|_| Error::new(ENOMEM))?; - PROCESSES.write().insert(pid, Arc::clone(&proc)); - Ok(proc) -} diff --git a/src/context/signal.rs b/src/context/signal.rs index 24df641b38..e2a272c46f 100644 --- a/src/context/signal.rs +++ b/src/context/signal.rs @@ -80,7 +80,8 @@ pub fn excp_handler(_signal: usize) { let Some(_eh) = context.sig.as_ref().and_then(|s| s.excp_handler) else { drop(context); - crate::syscall::process::exit(SIGKILL << 8); + // TODO: Send exception event to process manager + todo!() }; // TODO diff --git a/src/context/switch.rs b/src/context/switch.rs index 60f99e0788..dcfcfa9925 100644 --- a/src/context/switch.rs +++ b/src/context/switch.rs @@ -255,16 +255,17 @@ pub fn switch() -> SwitchResult { _next_guard: next_context_guard, })); - let (ptrace_session, ptrace_flags) = if let Some((session, bp)) = ptrace::sessions() + /*let (ptrace_session, ptrace_flags) = if let Some((session, bp)) = ptrace::sessions() .get(&next_context.pid) .map(|s| (Arc::downgrade(s), s.data.lock().breakpoint)) { (Some(session), bp.map_or(PtraceFlags::empty(), |f| f.flags)) } else { (None, PtraceFlags::empty()) - }; + };*/ + let ptrace_flags = PtraceFlags::empty(); - *percpu.ptrace_session.borrow_mut() = ptrace_session; + //*percpu.ptrace_session.borrow_mut() = ptrace_session; percpu.ptrace_flags.set(ptrace_flags); prev_context.inside_syscall = percpu.inside_syscall.replace(next_context.inside_syscall); diff --git a/src/main.rs b/src/main.rs index cdf58ed763..d1d7ec53aa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -64,10 +64,7 @@ extern crate bitflags; use core::sync::atomic::{AtomicU32, Ordering}; use crate::{ - context::{ - process::{new_process, ProcessInfo, INIT}, - switch::SwitchResult, - }, + context::switch::SwitchResult, scheme::SchemeNamespace, }; @@ -202,8 +199,7 @@ fn kmain(cpu_count: u32, bootstrap: Bootstrap) -> ! { //Initialize global schemes, such as `acpi:`. scheme::init_globals(); - let pid = syscall::getpid(); - info!("BSP: {:?} {}", pid, cpu_count); + info!("BSP: {}", cpu_count); info!("Env: {:?}", ::core::str::from_utf8(bootstrap.env)); BOOTSTRAP.call_once(|| bootstrap); @@ -211,30 +207,12 @@ fn kmain(cpu_count: u32, bootstrap: Bootstrap) -> ! { #[cfg(feature = "profiling")] profiling::ready_for_profiling(); - let process = new_process(|_| ProcessInfo { - pid: INIT, - ppid: INIT, - pgid: INIT, - session_id: INIT, - ruid: 0, - rgid: 0, - euid: 0, - egid: 0, - rns: SchemeNamespace::new(0), - ens: SchemeNamespace::new(0), - }) - .expect("failed to create init process"); - - match context::spawn(true, process, userspace_init) { + match context::spawn(true, userspace_init) { Ok(context_lock) => { { let mut context = context_lock.write(); context.status = context::Status::Runnable; context.name = "bootstrap".into(); - - let mut process = context.process.write(); - process.rns = SchemeNamespace::from(1); - process.ens = SchemeNamespace::from(1); } INIT_THREAD.call_once(move || context_lock); } diff --git a/src/ptrace.rs b/src/ptrace.rs index e9ae14bc8a..d36692a90e 100644 --- a/src/ptrace.rs +++ b/src/ptrace.rs @@ -97,7 +97,7 @@ impl Session { } } -type SessionMap = HashMap>; +type SessionMap = HashMap>; static SESSIONS: Once> = Once::new(); diff --git a/src/scheme/proc.rs b/src/scheme/proc.rs index 4fed12e9dd..55f1e0812b 100644 --- a/src/scheme/proc.rs +++ b/src/scheme/proc.rs @@ -5,7 +5,6 @@ use crate::{ context::{HardBlockedReason, SignalState}, file::{FileDescriptor, InternalFlags}, memory::{handle_notify_files, AddrSpaceWrapper, Grant, PageSpan}, - process::{self, Process, ProcessId, ProcessInfo, ProcessStatus}, Context, Status, }, memory::PAGE_SIZE, @@ -17,7 +16,7 @@ use crate::{ error::*, flag::*, usercopy::{UserSliceRo, UserSliceWo}, - EnvRegisters, FloatRegisters, IntRegisters, KillMode, KillTarget, + EnvRegisters, FloatRegisters, IntRegisters, KillMode, }, }; @@ -97,11 +96,6 @@ enum RegsKind { } #[derive(Clone)] enum ProcHandle { - Trace { - pid: ProcessId, - clones: Vec, - excl: bool, - }, Static { ty: &'static str, bytes: Box<[u8]>, @@ -158,10 +152,6 @@ enum Handle { context: Arc>, kind: ContextHandle, }, - Process { - process: Arc>, - kind: ProcHandle, - }, } #[derive(Clone, Copy, PartialEq, Eq)] enum Attr { @@ -169,65 +159,6 @@ enum Attr { Gid, // TODO: namespace, tid, etc. } -impl Handle { - fn needs_child_process(&self) -> bool { - matches!( - self, - Self::Process { - kind: ProcHandle::Trace { .. } | ProcHandle::SessionId, - .. - } | Self::Context { - kind: ContextHandle::Regs(_) - | ContextHandle::Filetable { .. } - | ContextHandle::NewFiletable { .. } - | ContextHandle::AddrSpace { .. } - | ContextHandle::CurrentAddrSpace - | ContextHandle::CurrentFiletable - | ContextHandle::Sighandler, - .. - } - ) - } - fn needs_root(&self) -> bool { - matches!( - self, - Self::Process { - kind: ProcHandle::Attr { .. }, - .. - } - ) - } -} -impl Handle { - fn continue_ignored_children(&mut self) -> Option<()> { - let Handle::Process { - kind: ProcHandle::Trace { clones, .. }, - .. - } = self - else { - return None; - }; - - for pid in clones.drain(..) { - if ptrace::is_traced(pid) { - continue; - } - let Some(child_process) = process::PROCESSES.read().get(&pid).map(Arc::clone) else { - continue; - }; - for thread in child_process - .read() - .threads - .iter() - .filter_map(|t| t.upgrade()) - { - thread.write().status = context::Status::Runnable; - } - } - Some(()) - } -} - pub struct ProcScheme; static NEXT_ID: AtomicUsize = AtomicUsize::new(1); @@ -256,7 +187,6 @@ fn new_handle((handle, fl): (Handle, InternalFlags)) -> Result<(usize, InternalF } enum OpenTy { - Proc(ProcessId), Ctxt(Arc>), } @@ -309,44 +239,6 @@ impl ProcScheme { _ => return Ok(None), })) } - fn openat_process( - &self, - target: &Arc>, - name: &str, - flags: usize, - ) -> Result> { - Ok(Some(match name { - "trace" => ( - ProcHandle::Trace { - pid: target.read().pid, - clones: Vec::new(), - excl: flags & O_EXCL == O_EXCL, - }, - false, - ), - "exe" => ( - ProcHandle::Static { - ty: "exe", - // FIXME: allow opening any thread - bytes: target - .read() - .threads - .first() - .and_then(|f| f.upgrade()) - .ok_or(Error::new(ESRCH))? - .read() - .name - .as_bytes() - .into(), - }, - true, - ), - "uid" => (ProcHandle::Attr { attr: Attr::Uid }, true), - "gid" => (ProcHandle::Attr { attr: Attr::Gid }, true), - "session_id" => (ProcHandle::SessionId, true), - _ => return Ok(None), - })) - } fn open_inner( &self, ty: OpenTy, @@ -355,42 +247,24 @@ impl ProcScheme { uid: u32, gid: u32, ) -> Result<(usize, InternalFlags)> { - let target = match ty { - OpenTy::Proc(pid) => { - let processes = process::PROCESSES.read(); - Arc::clone(processes.get(&pid).ok_or(Error::new(ESRCH))?) - } - OpenTy::Ctxt(ref context) => Arc::clone(&context.read().process), - }; - let operation_name = operation_str.ok_or(Error::new(EINVAL))?; let (mut handle, positioned) = { - if let Some((kind, positioned)) = self.openat_process(&target, operation_name, flags)? { - ( - Handle::Process { - process: Arc::clone(&target), - kind, - }, - positioned, - ) + let context = match ty { + OpenTy::Proc(_) => target + .read() + .threads + .first() + .ok_or(Error::new(ESRCH))? + .upgrade() + .ok_or(Error::new(ESRCH))?, + OpenTy::Ctxt(ref ctxt) => Arc::clone(&ctxt), + }; + if let Some((kind, positioned)) = + self.openat_context(operation_name, Arc::clone(&context))? + { + (Handle::Context { context, kind }, positioned) } else { - let context = match ty { - OpenTy::Proc(_) => target - .read() - .threads - .first() - .ok_or(Error::new(ESRCH))? - .upgrade() - .ok_or(Error::new(ESRCH))?, - OpenTy::Ctxt(ref ctxt) => Arc::clone(&ctxt), - }; - if let Some((kind, positioned)) = - self.openat_context(operation_name, Arc::clone(&context))? - { - (Handle::Context { context, kind }, positioned) - } else { - return Err(Error::new(EINVAL)); - } + return Err(Error::new(EINVAL)); } }; @@ -401,36 +275,6 @@ impl ProcScheme { return Err(Error::new(ESRCH)); } - // Unless root, check security - if handle.needs_child_process() && uid != 0 && gid != 0 { - let current = process::current()?; - let current = current.read(); - - // Are we the process? - if target.pid != current.pid { - // Do we own the process? - if uid != target.euid && gid != target.egid { - return Err(Error::new(EPERM)); - } - - // Is it a subprocess of us? In the future, a capability could - // bypass this check. - match process::ancestors(&*process::PROCESSES.read(), target.ppid) - .find(|&(pid, _context)| pid == current.pid) - { - Some((id, context)) => { - // Paranoid sanity check, as ptrace security holes - // wouldn't be fun - assert_eq!(id, current.pid); - assert_eq!(id, context.read().pid); - } - None => return Err(Error::new(EPERM)), - } - } - } else if handle.needs_root() && (uid != 0 || gid != 0) { - return Err(Error::new(EPERM)); - } - let filetable_opt = match handle { Handle::Context { kind: @@ -477,27 +321,6 @@ impl ProcScheme { }, ))?; - if let Handle::Process { - kind: ProcHandle::Trace { pid, .. }, - .. - } = handle - { - if !ptrace::try_new_session(pid, id) { - // There is no good way to handle id being occupied for nothing - // here, is there? - return Err(Error::new(EBUSY)); - } - - if flags & O_TRUNC == O_TRUNC { - let target = target.read(); - for thread in target.threads.iter().filter_map(|t| t.upgrade()) { - thread.write().status = context::Status::HardBlocked { - reason: HardBlockedReason::PtraceStop, - }; - } - } - } - Ok((id, int_fl)) } } @@ -505,21 +328,6 @@ impl ProcScheme { impl KernelScheme for ProcScheme { fn kopen(&self, path: &str, flags: usize, ctx: CallerCtx) -> Result { let mut parts = path.splitn(2, '/'); - let pid_str = parts.next().ok_or(Error::new(ENOENT))?; - - let pid = if pid_str == "current" { - OpenTy::Ctxt(context::current()) - } else if pid_str == "new" || pid_str == "new-child" { - OpenTy::Ctxt(new_child()?) - } else if pid_str == "new-thread" { - OpenTy::Ctxt(new_thread()?) - } else if !FULL { - return Err(Error::new(EACCES)); - } else { - OpenTy::Proc(ProcessId::new( - pid_str.parse().map_err(|_| Error::new(ENOENT))?, - )) - }; self.open_inner(pid, parts.next(), flags, ctx.uid, ctx.gid) .map(|(r, fl)| OpenResult::SchemeLocal(r, fl)) @@ -530,19 +338,12 @@ impl KernelScheme for ProcScheme { let handle = handles.get(&id).ok_or(Error::new(EBADF))?; match handle { - Handle::Process { - kind: ProcHandle::Trace { pid, .. }, - process: _, - } => ptrace::Session::with_session(*pid, |session| { - Ok(session.data.lock().session_fevent_flags()) - }), _ => Ok(EventFlags::empty()), } } fn close(&self, id: usize) -> Result<()> { let mut handle = HANDLES.write().remove(&id).ok_or(Error::new(EBADF))?; - handle.continue_ignored_children(); match handle { Handle::Context { @@ -577,26 +378,6 @@ impl KernelScheme for ProcScheme { } => { context.write().files = new_ft; } - Handle::Process { - kind: ProcHandle::Trace { pid, excl, .. }, - process, - } => { - ptrace::close_session(pid); - - if excl { - syscall::kill(pid, SIGKILL, KillMode::Idempotent)?; - } - - let threads = process.read().threads.clone(); - - for thread in threads { - let Some(context) = thread.upgrade() else { - continue; - }; - let mut context = context.write(); - context.status = context::Status::Runnable; - } - } _ => (), } Ok(()) @@ -694,9 +475,6 @@ impl KernelScheme for ProcScheme { match handle { Handle::Context { context, kind } => kind.kreadoff(id, context, buf, offset), - Handle::Process { process, kind } => { - kind.kreadoff(id, process, buf, offset, read_flags) - } } } fn kwriteoff( @@ -713,12 +491,10 @@ impl KernelScheme for ProcScheme { let handle = { let mut handles = HANDLES.write(); let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; - handle.continue_ignored_children(); handle.clone() }; match handle { - Handle::Process { process, kind } => kind.kwriteoff(process, buf), Handle::Context { context, kind } => kind.kwriteoff(id, context, buf), } } @@ -727,21 +503,6 @@ impl KernelScheme for ProcScheme { let handle = handles.get(&id).ok_or(Error::new(EBADF))?; let path = match handle { - Handle::Process { process, kind } => format!( - "proc:{}/{}", - process.read().pid.get(), - match kind { - ProcHandle::Attr { - attr: Attr::Uid, .. - } => "uid", - ProcHandle::Attr { - attr: Attr::Gid, .. - } => "gid", - ProcHandle::Trace { .. } => "trace", - ProcHandle::Static { ty, .. } => ty, - ProcHandle::SessionId => "session_id", - }, - ), Handle::Context { context, kind } => format!( "proc:{}/{}", context.read().pid.get(), @@ -818,17 +579,12 @@ impl KernelScheme for ProcScheme { kind: ContextHandle::OpenViaDup, context, } => { - let (uid, gid) = match &*process::current()?.read() { - process => (process.euid, process.egid), - }; return self .open_inner( OpenTy::Ctxt(context), Some(core::str::from_utf8(buf).map_err(|_| Error::new(EINVAL))?) .filter(|s| !s.is_empty()), O_RDWR | O_CLOEXEC, - uid, - gid, ) .map(|(r, fl)| OpenResult::SchemeLocal(r, fl)); } @@ -922,38 +678,6 @@ extern "C" fn clone_handler() { // usermode. } -fn new_thread() -> Result>> { - let current_process = process::current()?; - context::spawn(true, current_process, clone_handler) -} - -fn new_child() -> Result>> { - let new_context = { - let current_process_info = process::current()?.read().info; - let new_process = process::new_process(|new_pid| ProcessInfo { - pid: new_pid, - ppid: current_process_info.pid, - ..current_process_info - })?; - context::spawn(true, new_process, clone_handler)? - }; - - if ptrace::send_event(crate::syscall::ptrace_event!( - PTRACE_EVENT_CLONE, - new_context.read().pid.into() - )) - .is_some() - { - // Freeze the clone, allow ptrace to put breakpoints - // to it before it starts - let mut context = new_context.write(); - context.status = context::Status::HardBlocked { - reason: HardBlockedReason::PtraceStop, - }; - } - - Ok(new_context) -} fn extract_scheme_number(fd: usize) -> Result<(KernelSchemes, usize)> { let (scheme_id, number) = match &*context::current() .read() @@ -983,10 +707,6 @@ fn verify_scheme(scheme: KernelSchemes) -> Result<()> { impl Handle { fn fsize(&self) -> Result { match self { - Self::Process { - kind: ProcHandle::Static { ref bytes, .. }, - .. - } => Ok(bytes.len() as u64), Self::Context { kind: ContextHandle::Filetable { ref data, .. } @@ -997,183 +717,6 @@ impl Handle { } } } -impl ProcHandle { - fn kwriteoff(self, process: Arc>, buf: UserSliceRo) -> Result { - match self { - Self::Static { .. } => Err(Error::new(EBADF)), - Self::Trace { pid, .. } => { - let op = buf.read_u64()?; - let op = PtraceFlags::from_bits(op).ok_or(Error::new(EINVAL))?; - - // Set next breakpoint - ptrace::Session::with_session(pid, |session| { - session.data.lock().set_breakpoint( - Some(op).filter(|op| op.intersects(PTRACE_STOP_MASK | PTRACE_EVENT_MASK)), - ); - Ok(()) - })?; - - let first = process - .read() - .threads - .first() - .and_then(|f| f.upgrade()) - .ok_or(Error::new(ESRCH))?; - - if op.contains(PTRACE_STOP_SINGLESTEP) { - try_stop_context(first, |context| match context.regs_mut() { - None => { - println!( - "{}:{}: Couldn't read registers from stopped process", - file!(), - line!() - ); - Err(Error::new(ENOTRECOVERABLE)) - } - Some(stack) => { - stack.set_singlestep(true); - Ok(()) - } - })?; - } - - // disable the ptrace_stop flag, which is used in some cases - for thread in process.read().threads.iter().filter_map(|t| t.upgrade()) { - thread.write().status = context::Status::HardBlocked { - reason: HardBlockedReason::PtraceStop, - }; - } - - // and notify the tracee's WaitCondition, which is used in other cases - ptrace::Session::with_session(pid, |session| { - session.tracee.notify(); - Ok(()) - })?; - - Ok(mem::size_of::()) - } - Self::Attr { attr } => { - // TODO: What limit? - let mut str_buf = [0_u8; 32]; - let bytes_copied = buf.copy_common_bytes_to_slice(&mut str_buf)?; - - let id = core::str::from_utf8(&str_buf[..bytes_copied]) - .map_err(|_| Error::new(EINVAL))? - .parse::() - .map_err(|_| Error::new(EINVAL))?; - - match attr { - Attr::Uid => process.write().euid = id, - Attr::Gid => process.write().egid = id, - } - Ok(buf.len()) - } - Self::SessionId => { - let session_id = ProcessId::new(buf.read_usize()?); - - if session_id != process.read().pid { - // Session ID can only be set to this process's ID - return Err(Error::new(EPERM)); - } - - for (_pid, process_lock) in process::PROCESSES.read().iter() { - if session_id == process_lock.read().pgid { - // The session ID cannot match the PGID of any process - return Err(Error::new(EPERM)); - } - } - - { - let mut process = process.write(); - process.pgid = session_id; - process.session_id = session_id; - } - - Ok(buf.len()) - } - } - } - fn kreadoff( - self, - id: usize, - process: Arc>, - buf: UserSliceWo, - offset: u64, - read_flags: u32, - ) -> Result { - match self { - Self::Static { bytes, .. } => read_from(buf, &bytes, offset), - Self::Trace { pid, .. } => { - // Wait for event - if (read_flags as usize) & O_NONBLOCK != O_NONBLOCK { - ptrace::wait(pid)?; - } - - // Check if process exists - let _ = process::PROCESSES - .read() - .get(&pid) - .ok_or(Error::new(ESRCH))?; - - let mut src_buf = [PtraceEvent::default(); 4]; - - // Read events - let src_len = src_buf.len(); - let slice = &mut src_buf - [..core::cmp::min(src_len, buf.len() / mem::size_of::())]; - - let (read, reached) = ptrace::Session::with_session(pid, |session| { - let mut data = session.data.lock(); - Ok((data.recv_events(slice), data.is_reached())) - })?; - let mut handles = HANDLES.write(); - let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; - let Handle::Process { - kind: ProcHandle::Trace { ref mut clones, .. }, - .. - } = handle - else { - return Err(Error::new(EBADFD)); - }; - - // Save child processes in a list of processes to restart - for event in &slice[..read] { - if event.cause == PTRACE_EVENT_CLONE { - clones.push(ProcessId::from(event.a)); - } - } - - // If there are no events, and breakpoint isn't reached, we - // must not have waited. - if read == 0 && !reached { - return Err(Error::new(EAGAIN)); - } - - for (dst, src) in buf - .in_exact_chunks(mem::size_of::()) - .zip(slice.iter()) - { - dst.copy_exactly(src)?; - } - - // Return read events - Ok(read * mem::size_of::()) - } - Self::SessionId => { - read_from(buf, &process.read().session_id.get().to_ne_bytes(), offset) - } - Self::Attr { attr } => { - let src_buf = match (attr, process.read()) { - (Attr::Uid, process) => process.euid.to_string(), - (Attr::Gid, process) => process.egid.to_string(), - } - .into_bytes(); - - read_from(buf, &src_buf, offset) - } - } - } -} impl ContextHandle { fn kwriteoff( self, @@ -1357,7 +900,6 @@ impl ContextHandle { return Err(Error::new(EBADF)); }; let filetable = match *entry.get_mut() { - Handle::Process { .. } => return Err(Error::new(EBADF)), Handle::Context { kind: ContextHandle::Filetable { ref filetable, .. }, .. @@ -1445,18 +987,6 @@ impl ContextHandle { } let is_current = context::is_current(&context); - { - let process = Arc::clone(&context.read().process); - let mut process = process.write(); - if let Some(pos) = process - .threads - .iter() - .position(|p| Weak::as_ptr(p) == Arc::as_ptr(&context)) - { - process.threads.remove(pos); - } - } - if is_current { crate::syscall::exit_this_context(); } else { @@ -1487,14 +1017,6 @@ impl ContextHandle { } } ContextHandle::Signal => { - let me = { - let p = process::current()?; - let p = p.read(); - SenderInfo { - pid: p.pid.get().try_into().unwrap_or(0), - ruid: p.ruid, - } - }; let sig = buf.read_u32()?; let mut killed_self = false; crate::syscall::process::send_signal( diff --git a/src/scheme/sys/scheme_num.rs b/src/scheme/sys/scheme_num.rs index 880ef80e97..fbecf24018 100644 --- a/src/scheme/sys/scheme_num.rs +++ b/src/scheme/sys/scheme_num.rs @@ -1,9 +1,10 @@ use alloc::vec::Vec; -use crate::{context::process, scheme, syscall::error::Result}; +use crate::context; +use crate::{scheme, syscall::error::Result}; pub fn resource() -> Result> { - let scheme_ns = process::current()?.read().ens; + let scheme_ns = context::current().read().ens; let mut data = Vec::new(); diff --git a/src/syscall/mod.rs b/src/syscall/mod.rs index d549fa540c..6c2ce9f891 100644 --- a/src/syscall/mod.rs +++ b/src/syscall/mod.rs @@ -194,12 +194,7 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -> us clock_gettime(b, UserSlice::wo(c, core::mem::size_of::())?).map(|()| 0) } SYS_FUTEX => futex(b, c, d, e, f), - SYS_GETPID => getpid().map(ProcessId::into), - SYS_GETPGID => getpgid(ProcessId::from(b)).map(ProcessId::into), - SYS_GETPPID => getppid().map(ProcessId::into), - SYS_EXIT => exit(b), - SYS_KILL => kill(ProcessId::from(b), c, KillMode::Idempotent), SYS_SIGENQUEUE => kill( ProcessId::from(b), c, @@ -210,33 +205,16 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -> us SYS_SIGDEQUEUE => { sigdequeue(UserSlice::wo(b, size_of::())?, c as u32).map(|()| 0) } - SYS_WAITPID => waitpid( - ProcessId::from(b), - if c == 0 { - None - } else { - Some(UserSlice::wo(c, core::mem::size_of::())?) - }, - WaitFlags::from_bits_truncate(d), - ) - .map(ProcessId::into), SYS_IOPL => iopl(b), - SYS_GETEGID => getegid(), SYS_GETENS => getens(), - SYS_GETEUID => geteuid(), - SYS_GETGID => getgid(), SYS_GETNS => getns(), - SYS_GETUID => getuid(), SYS_MPROTECT => mprotect(b, c, MapFlags::from_bits_truncate(d)).map(|()| 0), SYS_MKNS => mkns(UserSlice::ro( b, c.checked_mul(core::mem::size_of::<[usize; 2]>()) .ok_or(Error::new(EOVERFLOW))?, )?), - SYS_SETPGID => setpgid(ProcessId::from(b), ProcessId::from(c)).map(|()| 0), - SYS_SETREUID => setreuid(b as u32, c as u32).map(|()| 0), SYS_SETRENS => setrens(SchemeNamespace::from(b), SchemeNamespace::from(c)).map(|()| 0), - SYS_SETREGID => setregid(b as u32, c as u32).map(|()| 0), SYS_VIRTTOPHYS => virttophys(b), SYS_MREMAP => mremap(b, c, d, e, f), diff --git a/src/syscall/process.rs b/src/syscall/process.rs index 7dbe4ff29e..c857db4cdd 100644 --- a/src/syscall/process.rs +++ b/src/syscall/process.rs @@ -10,7 +10,6 @@ use spin::RwLock; use crate::context::{ memory::{AddrSpace, Grant, PageSpan}, - process::{self, Process, ProcessId, ProcessInfo, ProcessStatus}, Context, ContextRef, WaitpidKey, }; @@ -20,10 +19,7 @@ use crate::{ ptrace, syscall::{ error::*, - flag::{ - wifcontinued, wifstopped, MapFlags, WaitFlags, PTRACE_STOP_EXIT, SIGCONT, WCONTINUED, - WNOHANG, WUNTRACED, - }, + flag::MapFlags, ptrace_event, }, Bootstrap, CurrentRmmArch, @@ -72,133 +68,8 @@ pub fn wait_for_exit(context_lock: Arc>) { } } -pub fn exit(status: usize) -> ! { - if matches!( - mem::replace( - &mut process::current().unwrap().write().status, - ProcessStatus::Exiting - ), - ProcessStatus::Exiting - ) { - // already exiting the current process, so just set our status to Dead and context switch. - exit_this_context(); - } - - ptrace::breakpoint_callback( - PTRACE_STOP_EXIT, - Some(ptrace_event!(PTRACE_STOP_EXIT, status)), - ); - - let current_pid; - let current_ruid; - { - let current_context = context::current(); - let current_process = process::current().expect("no active process during exit syscall"); - current_pid = current_process.read().pid; - - let threads = core::mem::take(&mut current_process.write().threads); - - for context_lock in threads.into_iter().filter_map(|t| t.upgrade()) { - // Current context must be closed last, as it would otherwise be impossible to context - // switch back, if closing file descriptors require scheme calls. - if Arc::ptr_eq(&context_lock, ¤t_context) { - continue; - } - wait_for_exit(context_lock); - } - - { - // PGID and PPID must be grabbed after close, as context switches could change PGID or PPID if parent exits - let (pgid, ppid) = { - let process = current_process.read(); - current_ruid = process.ruid; - (process.pgid, process.ppid) - }; - if let Some(parent) = process::PROCESSES.read().get(&ppid).map(Arc::clone) { - let _ = send_signal( - KillTarget::Process(parent), - SIGCHLD, - KillMode::Idempotent, - true, - &mut false, - SenderInfo { - pid: current_pid.get().try_into().unwrap_or(0), - ruid: current_ruid, - }, - ); - } - - // Transfer child processes to parent (TODO: to init) - { - let processes = context::process::PROCESSES.read(); - for (_child_pid, child_process_lock) in processes.iter() { - let mut process = child_process_lock.write(); - if process.ppid == current_pid { - process.ppid = ppid; - } - } - } - - current_process.write().status = ProcessStatus::Exited(status); - - let children = current_process.write().waitpid.receive_all(); - - { - let processes = process::PROCESSES.read(); - if let Some(parent_lock) = processes.get(&ppid) { - let waitpid = Arc::clone(&parent_lock.write().waitpid); - - for (c_pid, c_status) in children { - waitpid.send(c_pid, c_status); - } - - waitpid.send( - WaitpidKey { - pid: Some(current_pid), - pgid: Some(pgid), - }, - (current_pid, status), - ); - } - } - - // Alert any tracers waiting of this process - ptrace::close_tracee(current_pid); - } - } - exit_this_context(); -} - -pub fn getpid() -> Result { - context::current_pid() -} - -pub fn getpgid(pid: ProcessId) -> Result { - let process_lock = if pid.get() == 0 { - process::current()? - } else { - Arc::clone( - process::PROCESSES - .read() - .get(&pid) - .ok_or(Error::new(ESRCH))?, - ) - }; - let process = process_lock.read(); - Ok(process.pgid) -} - -pub fn getppid() -> Result { - Ok(process::current()?.read().ppid) -} - -pub enum KillTarget { - Process(Arc>), - Thread(Arc>), -} - pub fn send_signal( - target: KillTarget, + context: Arc>, sig: usize, mode: KillMode, is_sigchld_to_parent: bool, @@ -229,13 +100,9 @@ pub fn send_signal( enum SendResult { Succeeded, SucceededSigchld { - ppid: ProcessId, - pgid: ProcessId, orig_signal: usize, }, SucceededSigcont { - ppid: ProcessId, - pgid: ProcessId, }, FullQ, Invalid, @@ -290,8 +157,6 @@ pub fn send_signal( } // POSIX XSI allows but does not reqiure SIGCHLD to be sent when SIGCONT occurs. return SendResult::SucceededSigcont { - ppid: proc_info.ppid, - pgid: proc_info.pgid, }; } drop(process_guard); @@ -325,8 +190,6 @@ pub fn send_signal( } return SendResult::SucceededSigchld { - ppid: proc_info.ppid, - pgid: proc_info.pgid, orig_signal: sig, }; } @@ -429,42 +292,8 @@ pub fn send_signal( pgid, orig_signal, } => { - let parent = process::PROCESSES - .read() - .get(&ppid) - .map(Arc::clone) - .ok_or(Error::new(ESRCH))?; - let waitpid = Arc::clone(&parent.read().waitpid); - waitpid.send( - WaitpidKey { - pid: Some(proc_info.pid), - pgid: Some(pgid), - }, - (proc_info.pid, (orig_signal << 8) | 0x7f), - ); - send_signal( - KillTarget::Process(parent), - SIGCHLD, - mode, - true, - killed_self, - sender, - )?; } SendResult::SucceededSigcont { ppid, pgid } => { - let parent = process::PROCESSES - .read() - .get(&ppid) - .map(Arc::clone) - .ok_or(Error::new(ESRCH))?; - let waitpid = Arc::clone(&parent.read().waitpid); - waitpid.send( - WaitpidKey { - pid: Some(proc_info.pid), - pgid: Some(pgid), - }, - (proc_info.pid, 0xffff), - ); // POSIX XSI allows but does not require SIGCONT to send signals to the parent. //send_signal(KillTarget::Process(parent), SIGCHLD, true, killed_self)?; } @@ -479,106 +308,6 @@ pub enum KillMode { Queued(RtSigInfo), } -pub fn kill(pid: ProcessId, sig: usize, mode: KillMode) -> Result { - let (current_ruid, current_euid, current_pgid, current_pid) = { - let process_lock = process::current()?; - let process = process_lock.read(); - (process.ruid, process.euid, process.pgid, process.pid) - }; - let sender = SenderInfo { - pid: current_pid.get().try_into().unwrap_or(0), - ruid: current_ruid, - }; - - let mut found = 0; - let mut sent = 0; - let mut killed_self = false; - - // Non-root users cannot kill arbitrarily. - let can_send = |proc_info: &ProcessInfo| { - current_euid == 0 || current_euid == proc_info.ruid || current_ruid == proc_info.ruid - }; - - { - let processes = process::PROCESSES.read(); - - if pid.get() as isize > 0 { - // Send to a single process - if let Some(process_lock) = processes.get(&pid).map(Arc::clone) { - found += 1; - if can_send(&process_lock.read().info) { - sent += 1; - send_signal( - KillTarget::Process(process_lock), - sig, - mode, - false, - &mut killed_self, - sender, - )?; - } - } - } else if pid.get() == 1_usize.wrapping_neg() { - // Send to every process with permission, except for init - for (pid, process_lock) in processes.iter() { - if pid.get() <= 1 { - continue; - } - found += 1; - if can_send(&process_lock.read().info) { - sent += 1; - send_signal( - KillTarget::Process(Arc::clone(process_lock)), - sig, - mode, - false, - &mut killed_self, - sender, - )?; - } - } - } else { - let pgid = if pid.get() == 0 { - current_pgid - } else { - ProcessId::from(pid.get().wrapping_neg()) - }; - - // Send to every process in the process group whose ID - for (_pid, process_lock) in processes.iter() { - if process_lock.read().pgid != pgid { - continue; - } - found += 1; - - if can_send(&process_lock.read().info) { - sent += 1; - send_signal( - KillTarget::Process(Arc::clone(process_lock)), - sig, - mode, - false, - &mut killed_self, - sender, - )?; - } - } - } - } - - if found == 0 { - Err(Error::new(ESRCH)) - } else if sent == 0 { - Err(Error::new(EPERM)) - } else if killed_self { - // Inform userspace it should check its own mask - - Err(Error::new(EINTR)) - } else { - Ok(0) - } -} - pub fn mprotect(address: usize, size: usize, flags: MapFlags) -> Result<()> { // println!("mprotect {:#X}, {}, {:#X}", address, size, flags); @@ -588,222 +317,6 @@ pub fn mprotect(address: usize, size: usize, flags: MapFlags) -> Result<()> { AddrSpace::current()?.mprotect(span, flags) } -pub fn setpgid(pid: ProcessId, pgid: ProcessId) -> Result<()> { - let current_pid = context::current_pid()?; - - let processes = process::PROCESSES.read(); - - let process_lock = if pid.get() == 0 { - process::current()? - } else { - Arc::clone(processes.get(&pid).ok_or(Error::new(ESRCH))?) - }; - - let mut process = process_lock.write(); - if process.pid == current_pid || process.ppid == current_pid { - if pgid.get() == 0 { - process.pgid = process.pid; - } else { - process.pgid = pgid; - } - Ok(()) - } else { - Err(Error::new(ESRCH)) - } -} - -fn reap(pid: ProcessId) -> Result { - let process_lock = Arc::clone( - process::PROCESSES - .read() - .get(&pid) - .ok_or(Error::new(ESRCH))?, - ); - - // Spin until not running - loop { - // TODO: exit WaitCondition? - { - let process = process_lock.read(); - if process - .threads - .iter() - .all(|t| t.upgrade().map_or(true, |t| !t.read().running)) - { - break; - } - } - - // TODO: context switch? - interrupt::pause(); - } - - let _ = process::PROCESSES - .write() - .remove(&pid) - .ok_or(Error::new(ESRCH))?; - - Ok(pid) -} - -pub fn waitpid( - pid: ProcessId, - status_ptr: Option, - flags: WaitFlags, -) -> Result { - let (ppid, waitpid) = { - let process_lock = process::current()?; - let process = process_lock.read(); - (process.pid, Arc::clone(&process.waitpid)) - }; - - let write_status = |value| { - status_ptr - .map(|ptr| ptr.write_usize(value)) - .unwrap_or(Ok(())) - }; - - let grim_reaper = |w_pid: ProcessId, status: usize| -> Option> { - if wifcontinued(status) { - if flags & WCONTINUED == WCONTINUED { - Some(write_status(status).map(|()| w_pid)) - } else { - None - } - } else if wifstopped(status) { - if flags & WUNTRACED == WUNTRACED { - Some(write_status(status).map(|()| w_pid)) - } else { - None - } - } else { - Some(write_status(status).and_then(|()| reap(w_pid))) - } - }; - - loop { - let res_opt = if pid.get() == 0 { - // Check for existence of child - { - let mut found = false; - - let processes = process::PROCESSES.read(); - for (_id, process_lock) in processes.iter() { - let process = process_lock.read(); - if process.ppid == ppid { - found = true; - break; - } - } - - if !found { - return Err(Error::new(ECHILD)); - } - } - if flags & WNOHANG == WNOHANG { - if let Some((_wid, (w_pid, status))) = waitpid.receive_any_nonblock() { - grim_reaper(w_pid, status) - } else { - Some(Ok(ProcessId::from(0))) - } - } else { - let (_wid, (w_pid, status)) = waitpid.receive_any("waitpid any"); - grim_reaper(w_pid, status) - } - } else if (pid.get() as isize) < 0 { - let pgid = ProcessId::from(-(pid.get() as isize) as usize); - - // Check for existence of child in process group PGID - { - let mut found = false; - - let processes = process::PROCESSES.read(); - for (_pid, process_lock) in processes.iter() { - let process = process_lock.read(); - if process.pgid == pgid { - found = true; - break; - } - } - - if !found { - return Err(Error::new(ECHILD)); - } - } - - if flags & WNOHANG == WNOHANG { - if let Some((w_pid, status)) = waitpid.receive_nonblock(&WaitpidKey { - pid: None, - pgid: Some(pgid), - }) { - grim_reaper(w_pid, status) - } else { - Some(Ok(ProcessId::from(0))) - } - } else { - let (w_pid, status) = waitpid - .receive( - &WaitpidKey { - pid: None, - pgid: Some(pgid), - }, - "waitpid pgid", - ) - .ok_or(Error::new(EINTR))?; - grim_reaper(w_pid, status) - } - } else { - let status = { - let process_lock = Arc::clone( - process::PROCESSES - .read() - .get(&pid) - .ok_or(Error::new(ESRCH))?, - ); - let process_guard = process_lock.read(); - - if process_guard.ppid != ppid { - return Err(Error::new(ECHILD)); - } - process_guard.status - }; - - if let ProcessStatus::Exited(status) = status { - let _ = waitpid.receive_nonblock(&WaitpidKey { - pid: Some(pid), - pgid: None, - }); - grim_reaper(pid, status) - } else if flags & WNOHANG == WNOHANG { - let res = waitpid.receive_nonblock(&WaitpidKey { - pid: Some(pid), - pgid: None, - }); - if let Some((w_pid, status)) = res { - grim_reaper(w_pid, status) - } else { - Some(Ok(ProcessId::from(0))) - } - } else { - let (w_pid, status) = waitpid - .receive( - &WaitpidKey { - pid: Some(pid), - pgid: None, - }, - "waitpid pid", - ) - .ok_or(Error::new(EINTR))?; - grim_reaper(w_pid, status) - } - }; - - if let Some(res) = res_opt { - return res; - } - } -} - pub unsafe fn usermode_bootstrap(bootstrap: &Bootstrap) { assert_ne!(bootstrap.page_count, 0);