Skip to content

feat(sched): made tasks reference counted and closed use-after-free races in the wake and kill paths - #178

Merged
FlareCoding merged 12 commits into
masterfrom
pr/task-lifetime-refcounting
Aug 28, 2026
Merged

feat(sched): made tasks reference counted and closed use-after-free races in the wake and kill paths#178
FlareCoding merged 12 commits into
masterfrom
pr/task-lifetime-refcounting

Conversation

@FlareCoding

@FlareCoding FlareCoding commented Aug 28, 2026

Copy link
Copy Markdown
Owner

Note

High Risk
Touches core scheduler teardown, signal delivery, and synchronization primitives; refcount or lock-order mistakes could cause use-after-free, missed wakeups, or stuck tasks.

Overview
Makes sched::task refcounted so teardown goes through release()task::ref_destroy() → the reaper, with the scheduler dropping the initial reference only after off-CPU publication in finalize_pending_off_cpu.

Adds task_ref / task_ref_by_tid and updates wake, kill, signals, futex, wait queues, and proc close/kill to hold strong_ref pins and call sched::wake / force_wake_for_kill only after spinlocks drop, avoiding use-after-free when a remote wake spins for off-CPU.

Leader exit batches thread teardown under tg->lock, defers wake_all on proc wait queues and kill wakes until the lock is released, and uses refcount drops instead of immediate reaper::defer on every thread. destroy_unstarted_task claims TASK_STATE_CREATED, drops proc refs, and joins the same staged reaper path instead of freeing inline.

On context switch, fatal signals are not applied while TASK_FLAG_IN_SYSCALL is set (syscall exit still handles death). send_to_group_id no longer stops at 64 groups—it iterates by smallest leader pid above a cursor until every matching process group is signaled. Tests add task pins for kill paths and a 67-group group-id send regression.

Reviewed by Cursor Bugbot for commit 499ab98. Bugbot is set up for automated code reviews on this repo. Configure here.

cursor[bot]

This comment was marked as resolved.

A group-id send collected matching groups into a fixed 64-entry batch
and silently skipped the rest while still reporting success, so a kill
of a large process group left some of its processes running. Each
registry pass now sends to the group with the smallest leader pid above
a cursor, visiting every matching group exactly once however many
exist. Leader pids are allocated monotonically and never reused, which
makes the cursor a stable iteration order.
…n unstarted task

Closing a process handle released the child's proc resource reference
before claiming the task, while a concurrent group teardown claiming
the same CREATED task released it again after winning the state CAS,
dropping the reference twice. The CAS is the mutual exclusion for
unstarted teardown, so the release now lives behind it and only the
winning path touches the reference. Every other destroy_unstarted_task
caller runs before a proc resource exists, so the move changes nothing
for them.
…r its lock

The wake pin contract forbids holding an irqsave spinlock across a wake
because of the remote off-CPU spin, yet the timer expiry walk does
exactly that and is correct. Sleepers always re-take the queue lock in
cancel_sleep before they can exit, and a task sleeps on the CPU whose
queue holds it, so an expiry wake never spins. Recording the argument
keeps the walk from being either miscorrected or copied into a context
where it does not hold.
…erences

The leader teardown batch carried raw proc_resource pointers with
hand-rolled release and destroy calls, the one remaining wake batch not
expressed through strong_ref. Adopting the thread's reference into the
batch lets scope handle the release and keeps every deferred-wake batch
on the same ownership idiom.
@FlareCoding
FlareCoding merged commit 90faaa5 into master Aug 28, 2026
19 checks passed
@FlareCoding
FlareCoding deleted the pr/task-lifetime-refcounting branch August 28, 2026 18:56
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.

1 participant