@@ -52,30 +52,40 @@ impl Supervisor {
5252 // If the supervisor is not initialised for whatever reason, fast-fail.
5353 // This might be desired behaviour, as even on platforms where ptracing
5454 // is not implemented it enables us to enforce that only one FFI call
55- // happens at a time
55+ // happens at a time.
5656 let Some ( sv) = sv_guard. take ( ) else {
5757 return ( sv_guard, None ) ;
5858 } ;
5959
6060 // Get pointers to all the pages the supervisor must allow accesses in
61- // and prepare the fake stack
61+ // and prepare the fake stack.
6262 let page_ptrs = alloc. borrow ( ) . pages ( ) ;
6363 let raw_stack_ptr: * mut [ u8 ; FAKE_STACK_SIZE ] =
6464 Box :: leak ( Box :: new ( [ 0u8 ; FAKE_STACK_SIZE ] ) ) . as_mut_ptr ( ) . cast ( ) ;
6565 let stack_ptr = raw_stack_ptr. expose_provenance ( ) ;
6666 let start_info = StartFfiInfo { page_ptrs, stack_ptr } ;
6767
68+ // SAFETY: We do not access machine memory past this point until the
69+ // supervisor is ready to allow it.
70+ unsafe {
71+ if alloc. borrow_mut ( ) . prepare_ffi ( ) . is_err ( ) {
72+ // Don't mess up unwinding by maybe leaving the memory partly protected
73+ alloc. borrow_mut ( ) . unprep_ffi ( ) ;
74+ panic ! ( "Cannot protect memory for FFI call!" ) ;
75+ }
76+ }
77+
6878 // Send over the info.
6979 // NB: if we do not wait to receive a blank confirmation response, it is
7080 // possible that the supervisor is alerted of the SIGSTOP *before* it has
7181 // actually received the start_info, thus deadlocking! This way, we can
72- // enforce an ordering for these events
82+ // enforce an ordering for these events.
7383 sv. message_tx . send ( TraceRequest :: StartFfi ( start_info) ) . unwrap ( ) ;
7484 sv. confirm_rx . recv ( ) . unwrap ( ) ;
7585 * sv_guard = Some ( sv) ;
7686 // We need to be stopped for the supervisor to be able to make certain
7787 // modifications to our memory - simply waiting on the recv() doesn't
78- // count
88+ // count.
7989 signal:: raise ( signal:: SIGSTOP ) . unwrap ( ) ;
8090 ( sv_guard, Some ( raw_stack_ptr) )
8191 }
@@ -90,7 +100,7 @@ impl Supervisor {
90100 /// one passed to it also.
91101 pub unsafe fn end_ffi (
92102 mut sv_guard : std:: sync:: MutexGuard < ' static , Option < Supervisor > > ,
93- _alloc : Rc < RefCell < IsolatedAlloc > > ,
103+ alloc : Rc < RefCell < IsolatedAlloc > > ,
94104 raw_stack_ptr : Option < * mut [ u8 ; FAKE_STACK_SIZE ] > ,
95105 ) -> Option < MemEvents > {
96106 // We can't use IPC channels here to signal that FFI mode has ended,
@@ -99,19 +109,22 @@ impl Supervisor {
99109 // simpler and more robust to simply use the signals which are left for
100110 // arbitrary usage. Since this will block until we are continued by the
101111 // supervisor, we can assume past this point that everything is back to
102- // normal
112+ // normal.
103113 signal:: raise ( signal:: SIGUSR1 ) . unwrap ( ) ;
104114
115+ // This is safe! It just sets memory to normal expected permissions.
116+ alloc. borrow_mut ( ) . unprep_ffi ( ) ;
117+
105118 // If this is `None`, then `raw_stack_ptr` is None and does not need to
106119 // be deallocated (and there's no need to worry about the guard, since
107- // it contains nothing)
120+ // it contains nothing).
108121 let sv = sv_guard. take ( ) ?;
109122 // SAFETY: Caller upholds that this pointer was allocated as a box with
110- // this type
123+ // this type.
111124 unsafe {
112125 drop ( Box :: from_raw ( raw_stack_ptr. unwrap ( ) ) ) ;
113126 }
114- // On the off-chance something really weird happens, don't block forever
127+ // On the off-chance something really weird happens, don't block forever.
115128 let ret = sv
116129 . event_rx
117130 . try_recv_timeout ( std:: time:: Duration :: from_secs ( 5 ) )
@@ -138,71 +151,71 @@ impl Supervisor {
138151/// The invariants for `fork()` must be upheld by the caller.
139152pub unsafe fn init_sv ( ) -> Result < ( ) , SvInitError > {
140153 // FIXME: Much of this could be reimplemented via the mitosis crate if we upstream the
141- // relevant missing bits
154+ // relevant missing bits.
142155
143156 // On Linux, this will check whether ptrace is fully disabled by the Yama module.
144157 // If Yama isn't running or we're not on Linux, we'll still error later, but
145- // this saves a very expensive fork call
158+ // this saves a very expensive fork call.
146159 let ptrace_status = std:: fs:: read_to_string ( "/proc/sys/kernel/yama/ptrace_scope" ) ;
147160 if let Ok ( stat) = ptrace_status {
148161 if let Some ( stat) = stat. chars ( ) . next ( ) {
149- // Fast-error if ptrace is fully disabled on the system
162+ // Fast-error if ptrace is fully disabled on the system.
150163 if stat == '3' {
151164 return Err ( SvInitError ) ;
152165 }
153166 }
154167 }
155168
156- // Initialise the supervisor if it isn't already, placing it into SUPERVISOR
169+ // Initialise the supervisor if it isn't already, placing it into SUPERVISOR.
157170 let mut lock = SUPERVISOR . lock ( ) . unwrap ( ) ;
158171 if lock. is_some ( ) {
159172 return Ok ( ( ) ) ;
160173 }
161174
162- // Prepare the IPC channels we need
175+ // Prepare the IPC channels we need.
163176 let ( message_tx, message_rx) = ipc:: channel ( ) . unwrap ( ) ;
164177 let ( confirm_tx, confirm_rx) = ipc:: channel ( ) . unwrap ( ) ;
165178 let ( event_tx, event_rx) = ipc:: channel ( ) . unwrap ( ) ;
166- // SAFETY: Calling sysconf(_SC_PAGESIZE) is always safe and cannot error
179+ // SAFETY: Calling sysconf(_SC_PAGESIZE) is always safe and cannot error.
167180 let page_size = unsafe { libc:: sysconf ( libc:: _SC_PAGESIZE) } . try_into ( ) . unwrap ( ) ;
181+ super :: parent:: PAGE_SIZE . store ( page_size, std:: sync:: atomic:: Ordering :: Relaxed ) ;
168182
169183 unsafe {
170184 // TODO: Maybe use clone3() instead for better signalling of when the child exits?
171185 // SAFETY: Caller upholds that only one thread exists.
172186 match unistd:: fork ( ) . unwrap ( ) {
173187 unistd:: ForkResult :: Parent { child } => {
174188 // If somehow another thread does exist, prevent it from accessing the lock
175- // and thus breaking our safety invariants
189+ // and thus breaking our safety invariants.
176190 std:: mem:: forget ( lock) ;
177191 // The child process is free to unwind, so we won't to avoid doubly freeing
178- // system resources
192+ // system resources.
179193 let init = std:: panic:: catch_unwind ( || {
180194 let listener =
181195 ChildListener { message_rx, attached : false , override_retcode : None } ;
182- // Trace as many things as possible, to be able to handle them as needed
196+ // Trace as many things as possible, to be able to handle them as needed.
183197 let options = ptrace:: Options :: PTRACE_O_TRACESYSGOOD
184198 | ptrace:: Options :: PTRACE_O_TRACECLONE
185199 | ptrace:: Options :: PTRACE_O_TRACEFORK ;
186- // Attach to the child process without stopping it
200+ // Attach to the child process without stopping it.
187201 match ptrace:: seize ( child, options) {
188202 // Ptrace works :D
189203 Ok ( _) => {
190- let code = sv_loop ( listener, child, event_tx, confirm_tx, page_size)
191- . unwrap_err ( ) ;
204+ let code = sv_loop ( listener, child, event_tx, confirm_tx) . unwrap_err ( ) ;
192205 // If a return code of 0 is not explicitly given, assume something went
193- // wrong and return 1
206+ // wrong and return 1.
194207 std:: process:: exit ( code. unwrap_or ( 1 ) )
195208 }
196- // Ptrace does not work and we failed to catch that
209+ // Ptrace does not work and we failed to catch that.
197210 Err ( _) => {
198- // If we can't ptrace, Miri continues being the parent
211+ // If we can't ptrace, Miri continues being the parent.
199212 signal:: kill ( child, signal:: SIGKILL ) . unwrap ( ) ;
200213 SvInitError
201214 }
202215 }
203216 } ) ;
204217 match init {
205- // The "Ok" case means that we couldn't ptrace
218+ // The "Ok" case means that we couldn't ptrace.
206219 Ok ( e) => return Err ( e) ,
207220 Err ( p) => {
208221 eprintln ! ( "Supervisor process panicked!\n {p:?}" ) ;
@@ -212,12 +225,12 @@ pub unsafe fn init_sv() -> Result<(), SvInitError> {
212225 }
213226 unistd:: ForkResult :: Child => {
214227 // Make sure we never get orphaned and stuck in SIGSTOP or similar
215- // SAFETY: prctl PR_SET_PDEATHSIG is always safe to call
228+ // SAFETY: prctl PR_SET_PDEATHSIG is always safe to call.
216229 let ret = libc:: prctl ( libc:: PR_SET_PDEATHSIG , libc:: SIGTERM ) ;
217230 assert_eq ! ( ret, 0 ) ;
218231 // First make sure the parent succeeded with ptracing us!
219232 signal:: raise ( signal:: SIGSTOP ) . unwrap ( ) ;
220- // If we're the child process, save the supervisor info
233+ // If we're the child process, save the supervisor info.
221234 * lock = Some ( Supervisor { message_tx, confirm_rx, event_rx } ) ;
222235 }
223236 }
0 commit comments