Skip to content

Fix GH-22845: use-after-free with a stashed user-filter bucket brigade#22850

Open
iliaal wants to merge 1 commit into
php:PHP-8.4from
iliaal:fix/gh-22845-bucket-brigade-uaf-8.4
Open

Fix GH-22845: use-after-free with a stashed user-filter bucket brigade#22850
iliaal wants to merge 1 commit into
php:PHP-8.4from
iliaal:fix/gh-22845-bucket-brigade-uaf-8.4

Conversation

@iliaal

@iliaal iliaal commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

A user stream filter's filter($in, $out, ...) receives its bucket brigades as le_bucket_brigade resources, but every caller that dispatches a filter allocates those brigades on its own C stack. userfilter_filter only zval_ptr_dtors the argument zvals after the callback and never closes the resources, so a filter that stashes $in or $out keeps a resource whose ptr still points at the popped stack frame. stream_bucket_make_writeable() and stream_bucket_append() fetch by resource type only, so reusing a stashed brigade dereferences freed stack (ASAN reports stack-use-after-return). Closing both resources right after the callback invalidates any stashed copy, which then throws a TypeError instead of corrupting memory.

The callback is wrapped in zend_try/zend_catch so the close runs even when the filter bails out (a fatal error would otherwise longjmp past it, leaving the resource fetchable from a register_shutdown_function).

Fixes #22845

…gade

The bucket brigades passed to a user filter's filter() method are
allocated on the filter caller's C stack and handed to userland as
le_bucket_brigade resources, but userfilter_filter never closed them.
A filter that stashed $in or $out (e.g. in a global) kept a resource
whose ptr still pointed at the popped stack frame; the stream_bucket_*()
functions fetch by resource type only, so a later call dereferenced
freed stack. Close both resources after the callback so a stashed copy
becomes non-fetchable and throws instead, and wrap the callback in
zend_try/zend_catch so the close still runs when the filter bails out
(which otherwise longjmps past it and leaves the resource reachable from
a shutdown function).

Fixes phpGH-22845
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bucket brigade UAF

1 participant