Bucket brigade UAF
- 主要语言
- C
- 星标
- 40.4k
- 派生
- 8.2k
- 平均合并
- 2 天 15 小时
- 30 天内合并 PR
- 103
描述
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
贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
评估
这个 Issue 还没有评估数据。