Fix GH-22063: stream filter chain UAF on self-removal during callback#22083
Fix GH-22063: stream filter chain UAF on self-removal during callback#22083iliaal wants to merge 1 commit into
Conversation
A stream filter struct must stay live while a fops->filter() callback or chain iteration holds it. A php_user_filter that removes its own resource inside filter() frees the struct under userfilter_filter (&thisfilter->abstract deref) and under the three chain-walk sites (current->next read). Defer pefree via an in_callback counter until every C-level frame holding the filter releases it. Closes phpGH-22063
arnaud-lb
left a comment
There was a problem hiding this comment.
This looks right, but I'm wondering if it is possible to fix this in a way that doesn't force all filter iterators to pay attention to removal.
This affects only user filters, and only when removing themselves.
A related issue with user filters is that they were able to close the stream. This has been fixed by flagging the stream in userfilter_filter().
|
The iterators' Closest alternative: stream-level deferred-free flag + list, each iterator brackets its loop with set/clear/drain. That moves per-iteration logic to per-loop boundaries, I can try that approach if you want? |
A
php_user_filterthat callsstream_filter_removeon its own resource from insidefilter()frees thephp_stream_filterstruct whileuserfilter_filterstill dereferences&thisfilter->abstractand while the chain walks in_php_stream_filter_flush,_php_stream_write_filtered, and_php_stream_fill_read_bufferstill needcurrent->next. Two new fields onphp_stream_filter,in_callbackanddeferred_dtor, carry the deferral:php_stream_filter_remove(filter, true)unlinks and runszend_list_deleteimmediately but defers thepefree.