fix(bug-1733): fix heap-use-after-free race in vtask_enq()

vtask_enq() published a task onto the shared dispatch queue via
dataq_enq() before finishing its own initialization (task->owner) -- a
concurrent vcpu could dequeue, run, and free the task before the
producer's own write executed, an ASAN-confirmed UAF that crashed 2 of
3 controllers under a heavy burst-array-job HA workload. Moved
task->owner = vtaskmgr before the publish, mirroring the endpoint_ref-
before-publish discipline already established two lines above it
(bug-1298). Adds a stress-test regression guard (test_vtask_enq_race.c).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019QxaSzHRB7pmYFp4cVnwkA
This commit is contained in:
Rongsong Shen 2026-08-29 11:28:48 +00:00
parent b1323f8dab
commit 42e1eeaa29
No known key found for this signature in database
GPG key ID: 5BCDAAE0123E9FE2
4 changed files with 159 additions and 1 deletions

View file

@ -511,10 +511,19 @@ int vtask_enq(vtaskmgr_t* vtaskmgr, vtask_t* task)
endpoint_ref(ep);
}
/* bug-1733: task->owner must be set BEFORE dataq_enq() publishes the task
* to the dispatcher, mirroring the endpoint_ref-before-publish discipline
* just above — a concurrent vcpu can dequeue, run (run_task() itself reads
* task->owner to release a REQ_BLOCK admission slot and wake the
* dispatcher), and free this task before the next line here would
* otherwise run, which is a heap-use-after-free write on freed memory
* (and, short of that exact timing, a missed admission-release/wakeup if
* run_task read owner while it was still NULL). */
task->owner = vtaskmgr;
rc = dataq_enq(&(vtaskmgr->taskq), &(task->link));
if (rc >= 0) {
/* wake up task dispatcher */
task->owner = vtaskmgr;
vtaskmgr_wakeup(vtaskmgr);
} else if (ep != NULL) {
/* enqueue failed — the task never entered the queue; drop the ref we