[php-src] PR #25321: [8.6 regression] Fix UAF of the default stream context in the stream error code

From: Date: Sun, 08 Nov 2026 15:26:39 +0000
Subject: [php-src] PR #25321: [8.6 regression] Fix UAF of the default stream context in the stream error code
Groups: php.git-pulls 
Request: Send a blank email to git-pulls+get-40437@lists.php.net to get a copy of this message
Pull Request: https://github.com/php/php-src/pull/25321 Author: zeriyoshi Found while reworking #22730. FG(default_context) is freed with the request's resources, but the pointer is only reset in ext/standard's RINIT. The new stream error code (8.6+) falls back to it when no context is given, so an error raised before RINIT, for example a POST body over 16 KiB that cannot be spooleds the previous request's freed context: ASan reports a heap-use-after-free, a release build dies with SIGSEGV. Clear FG(default_context) when its resource is destroyed. Only PHP-8.6 and master have the reader, 8.5 and earlier are not affected. Test: sapi/cgi/tests/stream_* fails before the change and passes after it. PoC: ```sh printf 'display_errors=1\nlog_errors=0\nsys_temp_dir=/nonexistent\n' > php.ini printf '<?php file_get_contents(__FILE__); echo "ok ", count($_POST), "\\n";' > ctx.php head -c 20480 /dev/zero | tr '\0' a | sed 's/^/a=/' > body; cat body body body body body > body5 REDIRECT_STATUS=1 REQUEST_METHOD=POST SCRIPT_FILENAME=$PWD/ctx.php CONTENT_TYPE=application/x-www-form-urlencoded \ CONTENT_LENGTH=20482 php-cgi -c php.ini -T 5 < body5; echo "exit $?" ``` gdb: ``` Program received signal SIGSEGV, Segmentation fault. php_stream_error_operation_end (context=<optimized out>, context@entry=0x0) at main/streams/stream_errors.c:485 485 GC_ADDREF(context->res); #1 php_stream_wrapper_error_internal (..., context=0x0, ...) at main/streams/stream_errors.c:624 #2 php_stream_wrapper_error (wrapper=0x0, context=0x0, ..., fmt="Unable to create temporary file, Check permissions in temporary files directory.") at main/streams/stream_errors.c:662 #3 php_stream_temp_write (stream=..., count=16384) at main/streams/memory.c:377 #7 sapi_read_standard_form_data () at main/SAPI.c:252 #9 sapi_activate () at main/SAPI.c:447 #10 php_request_startup () at main/main.c:1888 ``` Debug + ASan build of the same head (USE_ZEND_ALLOC=0 USE_TRACKED_ALLOC=1): ``` ERROR: AddressSanitizer: heap-use-after-free on address 0x5030000148c8 ... READ of size 8 #0 php_stream_context_get_option main/streams/streams.c:2377 #1 php_stream_get_error_mode main/streams/stream_errors.c:122 #2 php_stream_error_operation_end main/streams/stream_errors.c:479 #3 php_stream_wrapper_error_internal main/streams/stream_errors.c:624 #4 php_stream_wrapper_error main/streams/stream_errors.c:662 #5 php_stream_temp_write main/streams/memory.c:377 #6 php_stream_write_buffer main/streams/streams.c:1133 #7 php_stream_write main/streams/streams.c:1278 #8 sapi_read_standard_form_data main/SAPI.c:252 #9 sapi_read_post_data main/SAPI.c:200 #10 sapi_activate main/SAPI.c:447 #11 php_request_startup main/main.c:1888 #12 main sapi/cgi/cgi_main.c:2460 0x5030000148c8 is located 8 bytes inside of 32-byte region freed by thread T0 here: #2 _efree Zend/zend_alloc.c:3052 #3 php_stream_context_free main/streams/streams.c:2345 #4 file_context_dtor ext/standard/file.c:118 #5 zend_resource_dtor Zend/zend_list.c:72 #6 zend_close_rsrc_list Zend/zend_list.c:227 #7 zend_shutdown_executor_values Zend/zend_execute_API.c:284 #8 shutdown_executor Zend/zend_execute_API.c:479 #9 zend_deactivate Zend/zend.c:1367 #10 php_request_shutdown main/main.c:2014 #11 main sapi/cgi/cgi_main.c:2565 previously allocated by thread T0 here: #3 _ecalloc Zend/zend_alloc.c:3130 #4 php_stream_context_alloc main/streams/streams.c:2352 #5 zif_file_get_contents ext/standard/file.c:414 SUMMARY: AddressSanitizer: heap-use-after-free main/streams/streams.c:2377 in php_stream_context_get_option ```

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