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:
jD91mZM2
2019-07-21 19:58:32 +02:00
parent 7426e48105
commit a7da393cf5
6 changed files with 25 additions and 16 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

Submodule syscall updated: f3bb1f7b68...844650c4fb