From dcacbaed80fb6978df1b881d564e074f1c6498c8 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Fri, 19 Jul 2019 17:20:12 +0200 Subject: [PATCH 1/4] Add PtraceEvent for catching tracee forks --- src/data.rs | 82 ++++++++++++++++++++++++++++++++++++++++------------- src/flag.rs | 2 ++ 2 files changed, 65 insertions(+), 19 deletions(-) diff --git a/src/data.rs b/src/data.rs index 0b3845e..ee75c05 100644 --- a/src/data.rs +++ b/src/data.rs @@ -1,5 +1,5 @@ use core::ops::{Deref, DerefMut}; -use core::{mem, slice}; +use core::{fmt, mem, slice}; #[derive(Copy, Clone, Debug, Default)] #[repr(C)] @@ -13,7 +13,7 @@ impl Deref for Event { type Target = [u8]; fn deref(&self) -> &[u8] { unsafe { - slice::from_raw_parts(self as *const Event as *const u8, mem::size_of::()) as &[u8] + slice::from_raw_parts(self as *const Event as *const u8, mem::size_of::()) } } } @@ -21,7 +21,7 @@ impl Deref for Event { impl DerefMut for Event { fn deref_mut(&mut self) -> &mut [u8] { unsafe { - slice::from_raw_parts_mut(self as *mut Event as *mut u8, mem::size_of::()) as &mut [u8] + slice::from_raw_parts_mut(self as *mut Event as *mut u8, mem::size_of::()) } } } @@ -38,7 +38,7 @@ impl Deref for ITimerSpec { fn deref(&self) -> &[u8] { unsafe { slice::from_raw_parts(self as *const ITimerSpec as *const u8, - mem::size_of::()) as &[u8] + mem::size_of::()) } } } @@ -47,7 +47,7 @@ impl DerefMut for ITimerSpec { fn deref_mut(&mut self) -> &mut [u8] { unsafe { slice::from_raw_parts_mut(self as *mut ITimerSpec as *mut u8, - mem::size_of::()) as &mut [u8] + mem::size_of::()) } } } @@ -64,7 +64,7 @@ impl Deref for Map { type Target = [u8]; fn deref(&self) -> &[u8] { unsafe { - slice::from_raw_parts(self as *const Map as *const u8, mem::size_of::()) as &[u8] + slice::from_raw_parts(self as *const Map as *const u8, mem::size_of::()) } } } @@ -72,7 +72,7 @@ impl Deref for Map { impl DerefMut for Map { fn deref_mut(&mut self) -> &mut [u8] { unsafe { - slice::from_raw_parts_mut(self as *mut Map as *mut u8, mem::size_of::()) as &mut [u8] + slice::from_raw_parts_mut(self as *mut Map as *mut u8, mem::size_of::()) } } } @@ -94,7 +94,7 @@ impl Deref for Packet { type Target = [u8]; fn deref(&self) -> &[u8] { unsafe { - slice::from_raw_parts(self as *const Packet as *const u8, mem::size_of::()) as &[u8] + slice::from_raw_parts(self as *const Packet as *const u8, mem::size_of::()) } } } @@ -102,7 +102,7 @@ impl Deref for Packet { impl DerefMut for Packet { fn deref_mut(&mut self) -> &mut [u8] { unsafe { - slice::from_raw_parts_mut(self as *mut Packet as *mut u8, mem::size_of::()) as &mut [u8] + slice::from_raw_parts_mut(self as *mut Packet as *mut u8, mem::size_of::()) } } } @@ -150,7 +150,7 @@ impl Deref for Stat { fn deref(&self) -> &[u8] { unsafe { slice::from_raw_parts(self as *const Stat as *const u8, - mem::size_of::()) as &[u8] + mem::size_of::()) } } } @@ -159,7 +159,7 @@ impl DerefMut for Stat { fn deref_mut(&mut self) -> &mut [u8] { unsafe { slice::from_raw_parts_mut(self as *mut Stat as *mut u8, - mem::size_of::()) as &mut [u8] + mem::size_of::()) } } } @@ -178,7 +178,7 @@ impl Deref for StatVfs { fn deref(&self) -> &[u8] { unsafe { slice::from_raw_parts(self as *const StatVfs as *const u8, - mem::size_of::()) as &[u8] + mem::size_of::()) } } } @@ -187,7 +187,7 @@ impl DerefMut for StatVfs { fn deref_mut(&mut self) -> &mut [u8] { unsafe { slice::from_raw_parts_mut(self as *mut StatVfs as *mut u8, - mem::size_of::()) as &mut [u8] + mem::size_of::()) } } } @@ -204,7 +204,7 @@ impl Deref for TimeSpec { fn deref(&self) -> &[u8] { unsafe { slice::from_raw_parts(self as *const TimeSpec as *const u8, - mem::size_of::()) as &[u8] + mem::size_of::()) } } } @@ -213,7 +213,7 @@ impl DerefMut for TimeSpec { fn deref_mut(&mut self) -> &mut [u8] { unsafe { slice::from_raw_parts_mut(self as *mut TimeSpec as *mut u8, - mem::size_of::()) as &mut [u8] + mem::size_of::()) } } } @@ -257,7 +257,7 @@ impl Deref for IntRegisters { type Target = [u8]; fn deref(&self) -> &[u8] { unsafe { - slice::from_raw_parts(self as *const IntRegisters as *const u8, mem::size_of::()) as &[u8] + slice::from_raw_parts(self as *const IntRegisters as *const u8, mem::size_of::()) } } } @@ -265,7 +265,7 @@ impl Deref for IntRegisters { impl DerefMut for IntRegisters { fn deref_mut(&mut self) -> &mut [u8] { unsafe { - slice::from_raw_parts_mut(self as *mut IntRegisters as *mut u8, mem::size_of::()) as &mut [u8] + slice::from_raw_parts_mut(self as *mut IntRegisters as *mut u8, mem::size_of::()) } } } @@ -291,7 +291,7 @@ impl Deref for FloatRegisters { type Target = [u8]; fn deref(&self) -> &[u8] { unsafe { - slice::from_raw_parts(self as *const FloatRegisters as *const u8, mem::size_of::()) as &[u8] + slice::from_raw_parts(self as *const FloatRegisters as *const u8, mem::size_of::()) } } } @@ -299,7 +299,51 @@ impl Deref for FloatRegisters { impl DerefMut for FloatRegisters { fn deref_mut(&mut self) -> &mut [u8] { unsafe { - slice::from_raw_parts_mut(self as *mut FloatRegisters as *mut u8, mem::size_of::()) as &mut [u8] + slice::from_raw_parts_mut(self as *mut FloatRegisters as *mut u8, mem::size_of::()) + } + } +} + +#[derive(Clone, Copy)] +#[repr(C)] +pub union PtraceEventContent { + pub clone: usize, +} + +impl Default for PtraceEventContent { + fn default() -> Self { + Self { + clone: 0 + } + } +} + +impl fmt::Debug for PtraceEventContent { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "PtraceEventContent(...)") + } +} + +#[derive(Clone, Copy, Debug, Default)] +#[repr(C)] +pub struct PtraceEvent { + pub tag: u16, + pub data: PtraceEventContent, +} + +impl Deref for PtraceEvent { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const PtraceEvent as *const u8, mem::size_of::()) + } + } +} + +impl DerefMut for PtraceEvent { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut PtraceEvent as *mut u8, mem::size_of::()) } } } diff --git a/src/flag.rs b/src/flag.rs index e6c4cbf..5fc6ba7 100644 --- a/src/flag.rs +++ b/src/flag.rs @@ -72,6 +72,8 @@ pub const PTRACE_WAIT: u8 = 0b0000_0100; pub const PTRACE_OPERATIONMASK: u8 = 0b0000_1111; pub const PTRACE_SYSEMU: u8 = 0b0001_0000; +pub const PTRACE_EVENT_CLONE: u16 = 0; + pub const SEEK_SET: usize = 0; pub const SEEK_CUR: usize = 1; pub const SEEK_END: usize = 2; From 35b30e6fa913ac6521989948398d61eb3eb44680 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Sat, 20 Jul 2019 22:10:43 +0200 Subject: [PATCH 2/4] Fix sigaction Undefind Behavior Rust does not allow a `fn`-pointer to be null. This fixes that, while luckily doing it in a way that leaves system calls backwards-compatible :) --- src/data.rs | 19 ++++++++--------- src/tests.rs | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 10 deletions(-) diff --git a/src/data.rs b/src/data.rs index ee75c05..b6b261f 100644 --- a/src/data.rs +++ b/src/data.rs @@ -107,22 +107,21 @@ impl DerefMut for Packet { } } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Default, PartialEq)] #[repr(C)] pub struct SigAction { - pub sa_handler: extern "C" fn(usize), + pub sa_handler: Option, pub sa_mask: [u64; 2], pub sa_flags: usize, } -impl Default for SigAction { - fn default() -> Self { - Self { - sa_handler: unsafe { mem::transmute(0usize) }, - sa_mask: [0; 2], - sa_flags: 0, - } - } +#[allow(dead_code)] +unsafe fn _assert_size_of_function_is_sane() { + // Transmuting will complain *at compile time* if sizes differ. + // Rust forbids a fn-pointer from being 0 so to allow SIG_DFL to + // exist, we use Option which will mean 0 + // becomes None + let _ = mem::transmute::, usize>(None); } #[derive(Copy, Clone, Debug, Default, PartialEq)] diff --git a/src/tests.rs b/src/tests.rs index 03273d4..e2a7905 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -409,3 +409,62 @@ fn unlink() { fn sched_yield() { assert_eq!(dbg!(crate::sched_yield()), Ok(0)); } + +#[test] +fn sigaction() { + use std::{ + mem, + sync::atomic::{AtomicBool, Ordering} + }; + + let child = unsafe { dbg!(crate::clone(0)).unwrap() }; + + if child == 0 { + static SA_HANDLER_WAS_RAN: AtomicBool = AtomicBool::new(false); + + let pid = dbg!(crate::getpid()).unwrap(); + + extern "C" fn hello_im_a_signal_handler(signal: usize) { + assert_eq!(dbg!(signal), crate::SIGUSR1); + SA_HANDLER_WAS_RAN.store(true, Ordering::SeqCst); + } + + let my_signal_handler = crate::SigAction { + sa_handler: Some(hello_im_a_signal_handler), + ..Default::default() + }; + dbg!(crate::sigaction(crate::SIGUSR1, Some(&my_signal_handler), None)).unwrap(); + + dbg!(crate::kill(pid, crate::SIGUSR1)).unwrap(); // calls handler + + let mut old_signal_handler = crate::SigAction::default(); + dbg!(crate::sigaction( + crate::SIGUSR1, + Some(&crate::SigAction { + sa_handler: unsafe { mem::transmute::>(crate::SIG_IGN) }, + ..Default::default() + }), + Some(&mut old_signal_handler) + )).unwrap(); + assert_eq!(my_signal_handler, old_signal_handler); + + dbg!(crate::kill(pid, crate::SIGUSR1)).unwrap(); // does nothing + + dbg!(crate::sigaction( + crate::SIGUSR1, + Some(&crate::SigAction { + sa_handler: unsafe { mem::transmute::>(crate::SIG_DFL) }, + ..Default::default() + }), + Some(&mut old_signal_handler) + )).unwrap(); + + dbg!(crate::kill(pid, crate::SIGUSR1)).unwrap(); // actually exits + } else { + let mut status = 0; + dbg!(crate::waitpid(child, &mut status, 0)).unwrap(); + + assert!(crate::wifsignaled(status)); + assert_eq!(crate::wtermsig(status), crate::SIGUSR1); + } +} From 1ee9229c6a43cf7ed563bdb34b57b35b643e6c2d Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Sun, 21 Jul 2019 15:03:10 +0200 Subject: [PATCH 3/4] fixup! Fix sigaction Undefind Behavior --- src/tests.rs | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/tests.rs b/src/tests.rs index e2a7905..7dd2bad 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -417,15 +417,16 @@ fn sigaction() { sync::atomic::{AtomicBool, Ordering} }; - let child = unsafe { dbg!(crate::clone(0)).unwrap() }; + static SA_HANDLER_WAS_RAN: AtomicBool = AtomicBool::new(false); + static SA_HANDLER_2_WAS_IGNORED: AtomicBool = AtomicBool::new(false); + + let child = unsafe { crate::clone(crate::CLONE_VM).unwrap() }; if child == 0 { - static SA_HANDLER_WAS_RAN: AtomicBool = AtomicBool::new(false); - - let pid = dbg!(crate::getpid()).unwrap(); + let pid = crate::getpid().unwrap(); extern "C" fn hello_im_a_signal_handler(signal: usize) { - assert_eq!(dbg!(signal), crate::SIGUSR1); + assert_eq!(signal, crate::SIGUSR1); SA_HANDLER_WAS_RAN.store(true, Ordering::SeqCst); } @@ -433,38 +434,43 @@ fn sigaction() { sa_handler: Some(hello_im_a_signal_handler), ..Default::default() }; - dbg!(crate::sigaction(crate::SIGUSR1, Some(&my_signal_handler), None)).unwrap(); + crate::sigaction(crate::SIGUSR1, Some(&my_signal_handler), None).unwrap(); - dbg!(crate::kill(pid, crate::SIGUSR1)).unwrap(); // calls handler + crate::kill(pid, crate::SIGUSR1).unwrap(); // calls handler let mut old_signal_handler = crate::SigAction::default(); - dbg!(crate::sigaction( + crate::sigaction( crate::SIGUSR1, Some(&crate::SigAction { sa_handler: unsafe { mem::transmute::>(crate::SIG_IGN) }, ..Default::default() }), Some(&mut old_signal_handler) - )).unwrap(); + ).unwrap(); assert_eq!(my_signal_handler, old_signal_handler); - dbg!(crate::kill(pid, crate::SIGUSR1)).unwrap(); // does nothing + crate::kill(pid, crate::SIGUSR1).unwrap(); // does nothing - dbg!(crate::sigaction( + SA_HANDLER_2_WAS_IGNORED.store(true, Ordering::SeqCst); + + crate::sigaction( crate::SIGUSR1, Some(&crate::SigAction { sa_handler: unsafe { mem::transmute::>(crate::SIG_DFL) }, ..Default::default() }), Some(&mut old_signal_handler) - )).unwrap(); + ).unwrap(); - dbg!(crate::kill(pid, crate::SIGUSR1)).unwrap(); // actually exits + crate::kill(pid, crate::SIGUSR1).unwrap(); // actually exits } else { let mut status = 0; dbg!(crate::waitpid(child, &mut status, 0)).unwrap(); assert!(crate::wifsignaled(status)); assert_eq!(crate::wtermsig(status), crate::SIGUSR1); + + assert!(SA_HANDLER_WAS_RAN.load(Ordering::SeqCst)); + assert!(SA_HANDLER_2_WAS_IGNORED.load(Ordering::SeqCst)); } } From 85a45f382cacb2a243446f5ff263fd5b70b80c26 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Sun, 21 Jul 2019 19:56:19 +0200 Subject: [PATCH 4/4] 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. --- src/data.rs | 13 +++++++------ src/flag.rs | 3 +++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/data.rs b/src/data.rs index b6b261f..6ad8d8b 100644 --- a/src/data.rs +++ b/src/data.rs @@ -305,21 +305,22 @@ impl DerefMut for FloatRegisters { #[derive(Clone, Copy)] #[repr(C)] -pub union PtraceEventContent { +pub union PtraceEventData { pub clone: usize, + pub signal: usize } -impl Default for PtraceEventContent { +impl Default for PtraceEventData { fn default() -> Self { Self { - clone: 0 + clone: 0, } } } -impl fmt::Debug for PtraceEventContent { +impl fmt::Debug for PtraceEventData { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "PtraceEventContent(...)") + write!(f, "PtraceEventData(...)") } } @@ -327,7 +328,7 @@ impl fmt::Debug for PtraceEventContent { #[repr(C)] pub struct PtraceEvent { pub tag: u16, - pub data: PtraceEventContent, + pub data: PtraceEventData, } impl Deref for PtraceEvent { diff --git a/src/flag.rs b/src/flag.rs index 5fc6ba7..9c928b4 100644 --- a/src/flag.rs +++ b/src/flag.rs @@ -69,10 +69,13 @@ pub const PTRACE_CONT: u8 = 0b0000_0001; pub const PTRACE_SINGLESTEP: u8 = 0b0000_0010; pub const PTRACE_SYSCALL: u8 = 0b0000_0011; pub const PTRACE_WAIT: u8 = 0b0000_0100; +pub const PTRACE_SIGNAL: u8 = 0b0000_0101; + pub const PTRACE_OPERATIONMASK: u8 = 0b0000_1111; pub const PTRACE_SYSEMU: u8 = 0b0001_0000; pub const PTRACE_EVENT_CLONE: u16 = 0; +pub const PTRACE_EVENT_SIGNAL: u16 = 1; pub const SEEK_SET: usize = 0; pub const SEEK_CUR: usize = 1;