WIP(ptrace): Better support for signals
Signals now cause an event, and there's a way to continue until the next signal. I can see this being used for detection of `int3` although I'm not entirely sure as it may prove being too late to stop abortion of process.
This commit is contained in:
@@ -21,7 +21,8 @@ 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::PTRACE_SYSCALL);
|
||||
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 $stack = &mut *stack;
|
||||
|
||||
@@ -3,8 +3,9 @@ use core::mem;
|
||||
|
||||
use crate::context::{contexts, switch, Status, WaitpidKey};
|
||||
use crate::start::usermode;
|
||||
use crate::syscall;
|
||||
use crate::syscall::flag::{SIG_DFL, SIG_IGN, SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU};
|
||||
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};
|
||||
|
||||
pub fn is_user_handled(handler: Option<extern "C" fn(usize)>) -> bool {
|
||||
let handler = handler.map(|ptr| ptr as usize).unwrap_or(0);
|
||||
@@ -20,6 +21,11 @@ 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);
|
||||
if handler == SIG_DFL {
|
||||
match sig {
|
||||
@@ -94,6 +100,8 @@ 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,7 +114,7 @@ pub fn close_session(pid: ContextId) {
|
||||
}
|
||||
|
||||
/// Trigger a notification to the event: scheme
|
||||
pub fn proc_trigger_event(file_id: usize, flags: usize) {
|
||||
fn proc_trigger_event(file_id: usize, flags: usize) {
|
||||
event::trigger(proc::PROC_SCHEME_ID.load(Ordering::SeqCst), file_id, flags);
|
||||
}
|
||||
|
||||
@@ -244,9 +244,9 @@ pub fn wait(pid: ContextId) -> Result<Option<PtraceEvent>> {
|
||||
|
||||
/// Notify the tracer and await green flag to continue.
|
||||
/// Note: Don't call while holding any locks, this will switch contexts
|
||||
pub fn breakpoint_callback(flags: u8) -> Option<bool> {
|
||||
pub fn breakpoint_callback(match_flags: u8) -> Option<u8> {
|
||||
// Can't hold any locks when executing wait()
|
||||
let (tracee, sysemu) = {
|
||||
let (tracee, flags) = {
|
||||
let contexts = context::contexts();
|
||||
let context = contexts.current()?;
|
||||
let context = context.read();
|
||||
@@ -258,7 +258,7 @@ pub fn breakpoint_callback(flags: u8) -> Option<bool> {
|
||||
// TODO: How should singlesteps interact with syscalls? How
|
||||
// does Linux handle this?
|
||||
|
||||
if breakpoint.flags & PTRACE_OPERATIONMASK != flags & PTRACE_OPERATIONMASK {
|
||||
if breakpoint.flags & PTRACE_OPERATIONMASK != match_flags & PTRACE_OPERATIONMASK {
|
||||
return None;
|
||||
}
|
||||
|
||||
@@ -271,13 +271,13 @@ pub fn breakpoint_callback(flags: u8) -> Option<bool> {
|
||||
|
||||
(
|
||||
Arc::clone(&breakpoint.tracee),
|
||||
breakpoint.flags & PTRACE_SYSEMU == PTRACE_SYSEMU
|
||||
breakpoint.flags
|
||||
)
|
||||
};
|
||||
|
||||
while !tracee.wait() {}
|
||||
|
||||
Some(sysemu)
|
||||
Some(flags)
|
||||
}
|
||||
|
||||
/// Call when a context is closed to alert any tracers
|
||||
|
||||
@@ -374,7 +374,7 @@ impl Scheme for ProcScheme {
|
||||
|
||||
match op & PTRACE_OPERATIONMASK {
|
||||
PTRACE_CONT => { ptrace::cont(pid); },
|
||||
PTRACE_SYSCALL | PTRACE_SINGLESTEP => { // <- not a bitwise OR
|
||||
PTRACE_SYSCALL | PTRACE_SINGLESTEP | PTRACE_SIGNAL => { // <- not a bitwise OR
|
||||
singlestep = op & PTRACE_OPERATIONMASK == PTRACE_SINGLESTEP;
|
||||
ptrace::set_breakpoint(pid, op);
|
||||
},
|
||||
|
||||
@@ -21,7 +21,7 @@ use crate::paging::{ActivePageTable, InactivePageTable, Page, VirtualAddress, PA
|
||||
use crate::ptrace;
|
||||
use crate::scheme::FileHandle;
|
||||
use crate::start::usermode;
|
||||
use crate::syscall::data::{PtraceEvent, PtraceEventContent, SigAction, Stat};
|
||||
use crate::syscall::data::{PtraceEvent, PtraceEventData, 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,
|
||||
@@ -587,7 +587,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> {
|
||||
|
||||
let ptrace_event = PtraceEvent {
|
||||
tag: PTRACE_EVENT_CLONE,
|
||||
data: PtraceEventContent {
|
||||
data: PtraceEventData {
|
||||
clone: pid.into()
|
||||
}
|
||||
};
|
||||
@@ -1124,9 +1124,6 @@ pub fn exit(status: usize) -> ! {
|
||||
(vfork, children)
|
||||
};
|
||||
|
||||
// Alert any tracers waiting for process (important: AFTER sending waitpid event)
|
||||
ptrace::close_tracee(pid);
|
||||
|
||||
{
|
||||
let contexts = context::contexts();
|
||||
if let Some(parent_lock) = contexts.get(ppid) {
|
||||
@@ -1153,6 +1150,9 @@ pub fn exit(status: usize) -> ! {
|
||||
}
|
||||
}
|
||||
|
||||
// Alert any tracers waiting for process (important: AFTER sending waitpid event)
|
||||
ptrace::close_tracee(pid);
|
||||
|
||||
if pid == ContextId::from(1) {
|
||||
println!("Main kernel thread exited with status {:X}", status);
|
||||
|
||||
|
||||
2
syscall
2
syscall
Submodule syscall updated: f3bb1f7b68...844650c4fb
Reference in New Issue
Block a user