Skip to content

Commit e560782

Browse files
committed
fix the early init
1 parent b65f449 commit e560782

File tree

1 file changed

+31
-30
lines changed

1 file changed

+31
-30
lines changed

src/shims/trace/parent.rs

Lines changed: 31 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,6 @@ pub enum ExecEvent {
125125
pub struct ChildListener {
126126
/// The matching channel for the child's `Supervisor` struct.
127127
pub message_rx: ipc::IpcReceiver<TraceRequest>,
128-
/// The main child process' pid.
129-
pub pid: unistd::Pid,
130128
/// Whether an FFI call is currently ongoing.
131129
pub attached: bool,
132130
/// If `Some`, overrides the return code with the given value.
@@ -179,11 +177,8 @@ impl Iterator for ChildListener {
179177
return Some(ExecEvent::Status(pid, signal));
180178
}
181179
} 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();
187182
},
188183
// Child was stopped at the given signal. Same logic as for
189184
// WaitStatus::PtraceEvent
@@ -196,8 +191,7 @@ impl Iterator for ChildListener {
196191
return Some(ExecEvent::Status(pid, signal));
197192
}
198193
} else {
199-
eprintln!("Ignoring Stopped {signal:?}");
200-
signal::kill(pid, signal).unwrap();
194+
ptrace::cont(pid, signal).unwrap();
201195
},
202196
_ => (),
203197
},
@@ -242,6 +236,7 @@ enum ExecError {
242236
/// created before the fork - like statics - are the same).
243237
pub fn sv_loop(
244238
listener: ChildListener,
239+
init_pid: unistd::Pid,
245240
event_tx: ipc::IpcSender<MemEvents>,
246241
confirm_tx: ipc::IpcSender<Confirmation>,
247242
page_size: usize,
@@ -256,18 +251,18 @@ pub fn sv_loop(
256251
// An instance of the Capstone disassembler, so we don't spawn one on every access
257252
let cs = get_disasm();
258253

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

263258
// 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| {
265260
match e {
266261
ExecError::Died(code) => code,
267262
ExecError::Shrug => None,
268263
}
269264
})?;
270-
ptrace::cont(main_pid, None).unwrap();
265+
ptrace::cont(curr_pid, None).unwrap();
271266

272267
for evt in listener {
273268
match evt {
@@ -283,9 +278,11 @@ pub fn sv_loop(
283278
// raise a SIGSTOP. We need it to be signal-stopped *and waited for* in
284279
// order to do most ptrace operations!
285280
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();
287284

288-
ptrace::syscall(main_pid, None).unwrap();
285+
ptrace::syscall(curr_pid, None).unwrap();
289286
}
290287
// end_ffi was called by the child
291288
ExecEvent::End => {
@@ -296,7 +293,7 @@ pub fn sv_loop(
296293
ch_stack = None;
297294

298295
// 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();
300297
}
301298
// Child process was stopped by a signal
302299
ExecEvent::Status(pid, signal) =>
@@ -370,41 +367,45 @@ fn get_disasm() -> capstone::Capstone {
370367

371368
/// Waits for `wait_signal`. If `init_cont`, it will first do a `ptrace::cont`.
372369
/// 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.
373372
fn wait_for_signal(
374-
pid: unistd::Pid,
373+
pid: Option<unistd::Pid>,
375374
wait_signal: signal::Signal,
376375
init_cont: bool,
377-
) -> Result<(), ExecError> {
376+
) -> Result<unistd::Pid, ExecError> {
378377
if init_cont {
379-
ptrace::cont(pid, None).unwrap();
378+
ptrace::cont(pid.unwrap(), None).unwrap();
380379
}
381380
// Repeatedly call `waitid` until we get the signal we want, or the process dies
382381
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 {
386388
// Report the cause of death, if we know it
387389
wait::WaitStatus::Exited(_, code) => {
388390
//eprintln!("Exited sig1 {code}");
389391
return Err(ExecError::Died(Some(code)));
390392
}
391393
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),
394396
// This covers PtraceSyscall and variants that are impossible with
395397
// the flags set (e.g. WaitStatus::StillAlive)
396398
_ => {
397-
ptrace::cont(pid, None).unwrap();
399+
ptrace::cont(pid.unwrap(), None).unwrap();
398400
continue;
399401
}
400402
};
401403
if signal == wait_signal {
402-
break;
404+
return Ok(pid);
403405
} else {
404406
ptrace::cont(pid, None).map_err(|_| ExecError::Died(None))?;
405407
}
406408
}
407-
Ok(())
408409
}
409410

410411
/// Grabs the access that caused a segfault and logs it down if it's to our memory,
@@ -582,7 +583,7 @@ fn handle_segfault(
582583
ptrace::setregs(pid, new_regs).unwrap();
583584

584585
// 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)?;
586587

587588
// Step 1 instruction
588589
ptrace::setregs(pid, regs_bak).unwrap();
@@ -625,7 +626,7 @@ fn handle_segfault(
625626
new_regs.set_ip(mempr_on as usize);
626627
new_regs.set_sp(stack_ptr);
627628
ptrace::setregs(pid, new_regs).unwrap();
628-
wait_for_signal(pid, signal::SIGSTOP, true)?;
629+
wait_for_signal(Some(pid), signal::SIGSTOP, true)?;
629630

630631
ptrace::setregs(pid, regs_bak).unwrap();
631632
ptrace::syscall(pid, None).unwrap();

0 commit comments

Comments
 (0)