|
| 1 | +#![allow(unused)] |
1 | 2 | use std::sync::atomic::{AtomicPtr, AtomicUsize};
|
2 | 3 |
|
3 | 4 | use ipc_channel::ipc;
|
@@ -401,7 +402,7 @@ fn handle_segfault(
|
401 | 402 | ch_stack: usize,
|
402 | 403 | page_size: usize,
|
403 | 404 | cs: &capstone::Capstone,
|
404 |
| - acc_events: &mut Vec<AccessEvent>, |
| 405 | + acc_events: &mut [AccessEvent], |
405 | 406 | ) -> Result<(), ExecEnd> {
|
406 | 407 | /// This is just here to not pollute the main namespace with `capstone::prelude::*`.
|
407 | 408 | #[inline]
|
@@ -520,122 +521,7 @@ fn handle_segfault(
|
520 | 521 | Ok(())
|
521 | 522 | }
|
522 | 523 |
|
523 |
| - // Get information on what caused the segfault. This contains the address |
524 |
| - // that triggered it. |
525 |
| - let siginfo = ptrace::getsiginfo(pid).unwrap(); |
526 |
| - // All x86, ARM, etc. instructions only have at most one memory operand |
527 |
| - // (thankfully!) |
528 |
| - // SAFETY: si_addr is safe to call. |
529 |
| - let addr = unsafe { siginfo.si_addr().addr() }; |
530 |
| - let page_addr = addr.strict_sub(addr.strict_rem(page_size)); |
531 |
| - |
532 |
| - if !ch_pages.iter().any(|pg| (*pg..pg.strict_add(page_size)).contains(&addr)) { |
533 |
| - // This was a real segfault (not one of the Miri memory pages), so print some debug info and |
534 |
| - // quit. |
535 |
| - let regs = ptrace::getregs(pid).unwrap(); |
536 |
| - eprintln!("Segfault occurred during FFI at {addr:#018x}"); |
537 |
| - eprintln!("Expected access on pages: {ch_pages:#018x?}"); |
538 |
| - eprintln!("Register dump: {regs:#x?}"); |
539 |
| - ptrace::kill(pid).unwrap(); |
540 |
| - return Err(ExecEnd(None)); |
541 |
| - } |
542 |
| - |
543 |
| - // Overall structure: |
544 |
| - // - Get the address that caused the segfault |
545 |
| - // - Unprotect the memory: we force the child to execute `mempr_off`, passing parameters via |
546 |
| - // global atomic variables. This is what we use the temporary callback stack for. |
547 |
| - // - Step 1 instruction |
548 |
| - // - Parse executed code to estimate size & type of access |
549 |
| - // - Reprotect the memory by executing `mempr_on` in the child. |
550 |
| - // - Continue |
551 |
| - |
552 |
| - // Ensure the stack is properly zeroed out! |
553 |
| - for a in (ch_stack..ch_stack.strict_add(CALLBACK_STACK_SIZE)).step_by(ARCH_WORD_SIZE) { |
554 |
| - ptrace::write(pid, std::ptr::with_exposed_provenance_mut(a), 0).unwrap(); |
555 |
| - } |
556 |
| - |
557 |
| - // Guard against both architectures with upwards and downwards-growing stacks. |
558 |
| - let stack_ptr = ch_stack.strict_add(CALLBACK_STACK_SIZE / 2); |
559 |
| - let regs_bak = ptrace::getregs(pid).unwrap(); |
560 |
| - let mut new_regs = regs_bak; |
561 |
| - let ip_prestep = regs_bak.ip(); |
562 |
| - |
563 |
| - // Move the instr ptr into the deprotection code. |
564 |
| - #[expect(clippy::as_conversions)] |
565 |
| - new_regs.set_ip(mempr_off as usize); |
566 |
| - // Don't mess up the stack by accident! |
567 |
| - new_regs.set_sp(stack_ptr); |
568 |
| - |
569 |
| - // Modify the PAGE_ADDR global on the child process to point to the page |
570 |
| - // that we want unprotected. |
571 |
| - ptrace::write( |
572 |
| - pid, |
573 |
| - (&raw const PAGE_ADDR).cast_mut().cast(), |
574 |
| - libc::c_long::try_from(page_addr).unwrap(), |
575 |
| - ) |
576 |
| - .unwrap(); |
577 |
| - |
578 |
| - // Check if we also own the next page, and if so unprotect it in case |
579 |
| - // the access spans the page boundary. |
580 |
| - let flag = if ch_pages.contains(&page_addr.strict_add(page_size)) { 2 } else { 1 }; |
581 |
| - ptrace::write(pid, (&raw const PAGE_COUNT).cast_mut().cast(), flag).unwrap(); |
582 |
| - |
583 |
| - ptrace::setregs(pid, new_regs).unwrap(); |
584 |
| - |
585 |
| - // Our mempr_* functions end with a raise(SIGSTOP). |
586 |
| - wait_for_signal(Some(pid), signal::SIGSTOP, true)?; |
587 |
| - |
588 |
| - // Step 1 instruction. |
589 |
| - ptrace::setregs(pid, regs_bak).unwrap(); |
590 |
| - ptrace::step(pid, None).unwrap(); |
591 |
| - // Don't use wait_for_signal here since 1 instruction doesn't give room |
592 |
| - // for any uncertainty + we don't want it `cont()`ing randomly by accident |
593 |
| - // Also, don't let it continue with unprotected memory if something errors! |
594 |
| - let _ = wait::waitid(wait::Id::Pid(pid), WAIT_FLAGS).map_err(|_| ExecEnd(None))?; |
595 |
| - |
596 |
| - // Zero out again to be safe |
597 |
| - for a in (ch_stack..ch_stack.strict_add(CALLBACK_STACK_SIZE)).step_by(ARCH_WORD_SIZE) { |
598 |
| - ptrace::write(pid, std::ptr::with_exposed_provenance_mut(a), 0).unwrap(); |
599 |
| - } |
600 |
| - |
601 |
| - // Save registers and grab the bytes that were executed. This would |
602 |
| - // be really nasty if it was a jump or similar but those thankfully |
603 |
| - // won't do memory accesses and so can't trigger this! |
604 |
| - let regs_bak = ptrace::getregs(pid).unwrap(); |
605 |
| - new_regs = regs_bak; |
606 |
| - let ip_poststep = regs_bak.ip(); |
607 |
| - // We need to do reads/writes in word-sized chunks. |
608 |
| - let diff = (ip_poststep.strict_sub(ip_prestep)).div_ceil(ARCH_WORD_SIZE); |
609 |
| - let instr = (ip_prestep..ip_prestep.strict_add(diff)).fold(vec![], |mut ret, ip| { |
610 |
| - // This only needs to be a valid pointer in the child process, not ours. |
611 |
| - ret.append( |
612 |
| - &mut ptrace::read(pid, std::ptr::without_provenance_mut(ip)) |
613 |
| - .unwrap() |
614 |
| - .to_ne_bytes() |
615 |
| - .to_vec(), |
616 |
| - ); |
617 |
| - ret |
618 |
| - }); |
619 |
| - |
620 |
| - // Now figure out the size + type of access and log it down. |
621 |
| - // This will mark down e.g. the same area being read multiple times, |
622 |
| - // since it's more efficient to compress the accesses at the end. |
623 |
| - if capstone_disassemble(&instr, addr, cs, acc_events).is_err() { |
624 |
| - // Read goes first because we need to be pessimistic. |
625 |
| - acc_events.push(AccessEvent::Read(addr..addr.strict_add(ARCH_MAX_ACCESS_SIZE))); |
626 |
| - acc_events.push(AccessEvent::Write(addr..addr.strict_add(ARCH_MAX_ACCESS_SIZE))); |
627 |
| - } |
628 |
| - |
629 |
| - // Reprotect everything and continue. |
630 |
| - #[expect(clippy::as_conversions)] |
631 |
| - new_regs.set_ip(mempr_on as usize); |
632 |
| - new_regs.set_sp(stack_ptr); |
633 |
| - ptrace::setregs(pid, new_regs).unwrap(); |
634 |
| - wait_for_signal(Some(pid), signal::SIGSTOP, true)?; |
635 |
| - |
636 |
| - ptrace::setregs(pid, regs_bak).unwrap(); |
637 |
| - ptrace::syscall(pid, None).unwrap(); |
638 |
| - Ok(()) |
| 524 | + todo!() |
639 | 525 | }
|
640 | 526 |
|
641 | 527 | // We only get dropped into these functions via offsetting the instr pointer
|
|
0 commit comments