[php-src] PR #24168: Use-after-free in stream_filter_remove() called from a stream callback

From: Date: Tue, 06 Oct 2026 18:40:39 +0000
Subject: [php-src] PR #24168: Use-after-free in stream_filter_remove() called from a stream callback
Groups: php.git-pulls 
Request: Send a blank email to git-pulls+get-39220@lists.php.net to get a copy of this message
Pull Request: https://github.com/php/php-src/pull/24168 Author: EdmondDantes stream_filter_remove() flushes the filter, then unlinks and frees it. The flush can run PHP code: a user filter's filter() method, or a user wrapper's stream_write() for the flushed data. If that code removes the same filter, the outer call continues on freed memory. A user filter can also remove itself (or another filter of its stream) from filter(), or from other code while filter() is suspended in a Fiber; userfilter_filter() and the filter chain walks then use the freed filter after the callback returns. Valgrind shows invalid reads in userfilter_filter() and php_stream_filter_remove(). The fix: - userfilter_filter() sets a new stream flag, PHP_STREAM_FLAG_USER_FILTER_RUNNING, around the callback, next to the existing PHP_STREAM_FLAG_NO_FCLOSE. stream_filter_remove() refuses with a warning while it is set, as fclose() already does. - After the flush, stream_filter_remove() checks that the filter resource is still alive, for the case where a user wrapper removed it from stream_write(). Tests: ext/standard/tests/filters/stream_filter_remove_in_filter.phpt (removal from filter() and while filter() is suspended in a Fiber) and stream_filter_remove_during_flush.phpt (removal from a user wrapper's stream_write() during the flush). Both fail without the fix, with invalid reads under valgrind. Known limits, left for separate changes: the flag is saved and restored per call, so Fibers resumed out of order can clear it early, as with PHP_STREAM_FLAG_NO_FCLOSE today; pclose() and closedir() free a stream without checking PHP_STREAM_FLAG_NO_FCLOSE.

« previous php.git-pulls (#39220) next »