@@ -125,8 +125,6 @@ pub enum ExecEvent {
125
125
pub struct ChildListener {
126
126
/// The matching channel for the child's `Supervisor` struct.
127
127
pub message_rx : ipc:: IpcReceiver < TraceRequest > ,
128
- /// The main child process' pid.
129
- pub pid : unistd:: Pid ,
130
128
/// Whether an FFI call is currently ongoing.
131
129
pub attached : bool ,
132
130
/// If `Some`, overrides the return code with the given value.
@@ -179,11 +177,8 @@ impl Iterator for ChildListener {
179
177
return Some ( ExecEvent :: Status ( pid, signal) ) ;
180
178
}
181
179
} else {
182
- // Log that this happened and pass along the signal.
183
- // If we don't do the kill, the child will instead
184
- // act as if it never received this signal!
185
- eprintln ! ( "Ignoring PtraceEvent {signal:?}" ) ;
186
- signal:: kill ( pid, signal) . unwrap ( ) ;
180
+ // Just pass along the signal
181
+ ptrace:: cont ( pid, signal) . unwrap ( ) ;
187
182
} ,
188
183
// Child was stopped at the given signal. Same logic as for
189
184
// WaitStatus::PtraceEvent
@@ -196,8 +191,7 @@ impl Iterator for ChildListener {
196
191
return Some ( ExecEvent :: Status ( pid, signal) ) ;
197
192
}
198
193
} else {
199
- eprintln ! ( "Ignoring Stopped {signal:?}" ) ;
200
- signal:: kill ( pid, signal) . unwrap ( ) ;
194
+ ptrace:: cont ( pid, signal) . unwrap ( ) ;
201
195
} ,
202
196
_ => ( ) ,
203
197
} ,
@@ -242,6 +236,7 @@ enum ExecError {
242
236
/// created before the fork - like statics - are the same).
243
237
pub fn sv_loop (
244
238
listener : ChildListener ,
239
+ init_pid : unistd:: Pid ,
245
240
event_tx : ipc:: IpcSender < MemEvents > ,
246
241
confirm_tx : ipc:: IpcSender < Confirmation > ,
247
242
page_size : usize ,
@@ -256,18 +251,18 @@ pub fn sv_loop(
256
251
// An instance of the Capstone disassembler, so we don't spawn one on every access
257
252
let cs = get_disasm ( ) ;
258
253
259
- // The pid of the process that we forked from , used by default if we don't
260
- // have a reason to use another one.
261
- let main_pid = listener . pid ;
254
+ // The pid of the last process we interacted with , used by default if we don't have a
255
+ // reason to use a different one
256
+ let mut curr_pid = init_pid ;
262
257
263
258
// There's an initial sigstop we need to deal with
264
- wait_for_signal ( main_pid , signal:: SIGSTOP , false ) . map_err ( |e| {
259
+ wait_for_signal ( Some ( curr_pid ) , signal:: SIGSTOP , false ) . map_err ( |e| {
265
260
match e {
266
261
ExecError :: Died ( code) => code,
267
262
ExecError :: Shrug => None ,
268
263
}
269
264
} ) ?;
270
- ptrace:: cont ( main_pid , None ) . unwrap ( ) ;
265
+ ptrace:: cont ( curr_pid , None ) . unwrap ( ) ;
271
266
272
267
for evt in listener {
273
268
match evt {
@@ -283,9 +278,11 @@ pub fn sv_loop(
283
278
// raise a SIGSTOP. We need it to be signal-stopped *and waited for* in
284
279
// order to do most ptrace operations!
285
280
confirm_tx. send ( Confirmation ) . unwrap ( ) ;
286
- wait_for_signal ( main_pid, signal:: SIGSTOP , false ) . unwrap ( ) ;
281
+ // We can't trust simply calling `Pid::this()` in the child process to give the right
282
+ // PID for us, so we get it this way
283
+ curr_pid = wait_for_signal ( None , signal:: SIGSTOP , false ) . unwrap ( ) ;
287
284
288
- ptrace:: syscall ( main_pid , None ) . unwrap ( ) ;
285
+ ptrace:: syscall ( curr_pid , None ) . unwrap ( ) ;
289
286
}
290
287
// end_ffi was called by the child
291
288
ExecEvent :: End => {
@@ -296,7 +293,7 @@ pub fn sv_loop(
296
293
ch_stack = None ;
297
294
298
295
// No need to monitor syscalls anymore, they'd just be ignored
299
- ptrace:: cont ( main_pid , None ) . unwrap ( ) ;
296
+ ptrace:: cont ( curr_pid , None ) . unwrap ( ) ;
300
297
}
301
298
// Child process was stopped by a signal
302
299
ExecEvent :: Status ( pid, signal) =>
@@ -370,41 +367,45 @@ fn get_disasm() -> capstone::Capstone {
370
367
371
368
/// Waits for `wait_signal`. If `init_cont`, it will first do a `ptrace::cont`.
372
369
/// We want to avoid that in some cases, like at the beginning of FFI.
370
+ ///
371
+ /// If `pid` is `None`, only one wait will be done and `init_cont` should be false.
373
372
fn wait_for_signal (
374
- pid : unistd:: Pid ,
373
+ pid : Option < unistd:: Pid > ,
375
374
wait_signal : signal:: Signal ,
376
375
init_cont : bool ,
377
- ) -> Result < ( ) , ExecError > {
376
+ ) -> Result < unistd :: Pid , ExecError > {
378
377
if init_cont {
379
- ptrace:: cont ( pid, None ) . unwrap ( ) ;
378
+ ptrace:: cont ( pid. unwrap ( ) , None ) . unwrap ( ) ;
380
379
}
381
380
// Repeatedly call `waitid` until we get the signal we want, or the process dies
382
381
loop {
383
- let stat =
384
- wait:: waitid ( wait:: Id :: Pid ( pid) , WAIT_FLAGS ) . map_err ( |_| ExecError :: Died ( None ) ) ?;
385
- let signal = match stat {
382
+ let wait_id = match pid {
383
+ Some ( pid) => wait:: Id :: Pid ( pid) ,
384
+ None => wait:: Id :: All ,
385
+ } ;
386
+ let stat = wait:: waitid ( wait_id, WAIT_FLAGS ) . map_err ( |_| ExecError :: Died ( None ) ) ?;
387
+ let ( signal, pid) = match stat {
386
388
// Report the cause of death, if we know it
387
389
wait:: WaitStatus :: Exited ( _, code) => {
388
390
//eprintln!("Exited sig1 {code}");
389
391
return Err ( ExecError :: Died ( Some ( code) ) ) ;
390
392
}
391
393
wait:: WaitStatus :: Signaled ( _, _, _) => return Err ( ExecError :: Died ( None ) ) ,
392
- wait:: WaitStatus :: Stopped ( _ , signal) => signal,
393
- wait:: WaitStatus :: PtraceEvent ( _ , signal, _) => signal,
394
+ wait:: WaitStatus :: Stopped ( pid , signal) => ( signal, pid ) ,
395
+ wait:: WaitStatus :: PtraceEvent ( pid , signal, _) => ( signal, pid ) ,
394
396
// This covers PtraceSyscall and variants that are impossible with
395
397
// the flags set (e.g. WaitStatus::StillAlive)
396
398
_ => {
397
- ptrace:: cont ( pid, None ) . unwrap ( ) ;
399
+ ptrace:: cont ( pid. unwrap ( ) , None ) . unwrap ( ) ;
398
400
continue ;
399
401
}
400
402
} ;
401
403
if signal == wait_signal {
402
- break ;
404
+ return Ok ( pid ) ;
403
405
} else {
404
406
ptrace:: cont ( pid, None ) . map_err ( |_| ExecError :: Died ( None ) ) ?;
405
407
}
406
408
}
407
- Ok ( ( ) )
408
409
}
409
410
410
411
/// Grabs the access that caused a segfault and logs it down if it's to our memory,
@@ -582,7 +583,7 @@ fn handle_segfault(
582
583
ptrace:: setregs ( pid, new_regs) . unwrap ( ) ;
583
584
584
585
// Our mempr_* functions end with a raise(SIGSTOP)
585
- wait_for_signal ( pid, signal:: SIGSTOP , true ) ?;
586
+ wait_for_signal ( Some ( pid) , signal:: SIGSTOP , true ) ?;
586
587
587
588
// Step 1 instruction
588
589
ptrace:: setregs ( pid, regs_bak) . unwrap ( ) ;
@@ -625,7 +626,7 @@ fn handle_segfault(
625
626
new_regs. set_ip ( mempr_on as usize ) ;
626
627
new_regs. set_sp ( stack_ptr) ;
627
628
ptrace:: setregs ( pid, new_regs) . unwrap ( ) ;
628
- wait_for_signal ( pid, signal:: SIGSTOP , true ) ?;
629
+ wait_for_signal ( Some ( pid) , signal:: SIGSTOP , true ) ?;
629
630
630
631
ptrace:: setregs ( pid, regs_bak) . unwrap ( ) ;
631
632
ptrace:: syscall ( pid, None ) . unwrap ( ) ;
0 commit comments