From 25974bec6e469bbbf6c070118ae56983d2ce6fa5 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Mon, 8 Jul 2024 21:41:34 +0200 Subject: [PATCH] It compiles. --- src/scheme/proc.rs | 239 +++++++++++++++++++++++++---------------- src/syscall/process.rs | 2 +- 2 files changed, 150 insertions(+), 91 deletions(-) diff --git a/src/scheme/proc.rs b/src/scheme/proc.rs index 3b50ec20ab..5d96353f84 100644 --- a/src/scheme/proc.rs +++ b/src/scheme/proc.rs @@ -221,18 +221,23 @@ impl Handle { } impl Handle { fn continue_ignored_children(&mut self) -> Option<()> { - let data = self.data.trace_data()?; + let Handle::Process { + process, + kind: ProcHandle::Trace { pid, clones, .. }, + } = self + else { + return None; + }; let contexts = context::contexts(); - for pid in data.clones.drain(..) { + for pid in clones.drain(..) { if ptrace::is_traced(pid) { continue; } - if let Some(context) = contexts.get(pid) { - let mut context = context.write(); - context.status = context::Status::HardBlocked { - reason: HardBlockedReason::PtraceStop, - }; + if let Some(process) = process::PROCESSES.read().get(&pid) { + let mut process = process.write(); + // FIXME + //context.status = context::Status::Runnable; } } Some(()) @@ -257,10 +262,18 @@ fn get_context(id: ContextId) -> Result>> { .ok_or(Error::new(ENOENT)) .map(Arc::clone) } +enum OpenTy { + Proc(ProcessId), + Ctxt(ContextId), +} impl ProcScheme { - fn openat_context(&self, path: &str, context: Arc>) -> Result<()> { - let kind = match path { + fn openat_context( + &self, + path: &str, + context: Arc>, + ) -> Result> { + Ok(Some(match path { "addrspace" => ( ContextHandle::AddrSpace { addrspace: Arc::clone( @@ -298,75 +311,81 @@ impl ProcScheme { false, ), "sched-affinity" => (ContextHandle::SchedAffinity, true), - _ => return Err(Error::new(EINVAL)), - }; + _ => 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 + 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, - pid: ProcessId, + ty: OpenTy, operation_str: Option<&str>, flags: usize, uid: u32, gid: u32, ) -> Result<(usize, InternalFlags)> { - let processes = process::PROCESSES.read(); - let target = processes.get(&pid).ok_or(Error::new(ESRCH))?; + let target = match ty { + OpenTy::Proc(pid) => { + let processes = process::PROCESSES.read(); + Arc::clone(processes.get(&pid).ok_or(Error::new(ESRCH))?) + } + OpenTy::Ctxt(cid) => Arc::clone( + &context::contexts() + .get(cid) + .ok_or(Error::new(ESRCH))? + .read() + .process, + ), + }; - let (handle, positioned) = match operation_str.ok_or(Error::new(EINVAL))? { - "trace" => ( - Handle::Process { - process: Arc::clone(target), - kind: ProcHandle::Trace { - pid, - clones: Vec::new(), - excl: flags & O_EXCL == O_EXCL, - }, - }, - false, - ), - "exe" => ( - Handle::Process { - process: Arc::clone(target), - kind: ProcHandle::Static { - ty: "exe", - // FIXME - bytes: target - .read() - .threads - .first() - .and_then(|f| f.upgrade()) - .ok_or(Error::new(ESRCH))? - .read() - .name - .as_bytes() - .to_owned(), - }, - }, - true, - ), - "uid" => ( - Handle::Process { - kind: ProcHandle::Attr { attr: Attr::Uid }, - process: Arc::clone(target), - }, - true, - ), - "gid" => ( - Handle::Process { - kind: ProcHandle::Attr { attr: Attr::Gid }, - process: Arc::clone(target), - }, - true, - ), - "session_id" => ( - Handle::Process { - kind: ProcHandle::SessionId, - process: Arc::clone(target), - }, - true, - ), + let (mut handle, positioned) = { + let name = operation_str.ok_or(Error::new(EINVAL))?; - other => { + if let Some((kind, positioned)) = self.openat_process(&target, name, flags)? { + ( + Handle::Process { + process: Arc::clone(&target), + kind, + }, + positioned, + ) + } else { let first_thread = target .read() .threads @@ -374,18 +393,31 @@ impl ProcScheme { .ok_or(Error::new(ESRCH))? .upgrade() .ok_or(Error::new(ESRCH))?; - self.openat_context(other, first_thread) + if let Some((kind, positioned)) = + self.openat_context(name, Arc::clone(&first_thread))? + { + ( + Handle::Context { + context: first_thread, + kind, + }, + positioned, + ) + } else { + return Err(Error::new(EINVAL)); + } } }; - let mut data; - { let target = target.read(); + // FIXME + /* if let Status::Exited(_) = target.status { return Err(Error::new(ESRCH)); } + */ // Unless root, check security if handle.needs_child_process() && uid != 0 && gid != 0 { @@ -402,7 +434,7 @@ impl ProcScheme { // Is it a subprocess of us? In the future, a capability could // bypass this check. match process::ancestors(&*process::PROCESSES.read(), target.ppid) - .find(|&(id, _context)| pid == current.pid) + .find(|&(pid, _context)| pid == current.pid) { Some((id, context)) => { // Paranoid sanity check, as ptrace security holes @@ -418,13 +450,21 @@ impl ProcScheme { } let filetable_opt = match handle { - ContextHandle::Filetable { - ref filetable, - ref mut data, + Handle::Context { + kind: + ContextHandle::Filetable { + ref filetable, + ref mut data, + }, + .. } => Some((filetable.upgrade().ok_or(Error::new(EOWNERDEAD))?, data)), - ContextHandle::NewFiletable { - ref filetable, - ref mut data, + Handle::Context { + kind: + ContextHandle::NewFiletable { + ref filetable, + ref mut data, + }, + .. } => Some((Arc::clone(filetable), data)), _ => None, }; @@ -447,7 +487,7 @@ impl ProcScheme { }; let (id, int_fl) = new_handle(( - handle, + handle.clone(), if positioned { InternalFlags::POSITIONED } else { @@ -455,7 +495,11 @@ impl ProcScheme { }, ))?; - if let ContextHandle::Trace = operation { + 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? @@ -479,13 +523,15 @@ impl KernelScheme for ProcScheme { let pid_str = parts.next().ok_or(Error::new(ENOENT))?; let pid = if pid_str == "current" { - context::current_cid() + OpenTy::Ctxt(context::current_cid()) } else if pid_str == "new" { - new_child()? + OpenTy::Ctxt(new_child()?) } else if !FULL { return Err(Error::new(EACCES)); } else { - ContextId::new(pid_str.parse().map_err(|_| Error::new(ENOENT))?) + OpenTy::Ctxt(ContextId::new( + pid_str.parse().map_err(|_| Error::new(ENOENT))?, + )) }; self.open_inner(pid, parts.next(), flags, ctx.uid, ctx.gid) @@ -797,7 +843,7 @@ impl KernelScheme for ProcScheme { }; return self .open_inner( - context.read().pid, + OpenTy::Ctxt(context.read().cid), Some(core::str::from_utf8(buf).map_err(|_| Error::new(EINVAL))?) .filter(|s| !s.is_empty()), O_RDWR | O_CLOEXEC, @@ -994,7 +1040,14 @@ impl ProcHandle { Ok(()) })?; - let first = process.read().threads.first().and_then(|f| f.upgrade()).ok_or(Error::new(ESRCH))?.read().cid; + let first = process + .read() + .threads + .first() + .and_then(|f| f.upgrade()) + .ok_or(Error::new(ESRCH))? + .read() + .cid; if op.contains(PTRACE_STOP_SINGLESTEP) { try_stop_context(first, |context| match context.regs_mut() { @@ -1107,12 +1160,18 @@ impl ProcHandle { })?; let mut handles = HANDLES.write(); let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; - let data = handle.data.trace_data().expect("operations can't change"); + 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 { - data.clones.push(ContextId::from(event.a)); + clones.push(ProcessId::from(event.a)); } } @@ -1435,13 +1494,13 @@ impl ContextHandle { let context = context.read(); // NOTE: The kernel will never touch floats - Ok(( + ( Output { float: context.get_fx_regs(), }, mem::size_of::(), - )) - }?, + ) + } RegsKind::Int => { try_stop_context(context.read().cid, |context| match context.regs() { None => { diff --git a/src/syscall/process.rs b/src/syscall/process.rs index d7f7cc26a6..fc30d10cec 100644 --- a/src/syscall/process.rs +++ b/src/syscall/process.rs @@ -279,7 +279,7 @@ pub fn kill(pid: ProcessId, sig: usize, parent_sigchld: bool) -> Result { } SendResult::SucceededSigcont { ppid, pgid } => { sent += 1; - &process::PROCESSES + process::PROCESSES .read() .get(&ppid) .ok_or(Error::new(ESRCH))?