From 0096d1896083f0df73e086b1e086ec52f610b7bf Mon Sep 17 00:00:00 2001 From: Matt Hunter Date: Wed, 3 Sep 2025 01:21:34 -0400 Subject: Manually uninstall breakpoints on process fork Previously, there was a bug on PTRACE_EVENT_FORK in which the forked child process inherits all installed breakpoints due to their interrupt instructions being resident in memory at the time of the fork, but the debugger initializes the new process model with an empty list of breakpoints. There are some differing opinions on what the correct behavior ought to be here, but at a minimum these two realities must be brought into sync to prevent data corruption or any process crash of the fork child. For the time being, manually "uninstall" the residual breakpoint interrupts from a newly forked child that we attach to, leaving it with no breakpoints of any kind. Process model initialization in the debugger is left as-is. Signed-off-by: Matt Hunter --- debugger.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'debugger.c') diff --git a/debugger.c b/debugger.c index 7378298..c3c9fa1 100644 --- a/debugger.c +++ b/debugger.c @@ -113,6 +113,15 @@ static void uninstall_breakpoints(struct thread *th) { } } +static void clean_fork_breakpoints(struct thread *th, const struct process *parent) { + const struct list *breaks = &parent->breakpoints; + for (struct breakpoint *b = breaks->tail; b != breaks->end; b = b->prev) { + if (b->installed) { + ptrace(PTRACE_POKETEXT, th->id, b->address, b->text); + } + } +} + static int detect_breakpoint(struct thread *th, int *restart) { int is_bp = 0; /* at least 1 effective breakpoint at this PC */ int is_user = 0; /* at least 1 user-defined bp at this PC */ @@ -393,6 +402,8 @@ static int wait_thread(struct thread *th) { //while (!wait_thread(eventth)) {} dbg_sync(eventproc); + clean_fork_breakpoints(eventth, th->proc); + th->stopped = 1; th->signal = 0; th->doing = 0; -- cgit v1.2.3