php / php/php-src

Bucket brigade UAF

Open
#22,845 4 comments 0 reactions 1 assignee View on GitHub

@iliaal is already working on this.

Since Jul 21, 2026.

Bug Category: Streams Status: Verified
Dominant language
C
Stars
40.4k
Forks
8.1k
Avg merge
2d 13h
Merged PRs (30d)
96

Description

Description

php_user_filter's filter($in, $out, ...) receives $in and $out as PHP resources created by zend_register_resource() in userfilter_filter() but those php_stream_bucket_brigade structures are allocated on the C stack of the calling function (brig_a/brig_b in _php_stream_filter_flush, filter.c:452; brig_in/brig_out in _php_stream_filter_append filter.c:366). The le_bucket_brigade resource type has no destructor (user_filters.c:91), and after the callback returns the code only runs zval_ptr_dtor() on its local references (user_filters.c:249-250) without ever calling zend_list_close() so a resource copy stashed by userland (e.g. $GLOBALS['x'] = $in;) survives with res->ptr still pointing at the now-freed stack frame. When that stale resource is later passed to stream_bucket_make_writeable() or stream_bucket_append(), zend_fetch_resource() succeeds (it only checks the resource type, not liveness) and returns the dangling brigade pointer, which is then dereferenced - a use-after-free read and via brigade->tail->next = bucket a use-after-free write into freed stack memory. The root cause is that a request-lived PHP resource is allowed to outlive its stack-allocated backing store without being invalidated. The fix is to call zend_list_close(Z_RES(args[0])) / zend_list_close(Z_RES(args[1])) immediately after the filter() call (before the zval_ptr_dtors) so any stored copies become non-fetchable, or to stop backing these resources with stack memory.

PHP Version
8.6.0-dev
Operating System

No response

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.