@@ -3,6 +3,7 @@ use nix::sys::{ptrace, signal, wait};
3
3
use nix:: unistd;
4
4
5
5
use crate :: discrete_alloc;
6
+ use crate :: helpers:: ToU64 ;
6
7
7
8
#[ cfg( target_pointer_width = "64" ) ]
8
9
const BITS : u32 = 64 ;
@@ -17,7 +18,7 @@ const BREAKPT_INSTR: i64 = 0xD420;
17
18
// We do NOT ever want to block the child from accessing this!!
18
19
static SUPERVISOR : std:: sync:: Mutex < Option < Supervisor > > = std:: sync:: Mutex :: new ( None ) ;
19
20
static 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 ;
21
22
static mut CLICK_HERE_4_FREE_STACK : [ u8 ; 1024 ] = [ 0 ; 1024 ] ;
22
23
23
24
trait ArchIndependentRegs {
@@ -83,6 +84,16 @@ pub struct Supervisor {
83
84
84
85
impl Supervisor {
85
86
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
+
86
97
let sv = SUPERVISOR . lock ( ) . map_err ( |_| ( ) ) ?;
87
98
let is_none = sv. is_none ( ) ;
88
99
@@ -113,42 +124,42 @@ impl Supervisor {
113
124
unistd:: ForkResult :: Child => {
114
125
let mut sv = SUPERVISOR . lock ( ) . map_err ( |_| ( ) ) ?;
115
126
* sv = Some ( Supervisor { t_message, r_event } ) ;
116
- Ok ( ( ) )
117
127
}
118
128
}
119
129
}
120
- } else {
121
- Err ( ( ) )
122
130
}
131
+ Ok ( ( ) )
123
132
}
124
133
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
+ }
135
146
}
147
+ signal:: raise ( signal:: SIGSTOP ) . unwrap ( ) ;
136
148
}
137
- signal:: raise ( signal:: SIGSTOP ) . unwrap ( ) ;
138
- Some ( ( ) )
139
149
}
140
150
141
151
pub unsafe fn end_ffi ( ) {
142
152
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
+ }
148
159
}
149
160
150
161
pub fn get_events ( ) -> Option < MemEvents > {
151
- let mut sv_guard = SUPERVISOR . lock ( ) . ok ( ) ? ;
162
+ let mut sv_guard = SUPERVISOR . lock ( ) . unwrap ( ) ;
152
163
let sv = sv_guard. take ( ) ?;
153
164
let ret = sv. r_event . recv ( ) . ok ( ) ;
154
165
* sv_guard = Some ( sv) ;
@@ -158,15 +169,15 @@ impl Supervisor {
158
169
159
170
#[ derive( Clone , Debug , serde:: Serialize , serde:: Deserialize ) ]
160
171
pub enum TraceRequest {
161
- BeginFfi ( Vec < usize > ) ,
172
+ BeginFfi ( Vec < u64 > ) ,
162
173
EndFfi ,
163
174
Die ,
164
175
}
165
176
166
177
#[ derive( serde:: Serialize , serde:: Deserialize , Debug ) ]
167
178
pub 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 ) > ,
170
181
}
171
182
172
183
#[ derive( serde:: Serialize , serde:: Deserialize , Debug , Clone ) ]
@@ -192,6 +203,20 @@ impl MemAccessType {
192
203
MemAccessType :: ReadWrite => ( ) ,
193
204
}
194
205
}
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
+ }
195
220
}
196
221
197
222
struct ChildListener {
@@ -249,8 +274,8 @@ impl Iterator for ChildListener {
249
274
/// created before the fork are the same).
250
275
fn sv_loop ( listener : ChildListener , t_event : ipc:: IpcSender < MemEvents > ) -> ! {
251
276
// 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 ! [ ] ;
254
279
255
280
// Memory allocated on the MiriMachine
256
281
let mut ch_pages = vec ! [ ] ;
@@ -329,7 +354,7 @@ fn sv_loop(listener: ChildListener, t_event: ipc::IpcSender<MemEvents>) -> ! {
329
354
#[ expect( clippy:: as_conversions) ]
330
355
if regs. retval ( ) as isize > 0 {
331
356
let addr = regs. retval ( ) ;
332
- mappings. push ( ( addr, len) ) ;
357
+ mappings. push ( ( addr. to_u64 ( ) , len. to_u64 ( ) ) ) ;
333
358
}
334
359
}
335
360
Err ( ret) => {
@@ -484,12 +509,12 @@ fn wait_for_syscall(pid: unistd::Pid, syscall: i64) -> Result<libc::user_regs_st
484
509
fn handle_munmap (
485
510
pid : unistd:: Pid ,
486
511
regs : libc:: user_regs_struct ,
487
- mappings : & mut Vec < ( usize , usize ) > ,
512
+ mappings : & mut Vec < ( u64 , u64 ) > ,
488
513
) -> Result < ( ) , i32 > {
489
514
// The unmap call might hit multiple mappings we've saved,
490
515
// 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 ( ) ;
493
518
let um_end = um_start. strict_add ( um_len) ;
494
519
let mut idxes = vec ! [ ] ;
495
520
for ( idx, & ( mp_start, len) ) in mappings. iter ( ) . enumerate ( ) {
@@ -536,11 +561,11 @@ fn handle_munmap(
536
561
537
562
fn handle_segfault (
538
563
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 ) > ,
541
566
) -> Result < ( ) , i32 > {
542
567
let siginfo = ptrace:: getsiginfo ( pid) . unwrap ( ) ;
543
- let addr = unsafe { siginfo. si_addr ( ) . addr ( ) } ;
568
+ let addr = unsafe { siginfo. si_addr ( ) . addr ( ) . to_u64 ( ) } ;
544
569
let page_addr = addr. strict_sub ( addr. strict_rem ( unsafe { PAGE_SIZE } ) ) ;
545
570
546
571
if ch_pages. contains ( & page_addr) {
@@ -590,7 +615,7 @@ fn handle_segfault(
590
615
let mut decoder = iced_x86:: Decoder :: new ( BITS , instr. as_slice ( ) , 0 ) ;
591
616
let mut fac = iced_x86:: InstructionInfoFactory :: new ( ) ;
592
617
let instr = decoder. decode ( ) ;
593
- let memsize = instr. op_code ( ) . memory_size ( ) . size ( ) ;
618
+ let memsize = instr. op_code ( ) . memory_size ( ) . size ( ) . to_u64 ( ) ;
594
619
let mem = fac. info ( & instr) . used_memory ( ) ;
595
620
let acc = mem. iter ( ) . fold ( None , |mut curr : Option < MemAccessType > , m| {
596
621
if let Some ( m) = match m. access ( ) {
@@ -635,7 +660,7 @@ fn handle_segfault(
635
660
636
661
fn handle_sigtrap (
637
662
pid : unistd:: Pid ,
638
- mappings : & mut Vec < ( usize , usize ) > ,
663
+ mappings : & mut Vec < ( u64 , u64 ) > ,
639
664
malloc_bytes : i64 ,
640
665
realloc_bytes : i64 ,
641
666
free_bytes : i64 ,
@@ -651,24 +676,28 @@ fn handle_sigtrap(
651
676
let regs = ptrace:: getregs ( pid) . unwrap ( ) ;
652
677
match regs. ip ( ) . strict_sub ( 1 ) {
653
678
a if a == malloc_addr => {
654
- let size = regs. arg1 ( ) ; // !
679
+ let size = regs. arg1 ( ) . to_u64 ( ) ; // !
655
680
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
+ }
657
684
}
658
685
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 ( ) ;
661
688
let pos = mappings
662
689
. iter ( )
663
690
. position ( |& ( ptr, size) | ptr <= old_ptr && old_ptr < ptr. strict_add ( size) ) ;
664
691
if let Some ( pos) = pos {
665
692
let _ = mappings. remove ( pos) ;
666
693
}
667
694
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
+ }
669
698
}
670
699
a if a == free_addr => {
671
- let old_ptr = regs. arg1 ( ) ;
700
+ let old_ptr = regs. arg1 ( ) . to_u64 ( ) ;
672
701
//let size = regs.rdi;
673
702
let pos = mappings
674
703
. iter ( )
@@ -692,7 +721,7 @@ fn intercept_retptr(
692
721
mut regs : libc:: user_regs_struct ,
693
722
fn_addr : usize ,
694
723
fn_bytes : i64 ,
695
- ) -> Result < usize , i32 > {
724
+ ) -> Result < isize , i32 > {
696
725
// Outline:
697
726
// - Move instr ptr back before the sigtrap happened
698
727
// - Restore the function to what it's supposed to be
@@ -715,7 +744,8 @@ fn intercept_retptr(
715
744
716
745
// now we're getting the return hopefully
717
746
let mut regs = ptrace:: getregs ( pid) . unwrap ( ) ;
718
- let ptr = regs. retval ( ) ; // !
747
+ #[ expect( clippy:: as_conversions) ]
748
+ let ptr = regs. retval ( ) as isize ; // !
719
749
regs. set_ip ( regs. ip ( ) . strict_sub ( 1 ) ) ;
720
750
ptrace:: write ( pid, std:: ptr:: without_provenance_mut ( fn_addr) , BREAKPT_INSTR ) . unwrap ( ) ;
721
751
ptrace:: write ( pid, std:: ptr:: without_provenance_mut ( ret_addr) , ret_bytes) . unwrap ( ) ;
@@ -729,7 +759,12 @@ fn intercept_retptr(
729
759
// manually, so we *must not ever* unwind from it
730
760
pub unsafe extern "C" fn mempr_off ( ) {
731
761
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
+ {
733
768
std:: process:: exit ( -20 ) ;
734
769
}
735
770
// 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() {
748
783
749
784
pub unsafe extern "C" fn mempr_on ( ) {
750
785
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
+ {
752
788
std:: process:: exit ( -22 ) ;
753
789
}
754
790
//let _ = libc::mprotect(PAGE_ADDR.wrapping_add(PAGE_SIZE), PAGE_SIZE, libc::PROT_NONE);
0 commit comments