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