Merge branch 'ptrace-6' into 'master'

Ptrace overhaul & bitflags

See merge request redox-os/kernel!107
This commit is contained in:
Jeremy Soller
2019-07-31 20:29:54 +00:00
22 changed files with 439 additions and 369 deletions

11
Cargo.lock generated
View File

@@ -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"

View File

@@ -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, {

View File

@@ -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);
}
}
}

View File

@@ -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])),

View File

@@ -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();
}

View File

@@ -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(&reg_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 {

View File

@@ -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
}
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.
let mut sessions = sessions_mut();
let session = sessions.get_mut(&pid)?;
let breakpoint = session.breakpoint.take()?;
breakpoint.tracee.notify();
Some(breakpoint)
flags: PtraceFlags
}
/// Continue the process with the specified ID
pub fn cont(pid: ContextId) {
inner_cont(pid);
let mut sessions = sessions_mut();
let session = match sessions.get_mut(&pid) {
Some(session) => session,
None => return
};
// Remove the breakpoint to make sure any yet unreached but
// obsolete breakpoints don't stop the program.
session.breakpoint = None;
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(())
}

View File

@@ -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> {

View File

@@ -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> {

View File

@@ -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> {

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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();
let (output, size) = match kind {
RegsKind::Float => with_context(info.pid, |context| {
// NOTE: The kernel will never touch floats
break match kind {
RegsKind::Float => {
// 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(&regs);
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)
}

View File

@@ -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))?;

View File

@@ -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> {

View File

@@ -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> {

View File

@@ -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!(

View File

@@ -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)
}

View File

@@ -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) });

View File

@@ -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),

View File

@@ -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))?;

Submodule syscall updated: 9e9f47d2a5...bf5e138def