[php-src] PR #24169: Use-after-free when a user wrapper closes the other stream during stream_copy_to_stream()
| From: | EdmondDantes | Date: | Tue, 06 Oct 2026 18:43:31 +0000 |
| Subject: | [php-src] PR #24169: Use-after-free when a user wrapper closes the other stream during stream_copy_to_stream() | ||
| Groups: | php.git-pulls | ||
| Request: | Send a blank email to git-pulls+get-39221@lists.php.net to get a copy of this message | ||
Pull Request: https://github.com/php/php-src/pull/24169
Author: EdmondDantes
_php_stream_copy_to_stream_ex() reads from src and writes to
dest in a loop. When either is a user wrapper, its stream_write() or
stream_read() may fclose() the other stream, and the next turn of the loop
uses the freed stream (segfault, or an assertion in php_stream_memory_read() on a debug
build).
The fix sets PHP_STREAM_FLAG_NO_FCLOSE on both streams for the duration of the copy,
the same protection a stream already gets while its user filter runs, so such an
fclose() fails with the existing warning. Each stream's original flag is restored
afterwards (both are read before either is set, so src == dest is fine). The body moved
into a static helper so that none of its returns needed touching.
Test: ext/standard/tests/streams/stream_copy_to_stream_close_in_callback.phpt, both
directions. It segfaults without the fix.
Known limit, left for a separate change: pclose(), proc_close() and
closedir() free a stream without checking PHP_STREAM_FLAG_NO_FCLOSE (an
opendir() handle can be the source of a copy).