Skip to content

Commit

Permalink
Support PTRACE_EVENT_VFORK_DONE for vforks via clone(CLONE_VFORK)
Browse files Browse the repository at this point in the history
Resolves #3560
  • Loading branch information
rocallahan committed Jul 17, 2023
1 parent 973d0d7 commit 331af65
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 29 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1638,6 +1638,7 @@ set(TESTS_WITHOUT_PROGRAM
tty
unmap_vdso
unwind_on_signal
vfork_done_clone
vfork_exec
vfork_break_parent
vsyscall_singlestep
Expand Down
13 changes: 6 additions & 7 deletions src/record_syscall.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6393,15 +6393,15 @@ static void rec_process_syscall_arch(RecordTask* t,
// syscall completes --- and that our TaskSyscallState infrastructure can't
// handle.
switch (syscallno) {
case Arch::vfork: {
if (t->emulated_ptrace_options & PTRACE_O_TRACEVFORKDONE) {
case Arch::vfork:
case Arch::fork:
case Arch::clone:
if ((syscallno == Arch::vfork ||
(syscallno == Arch::clone && (t->regs().arg1() & CLONE_VFORK))) &&
(t->emulated_ptrace_options & PTRACE_O_TRACEVFORKDONE)) {
t->emulate_ptrace_stop(
WaitStatus::for_ptrace_event(PTRACE_EVENT_VFORK_DONE));
}
RR_FALLTHROUGH;
}
case Arch::fork:
case Arch::clone: {
if (Arch::is_x86ish()) {
// On a 3.19.0-39-generic #44-Ubuntu kernel we have observed clone()
// clearing the parity flag internally.
Expand All @@ -6410,7 +6410,6 @@ static void rec_process_syscall_arch(RecordTask* t,
t->set_regs(r);
}
break;
}

case Arch::execve:
case Arch::execveat:
Expand Down
58 changes: 36 additions & 22 deletions src/test/vfork_done.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,42 +5,56 @@
#include <signal.h>

static int EXECUTION_FENCE_PIPES[2];
static char force_clone;
static char stack[65536];

static void seize(const pid_t pid) {
const int opts =
PTRACE_O_TRACEVFORK | PTRACE_O_TRACEVFORKDONE | PTRACE_O_TRACESYSGOOD;
test_assert(0 == ptrace(PTRACE_SEIZE, pid, 0, opts));
}

static int tracees(void) {
switch (vfork()) {
case -1:
exit(EXIT_FAILURE);
break;
// vfork-child
case 0: {
long res = 0;
for(int i = 1; i < 1000000; i++) {
for(int j = 1; j < 100; j++) {
res = (res / 3) + 14*i;
if(res /= res > 2) {
res = 3;
}
}
static int vfork_child(__attribute__((unused)) void* p) {
long res = 0;
for (int i = 1; i < 1000000; i++) {
for (int j = 1; j < 100; j++) {
res = (res / 3) + 14*i;
if (res /= res > 2) {
res = 3;
}
exit(99);
break;
}
// vfork-parent (fork-child)
default:
exit(66);
break;
}
exit(99);
return 0;
}

static int tracees(void) {
pid_t child;
if (force_clone) {
child = clone(vfork_child, stack + sizeof(stack),
CLONE_VFORK | CLONE_VM | SIGCHLD, NULL);
} else {
child = vfork();
if (!child) {
vfork_child(NULL);
return 0;
}
}
if (child < 0) {
exit(EXIT_FAILURE);
} else {
exit(66);
}
}

int main(void) {
int main(int argc, char** argv) {
char notify;
assert(0 == pipe(EXECUTION_FENCE_PIPES));

if (argc > 1 && !strcmp(argv[1], "clone")) {
force_clone = 1;
}

pid_t fork_child = fork();

switch (fork_child) {
Expand Down
6 changes: 6 additions & 0 deletions src/test/vfork_done_clone.run
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
source `dirname $0`/util.sh

save_exe vfork_done$bitness
just_record vfork_done$bitness-$nonce clone
replay
check EXIT-SUCCESS

0 comments on commit 331af65

Please sign in to comment.