diff --git a/src/scheme/proc.rs b/src/scheme/proc.rs index 07f9d9198c4ae08a26fefb9dc04738bc78f57c1d..d5a95b9a27aa3ed5fb1e2a0c847e6212d276f89e 100644 --- a/src/scheme/proc.rs +++ b/src/scheme/proc.rs @@ -4,7 +4,7 @@ use crate::{ ptrace, scheme::{AtomicSchemeId, SchemeId}, syscall::{ - data::{FloatRegisters, IntRegisters, PtraceEvent}, + data::{FloatRegisters, IntRegisters, PtraceEvent, Stat}, error::*, flag::*, scheme::Scheme, @@ -14,8 +14,9 @@ use crate::{ }; use alloc::{ + boxed::Box, collections::BTreeMap, - vec::Vec + vec::Vec, }; use core::{ cmp, @@ -91,6 +92,17 @@ enum Operation { Memory, Regs(RegsKind), Trace, + Static(&'static str), +} +impl Operation { + fn needs_child_process(self) -> bool { + match self { + Self::Memory => true, + Self::Regs(_) => true, + Self::Trace => true, + Self::Static(_) => false, + } + } } struct MemData { offset: VirtualAddress, @@ -104,19 +116,25 @@ impl Default for MemData { struct TraceData { clones: Vec<ContextId>, } +struct StaticData { + buf: Box<[u8]>, + offset: usize, +} +impl StaticData { + fn new(buf: Box<[u8]>) -> Self { + Self { + buf, + offset: 0, + } + } +} enum OperationData { Memory(MemData), Trace(TraceData), + Static(StaticData), Other, } impl OperationData { - fn default_for(op: Operation) -> OperationData { - match op { - Operation::Memory => OperationData::Memory(MemData::default()), - Operation::Trace => OperationData::Trace(TraceData::default()), - _ => OperationData::Other, - } - } fn trace_data(&mut self) -> Option<&mut TraceData> { match self { OperationData::Trace(data) => Some(data), @@ -129,6 +147,12 @@ impl OperationData { _ => None, } } + fn static_data(&mut self) -> Option<&mut StaticData> { + match self { + OperationData::Static(data) => Some(data), + _ => None, + } + } } #[derive(Clone, Copy)] @@ -195,21 +219,31 @@ impl Scheme for ProcScheme { Some("regs/float") => Operation::Regs(RegsKind::Float), Some("regs/int") => Operation::Regs(RegsKind::Int), Some("trace") => Operation::Trace, + Some("exe") => Operation::Static("exe"), _ => return Err(Error::new(EINVAL)) }; let contexts = context::contexts(); let target = contexts.get(pid).ok_or(Error::new(ESRCH))?; + let data; + { let target = target.read(); + data = match operation { + Operation::Memory => OperationData::Memory(MemData::default()), + Operation::Trace => OperationData::Trace(TraceData::default()), + Operation::Static(_) => OperationData::Static(StaticData::new(target.name.lock().clone())), + _ => OperationData::Other, + }; + if let Status::Exited(_) = target.status { return Err(Error::new(ESRCH)); } // Unless root, check security - if uid != 0 && gid != 0 { + if operation.needs_child_process() && uid != 0 && gid != 0 { let current = contexts.current().ok_or(Error::new(ESRCH))?; let current = current.read(); @@ -227,10 +261,10 @@ impl Scheme for ProcScheme { assert_eq!(id, current.id); assert_eq!(id, context.read().id); }, - None => return Err(Error::new(EPERM)) + None => return Err(Error::new(EPERM)), } } - } + }; let id = self.next_id.fetch_add(1, Ordering::SeqCst); @@ -253,7 +287,7 @@ impl Scheme for ProcScheme { pid, operation, }, - data: OperationData::default_for(operation), + data, }); Ok(id) } @@ -309,6 +343,16 @@ impl Scheme for ProcScheme { }; match info.operation { + Operation::Static(_) => { + let mut handles = self.handles.write(); + let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; + let data = handle.data.static_data().expect("operations can't change"); + + let len = cmp::min(data.buf.len() - data.offset, buf.len()); + buf[..len].copy_from_slice(&data.buf[data.offset .. data.offset + len]); + data.offset += len; + Ok(len) + }, Operation::Memory => { // Won't context switch, don't worry about the locks let mut handles = self.handles.write(); @@ -420,6 +464,7 @@ impl Scheme for ProcScheme { }; match info.operation { + Operation::Static(_) => Err(Error::new(EBADF)), Operation::Memory => { // Won't context switch, don't worry about the locks let mut handles = self.handles.write(); @@ -526,7 +571,7 @@ impl Scheme for ProcScheme { })?; Ok(mem::size_of::<u64>()) - } + }, } } @@ -545,9 +590,12 @@ impl Scheme for ProcScheme { let handles = self.handles.read(); let handle = handles.get(&id).ok_or(Error::new(EBADF))?; - ptrace::Session::with_session(handle.info.pid, |session| { - Ok(session.data.lock().session_fevent_flags()) - }) + match handle.info.operation { + Operation::Trace => ptrace::Session::with_session(handle.info.pid, |session| { + Ok(session.data.lock().session_fevent_flags()) + }), + _ => Ok(EventFlags::empty()), + } } fn fpath(&self, id: usize, buf: &mut [u8]) -> Result<usize> { @@ -558,7 +606,8 @@ impl Scheme for ProcScheme { Operation::Memory => "mem", Operation::Regs(RegsKind::Float) => "regs/float", Operation::Regs(RegsKind::Int) => "regs/int", - Operation::Trace => "trace" + Operation::Trace => "trace", + Operation::Static(path) => path, }); let len = cmp::min(path.len(), buf.len()); @@ -567,6 +616,27 @@ impl Scheme for ProcScheme { Ok(len) } + fn fstat(&self, id: usize, stat: &mut Stat) -> Result<usize> { + let handles = self.handles.read(); + let handle = handles.get(&id).ok_or(Error::new(EBADF))?; + + stat.st_size = match handle.data { + OperationData::Static(ref data) => (data.buf.len() - data.offset) as u64, + _ => 0, + }; + *stat = Stat { + st_mode: MODE_FILE | 0o666, + st_size: match handle.data { + OperationData::Static(ref data) => (data.buf.len() - data.offset) as u64, + _ => 0, + }, + + ..Stat::default() + }; + + Ok(0) + } + fn close(&self, id: usize) -> Result<usize> { let mut handle = self.handles.write().remove(&id).ok_or(Error::new(EBADF))?; handle.continue_ignored_children();