Skip to content

#146 flock: move task data off the caller stack (UAF on cancel)#8

Merged
EdmondDantes merged 1 commit into
true-async-stablefrom
146-flock-stack-uaf-on-cancel
May 25, 2026
Merged

#146 flock: move task data off the caller stack (UAF on cancel)#8
EdmondDantes merged 1 commit into
true-async-stablefrom
146-flock-stack-uaf-on-cancel

Conversation

@EdmondDantes
Copy link
Copy Markdown

Bug

`php_stdiop_flock_task_data_t` was on the caller's stack while the libuv worker thread held a pointer to it. On AsyncCancellation mid-suspend the caller frame unwound and the still-running worker wrote into a freed stack slot. ASAN traced it precisely:

```
==…==ERROR: AddressSanitizer: stack-use-after-return
WRITE of size 4 in php_stdiop_flock_task_run main/streams/plain_wrapper.c:1097 (thread T4 = libuv worker)
```

Reproducible with ~20 lines (see php#146).

Fix

Allocate the task with inline-tail storage via the existing `ZEND_ASYNC_NEW_TASK_EX(run, data, extra_size)` API — `flock_data` lives at the tail of the task struct itself. The task is refcounted and survives caller unwind; `libuv_task_dispose`'s `pefree(task)` frees the inline data as part of normal cleanup.

No ABI changes, no new helpers — uses existing public task API.

Audit

Grepped for other `ZEND_ASYNC_NEW_TASK*` callsites in core: only this one. No similar stack-data-into-async-worker patterns elsewhere.

Test

Fixes php#146

php_stdiop_flock_task_data_t was on the caller's stack while the libuv
worker held a pointer to it. On AsyncCancellation mid-suspend the caller
frame unwound and the still-running worker wrote into a freed stack slot
(stack-use-after-return).

Allocate the task with inline-tail storage (ZEND_ASYNC_NEW_TASK_EX), so
flock_data lives at the tail of the task struct itself. The task is
refcounted and survives caller unwind; libuv_task_dispose's pefree(task)
frees the inline data on its own.

Found via ext/async/fuzzy-tests/io/flock_chaos.feature; the
cancel-mid-flock scenarios SEGV'd instantly on ASAN-ZTS. After this fix
they pass on fifo + 4 random seeds plus ASAN-ZTS; full ext/async/tests/io
suite (84 phpt) stays green.

Fixes true-async/php-async#146
@EdmondDantes EdmondDantes requested a review from bukka as a code owner May 24, 2026 16:53
@EdmondDantes EdmondDantes merged commit 4dc419c into true-async-stable May 25, 2026
10 of 18 checks passed
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