Skip to content

Don't inherit POSIX timers across fork - #2773

Open
emkey1 wants to merge 1 commit into
ish-app:masterfrom
emkey1:fix_fork_posix_timers
Open

Don't inherit POSIX timers across fork#2773
emkey1 wants to merge 1 commit into
ish-app:masterfrom
emkey1:fix_fork_posix_timers

Conversation

@emkey1

@emkey1 emkey1 commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

tgroup_copy does *group = *old_group, which copies posix_timers[] wholesale — including each entry's struct timer *. The child therefore starts life believing it owns the parent's timers, and timer_delete on an inherited id frees a timer object the parent still owns and whose callback is still armed.

Linux does not inherit POSIX timers across fork. (A thread clone shares the tgroup, so that case is already correct.) This clears the array in the copy.

Testing

Repro: parent creates a SIGEV_SIGNAL timer, arms it, forks; the child calls timer_delete on the inherited id, and the parent then deletes its own.

child's timer_delete(inherited) outcome
Linux (x86 Ubuntu) -1 EINVAL parent's timer unaffected
master 0 (succeeds) frees the parent's live timer, ish dies
this branch -1 EINVAL parent's own timer_delete still succeeds

One thing to note while you are looking at this: POSIX timers do not appear to deliver signals at all on master, fork or no fork — a SIGEV_SIGNAL timer armed with a 20ms interval never fired in my testing, with no fork involved. That is a separate gap and this PR does not touch it, but it means the "parent's timer keeps firing" half of the story cannot currently be demonstrated. The double-free is independently reproducible as above.

Also ran a shell smoke test over an Alpine rootfs (directory walks, /proc reads, fork/exec churn, redirects, pipes) with no change in behavior.

🤖 Generated with Claude Code

@saagarjha saagarjha left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While we care less about commit messages this is clear enough that it doesn't really need a body

Comment thread kernel/fork.c Outdated
Comment on lines +48 to +53
// POSIX timers are not inherited across fork. The struct copy above
// duplicated posix_timers[], including each entry's struct timer pointer,
// so the child saw the parent's timers as its own and timer_delete() in
// the child freed a timer the parent still owns and is still running.
for (int i = 0; i < TIMERS_MAX; i++)
group->posix_timers[i] = (struct posix_timer) {};

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// POSIX timers are not inherited across fork. The struct copy above
// duplicated posix_timers[], including each entry's struct timer pointer,
// so the child saw the parent's timers as its own and timer_delete() in
// the child freed a timer the parent still owns and is still running.
for (int i = 0; i < TIMERS_MAX; i++)
group->posix_timers[i] = (struct posix_timer) {};
// POSIX timers are not inherited across fork
for (int i = 0; i < TIMERS_MAX; i++) {
group->posix_timers[i] = (struct posix_timer) {};
}

@emkey1
emkey1 force-pushed the fix_fork_posix_timers branch from e384d05 to 8d12a90 Compare July 29, 2026 18:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants