Skip to content

Commit 428bee0

Browse files
committed
native-lib/trace: Handle accesses during libc fn calls also
1 parent 066aa78 commit 428bee0

1 file changed

Lines changed: 35 additions & 14 deletions

File tree

src/shims/native_lib/trace/parent.rs

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ pub fn sv_loop(
257257
let mut curr_pid = init_pid;
258258

259259
// There's an initial sigstop we need to deal with.
260-
wait_for_signal(Some(curr_pid), signal::SIGSTOP, InitialCont::No)?;
260+
wait_for_signal(Some(curr_pid), signal::SIGSTOP, InitialCont::No, None)?;
261261
ptrace::cont(curr_pid, None).unwrap();
262262

263263
for evt in listener {
@@ -276,7 +276,7 @@ pub fn sv_loop(
276276
confirm_tx.send(Confirmation).unwrap();
277277
// We can't trust simply calling `Pid::this()` in the child process to give the right
278278
// PID for us, so we get it this way.
279-
curr_pid = wait_for_signal(None, signal::SIGSTOP, InitialCont::No).unwrap();
279+
curr_pid = wait_for_signal(None, signal::SIGSTOP, InitialCont::No, None).unwrap();
280280
// Intercept libc events we care about.
281281
trap_libc(curr_pid);
282282
// Continue until next syscall.
@@ -301,16 +301,16 @@ pub fn sv_loop(
301301
// If it was a segfault, check if it was an artificial one
302302
// caused by it trying to access the MiriMachine memory.
303303
signal::SIGSEGV =>
304-
handle_segfault(
304+
handle_segfault(pid, &ch_pages, ch_stack.unwrap(), &cs, &mut acc_events)?,
305+
signal::SIGTRAP =>
306+
handle_sigtrap(
305307
pid,
306-
&ch_pages,
308+
&mut ch_pages,
309+
&event_tx,
310+
&mut acc_events,
307311
ch_stack.unwrap(),
308-
page_size,
309312
&cs,
310-
&mut acc_events,
311313
)?,
312-
signal::SIGTRAP =>
313-
handle_sigtrap(pid, page_size, &mut ch_pages, &event_tx, &mut acc_events)?,
314314
// Something weird happened.
315315
_ => {
316316
eprintln!("Process unexpectedly got {signal}; continuing...");
@@ -399,6 +399,13 @@ fn get_disasm() -> capstone::Capstone {
399399
.unwrap()
400400
}
401401

402+
struct SegfaultCatchingStuff<'a, 'b, 'c> {
403+
ch_pages: &'a [usize],
404+
ch_stack: usize,
405+
cs: &'b capstone::Capstone,
406+
acc_events: &'c mut Vec<AccessEvent>,
407+
}
408+
402409
/// Waits for `wait_signal`. If `init_cont`, it will first do a `ptrace::cont`.
403410
/// We want to avoid that in some cases, like at the beginning of FFI.
404411
///
@@ -407,6 +414,7 @@ fn wait_for_signal(
407414
pid: Option<unistd::Pid>,
408415
wait_signal: signal::Signal,
409416
init_cont: InitialCont,
417+
mut catch_segfaults: Option<SegfaultCatchingStuff<'_, '_, '_>>,
410418
) -> Result<unistd::Pid, ExecEnd> {
411419
if matches!(init_cont, InitialCont::Yes) {
412420
ptrace::cont(pid.unwrap(), None).unwrap();
@@ -435,6 +443,11 @@ fn wait_for_signal(
435443
};
436444
if signal == wait_signal {
437445
return Ok(pid);
446+
} else if let Some(ref mut sf) = catch_segfaults
447+
&& signal == signal::SIGSEGV
448+
{
449+
// Segfaults occuring during a wait should still be logged.
450+
handle_segfault(pid, sf.ch_pages, sf.ch_stack, sf.cs, sf.acc_events)?;
438451
} else {
439452
ptrace::cont(pid, signal).map_err(|_| ExecEnd(None))?;
440453
}
@@ -519,16 +532,19 @@ fn capstone_disassemble(
519532
Ok(())
520533
}
521534

535+
// THIS NEEDS TO SOMEHOW CATCH SEGFAULTS INSIDE IT!!!! AND ALSO IN THE FULL ONE IT
536+
// NEEDS TO GET THEM TO LOG THOSE ACCESSES AAAAAAAAAAAAAAAAA
537+
522538
/// Grabs the access that caused a segfault and logs it down if it's to our memory,
523539
/// or kills the child and returns the appropriate error otherwise.
524540
fn handle_segfault(
525541
pid: unistd::Pid,
526542
ch_pages: &[usize],
527543
ch_stack: usize,
528-
page_size: usize,
529544
cs: &capstone::Capstone,
530545
acc_events: &mut Vec<AccessEvent>,
531546
) -> Result<(), ExecEnd> {
547+
let page_size = PAGE_SIZE.load(Ordering::Relaxed);
532548
// Get information on what caused the segfault. This contains the address
533549
// that triggered it.
534550
let siginfo = ptrace::getsiginfo(pid).unwrap();
@@ -611,7 +627,7 @@ fn handle_segfault(
611627
ptrace::setregs(pid, new_regs).unwrap();
612628

613629
// Our mempr_* functions end with a raise(SIGSTOP).
614-
wait_for_signal(Some(pid), signal::SIGSTOP, InitialCont::Yes)?;
630+
wait_for_signal(Some(pid), signal::SIGSTOP, InitialCont::Yes, None)?;
615631

616632
// Step 1 instruction.
617633
ptrace::setregs(pid, regs_bak).unwrap();
@@ -645,7 +661,7 @@ fn handle_segfault(
645661
new_regs.set_ip(super::child::mempr_on as *const () as usize);
646662
new_regs.set_sp(stack_ptr);
647663
ptrace::setregs(pid, new_regs).unwrap();
648-
wait_for_signal(Some(pid), signal::SIGSTOP, InitialCont::Yes)?;
664+
wait_for_signal(Some(pid), signal::SIGSTOP, InitialCont::Yes, None)?;
649665

650666
ptrace::setregs(pid, regs_bak).unwrap();
651667
ptrace::syscall(pid, None).unwrap();
@@ -656,10 +672,11 @@ fn handle_segfault(
656672
/// to our shims to handle it instead.
657673
fn handle_sigtrap(
658674
pid: unistd::Pid,
659-
page_size: usize,
660675
pages: &mut Vec<usize>,
661676
_event_tx: &ipc::IpcSender<MemEvents>,
662-
_acc_events: &mut Vec<AccessEvent>,
677+
acc_events: &mut Vec<AccessEvent>,
678+
ch_stack: usize,
679+
cs: &capstone::Capstone,
663680
) -> Result<(), ExecEnd> {
664681
/// The libc functions we shim.
665682
enum LibcFn {
@@ -686,6 +703,7 @@ fn handle_sigtrap(
686703
}
687704
}
688705

706+
let page_size = PAGE_SIZE.load(Ordering::Relaxed);
689707
let regs = ptrace::getregs(pid).unwrap();
690708
match get_libc_fn(regs.ip()) {
691709
Some(_) => {
@@ -734,7 +752,10 @@ fn handle_sigtrap(
734752
ptrace::read(pid, std::ptr::without_provenance_mut(ret_addr)).unwrap();
735753
ptrace::write(pid, std::ptr::without_provenance_mut(ret_addr), BREAKPT_INSTR.into())
736754
.unwrap();
737-
wait_for_signal(Some(pid), signal::SIGTRAP, InitialCont::Yes).unwrap();
755+
let catch_segfaults =
756+
SegfaultCatchingStuff { ch_pages: &*pages, ch_stack, cs, acc_events };
757+
wait_for_signal(Some(pid), signal::SIGTRAP, InitialCont::Yes, Some(catch_segfaults))
758+
.unwrap();
738759

739760
// Unset the breakpoint stuff and move the ip back an instruction to compensate.
740761
ptrace::write(pid, std::ptr::without_provenance_mut(ret_addr), ret_addr_bytes).unwrap();

0 commit comments

Comments
 (0)