diff --git a/Cargo.lock b/Cargo.lock index db7f9e16953b2ff6607fa1305c97fe0827466f6c..48faff9c2ab4cb8e2c45ada61d76c6f2dd0eec30 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -55,7 +55,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bitflags" -version = "1.0.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -175,7 +175,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "kernel" version = "0.1.54" dependencies = [ - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "clippy 0.0.209 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.21 (registry+https://github.com/rust-lang/crates.io-index)", "linked_list_allocator 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -268,7 +268,7 @@ name = "raw-cpuid" version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", @@ -495,7 +495,7 @@ dependencies = [ "checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" -"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" +"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" "checksum cargo_metadata 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1efca0b863ca03ed4c109fb1c55e0bc4bbeb221d3e103d86251046b06a526bd0" "checksum cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)" = "5e5f3fee5eeb60324c2781f1e41286bdee933850fff9b3c672587fed5ec58c83" "checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4" diff --git a/src/arch/x86_64/interrupt/exception.rs b/src/arch/x86_64/interrupt/exception.rs index c98e579433a63195c83e16d152fbfb4744d7beb5..0aba0049be056c82aa4caa23f28bda6302fcfaf1 100644 --- a/src/arch/x86_64/interrupt/exception.rs +++ b/src/arch/x86_64/interrupt/exception.rs @@ -26,7 +26,7 @@ interrupt_stack!(debug, stack, { let had_singlestep = stack.iret.rflags & (1 << 8) == 1 << 8; stack.set_singlestep(false); - if ptrace::breakpoint_callback(syscall::PTRACE_SINGLESTEP).is_some() { + if ptrace::breakpoint_callback(PTRACE_STOP_SINGLESTEP, None).is_some() { handled = true; } else { // There was no breakpoint, restore original value diff --git a/src/arch/x86_64/interrupt/syscall.rs b/src/arch/x86_64/interrupt/syscall.rs index 6b9dfe615db217d6f51180a3dc9f23d84f1998fd..b01c1a5bb0bb92d37abf704338507cc98ff1b40a 100644 --- a/src/arch/x86_64/interrupt/syscall.rs +++ b/src/arch/x86_64/interrupt/syscall.rs @@ -1,5 +1,6 @@ use crate::arch::macros::InterruptStack; use crate::arch::{gdt, pti}; +use crate::syscall::flag::{PTRACE_STOP_PRE_SYSCALL, PTRACE_STOP_POST_SYSCALL, PTRACE_FLAG_SYSEMU}; use crate::{ptrace, syscall}; use x86::shared::msr; @@ -21,18 +22,14 @@ macro_rules! with_interrupt_stack { unsafe fn $wrapped(stack: *mut InterruptStack) { let _guard = ptrace::set_process_regs(stack); - let is_sysemu = ptrace::breakpoint_callback(syscall::flag::PTRACE_SYSCALL) - .map(|fl| fl & syscall::flag::PTRACE_SYSEMU == syscall::flag::PTRACE_SYSEMU); - if !is_sysemu.unwrap_or(false) { + ptrace::breakpoint_callback(PTRACE_STOP_PRE_SYSCALL, None); + let not_sysemu = ptrace::next_breakpoint().map(|b| b & PTRACE_FLAG_SYSEMU != PTRACE_FLAG_SYSEMU); + if not_sysemu.unwrap_or(true) { // If not on a sysemu breakpoint let $stack = &mut *stack; $stack.scratch.rax = $code; - if is_sysemu.is_some() { - // Only callback if there was a pre-syscall - // callback too. - ptrace::breakpoint_callback(::syscall::PTRACE_SYSCALL); - } + ptrace::breakpoint_callback(PTRACE_STOP_POST_SYSCALL, None); } } } diff --git a/src/context/signal.rs b/src/context/signal.rs index d5d2ff18cb3e48918ca16cb2532148fa6856b648..d89d31d4fe2c04fe56ff974e37071b2b15262d3a 100644 --- a/src/context/signal.rs +++ b/src/context/signal.rs @@ -1,11 +1,12 @@ use alloc::sync::Arc; use core::mem; +use syscall::data::PtraceEvent; +use syscall::flag::{PTRACE_STOP_SIGNAL, SIG_DFL, SIG_IGN, SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU}; +use syscall::ptrace_event; use crate::context::{contexts, switch, Status, WaitpidKey}; use crate::start::usermode; -use crate::{ptrace, syscall}; -use crate::syscall::flag::{PTRACE_EVENT_SIGNAL, PTRACE_SIGNAL, SIG_DFL, SIG_IGN, SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU}; -use crate::syscall::data::{PtraceEvent, PtraceEventData}; +use crate::ptrace; pub fn is_user_handled(handler: Option<extern "C" fn(usize)>) -> bool { let handler = handler.map(|ptr| ptr as usize).unwrap_or(0); @@ -21,12 +22,10 @@ pub extern "C" fn signal_handler(sig: usize) { actions[sig] }; - ptrace::send_event(PtraceEvent { - tag: PTRACE_EVENT_SIGNAL, - data: PtraceEventData { signal: sig } - }); - let handler = action.sa_handler.map(|ptr| ptr as usize).unwrap_or(0); + + ptrace::breakpoint_callback(PTRACE_STOP_SIGNAL, Some(ptrace_event!(PTRACE_STOP_SIGNAL, sig, handler))); + if handler == SIG_DFL { match sig { SIGCHLD => { @@ -92,7 +91,7 @@ pub extern "C" fn signal_handler(sig: usize) { }, _ => { // println!("Exit {}", sig); - syscall::exit(sig); + crate::syscall::exit(sig); } } } else if handler == SIG_IGN { @@ -100,8 +99,6 @@ pub extern "C" fn signal_handler(sig: usize) { } else { // println!("Call {:X}", handler); - ptrace::breakpoint_callback(PTRACE_SIGNAL); - unsafe { let mut sp = crate::USER_SIGSTACK_OFFSET + crate::USER_SIGSTACK_SIZE - 256; @@ -114,5 +111,5 @@ pub extern "C" fn signal_handler(sig: usize) { } } - syscall::sigreturn().unwrap(); + crate::syscall::sigreturn().unwrap(); } diff --git a/src/ptrace.rs b/src/ptrace.rs index 3f3390f492b7a6ee1b4bdb32737a3723f35c44dc..528f7bb14fa66757cc20ec8087639537c08b6fbc 100644 --- a/src/ptrace.rs +++ b/src/ptrace.rs @@ -1,3 +1,7 @@ +//! The backend of the "proc:" scheme. Most internal breakpoint +//! handling should go here, unless they closely depend on the design +//! of the scheme. + use crate::{ arch::{ macros::InterruptStack, @@ -33,7 +37,8 @@ use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard}; use syscall::{ data::PtraceEvent, error::*, - flag::* + flag::*, + ptrace_event }; // ____ _ @@ -44,10 +49,11 @@ use syscall::{ #[derive(Debug)] struct Session { - file_id: usize, - events: VecDeque<PtraceEvent>, breakpoint: Option<Breakpoint>, - tracer: Arc<WaitCondition> + events: VecDeque<PtraceEvent>, + file_id: usize, + tracee: Arc<WaitCondition>, + tracer: Arc<WaitCondition>, } type SessionMap = BTreeMap<ContextId, Session>; @@ -73,10 +79,11 @@ pub fn try_new_session(pid: ContextId, file_id: usize) -> bool { Entry::Occupied(_) => false, Entry::Vacant(vacant) => { vacant.insert(Session { - file_id, - events: VecDeque::new(), breakpoint: None, - tracer: Arc::new(WaitCondition::new()) + events: VecDeque::new(), + file_id, + tracee: Arc::new(WaitCondition::new()), + tracer: Arc::new(WaitCondition::new()), }); true } @@ -107,9 +114,7 @@ pub fn session_fevent_flags(pid: ContextId) -> Option<usize> { pub fn close_session(pid: ContextId) { if let Some(session) = sessions_mut().remove(&pid) { session.tracer.notify(); - if let Some(breakpoint) = session.breakpoint { - breakpoint.tracee.notify(); - } + session.tracee.notify(); } } @@ -164,39 +169,31 @@ pub fn recv_events(pid: ContextId, out: &mut [PtraceEvent]) -> Option<usize> { #[derive(Debug)] struct Breakpoint { - tracee: Arc<WaitCondition>, reached: bool, - flags: u8 + flags: u64 } -fn inner_cont(pid: ContextId) -> Option<Breakpoint> { - // Remove the breakpoint to both save space and also make sure any - // yet unreached but obsolete breakpoints don't stop the program. +/// Continue the process with the specified ID +pub fn cont(pid: ContextId) { let mut sessions = sessions_mut(); - let session = sessions.get_mut(&pid)?; - let breakpoint = session.breakpoint.take()?; - - breakpoint.tracee.notify(); + let session = match sessions.get_mut(&pid) { + Some(session) => session, + None => return + }; - Some(breakpoint) -} + // Remove the breakpoint to make sure any yet unreached but + // obsolete breakpoints don't stop the program. + session.breakpoint = None; -/// Continue the process with the specified ID -pub fn cont(pid: ContextId) { - inner_cont(pid); + session.tracee.notify(); } /// Create a new breakpoint for the specified tracee, optionally with /// a sysemu flag. Panics if the session is invalid. -pub fn set_breakpoint(pid: ContextId, flags: u8) { - let tracee = inner_cont(pid) - .map(|b| b.tracee) - .unwrap_or_else(|| Arc::new(WaitCondition::new())); - +pub fn set_breakpoint(pid: ContextId, flags: u64) { let mut sessions = sessions_mut(); let session = sessions.get_mut(&pid).expect("proc (set_breakpoint): invalid session"); session.breakpoint = Some(Breakpoint { - tracee, reached: false, flags }); @@ -244,7 +241,7 @@ pub fn wait(pid: ContextId) -> Result<Option<PtraceEvent>> { /// Notify the tracer and await green flag to continue. /// Note: Don't call while holding any locks, this will switch contexts -pub fn breakpoint_callback(match_flags: u8) -> Option<u8> { +pub fn breakpoint_callback(match_flags: u64, event: Option<PtraceEvent>) -> Option<u64> { // Can't hold any locks when executing wait() let (tracee, flags) = { let contexts = context::contexts(); @@ -258,10 +255,12 @@ pub fn breakpoint_callback(match_flags: u8) -> Option<u8> { // TODO: How should singlesteps interact with syscalls? How // does Linux handle this? - if breakpoint.flags & PTRACE_OPERATIONMASK != match_flags & PTRACE_OPERATIONMASK { + if breakpoint.flags & match_flags != match_flags { return None; } + session.events.push_back(event.unwrap_or(ptrace_event!(match_flags))); + // In case no tracer is waiting, make sure the next one gets // the memo breakpoint.reached = true; @@ -270,7 +269,7 @@ pub fn breakpoint_callback(match_flags: u8) -> Option<u8> { proc_trigger_event(session.file_id, EVENT_WRITE); ( - Arc::clone(&breakpoint.tracee), + Arc::clone(&session.tracee), breakpoint.flags ) }; @@ -280,6 +279,21 @@ pub fn breakpoint_callback(match_flags: u8) -> Option<u8> { Some(flags) } +/// Obtain the next breakpoint flags for the current process. This is +/// used for detecting whether or not the tracer decided to use sysemu +/// mode. +pub fn next_breakpoint() -> Option<u64> { + let contexts = context::contexts(); + let context = contexts.current()?; + let context = context.read(); + + let sessions = sessions(); + let session = sessions.get(&context.id)?; + let breakpoint = session.breakpoint.as_ref()?; + + Some(breakpoint.flags) +} + /// Call when a context is closed to alert any tracers pub fn close_tracee(pid: ContextId) -> Option<()> { let mut sessions = sessions_mut(); diff --git a/src/scheme/proc.rs b/src/scheme/proc.rs index 5a04f9d55479a2b881ae11307eefb059c93d5ff4..66e51ad7612c66c962a61dc50f85872273df6eb9 100644 --- a/src/scheme/proc.rs +++ b/src/scheme/proc.rs @@ -1,9 +1,16 @@ use crate::{ arch::paging::VirtualAddress, - context::{self, ContextId, Status}, + context::{self, Context, ContextId, Status}, ptrace, scheme::{ATOMIC_SCHEMEID_INIT, AtomicSchemeId, SchemeId}, - syscall::validate + syscall::{ + data::{FloatRegisters, IntRegisters, PtraceEvent}, + error::*, + flag::*, + scheme::Scheme, + self, + validate, + }, }; use alloc::{ @@ -17,12 +24,6 @@ use core::{ sync::atomic::{AtomicUsize, Ordering} }; use spin::{Mutex, RwLock}; -use syscall::{ - data::{FloatRegisters, IntRegisters, PtraceEvent}, - error::*, - flag::*, - scheme::Scheme -}; #[derive(Clone, Copy)] enum RegsKind { @@ -38,6 +39,67 @@ enum Operation { } } +fn with_context<F, T>(pid: ContextId, callback: F) -> Result<T> + where F: FnOnce(&Context) -> Result<T> +{ + let contexts = context::contexts(); + let context = contexts.get(pid).ok_or(Error::new(ESRCH))?; + let context = context.read(); + if let Status::Exited(_) = context.status { + return Err(Error::new(ESRCH)); + } + callback(&context) +} +fn with_context_mut<F, T>(pid: ContextId, callback: F) -> Result<T> + where F: FnOnce(&mut Context) -> Result<T> +{ + let contexts = context::contexts(); + let context = contexts.get(pid).ok_or(Error::new(ESRCH))?; + let mut context = context.write(); + if let Status::Exited(_) = context.status { + return Err(Error::new(ESRCH)); + } + callback(&mut context) +} +fn try_stop_context<F, T>(pid: ContextId, restart_after: bool, mut callback: F) -> Result<T> + where F: FnMut(&mut Context) -> Result<T> +{ + let mut first = true; + let mut was_stopped = false; // will never be read + + loop { + if !first { + // We've tried this before, so lets wait before retrying + unsafe { context::switch(); } + } + first = false; + + let contexts = context::contexts(); + let context = contexts.get(pid).ok_or(Error::new(ESRCH))?; + let mut context = context.write(); + if let Status::Exited(_) = context.status { + return Err(Error::new(ESRCH)); + } + + // Stop the process until we've done our thing + if first { + was_stopped = context.ptrace_stop; + } + context.ptrace_stop = true; + + if context.running { + // Process still running, wait until it has stopped + continue; + } + + let ret = callback(&mut context); + + context.ptrace_stop = restart_after && was_stopped; + + break ret; + } +} + #[derive(Clone, Copy)] struct Handle { flags: usize, @@ -140,8 +202,10 @@ impl Scheme for ProcScheme { return Err(Error::new(EBUSY)); } - let mut target = target.write(); - target.ptrace_stop = true; + if flags & O_TRUNC == O_TRUNC { + let mut target = target.write(); + target.ptrace_stop = true; + } } self.handles.write().insert(id, Arc::new(Mutex::new(Handle { @@ -228,42 +292,28 @@ impl Scheme for ProcScheme { float: FloatRegisters, int: IntRegisters } - let mut first = true; - let (output, size) = loop { - if !first { - // We've tried this before, so lets wait before retrying - unsafe { context::switch(); } - } - first = false; - let contexts = context::contexts(); - let context = contexts.get(handle.pid).ok_or(Error::new(ESRCH))?; - let context = context.read(); - - break match kind { - RegsKind::Float => { - // NOTE: The kernel will never touch floats + let (output, size) = match kind { + RegsKind::Float => with_context(handle.pid, |context| { + // NOTE: The kernel will never touch floats - // In the rare case of not having floating - // point registers uninitiated, return - // empty everything. - let fx = context.arch.get_fx_regs().unwrap_or_default(); - (Output { float: fx }, mem::size_of::<FloatRegisters>()) + // In the rare case of not having floating + // point registers uninitiated, return + // empty everything. + let fx = context.arch.get_fx_regs().unwrap_or_default(); + Ok((Output { float: fx }, mem::size_of::<FloatRegisters>())) + })?, + RegsKind::Int => try_stop_context(handle.pid, true, |context| match unsafe { ptrace::regs_for(&context) } { + None => { + println!("{}:{}: Couldn't read registers from stopped process", file!(), line!()); + Err(Error::new(ENOTRECOVERABLE)) }, - RegsKind::Int => match unsafe { ptrace::regs_for(&context) } { - None => { - // Another CPU is running this process, wait until it's stopped. - continue; - }, - Some(stack) => { - let mut regs = IntRegisters::default(); - - stack.save(&mut regs); - - (Output { int: regs }, mem::size_of::<IntRegisters>()) - } + Some(stack) => { + let mut regs = IntRegisters::default(); + stack.save(&mut regs); + Ok((Output { int: regs }, mem::size_of::<IntRegisters>())) } - }; + })? }; let bytes = unsafe { @@ -300,7 +350,6 @@ impl Scheme for ProcScheme { let pid = handle.pid; let flags = handle.flags; - let mut first = true; match handle.operation { Operation::Memory(ref mut offset) => { let contexts = context::contexts(); @@ -315,26 +364,16 @@ impl Scheme for ProcScheme { *offset = VirtualAddress::new(offset.get() + buf.len()); Ok(buf.len()) }, - Operation::Regs(kind) => loop { - if !first { - // We've tried this before, so lets wait before retrying - unsafe { context::switch(); } - } - first = false; - - let contexts = context::contexts(); - let context = contexts.get(handle.pid).ok_or(Error::new(ESRCH))?; - let mut context = context.write(); - - break match kind { - RegsKind::Float => { - if buf.len() < mem::size_of::<FloatRegisters>() { - return Ok(0); - } - let regs = unsafe { - *(buf as *const _ as *const FloatRegisters) - }; + Operation::Regs(kind) => match kind { + RegsKind::Float => { + if buf.len() < mem::size_of::<FloatRegisters>() { + return Ok(0); + } + let regs = unsafe { + *(buf as *const _ as *const FloatRegisters) + }; + with_context_mut(pid, |context| { // NOTE: The kernel will never touch floats // Ignore the rare case of floating point @@ -342,82 +381,73 @@ impl Scheme for ProcScheme { let _ = context.arch.set_fx_regs(regs); Ok(mem::size_of::<FloatRegisters>()) - }, - RegsKind::Int => match unsafe { ptrace::regs_for_mut(&mut context) } { + }) + }, + RegsKind::Int => { + if buf.len() < mem::size_of::<IntRegisters>() { + return Ok(0); + } + let regs = unsafe { + *(buf as *const _ as *const IntRegisters) + }; + + try_stop_context(handle.pid, true, |context| match unsafe { ptrace::regs_for_mut(context) } { None => { - // Another CPU is running this process, wait until it's stopped. - continue; + println!("{}:{}: Couldn't read registers from stopped process", file!(), line!()); + Err(Error::new(ENOTRECOVERABLE)) }, Some(stack) => { - if buf.len() < mem::size_of::<IntRegisters>() { - return Ok(0); - } - let regs = unsafe { - *(buf as *const _ as *const IntRegisters) - }; - stack.load(®s); Ok(mem::size_of::<IntRegisters>()) } - } - }; + }) + } }, Operation::Trace { ref mut new_child } => { - if buf.len() < 1 { + if buf.len() < mem::size_of::<u64>() { return Ok(0); } - let op = buf[0]; - let mut blocking = flags & O_NONBLOCK != O_NONBLOCK; - let mut singlestep = false; + let mut bytes = [0; mem::size_of::<u64>()]; + let len = bytes.len(); + bytes.copy_from_slice(&buf[0..len]); + let op = u64::from_ne_bytes(bytes); - match op & PTRACE_OPERATIONMASK { - PTRACE_CONT => { ptrace::cont(pid); }, - PTRACE_SYSCALL | PTRACE_SINGLESTEP | PTRACE_SIGNAL => { // <- not a bitwise OR - singlestep = op & PTRACE_OPERATIONMASK == PTRACE_SINGLESTEP; - ptrace::set_breakpoint(pid, op); - }, - PTRACE_WAIT => blocking = true, - _ => return Err(Error::new(EINVAL)) + if op & PTRACE_FLAG_WAIT != PTRACE_FLAG_WAIT || op & PTRACE_STOP_MASK != 0 { + ptrace::cont(pid); + } + if op & PTRACE_STOP_MASK != 0 { + ptrace::set_breakpoint(pid, op); } - let mut first = true; - loop { - if !first { - // We've tried this before, so lets wait before retrying - unsafe { context::switch(); } - } - first = false; - - let contexts = context::contexts(); - let context = contexts.get(pid).ok_or(Error::new(ESRCH))?; - let mut context = context.write(); - if let Status::Exited(_) = context.status { - return Err(Error::new(ESRCH)); - } - - if singlestep { - match unsafe { ptrace::regs_for_mut(&mut context) } { - None => continue, - Some(stack) => stack.set_singlestep(true) + if op & PTRACE_STOP_SINGLESTEP == PTRACE_STOP_SINGLESTEP { + try_stop_context(pid, false, |context| { + match unsafe { ptrace::regs_for_mut(context) } { + // If another CPU is running this process, + // await for it to be stopped and in such + // a way the registers can be read! + None => { + println!("{}:{}: Couldn't read registers from stopped process", file!(), line!()); + Err(Error::new(ENOTRECOVERABLE)) + }, + Some(stack) => { + stack.set_singlestep(true); + Ok(()) + } } - } - - context.ptrace_stop = false; - break; + })?; } - if blocking { + if op & PTRACE_FLAG_WAIT == PTRACE_FLAG_WAIT || flags & O_NONBLOCK != O_NONBLOCK { if let Some(event) = ptrace::wait(pid)? { - if event.tag == PTRACE_EVENT_CLONE { - *new_child = Some(ContextId::from(unsafe { event.data.clone })); + if event.cause == PTRACE_EVENT_CLONE { + *new_child = Some(ContextId::from(event.a)); } - return Ok(0); } } - Ok(1) + Ok(mem::size_of::<u64>()) } } } @@ -467,12 +497,16 @@ impl Scheme for ProcScheme { if let Operation::Trace { .. } = handle.operation { ptrace::close_session(handle.pid); - } - let contexts = context::contexts(); - if let Some(context) = contexts.get(handle.pid) { - let mut context = context.write(); - context.ptrace_stop = false; + if handle.flags & O_EXCL == O_EXCL { + syscall::kill(handle.pid, SIGKILL)?; + } else { + let contexts = context::contexts(); + if let Some(context) = contexts.get(handle.pid) { + let mut context = context.write(); + context.ptrace_stop = false; + } + } } Ok(0) } diff --git a/src/syscall/mod.rs b/src/syscall/mod.rs index f76f96b67670f1d087e2c99ddf8ec0da8ca6c977..33ac677acccb1f3c07d683b1330003e80f57a649 100644 --- a/src/syscall/mod.rs +++ b/src/syscall/mod.rs @@ -4,7 +4,7 @@ extern crate syscall; -pub use self::syscall::{data, error, flag, io, number, scheme}; +pub use self::syscall::{data, error, flag, io, number, ptrace_event, scheme}; pub use self::driver::*; pub use self::fs::*; diff --git a/src/syscall/process.rs b/src/syscall/process.rs index e683b4cfc644beeaff9d50765ad20fd31fcbbbd7..9c9aa2685c17153490fb9579a6cbbcd61c8cec9b 100644 --- a/src/syscall/process.rs +++ b/src/syscall/process.rs @@ -18,17 +18,17 @@ use crate::paging::entry::EntryFlags; use crate::paging::mapper::MapperFlushAll; use crate::paging::temporary_page::TemporaryPage; use crate::paging::{ActivePageTable, InactivePageTable, Page, VirtualAddress, PAGE_SIZE}; -use crate::ptrace; +use crate::{ptrace, syscall}; use crate::scheme::FileHandle; use crate::start::usermode; -use crate::syscall::data::{PtraceEvent, PtraceEventData, SigAction, Stat}; +use crate::syscall::data::{PtraceEvent, SigAction, Stat}; use crate::syscall::error::*; use crate::syscall::flag::{CLONE_VFORK, CLONE_VM, CLONE_FS, CLONE_FILES, CLONE_SIGHAND, CLONE_STACK, PROT_EXEC, PROT_READ, PROT_WRITE, PTRACE_EVENT_CLONE, SIG_DFL, SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK, SIGCONT, SIGTERM, WCONTINUED, WNOHANG, WUNTRACED, wifcontinued, wifstopped}; +use crate::syscall::ptrace_event; use crate::syscall::validate::{validate_slice, validate_slice_mut}; -use crate::syscall; pub fn brk(address: usize) -> Result<usize> { let contexts = context::contexts(); @@ -585,14 +585,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> { } } - let ptrace_event = PtraceEvent { - tag: PTRACE_EVENT_CLONE, - data: PtraceEventData { - clone: pid.into() - } - }; - - if ptrace::send_event(ptrace_event).is_some() { + if ptrace::send_event(ptrace_event!(PTRACE_EVENT_CLONE, pid.into())).is_some() { // Freeze the clone, allow ptrace to put breakpoints // to it before it starts let contexts = context::contexts(); diff --git a/syscall b/syscall index 9e9f47d2a570c55dd96cd80c83bc818d63cab8af..52441c28b1daa6f9febf1bc6588b625b167bd2c3 160000 --- a/syscall +++ b/syscall @@ -1 +1 @@ -Subproject commit 9e9f47d2a570c55dd96cd80c83bc818d63cab8af +Subproject commit 52441c28b1daa6f9febf1bc6588b625b167bd2c3