@@ -3,6 +3,7 @@ use nix::sys::{ptrace, signal, wait};
33use nix:: unistd;
44
55use crate :: discrete_alloc;
6+ use crate :: helpers:: ToU64 ;
67
78#[ cfg( target_pointer_width = "64" ) ]
89const BITS : u32 = 64 ;
@@ -17,7 +18,7 @@ const BREAKPT_INSTR: i64 = 0xD420;
1718// We do NOT ever want to block the child from accessing this!!
1819static SUPERVISOR : std:: sync:: Mutex < Option < Supervisor > > = std:: sync:: Mutex :: new ( None ) ;
1920static mut PAGE_ADDR : * mut libc:: c_void = std:: ptr:: null_mut ( ) ;
20- static mut PAGE_SIZE : usize = 4096 ;
21+ static mut PAGE_SIZE : u64 = 4096 ;
2122static mut CLICK_HERE_4_FREE_STACK : [ u8 ; 1024 ] = [ 0 ; 1024 ] ;
2223
2324trait ArchIndependentRegs {
@@ -83,6 +84,16 @@ pub struct Supervisor {
8384
8485impl Supervisor {
8586 pub fn init ( ) -> Result < ( ) , ( ) > {
87+ let ptrace_status = std:: fs:: read_to_string ( "/proc/sys/kernel/yama/ptrace_scope" ) ;
88+ if let Ok ( stat) = ptrace_status {
89+ if let Some ( stat) = stat. chars ( ) . next ( ) {
90+ // Fast-error if ptrace is disabled on the system and it's linux
91+ if stat != '0' && stat != '1' {
92+ return Err ( ( ) ) ;
93+ }
94+ }
95+ }
96+
8697 let sv = SUPERVISOR . lock ( ) . map_err ( |_| ( ) ) ?;
8798 let is_none = sv. is_none ( ) ;
8899
@@ -113,42 +124,42 @@ impl Supervisor {
113124 unistd:: ForkResult :: Child => {
114125 let mut sv = SUPERVISOR . lock ( ) . map_err ( |_| ( ) ) ?;
115126 * sv = Some ( Supervisor { t_message, r_event } ) ;
116- Ok ( ( ) )
117127 }
118128 }
119129 }
120- } else {
121- Err ( ( ) )
122130 }
131+ Ok ( ( ) )
123132 }
124133
125- pub unsafe fn start_ffi ( ) -> Option < ( ) > {
126- let mut sv_guard = SUPERVISOR . lock ( ) . ok ( ) ?;
127- let sv = sv_guard. take ( ) ?;
128- let exposed = discrete_alloc:: MachineAlloc :: pages ( ) ;
129- sv. t_message . send ( TraceRequest :: BeginFfi ( exposed) ) . ok ( ) ?;
130- * sv_guard = Some ( sv) ;
131- unsafe {
132- if discrete_alloc:: MachineAlloc :: prepare_ffi ( ) . is_err ( ) {
133- discrete_alloc:: MachineAlloc :: unprep_ffi ( ) ;
134- return None ;
134+ pub unsafe fn start_ffi ( ) {
135+ let mut sv_guard = SUPERVISOR . lock ( ) . unwrap ( ) ;
136+ if let Some ( sv) = sv_guard. take ( ) {
137+ let exposed = discrete_alloc:: MachineAlloc :: pages ( ) ;
138+ sv. t_message . send ( TraceRequest :: BeginFfi ( exposed) ) . unwrap ( ) ;
139+ * sv_guard = Some ( sv) ;
140+ unsafe {
141+ if discrete_alloc:: MachineAlloc :: prepare_ffi ( ) . is_err ( ) {
142+ // Don't mess up unwinding by maybe leaving the memory partly protected
143+ discrete_alloc:: MachineAlloc :: unprep_ffi ( ) ;
144+ panic ! ( "Cannot protect memory for FFI call!" ) ;
145+ }
135146 }
147+ signal:: raise ( signal:: SIGSTOP ) . unwrap ( ) ;
136148 }
137- signal:: raise ( signal:: SIGSTOP ) . unwrap ( ) ;
138- Some ( ( ) )
139149 }
140150
141151 pub unsafe fn end_ffi ( ) {
142152 let mut sv_guard = SUPERVISOR . lock ( ) . unwrap ( ) ;
143- let sv = sv_guard. take ( ) . unwrap ( ) ;
144- sv. t_message . send ( TraceRequest :: EndFfi ) . unwrap ( ) ;
145- * sv_guard = Some ( sv) ;
146- drop ( sv_guard) ;
147- discrete_alloc:: MachineAlloc :: unprep_ffi ( ) ;
153+ if let Some ( sv) = sv_guard. take ( ) {
154+ sv. t_message . send ( TraceRequest :: EndFfi ) . unwrap ( ) ;
155+ * sv_guard = Some ( sv) ;
156+ drop ( sv_guard) ;
157+ discrete_alloc:: MachineAlloc :: unprep_ffi ( ) ;
158+ }
148159 }
149160
150161 pub fn get_events ( ) -> Option < MemEvents > {
151- let mut sv_guard = SUPERVISOR . lock ( ) . ok ( ) ? ;
162+ let mut sv_guard = SUPERVISOR . lock ( ) . unwrap ( ) ;
152163 let sv = sv_guard. take ( ) ?;
153164 let ret = sv. r_event . recv ( ) . ok ( ) ;
154165 * sv_guard = Some ( sv) ;
@@ -158,15 +169,15 @@ impl Supervisor {
158169
159170#[ derive( Clone , Debug , serde:: Serialize , serde:: Deserialize ) ]
160171pub enum TraceRequest {
161- BeginFfi ( Vec < usize > ) ,
172+ BeginFfi ( Vec < u64 > ) ,
162173 EndFfi ,
163174 Die ,
164175}
165176
166177#[ derive( serde:: Serialize , serde:: Deserialize , Debug ) ]
167178pub struct MemEvents {
168- pub accesses : Vec < ( usize , usize , MemAccessType ) > ,
169- pub mappings : Vec < ( usize , usize ) > ,
179+ pub accesses : Vec < ( u64 , u64 , MemAccessType ) > ,
180+ pub mappings : Vec < ( u64 , u64 ) > ,
170181}
171182
172183#[ derive( serde:: Serialize , serde:: Deserialize , Debug , Clone ) ]
@@ -192,6 +203,20 @@ impl MemAccessType {
192203 MemAccessType :: ReadWrite => ( ) ,
193204 }
194205 }
206+
207+ pub fn did_read ( & self ) -> bool {
208+ match self {
209+ MemAccessType :: Write => false ,
210+ _ => true ,
211+ }
212+ }
213+
214+ pub fn did_write ( & self ) -> bool {
215+ match self {
216+ MemAccessType :: Read => false ,
217+ _ => true ,
218+ }
219+ }
195220}
196221
197222struct ChildListener {
@@ -249,8 +274,8 @@ impl Iterator for ChildListener {
249274/// created before the fork are the same).
250275fn sv_loop ( listener : ChildListener , t_event : ipc:: IpcSender < MemEvents > ) -> ! {
251276 // Things that we return to the child process
252- let mut accesses: Vec < ( usize , usize , MemAccessType ) > = vec ! [ ] ;
253- let mut mappings: Vec < ( usize , usize ) > = vec ! [ ] ;
277+ let mut accesses: Vec < ( u64 , u64 , MemAccessType ) > = vec ! [ ] ;
278+ let mut mappings: Vec < ( u64 , u64 ) > = vec ! [ ] ;
254279
255280 // Memory allocated on the MiriMachine
256281 let mut ch_pages = vec ! [ ] ;
@@ -329,7 +354,7 @@ fn sv_loop(listener: ChildListener, t_event: ipc::IpcSender<MemEvents>) -> ! {
329354 #[ expect( clippy:: as_conversions) ]
330355 if regs. retval ( ) as isize > 0 {
331356 let addr = regs. retval ( ) ;
332- mappings. push ( ( addr, len) ) ;
357+ mappings. push ( ( addr. to_u64 ( ) , len. to_u64 ( ) ) ) ;
333358 }
334359 }
335360 Err ( ret) => {
@@ -484,12 +509,12 @@ fn wait_for_syscall(pid: unistd::Pid, syscall: i64) -> Result<libc::user_regs_st
484509fn handle_munmap (
485510 pid : unistd:: Pid ,
486511 regs : libc:: user_regs_struct ,
487- mappings : & mut Vec < ( usize , usize ) > ,
512+ mappings : & mut Vec < ( u64 , u64 ) > ,
488513) -> Result < ( ) , i32 > {
489514 // The unmap call might hit multiple mappings we've saved,
490515 // or overlap with them partially (or both)
491- let um_start = regs. arg1 ( ) ;
492- let um_len = regs. arg2 ( ) ;
516+ let um_start = regs. arg1 ( ) . to_u64 ( ) ;
517+ let um_len = regs. arg2 ( ) . to_u64 ( ) ;
493518 let um_end = um_start. strict_add ( um_len) ;
494519 let mut idxes = vec ! [ ] ;
495520 for ( idx, & ( mp_start, len) ) in mappings. iter ( ) . enumerate ( ) {
@@ -536,11 +561,11 @@ fn handle_munmap(
536561
537562fn handle_segfault (
538563 pid : unistd:: Pid ,
539- ch_pages : & [ usize ] ,
540- accesses : & mut Vec < ( usize , usize , MemAccessType ) > ,
564+ ch_pages : & [ u64 ] ,
565+ accesses : & mut Vec < ( u64 , u64 , MemAccessType ) > ,
541566) -> Result < ( ) , i32 > {
542567 let siginfo = ptrace:: getsiginfo ( pid) . unwrap ( ) ;
543- let addr = unsafe { siginfo. si_addr ( ) . addr ( ) } ;
568+ let addr = unsafe { siginfo. si_addr ( ) . addr ( ) . to_u64 ( ) } ;
544569 let page_addr = addr. strict_sub ( addr. strict_rem ( unsafe { PAGE_SIZE } ) ) ;
545570
546571 if ch_pages. contains ( & page_addr) {
@@ -590,7 +615,7 @@ fn handle_segfault(
590615 let mut decoder = iced_x86:: Decoder :: new ( BITS , instr. as_slice ( ) , 0 ) ;
591616 let mut fac = iced_x86:: InstructionInfoFactory :: new ( ) ;
592617 let instr = decoder. decode ( ) ;
593- let memsize = instr. op_code ( ) . memory_size ( ) . size ( ) ;
618+ let memsize = instr. op_code ( ) . memory_size ( ) . size ( ) . to_u64 ( ) ;
594619 let mem = fac. info ( & instr) . used_memory ( ) ;
595620 let acc = mem. iter ( ) . fold ( None , |mut curr : Option < MemAccessType > , m| {
596621 if let Some ( m) = match m. access ( ) {
@@ -635,7 +660,7 @@ fn handle_segfault(
635660
636661fn handle_sigtrap (
637662 pid : unistd:: Pid ,
638- mappings : & mut Vec < ( usize , usize ) > ,
663+ mappings : & mut Vec < ( u64 , u64 ) > ,
639664 malloc_bytes : i64 ,
640665 realloc_bytes : i64 ,
641666 free_bytes : i64 ,
@@ -651,24 +676,28 @@ fn handle_sigtrap(
651676 let regs = ptrace:: getregs ( pid) . unwrap ( ) ;
652677 match regs. ip ( ) . strict_sub ( 1 ) {
653678 a if a == malloc_addr => {
654- let size = regs. arg1 ( ) ; // !
679+ let size = regs. arg1 ( ) . to_u64 ( ) ; // !
655680 let ptr = intercept_retptr ( pid, regs, malloc_addr, malloc_bytes) ?;
656- mappings. push ( ( ptr, size) ) ;
681+ if ptr > 0 {
682+ mappings. push ( ( ptr as u64 , size) ) ;
683+ }
657684 }
658685 a if a == realloc_addr => {
659- let old_ptr = regs. arg1 ( ) ;
660- let size = regs. arg2 ( ) ;
686+ let old_ptr = regs. arg1 ( ) . to_u64 ( ) ;
687+ let size = regs. arg2 ( ) . to_u64 ( ) ;
661688 let pos = mappings
662689 . iter ( )
663690 . position ( |& ( ptr, size) | ptr <= old_ptr && old_ptr < ptr. strict_add ( size) ) ;
664691 if let Some ( pos) = pos {
665692 let _ = mappings. remove ( pos) ;
666693 }
667694 let ptr = intercept_retptr ( pid, regs, realloc_addr, realloc_bytes) ?;
668- mappings. push ( ( ptr, size) ) ;
695+ if ptr > 0 {
696+ mappings. push ( ( ptr as u64 , size) ) ;
697+ }
669698 }
670699 a if a == free_addr => {
671- let old_ptr = regs. arg1 ( ) ;
700+ let old_ptr = regs. arg1 ( ) . to_u64 ( ) ;
672701 //let size = regs.rdi;
673702 let pos = mappings
674703 . iter ( )
@@ -692,7 +721,7 @@ fn intercept_retptr(
692721 mut regs : libc:: user_regs_struct ,
693722 fn_addr : usize ,
694723 fn_bytes : i64 ,
695- ) -> Result < usize , i32 > {
724+ ) -> Result < isize , i32 > {
696725 // Outline:
697726 // - Move instr ptr back before the sigtrap happened
698727 // - Restore the function to what it's supposed to be
@@ -715,7 +744,8 @@ fn intercept_retptr(
715744
716745 // now we're getting the return hopefully
717746 let mut regs = ptrace:: getregs ( pid) . unwrap ( ) ;
718- let ptr = regs. retval ( ) ; // !
747+ #[ expect( clippy:: as_conversions) ]
748+ let ptr = regs. retval ( ) as isize ; // !
719749 regs. set_ip ( regs. ip ( ) . strict_sub ( 1 ) ) ;
720750 ptrace:: write ( pid, std:: ptr:: without_provenance_mut ( fn_addr) , BREAKPT_INSTR ) . unwrap ( ) ;
721751 ptrace:: write ( pid, std:: ptr:: without_provenance_mut ( ret_addr) , ret_bytes) . unwrap ( ) ;
@@ -729,7 +759,12 @@ fn intercept_retptr(
729759// manually, so we *must not ever* unwind from it
730760pub unsafe extern "C" fn mempr_off ( ) {
731761 unsafe {
732- if libc:: mprotect ( PAGE_ADDR , PAGE_SIZE , libc:: PROT_READ | libc:: PROT_WRITE ) != 0 {
762+ if libc:: mprotect (
763+ PAGE_ADDR ,
764+ PAGE_SIZE . try_into ( ) . unwrap_unchecked ( ) ,
765+ libc:: PROT_READ | libc:: PROT_WRITE ,
766+ ) != 0
767+ {
733768 std:: process:: exit ( -20 ) ;
734769 }
735770 // This might error e.g. if the next page is unallocated or not owned by us - that's fine.
@@ -748,7 +783,8 @@ pub unsafe extern "C" fn mempr_off() {
748783
749784pub unsafe extern "C" fn mempr_on ( ) {
750785 unsafe {
751- if libc:: mprotect ( PAGE_ADDR , PAGE_SIZE , libc:: PROT_NONE ) != 0 {
786+ if libc:: mprotect ( PAGE_ADDR , PAGE_SIZE . try_into ( ) . unwrap_unchecked ( ) , libc:: PROT_NONE ) != 0
787+ {
752788 std:: process:: exit ( -22 ) ;
753789 }
754790 //let _ = libc::mprotect(PAGE_ADDR.wrapping_add(PAGE_SIZE), PAGE_SIZE, libc::PROT_NONE);
0 commit comments