diff --git a/Cargo.lock b/Cargo.lock index db7f9e16953b2ff6607fa1305c97fe0827466f6c..a9cc12c25891d2fec784955eab8d6c95df786af0 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)", @@ -278,6 +278,9 @@ dependencies = [ [[package]] name = "redox_syscall" version = "0.1.56" +dependencies = [ + "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "regex" @@ -495,7 +498,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..e76f39359e4e6186220516e9c7332c1d25353ad5 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 @@ -49,8 +49,15 @@ interrupt_stack!(non_maskable, stack, { interrupt_stack!(breakpoint, stack, { println!("Breakpoint trap"); - stack.dump(); - ksignal(SIGTRAP); + + let guard = ptrace::set_process_regs(stack); + + if ptrace::breakpoint_callback(PTRACE_STOP_BREAKPOINT, None).is_none() { + drop(guard); + + stack.dump(); + ksignal(SIGTRAP); + } }); interrupt_stack!(overflow, stack, { diff --git a/src/arch/x86_64/interrupt/syscall.rs b/src/arch/x86_64/interrupt/syscall.rs index 6b9dfe615db217d6f51180a3dc9f23d84f1998fd..dd6b812f52636f44182a898629c0df188054d34d 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_FLAG_IGNORE, PTRACE_STOP_PRE_SYSCALL, PTRACE_STOP_POST_SYSCALL}; use crate::{ptrace, syscall}; use x86::shared::msr; @@ -21,19 +22,16 @@ 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) { - // If not on a sysemu breakpoint + let thumbs_up = ptrace::breakpoint_callback(PTRACE_STOP_PRE_SYSCALL, None) + .and_then(|_| ptrace::next_breakpoint().map(|f| !f.contains(PTRACE_FLAG_IGNORE))); + + if thumbs_up.unwrap_or(true) { + // If syscall not ignored 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/context.rs b/src/context/context.rs index 0a0f1869b9c6ad635e9d2ba16a2284ff31550993..216726e512a8e7f07bc57d193410d8b98710ea3e 100644 --- a/src/context/context.rs +++ b/src/context/context.rs @@ -16,7 +16,7 @@ use crate::ipi::{ipi, IpiKind, IpiTarget}; use crate::scheme::{SchemeNamespace, FileHandle}; use crate::sync::WaitMap; use crate::syscall::data::SigAction; -use crate::syscall::flag::SIG_DFL; +use crate::syscall::flag::{SIG_DFL, SigActionFlags}; /// Unique identifier for a context (i.e. `pid`). use ::core::sync::atomic::AtomicUsize; @@ -222,7 +222,7 @@ impl Context { SigAction { sa_handler: unsafe { mem::transmute(SIG_DFL) }, sa_mask: [0; 2], - sa_flags: 0, + sa_flags: SigActionFlags::empty(), }, 0 ); 128])), diff --git a/src/context/signal.rs b/src/context/signal.rs index d5d2ff18cb3e48918ca16cb2532148fa6856b648..942fb28c11ed80dc738e2b5098dc9b47c86d44c7 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_FLAG_IGNORE, PTRACE_STOP_SIGNAL, SIG_DFL, SIG_IGN, SIGCHLD, SIGCONT, SIGKILL, 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,17 @@ 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); + + let thumbs_down = ptrace::breakpoint_callback(PTRACE_STOP_SIGNAL, Some(ptrace_event!(PTRACE_STOP_SIGNAL, sig, handler))) + .and_then(|_| ptrace::next_breakpoint().map(|f| f.contains(PTRACE_FLAG_IGNORE))); + + if sig != SIGKILL && thumbs_down.unwrap_or(false) { + // If signal can be and was ignored + crate::syscall::sigreturn().unwrap(); + unreachable!(); + } + if handler == SIG_DFL { match sig { SIGCHLD => { @@ -92,7 +98,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 +106,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 +118,5 @@ pub extern "C" fn signal_handler(sig: usize) { } } - syscall::sigreturn().unwrap(); + crate::syscall::sigreturn().unwrap(); } diff --git a/src/event.rs b/src/event.rs index 7a7d25e0623c6711ea2f1aa69085a9b2f7c6139e..4eba3be241bda239159d48e7b729ae8fd8880939 100644 --- a/src/event.rs +++ b/src/event.rs @@ -8,6 +8,7 @@ use crate::scheme::{self, SchemeId}; use crate::sync::WaitQueue; use crate::syscall::data::Event; use crate::syscall::error::{Error, Result, EBADF, EINTR, ESRCH}; +use crate::syscall::flag::EventFlags; int_like!(EventQueueId, AtomicEventQueueId, usize, AtomicUsize); @@ -53,7 +54,7 @@ impl EventQueue { ); let flags = sync(RegKey { scheme, number })?; - if flags > 0 { + if !flags.is_empty() { trigger(scheme, number, flags); } } @@ -100,10 +101,10 @@ pub struct RegKey { pub struct QueueKey { pub queue: EventQueueId, pub id: usize, - pub data: usize + pub data: usize, } -type Registry = BTreeMap<RegKey, BTreeMap<QueueKey, usize>>; +type Registry = BTreeMap<RegKey, BTreeMap<QueueKey, EventFlags>>; static REGISTRY: Once<RwLock<Registry>> = Once::new(); @@ -122,28 +123,28 @@ pub fn registry_mut() -> RwLockWriteGuard<'static, Registry> { REGISTRY.call_once(init_registry).write() } -pub fn register(reg_key: RegKey, queue_key: QueueKey, flags: usize) { +pub fn register(reg_key: RegKey, queue_key: QueueKey, flags: EventFlags) { let mut registry = registry_mut(); let entry = registry.entry(reg_key).or_insert_with(|| { BTreeMap::new() }); - if flags == 0 { + if flags.is_empty() { entry.remove(&queue_key); } else { entry.insert(queue_key, flags); } } -pub fn sync(reg_key: RegKey) -> Result<usize> { - let mut flags = 0; +pub fn sync(reg_key: RegKey) -> Result<EventFlags> { + let mut flags = EventFlags::empty(); { let registry = registry(); if let Some(queue_list) = registry.get(®_key) { - for (_queue_key, queue_flags) in queue_list.iter() { + for (_queue_key, &queue_flags) in queue_list.iter() { flags |= queue_flags; } } @@ -169,13 +170,13 @@ pub fn unregister_file(scheme: SchemeId, number: usize) { // // } -pub fn trigger(scheme: SchemeId, number: usize, flags: usize) { +pub fn trigger(scheme: SchemeId, number: usize, flags: EventFlags) { let registry = registry(); if let Some(queue_list) = registry.get(&RegKey { scheme, number }) { - for (queue_key, queue_flags) in queue_list.iter() { + for (queue_key, &queue_flags) in queue_list.iter() { let common_flags = flags & queue_flags; - if common_flags != 0 { + if !common_flags.is_empty() { let queues = queues(); if let Some(queue) = queues.get(&queue_key.queue) { queue.queue.send(Event { diff --git a/src/ptrace.rs b/src/ptrace.rs index 3f3390f492b7a6ee1b4bdb32737a3723f35c44dc..c296922a6ab9e2c2927bccc69d36844236b1204f 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, @@ -12,7 +16,13 @@ use crate::{ context::{self, signal, Context, ContextId, Status}, event, scheme::proc, - sync::WaitCondition + sync::WaitCondition, + syscall::{ + data::PtraceEvent, + error::*, + flag::*, + ptrace_event + }, }; use alloc::{ @@ -30,11 +40,6 @@ use core::{ sync::atomic::Ordering }; use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard}; -use syscall::{ - data::PtraceEvent, - error::*, - flag::* -}; // ____ _ // / ___| ___ ___ ___(_) ___ _ __ ___ @@ -44,10 +49,25 @@ 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>, +} +impl Session { + fn send_event(&mut self, event: PtraceEvent) { + self.events.push_back(event); + + // Notify nonblocking tracers + if self.events.len() == 1 { + // If the list of events was previously empty, alert now + proc_trigger_event(self.file_id, EVENT_READ); + } + + // Alert blocking tracers + self.tracer.notify(); + } } type SessionMap = BTreeMap<ContextId, Session>; @@ -73,10 +93,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 } @@ -89,16 +110,13 @@ pub fn is_traced(pid: ContextId) -> bool { } /// Used for getting the flags in fevent -pub fn session_fevent_flags(pid: ContextId) -> Option<usize> { +pub fn session_fevent_flags(pid: ContextId) -> Option<EventFlags> { let sessions = sessions(); let session = sessions.get(&pid)?; - let mut flags = 0; + let mut flags = EventFlags::empty(); if !session.events.is_empty() { flags |= EVENT_READ; } - if session.breakpoint.as_ref().map(|b| b.reached).unwrap_or(true) { - flags |= EVENT_WRITE; - } Some(flags) } @@ -107,14 +125,12 @@ 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(); } } /// Trigger a notification to the event: scheme -fn proc_trigger_event(file_id: usize, flags: usize) { +fn proc_trigger_event(file_id: usize, flags: EventFlags) { event::trigger(proc::PROC_SCHEME_ID.load(Ordering::SeqCst), file_id, flags); } @@ -128,17 +144,13 @@ pub fn send_event(event: PtraceEvent) -> Option<()> { let mut sessions = sessions_mut(); let session = sessions.get_mut(&context.id)?; + let breakpoint = session.breakpoint.as_ref()?; - session.events.push_back(event); - - // Notify nonblocking tracers - if session.events.len() == 1 { - // If the list of events was previously empty, alert now - proc_trigger_event(session.file_id, EVENT_READ); + if event.cause & breakpoint.flags != event.cause { + return None; } - // Alert blocking tracers - session.tracer.notify(); + session.send_event(event); Some(()) } @@ -164,39 +176,31 @@ pub fn recv_events(pid: ContextId, out: &mut [PtraceEvent]) -> Option<usize> { #[derive(Debug)] struct Breakpoint { - tracee: Arc<WaitCondition>, reached: bool, - flags: u8 + flags: PtraceFlags } -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: PtraceFlags) { 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 }); @@ -207,31 +211,22 @@ pub fn set_breakpoint(pid: ContextId, flags: u8) { /// /// Note: Don't call while holding any locks, this will switch /// contexts -pub fn wait(pid: ContextId) -> Result<Option<PtraceEvent>> { +pub fn wait(pid: ContextId) -> Result<()> { let tracer: Arc<WaitCondition> = { let sessions = sessions(); match sessions.get(&pid) { Some(session) if session.breakpoint.as_ref().map(|b| !b.reached).unwrap_or(true) => { - if let Some(event) = session.events.front() { - return Ok(Some(event.clone())); + if !session.events.is_empty() { + return Ok(()); } Arc::clone(&session.tracer) }, - _ => return Ok(None) + _ => return Ok(()) } }; while !tracer.wait() {} - { - let sessions = sessions(); - if let Some(session) = sessions.get(&pid) { - if let Some(event) = session.events.front() { - return Ok(Some(event.clone())); - } - } - } - let contexts = context::contexts(); let context = contexts.get(pid).ok_or(Error::new(ESRCH))?; let context = context.read(); @@ -239,12 +234,12 @@ pub fn wait(pid: ContextId) -> Result<Option<PtraceEvent>> { return Err(Error::new(ESRCH)); } - Ok(None) + Ok(()) } /// 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: PtraceFlags, event: Option<PtraceEvent>) -> Option<PtraceFlags> { // Can't hold any locks when executing wait() let (tracee, flags) = { let contexts = context::contexts(); @@ -255,10 +250,7 @@ pub fn breakpoint_callback(match_flags: u8) -> Option<u8> { let session = sessions.get_mut(&context.id)?; let breakpoint = session.breakpoint.as_mut()?; - // 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; } @@ -266,12 +258,12 @@ pub fn breakpoint_callback(match_flags: u8) -> Option<u8> { // the memo breakpoint.reached = true; - session.tracer.notify(); - proc_trigger_event(session.file_id, EVENT_WRITE); + let flags = breakpoint.flags; + session.send_event(event.unwrap_or(ptrace_event!(match_flags))); ( - Arc::clone(&breakpoint.tracee), - breakpoint.flags + Arc::clone(&session.tracee), + flags ) }; @@ -280,13 +272,32 @@ 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<PtraceFlags> { + 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(); let session = sessions.get_mut(&pid)?; + // Cause tracers to wake up. Any action will cause ESRCH which can + // be used to detect exit. session.breakpoint = None; session.tracer.notify(); + proc_trigger_event(session.file_id, EVENT_READ); + Some(()) } diff --git a/src/scheme/debug.rs b/src/scheme/debug.rs index 4ec00e5ad7bc6c3ae5accef1a4c4ba29409a0290..abcb60c03df42930a361495c5b74a460d33a6438 100644 --- a/src/scheme/debug.rs +++ b/src/scheme/debug.rs @@ -5,7 +5,7 @@ use crate::arch::debug::Writer; use crate::event; use crate::scheme::*; use crate::sync::WaitQueue; -use crate::syscall::flag::{EVENT_READ, F_GETFL, F_SETFL, O_ACCMODE, O_NONBLOCK}; +use crate::syscall::flag::{EventFlags, EVENT_READ, F_GETFL, F_SETFL, O_ACCMODE, O_NONBLOCK}; use crate::syscall::scheme::Scheme; pub static DEBUG_SCHEME_ID: AtomicSchemeId = ATOMIC_SCHEMEID_INIT; @@ -102,13 +102,13 @@ impl Scheme for DebugScheme { } } - fn fevent(&self, id: usize, _flags: usize) -> Result<usize> { + fn fevent(&self, id: usize, _flags: EventFlags) -> Result<EventFlags> { let _flags = { let handles = handles(); *handles.get(&id).ok_or(Error::new(EBADF))? }; - Ok(0) + Ok(EventFlags::empty()) } fn fpath(&self, id: usize, buf: &mut [u8]) -> Result<usize> { diff --git a/src/scheme/irq.rs b/src/scheme/irq.rs index eb51768b167fd563e704e6f09a18c8315f6f2cf7..f7a4e3739b2ab370dfdf799a13c61ff2293507c7 100644 --- a/src/scheme/irq.rs +++ b/src/scheme/irq.rs @@ -6,7 +6,7 @@ use crate::event; use crate::interrupt::irq::acknowledge; use crate::scheme::{AtomicSchemeId, ATOMIC_SCHEMEID_INIT, SchemeId}; use crate::syscall::error::*; -use crate::syscall::flag::EVENT_READ; +use crate::syscall::flag::{EventFlags, EVENT_READ}; use crate::syscall::scheme::Scheme; pub static IRQ_SCHEME_ID: AtomicSchemeId = ATOMIC_SCHEMEID_INIT; @@ -87,8 +87,8 @@ impl Scheme for IrqScheme { Ok(0) } - fn fevent(&self, _id: usize, _flags: usize) -> Result<usize> { - Ok(0) + fn fevent(&self, _id: usize, _flags: EventFlags) -> Result<EventFlags> { + Ok(EventFlags::empty()) } fn fpath(&self, id: usize, buf: &mut [u8]) -> Result<usize> { diff --git a/src/scheme/itimer.rs b/src/scheme/itimer.rs index 3a91c3a2c4bc2443f57be769d30ff0d5be3babfd..92ca1ab02a3c1fcb1b3e0bf602c7a9ea6fc6ac64 100644 --- a/src/scheme/itimer.rs +++ b/src/scheme/itimer.rs @@ -5,7 +5,7 @@ use spin::RwLock; use crate::syscall::data::ITimerSpec; use crate::syscall::error::*; -use crate::syscall::flag::{CLOCK_REALTIME, CLOCK_MONOTONIC}; +use crate::syscall::flag::{CLOCK_REALTIME, CLOCK_MONOTONIC, EventFlags}; use crate::syscall::scheme::Scheme; pub struct ITimerScheme { @@ -79,9 +79,9 @@ impl Scheme for ITimerScheme { Ok(0) } - fn fevent(&self, id: usize, _flags: usize) -> Result<usize> { + fn fevent(&self, id: usize, _flags: EventFlags) -> Result<EventFlags> { let handles = self.handles.read(); - handles.get(&id).ok_or(Error::new(EBADF)).and(Ok(0)) + handles.get(&id).ok_or(Error::new(EBADF)).and(Ok(EventFlags::empty())) } fn fpath(&self, id: usize, buf: &mut [u8]) -> Result<usize> { diff --git a/src/scheme/memory.rs b/src/scheme/memory.rs index fd14ab31592157f2f7449b62afbb8e380bb2186f..f9f7496fc47f90c773cfdbd6596334a77eb4c37c 100644 --- a/src/scheme/memory.rs +++ b/src/scheme/memory.rs @@ -47,13 +47,13 @@ impl Scheme for MemoryScheme { let mut to_address = crate::USER_GRANT_OFFSET; let mut entry_flags = EntryFlags::PRESENT | EntryFlags::USER_ACCESSIBLE; - if map.flags & PROT_EXEC == 0 { + if !map.flags.contains(PROT_EXEC) { entry_flags |= EntryFlags::NO_EXECUTE; } - if map.flags & PROT_READ > 0 { + if map.flags.contains(PROT_READ) { //TODO: PROT_READ } - if map.flags & PROT_WRITE > 0 { + if map.flags.contains(PROT_WRITE) { entry_flags |= EntryFlags::WRITABLE; } diff --git a/src/scheme/pipe.rs b/src/scheme/pipe.rs index 7c02c077f8f9074edd2292270fa6c1b1689864be..bfc523219e6b51e8bb8eb8133a2d86884bfd0a19 100644 --- a/src/scheme/pipe.rs +++ b/src/scheme/pipe.rs @@ -7,7 +7,7 @@ use crate::event; use crate::scheme::{AtomicSchemeId, ATOMIC_SCHEMEID_INIT, SchemeId}; use crate::sync::WaitCondition; use crate::syscall::error::{Error, Result, EAGAIN, EBADF, EINTR, EINVAL, EPIPE, ESPIPE}; -use crate::syscall::flag::{EVENT_READ, EVENT_WRITE, F_GETFL, F_SETFL, O_ACCMODE, O_NONBLOCK, MODE_FIFO}; +use crate::syscall::flag::{EventFlags, EVENT_READ, EVENT_WRITE, F_GETFL, F_SETFL, O_ACCMODE, O_NONBLOCK, MODE_FIFO}; use crate::syscall::scheme::Scheme; use crate::syscall::data::Stat; @@ -87,14 +87,14 @@ impl Scheme for PipeScheme { Err(Error::new(EBADF)) } - fn fevent(&self, id: usize, flags: usize) -> Result<usize> { + fn fevent(&self, id: usize, flags: EventFlags) -> Result<EventFlags> { let pipes = pipes(); if let Some(pipe) = pipes.0.get(&id) { if flags == EVENT_READ { // TODO: Return correct flags if pipe.vec.lock().is_empty() { - return Ok(0); + return Ok(EventFlags::empty()); } else { return Ok(EVENT_READ); } diff --git a/src/scheme/proc.rs b/src/scheme/proc.rs index 5a04f9d55479a2b881ae11307eefb059c93d5ff4..b91831a415ac39e41e18cab9ec3efc66ffa69caf 100644 --- a/src/scheme/proc.rs +++ b/src/scheme/proc.rs @@ -1,62 +1,131 @@ 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::{ collections::BTreeMap, - sync::Arc + sync::Arc, + vec::Vec }; use core::{ cmp, mem, slice, - sync::atomic::{AtomicUsize, Ordering} + sync::atomic::{AtomicUsize, Ordering}, }; use spin::{Mutex, RwLock}; -use syscall::{ - data::{FloatRegisters, IntRegisters, PtraceEvent}, - error::*, - flag::*, - scheme::Scheme -}; #[derive(Clone, Copy)] enum RegsKind { Float, Int } -#[derive(Clone, Copy)] +#[derive(Clone)] enum Operation { Memory(VirtualAddress), Regs(RegsKind), Trace { - new_child: Option<ContextId> + clones: Vec<ContextId> + } +} + +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, +struct Info { pid: ContextId, + flags: usize, +} +struct Handle { + info: Info, operation: Operation } impl Handle { - fn continue_ignored_child(&mut self) -> Option<()> { - let pid = match self.operation { - Operation::Trace { ref mut new_child } => new_child.take()?, + fn continue_ignored_children(&mut self) -> Option<()> { + let clones = match self.operation { + Operation::Trace { ref mut clones } => clones, _ => return None }; - if ptrace::is_traced(pid) { - return None; - } let contexts = context::contexts(); - let context = contexts.get(pid)?; - let mut context = context.write(); - context.ptrace_stop = false; + for pid in clones.drain(..) { + if ptrace::is_traced(pid) { + continue; + } + if let Some(context) = contexts.get(pid) { + let mut context = context.write(); + context.ptrace_stop = false; + } + } Some(()) } } @@ -92,7 +161,7 @@ impl Scheme for ProcScheme { Some("regs/float") => Operation::Regs(RegsKind::Float), Some("regs/int") => Operation::Regs(RegsKind::Int), Some("trace") => Operation::Trace { - new_child: None + clones: Vec::new() }, _ => return Err(Error::new(EINVAL)) }; @@ -140,14 +209,18 @@ 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 { - flags, - pid, - operation + info: Info { + flags, + pid, + }, + operation, }))); Ok(id) } @@ -160,14 +233,14 @@ impl Scheme for ProcScheme { /// let regs = syscall::dup(trace, "regs/int")?; /// ``` fn dup(&self, old_id: usize, buf: &[u8]) -> Result<usize> { - let handle = { + let info = { let handles = self.handles.read(); let handle = handles.get(&old_id).ok_or(Error::new(EBADF))?; let handle = handle.lock(); - *handle + handle.info }; - let mut path = format!("{}/", handle.pid.into()).into_bytes(); + let mut path = format!("{}/", info.pid.into()).into_bytes(); path.extend_from_slice(buf); let (uid, gid) = { @@ -177,7 +250,7 @@ impl Scheme for ProcScheme { (context.euid, context.egid) }; - self.open(&path, handle.flags, uid, gid) + self.open(&path, info.flags, uid, gid) } fn seek(&self, id: usize, pos: usize, whence: usize) -> Result<usize> { @@ -205,14 +278,13 @@ impl Scheme for ProcScheme { let handles = self.handles.read(); Arc::clone(handles.get(&id).ok_or(Error::new(EBADF))?) }; - // TODO: Make sure handle can't deadlock let mut handle = handle.lock(); - let pid = handle.pid; + let info = handle.info; match handle.operation { Operation::Memory(ref mut offset) => { let contexts = context::contexts(); - let context = contexts.get(pid).ok_or(Error::new(ESRCH))?; + let context = contexts.get(info.pid).ok_or(Error::new(ESRCH))?; let context = context.read(); ptrace::with_context_memory(&context, *offset, buf.len(), |ptr| { @@ -228,42 +300,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(info.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(info.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 { @@ -274,13 +332,20 @@ impl Scheme for ProcScheme { Ok(len) }, - Operation::Trace { .. } => { - let read = ptrace::recv_events(handle.pid, unsafe { + Operation::Trace { ref mut clones } => { + let slice = unsafe { slice::from_raw_parts_mut( buf.as_mut_ptr() as *mut PtraceEvent, buf.len() / mem::size_of::<PtraceEvent>() ) - }).unwrap_or(0); + }; + let read = ptrace::recv_events(info.pid, slice).unwrap_or(0); + + for event in &slice[..read] { + if event.cause == PTRACE_EVENT_CLONE { + clones.push(ContextId::from(event.a)); + } + } Ok(read * mem::size_of::<PtraceEvent>()) } @@ -294,17 +359,13 @@ impl Scheme for ProcScheme { Arc::clone(handles.get(&id).ok_or(Error::new(EBADF))?) }; let mut handle = handle.lock(); - handle.continue_ignored_child(); + let info = handle.info; + handle.continue_ignored_children(); - // Some operations borrow Operation:: mutably - let pid = handle.pid; - let flags = handle.flags; - - let mut first = true; match handle.operation { Operation::Memory(ref mut offset) => { let contexts = context::contexts(); - let context = contexts.get(pid).ok_or(Error::new(ESRCH))?; + let context = contexts.get(info.pid).ok_or(Error::new(ESRCH))?; let context = context.read(); ptrace::with_context_memory(&context, *offset, buf.len(), |ptr| { @@ -315,26 +376,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(info.pid, |context| { // NOTE: The kernel will never touch floats // Ignore the rare case of floating point @@ -342,82 +393,78 @@ 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(info.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 { + Operation::Trace { .. } => { + 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); + let op = PtraceFlags::from_bits(op).ok_or(Error::new(EINVAL))?; - 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.contains(PTRACE_FLAG_WAIT) || op.intersects(PTRACE_STOP_MASK) { + ptrace::cont(info.pid); + } + if op.intersects(PTRACE_STOP_MASK) { + ptrace::set_breakpoint(info.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.contains(PTRACE_STOP_SINGLESTEP) { + // try_stop_context with `false` will + // automatically disable ptrace_stop + try_stop_context(info.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; + })?; + } else { + // disable ptrace stop + with_context_mut(info.pid, |context| { + context.ptrace_stop = false; + Ok(()) + })?; } - if blocking { - if let Some(event) = ptrace::wait(pid)? { - if event.tag == PTRACE_EVENT_CLONE { - *new_child = Some(ContextId::from(unsafe { event.data.clone })); - } - return Ok(0); - } + if op.contains(PTRACE_FLAG_WAIT) || info.flags & O_NONBLOCK != O_NONBLOCK { + ptrace::wait(info.pid)?; } - Ok(1) + Ok(mem::size_of::<u64>()) } } } @@ -428,18 +475,18 @@ impl Scheme for ProcScheme { let mut handle = handle.lock(); match cmd { - F_SETFL => { handle.flags = arg; Ok(0) }, - F_GETFL => return Ok(handle.flags), + F_SETFL => { handle.info.flags = arg; Ok(0) }, + F_GETFL => return Ok(handle.info.flags), _ => return Err(Error::new(EINVAL)) } } - fn fevent(&self, id: usize, _flags: usize) -> Result<usize> { + fn fevent(&self, id: usize, _flags: EventFlags) -> Result<EventFlags> { let handles = self.handles.read(); let handle = handles.get(&id).ok_or(Error::new(EBADF))?; let handle = handle.lock(); - Ok(ptrace::session_fevent_flags(handle.pid).expect("proc (fevent): invalid session")) + Ok(ptrace::session_fevent_flags(handle.info.pid).expect("proc (fevent): invalid session")) } fn fpath(&self, id: usize, buf: &mut [u8]) -> Result<usize> { @@ -447,7 +494,7 @@ impl Scheme for ProcScheme { let handle = handles.get(&id).ok_or(Error::new(EBADF))?; let handle = handle.lock(); - let path = format!("proc:{}/{}", handle.pid.into(), match handle.operation { + let path = format!("proc:{}/{}", handle.info.pid.into(), match handle.operation { Operation::Memory(_) => "mem", Operation::Regs(RegsKind::Float) => "regs/float", Operation::Regs(RegsKind::Int) => "regs/int", @@ -463,16 +510,20 @@ impl Scheme for ProcScheme { fn close(&self, id: usize) -> Result<usize> { let handle = self.handles.write().remove(&id).ok_or(Error::new(EBADF))?; let mut handle = handle.lock(); - handle.continue_ignored_child(); + handle.continue_ignored_children(); if let Operation::Trace { .. } = handle.operation { - ptrace::close_session(handle.pid); - } + ptrace::close_session(handle.info.pid); - let contexts = context::contexts(); - if let Some(context) = contexts.get(handle.pid) { - let mut context = context.write(); - context.ptrace_stop = false; + if handle.info.flags & O_EXCL == O_EXCL { + syscall::kill(handle.info.pid, SIGKILL)?; + } else { + let contexts = context::contexts(); + if let Some(context) = contexts.get(handle.info.pid) { + let mut context = context.write(); + context.ptrace_stop = false; + } + } } Ok(0) } diff --git a/src/scheme/root.rs b/src/scheme/root.rs index 13f9089110e63ecc444caba7245772fb7e98b9f8..c4315cd4104e8bc2b8ac95c616bcf3e7c9315d0d 100644 --- a/src/scheme/root.rs +++ b/src/scheme/root.rs @@ -9,7 +9,7 @@ use spin::{Mutex, RwLock}; use crate::context; use crate::syscall::data::Stat; use crate::syscall::error::*; -use crate::syscall::flag::{O_CREAT, MODE_FILE, MODE_DIR, SEEK_SET, SEEK_CUR, SEEK_END}; +use crate::syscall::flag::{EventFlags, O_CREAT, MODE_FILE, MODE_DIR, SEEK_SET, SEEK_CUR, SEEK_END}; use crate::syscall::scheme::Scheme; use crate::scheme::{self, SchemeNamespace, SchemeId}; use crate::scheme::user::{UserInner, UserScheme}; @@ -226,7 +226,7 @@ impl Scheme for RootScheme { } } - fn fevent(&self, file: usize, flags: usize) -> Result<usize> { + fn fevent(&self, file: usize, flags: EventFlags) -> Result<EventFlags> { let handle = { let handles = self.handles.read(); let handle = handles.get(&file).ok_or(Error::new(EBADF))?; diff --git a/src/scheme/time.rs b/src/scheme/time.rs index 8b340fb4749700e5db0e0fb085cd3211c7da22aa..718d14dc710b5bfed8c9a421b159a4c960d86263 100644 --- a/src/scheme/time.rs +++ b/src/scheme/time.rs @@ -7,7 +7,7 @@ use crate::context::timeout; use crate::scheme::SchemeId; use crate::syscall::data::TimeSpec; use crate::syscall::error::*; -use crate::syscall::flag::{CLOCK_REALTIME, CLOCK_MONOTONIC}; +use crate::syscall::flag::{CLOCK_REALTIME, CLOCK_MONOTONIC, EventFlags}; use crate::syscall::scheme::Scheme; use crate::time; @@ -90,9 +90,9 @@ impl Scheme for TimeScheme { Ok(0) } - fn fevent(&self, id: usize, _flags: usize) -> Result<usize> { + fn fevent(&self, id: usize, _flags: EventFlags) -> Result<EventFlags> { let handles = self.handles.read(); - handles.get(&id).ok_or(Error::new(EBADF)).and(Ok(0)) + handles.get(&id).ok_or(Error::new(EBADF)).and(Ok(EventFlags::empty())) } fn fpath(&self, id: usize, buf: &mut [u8]) -> Result<usize> { diff --git a/src/scheme/user.rs b/src/scheme/user.rs index 11a86200261d6f17c159f8db4405f66d619eaf80..91f2d6fcffee63c876e9fe71d6ef1594ac337f1e 100644 --- a/src/scheme/user.rs +++ b/src/scheme/user.rs @@ -16,7 +16,7 @@ use crate::scheme::{AtomicSchemeId, ATOMIC_SCHEMEID_INIT, SchemeId}; use crate::sync::{WaitQueue, WaitMap}; use crate::syscall::data::{Map, Packet, Stat, StatVfs, TimeSpec}; use crate::syscall::error::*; -use crate::syscall::flag::{EVENT_READ, O_NONBLOCK, PROT_EXEC, PROT_READ, PROT_WRITE}; +use crate::syscall::flag::{EventFlags, EVENT_READ, O_NONBLOCK, MapFlags, PROT_EXEC, PROT_READ, PROT_WRITE}; use crate::syscall::number::*; use crate::syscall::scheme::Scheme; @@ -108,7 +108,7 @@ impl UserInner { UserInner::capture_inner(&self.context, buf.as_mut_ptr() as usize, buf.len(), PROT_WRITE, None) } - fn capture_inner(context_weak: &Weak<RwLock<Context>>, address: usize, size: usize, flags: usize, desc_opt: Option<FileDescriptor>) -> Result<usize> { + fn capture_inner(context_weak: &Weak<RwLock<Context>>, address: usize, size: usize, flags: MapFlags, desc_opt: Option<FileDescriptor>) -> Result<usize> { //TODO: Abstract with other grant creation if size == 0 { Ok(0) @@ -127,13 +127,13 @@ impl UserInner { let mut to_address = crate::USER_GRANT_OFFSET; let mut entry_flags = EntryFlags::PRESENT | EntryFlags::USER_ACCESSIBLE; - if flags & PROT_EXEC == 0 { + if !flags.contains(PROT_EXEC) { entry_flags |= EntryFlags::NO_EXECUTE; } - if flags & PROT_READ > 0 { + if flags.contains(PROT_READ) { //TODO: PROT_READ } - if flags & PROT_WRITE > 0 { + if flags.contains(PROT_WRITE) { entry_flags |= EntryFlags::WRITABLE; } @@ -232,7 +232,7 @@ impl UserInner { let mut packet = unsafe { *(buf.as_ptr() as *const Packet).offset(i as isize) }; if packet.id == 0 { match packet.a { - SYS_FEVENT => event::trigger(self.scheme_id.load(Ordering::SeqCst), packet.b, packet.c), + SYS_FEVENT => event::trigger(self.scheme_id.load(Ordering::SeqCst), packet.b, EventFlags::from_bits_truncate(packet.c)), _ => println!("Unknown scheme -> kernel message {}", packet.a) } } else { @@ -257,8 +257,8 @@ impl UserInner { Ok(i * packet_size) } - pub fn fevent(&self, _flags: usize) -> Result<usize> { - Ok(0) + pub fn fevent(&self, _flags: EventFlags) -> Result<EventFlags> { + Ok(EventFlags::empty()) } pub fn fsync(&self) -> Result<usize> { @@ -356,9 +356,9 @@ impl Scheme for UserScheme { inner.call(SYS_FCNTL, file, cmd, arg) } - fn fevent(&self, file: usize, flags: usize) -> Result<usize> { + fn fevent(&self, file: usize, flags: EventFlags) -> Result<EventFlags> { let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; - inner.call(SYS_FEVENT, file, flags, 0) + inner.call(SYS_FEVENT, file, flags.bits(), 0).map(EventFlags::from_bits_truncate) } fn fmap(&self, file: usize, map: &Map) -> Result<usize> { diff --git a/src/syscall/debug.rs b/src/syscall/debug.rs index 94f4552867d76bf43c456411a667824351b229aa..270453ce15d67542d799588639517eb4773643c1 100644 --- a/src/syscall/debug.rs +++ b/src/syscall/debug.rs @@ -175,8 +175,8 @@ pub fn format_call(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) - validate_slice_mut(c as *mut TimeSpec, 1) ), SYS_CLONE => format!( - "clone({})", - b + "clone({:?})", + CloneFlags::from_bits(b) ), SYS_EXIT => format!( "exit({})", @@ -256,10 +256,10 @@ pub fn format_call(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) - validate_slice(b as *const [usize; 2], c) ), SYS_MPROTECT => format!( - "mprotect({:#X}, {}, {:#X})", + "mprotect({:#X}, {}, {:?})", b, c, - d + MapFlags::from_bits(d) ), SYS_NANOSLEEP => format!( "nanosleep({:?}, ({}, {}))", @@ -277,10 +277,10 @@ pub fn format_call(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) - c ), SYS_PHYSMAP => format!( - "physmap({:#X}, {}, {:#X})", + "physmap({:#X}, {}, {:?})", b, c, - d + PhysmapFlags::from_bits(d) ), SYS_PHYSUNMAP => format!( "physunmap({:#X})", @@ -315,10 +315,10 @@ pub fn format_call(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) - b ), SYS_WAITPID => format!( - "waitpid({}, {:#X}, {})", + "waitpid({}, {:#X}, {:?})", b, c, - d + WaitFlags::from_bits(d) ), SYS_YIELD => format!("yield()"), _ => format!( diff --git a/src/syscall/driver.rs b/src/syscall/driver.rs index 1ab0a4cbe1b018aec2bc0303a0e32e5edc25faf4..e1655fdb514c1430972d4b321d2afc76a84a9ed0 100644 --- a/src/syscall/driver.rs +++ b/src/syscall/driver.rs @@ -5,7 +5,7 @@ use crate::paging::entry::EntryFlags; use crate::context; use crate::context::memory::Grant; use crate::syscall::error::{Error, EFAULT, EINVAL, ENOMEM, EPERM, ESRCH, Result}; -use crate::syscall::flag::{PHYSMAP_WRITE, PHYSMAP_WRITE_COMBINE, PHYSMAP_NO_CACHE}; +use crate::syscall::flag::{PhysmapFlags, PHYSMAP_WRITE, PHYSMAP_WRITE_COMBINE, PHYSMAP_NO_CACHE}; fn enforce_root() -> Result<()> { let contexts = context::contexts(); @@ -50,7 +50,7 @@ pub fn physfree(physical_address: usize, size: usize) -> Result<usize> { } //TODO: verify exlusive access to physical memory -pub fn inner_physmap(physical_address: usize, size: usize, flags: usize) -> Result<usize> { +pub fn inner_physmap(physical_address: usize, size: usize, flags: PhysmapFlags) -> Result<usize> { //TODO: Abstract with other grant creation if size == 0 { Ok(0) @@ -67,13 +67,13 @@ pub fn inner_physmap(physical_address: usize, size: usize, flags: usize) -> Resu let mut to_address = crate::USER_GRANT_OFFSET; let mut entry_flags = EntryFlags::PRESENT | EntryFlags::NO_EXECUTE | EntryFlags::USER_ACCESSIBLE; - if flags & PHYSMAP_WRITE == PHYSMAP_WRITE { + if flags.contains(PHYSMAP_WRITE) { entry_flags |= EntryFlags::WRITABLE; } - if flags & PHYSMAP_WRITE_COMBINE == PHYSMAP_WRITE_COMBINE { + if flags.contains(PHYSMAP_WRITE_COMBINE) { entry_flags |= EntryFlags::HUGE_PAGE; } - if flags & PHYSMAP_NO_CACHE == PHYSMAP_NO_CACHE { + if flags.contains(PHYSMAP_NO_CACHE) { entry_flags |= EntryFlags::NO_CACHE; } @@ -100,7 +100,7 @@ pub fn inner_physmap(physical_address: usize, size: usize, flags: usize) -> Resu Ok(to_address + offset) } } -pub fn physmap(physical_address: usize, size: usize, flags: usize) -> Result<usize> { +pub fn physmap(physical_address: usize, size: usize, flags: PhysmapFlags) -> Result<usize> { enforce_root()?; inner_physmap(physical_address, size, flags) } diff --git a/src/syscall/fs.rs b/src/syscall/fs.rs index 1746d77aca06fe945929aa2a9bbd8b248c4ba743..c4bcc6c909d74cfe1b4dec7223ec7f9ab2d36cf3 100644 --- a/src/syscall/fs.rs +++ b/src/syscall/fs.rs @@ -8,7 +8,7 @@ use crate::scheme::{self, FileHandle}; use crate::syscall; use crate::syscall::data::{Packet, Stat}; use crate::syscall::error::*; -use crate::syscall::flag::{F_GETFD, F_SETFD, F_GETFL, F_SETFL, F_DUPFD, O_ACCMODE, O_DIRECTORY, O_RDONLY, O_SYMLINK, O_WRONLY, MODE_DIR, MODE_FILE, O_CLOEXEC}; +use crate::syscall::flag::*; use crate::context::file::{FileDescriptor, FileDescription}; pub fn file_op(a: usize, fd: FileHandle, c: usize, d: usize) -> Result<usize> { @@ -92,7 +92,7 @@ pub fn open(path: &[u8], flags: usize) -> Result<FileHandle> { (context.canonicalize(path), context.euid, context.egid, context.ens, context.umask) }; - let flags = (flags & (!0o777)) | (flags & 0o777) & (!(umask & 0o777)); + let flags = (flags & (!0o777)) | ((flags & 0o777) & (!(umask & 0o777))); //println!("open {}", unsafe { ::core::str::from_utf8_unchecked(&path_canon) }); diff --git a/src/syscall/mod.rs b/src/syscall/mod.rs index f76f96b67670f1d087e2c99ddf8ec0da8ca6c977..de4014a0bccf6130ec6725ffd567d77b8506fe2e 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::*; @@ -16,6 +16,7 @@ pub use self::validate::*; use self::data::{SigAction, TimeSpec}; use self::error::{Error, Result, ENOSYS}; +use self::flag::{CloneFlags, MapFlags, PhysmapFlags, WaitFlags}; use self::number::*; use crate::context::ContextId; @@ -94,8 +95,9 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: u SYS_GETPGID => getpgid(ContextId::from(b)).map(ContextId::into), SYS_GETPPID => getppid().map(ContextId::into), SYS_CLONE => { + let b = CloneFlags::from_bits_truncate(b); let old_rsp = stack.iret.rsp; - if b & flag::CLONE_STACK == flag::CLONE_STACK { + if b.contains(flag::CLONE_STACK) { stack.iret.rsp = c; } let ret = clone(b, bp).map(ContextId::into); @@ -104,7 +106,7 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: u }, SYS_EXIT => exit((b & 0xFF) << 8), SYS_KILL => kill(ContextId::from(b), c), - SYS_WAITPID => waitpid(ContextId::from(b), c, d).map(ContextId::into), + SYS_WAITPID => waitpid(ContextId::from(b), c, WaitFlags::from_bits_truncate(d)).map(ContextId::into), SYS_CHDIR => chdir(validate_slice(b as *const u8, c)?), SYS_IOPL => iopl(b, stack), SYS_GETCWD => getcwd(validate_slice_mut(b as *mut u8, c)?), @@ -114,7 +116,7 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: u SYS_GETGID => getgid(), SYS_GETNS => getns(), SYS_GETUID => getuid(), - SYS_MPROTECT => mprotect(b, c, d), + SYS_MPROTECT => mprotect(b, c, MapFlags::from_bits_truncate(d)), SYS_MKNS => mkns(validate_slice(b as *const [usize; 2], c)?), SYS_SETPGID => setpgid(ContextId::from(b), ContextId::from(c)), SYS_SETREUID => setreuid(b as u32, c as u32), @@ -151,7 +153,7 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: u SYS_PIPE2 => pipe2(validate_slice_mut(b as *mut usize, 2)?, c), SYS_PHYSALLOC => physalloc(b), SYS_PHYSFREE => physfree(b, c), - SYS_PHYSMAP => physmap(b, c, d), + SYS_PHYSMAP => physmap(b, c, PhysmapFlags::from_bits_truncate(d)), SYS_PHYSUNMAP => physunmap(b), SYS_UMASK => umask(b), SYS_VIRTTOPHYS => virttophys(b), diff --git a/src/syscall/process.rs b/src/syscall/process.rs index e683b4cfc644beeaff9d50765ad20fd31fcbbbd7..646db9a1a1300cbed5966aea78abdb3fc3c36cf4 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::flag::{CloneFlags, CLONE_VFORK, CLONE_VM, CLONE_FS, CLONE_FILES, CLONE_SIGHAND, + CLONE_STACK, MapFlags, PROT_EXEC, PROT_READ, PROT_WRITE, PTRACE_EVENT_CLONE, + SigActionFlags, SIG_DFL, SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK, SIGCONT, SIGTERM, + WaitFlags, 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(); @@ -67,7 +67,7 @@ pub fn brk(address: usize) -> Result<usize> { } } -pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> { +pub fn clone(flags: CloneFlags, stack_base: usize) -> Result<ContextId> { let ppid; let pid; { @@ -114,7 +114,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> { sigmask = context.sigmask; umask = context.umask; - if flags & CLONE_VM == CLONE_VM { + if flags.contains(CLONE_VM) { cpu_id = context.cpu_id; } @@ -155,7 +155,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> { kstack_option = Some(new_stack); } - if flags & CLONE_VM == CLONE_VM { + if flags.contains(CLONE_VM) { for memory_shared in context.image.iter() { image.push(memory_shared.clone()); } @@ -206,7 +206,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> { } if let Some(ref stack_shared) = context.stack { - if flags & CLONE_STACK == CLONE_STACK { + if flags.contains(CLONE_STACK) { stack_option = Some(stack_shared.clone()); } else { stack_shared.with(|stack| { @@ -261,7 +261,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> { }; - if flags & CLONE_VM == CLONE_VM { + if flags.contains(CLONE_VM) { unsafe { new_tls.load(); } @@ -277,7 +277,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> { tls_option = Some(new_tls); } - if flags & CLONE_VM == CLONE_VM { + if flags.contains(CLONE_VM) { grants = Arc::clone(&context.grants); } else { let mut grants_vec = Vec::new(); @@ -288,25 +288,25 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> { grants = Arc::new(Mutex::new(grants_vec)); } - if flags & CLONE_VM == CLONE_VM { + if flags.contains(CLONE_VM) { name = Arc::clone(&context.name); } else { name = Arc::new(Mutex::new(context.name.lock().clone())); } - if flags & CLONE_FS == CLONE_FS { + if flags.contains(CLONE_FS) { cwd = Arc::clone(&context.cwd); } else { cwd = Arc::new(Mutex::new(context.cwd.lock().clone())); } - if flags & CLONE_FILES == CLONE_FILES { + if flags.contains(CLONE_FILES) { files = Arc::clone(&context.files); } else { files = Arc::new(Mutex::new(context.files.lock().clone())); } - if flags & CLONE_SIGHAND == CLONE_SIGHAND { + if flags.contains(CLONE_SIGHAND) { actions = Arc::clone(&context.actions); } else { actions = Arc::new(Mutex::new(context.actions.lock().clone())); @@ -315,7 +315,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> { // If not cloning files, dup to get a new number from scheme // This has to be done outside the context lock to prevent deadlocks - if flags & CLONE_FILES == 0 { + if !flags.contains(CLONE_FILES) { for (_fd, file_option) in files.lock().iter_mut().enumerate() { let new_file_option = if let Some(ref file) = *file_option { Some(FileDescriptor { @@ -331,7 +331,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> { } // If not cloning virtual memory, use fmap to re-obtain every grant where possible - if flags & CLONE_VM == 0 { + if !flags.contains(CLONE_VM) { let mut i = 0; while i < grants.lock().len() { let remove = false; @@ -350,7 +350,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> { // If vfork, block the current process // This has to be done after the operations that may require context switches - if flags & CLONE_VFORK == CLONE_VFORK { + if flags.contains(CLONE_VFORK) { let contexts = context::contexts(); let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; let mut context = context_lock.write(); @@ -430,7 +430,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> { // TODO: Clone ksig? // Setup image, heap, and grants - if flags & CLONE_VM == CLONE_VM { + if flags.contains(CLONE_VM) { // Copy user image mapping, if found if ! image.is_empty() { let frame = active_table.p4()[crate::USER_PML4].pointed_frame().expect("user image not mapped"); @@ -514,7 +514,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> { // Setup user stack if let Some(stack_shared) = stack_option { - if flags & CLONE_STACK == CLONE_STACK { + if flags.contains(CLONE_STACK) { let frame = active_table.p4()[crate::USER_STACK_PML4].pointed_frame().expect("user stack not mapped"); let flags = active_table.p4()[crate::USER_STACK_PML4].flags(); active_table.with(&mut new_table, &mut temporary_page, |mapper| { @@ -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(); @@ -860,7 +853,7 @@ fn fexec_noreturn( SigAction { sa_handler: unsafe { mem::transmute(SIG_DFL) }, sa_mask: [0; 2], - sa_flags: 0, + sa_flags: SigActionFlags::empty(), }, 0 ); 128])); @@ -1297,7 +1290,7 @@ pub fn kill(pid: ContextId, sig: usize) -> Result<usize> { } } -pub fn mprotect(address: usize, size: usize, flags: usize) -> Result<usize> { +pub fn mprotect(address: usize, size: usize, flags: MapFlags) -> Result<usize> { println!("mprotect {:#X}, {}, {:#X}", address, size, flags); let end_offset = size.checked_sub(1).ok_or(Error::new(EFAULT))?; @@ -1311,19 +1304,19 @@ pub fn mprotect(address: usize, size: usize, flags: usize) -> Result<usize> { let end_page = Page::containing_address(VirtualAddress::new(end_address)); for page in Page::range_inclusive(start_page, end_page) { if let Some(mut page_flags) = active_table.translate_page_flags(page) { - if flags & PROT_EXEC > 0 { + if flags.contains(PROT_EXEC) { page_flags.remove(EntryFlags::NO_EXECUTE); } else { page_flags.insert(EntryFlags::NO_EXECUTE); } - if flags & PROT_WRITE > 0 { + if flags.contains(PROT_WRITE) { //TODO: Not allowing gain of write privileges } else { page_flags.remove(EntryFlags::WRITABLE); } - if flags & PROT_READ > 0 { + if flags.contains(PROT_READ) { //TODO: No flags for readable pages } else { //TODO: No flags for readable pages @@ -1475,7 +1468,7 @@ fn reap(pid: ContextId) -> Result<ContextId> { Ok(pid) } -pub fn waitpid(pid: ContextId, status_ptr: usize, flags: usize) -> Result<ContextId> { +pub fn waitpid(pid: ContextId, status_ptr: usize, flags: WaitFlags) -> Result<ContextId> { let (ppid, waitpid) = { let contexts = context::contexts(); let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; diff --git a/syscall b/syscall index 9e9f47d2a570c55dd96cd80c83bc818d63cab8af..bf5e138def0f8ad9c4ce87b8eca2d96b57aef8ea 160000 --- a/syscall +++ b/syscall @@ -1 +1 @@ -Subproject commit 9e9f47d2a570c55dd96cd80c83bc818d63cab8af +Subproject commit bf5e138def0f8ad9c4ce87b8eca2d96b57aef8ea