diff --git a/NEWS b/NEWS index 697cc4de957a..3103c9e5634d 100644 --- a/NEWS +++ b/NEWS @@ -61,6 +61,9 @@ PHP NEWS callback). (Ilia Alshanetsky) . Fixed leaks and data loss when user filter leaves buckets on input brigade. (ndossche, Matthias Goergens, Jakub Zelenka) + . Fixed use-after-free of the previous request's default stream context when + a stream error is raised during request startup, such as when a POST body + cannot be buffered to a temporary file. (Go Kudo) . Fixed bug GH-24175 (Use-after-free when pclose() closes a stream from its user filter). (Edmond) diff --git a/ext/standard/file.c b/ext/standard/file.c index ff68374928c5..e64167df3283 100644 --- a/ext/standard/file.c +++ b/ext/standard/file.c @@ -111,6 +111,9 @@ PHPAPI int php_le_stream_context(void) static ZEND_RSRC_DTOR_FUNC(file_context_dtor) { php_stream_context *context = (php_stream_context*)res->ptr; + if (context == FG(default_context)) { + FG(default_context) = NULL; + } if (Z_TYPE(context->options) != IS_UNDEF) { zval_ptr_dtor(&context->options); ZVAL_UNDEF(&context->options); diff --git a/sapi/cgi/tests/stream_error_default_context.phpt b/sapi/cgi/tests/stream_error_default_context.phpt new file mode 100644 index 000000000000..240bd9342be7 --- /dev/null +++ b/sapi/cgi/tests/stream_error_default_context.phpt @@ -0,0 +1,63 @@ +--TEST-- +Stream errors before RINIT do not use the default stream context freed by the previous request +--SKIPIF-- + +--FILE-- + '1', + 'REQUEST_METHOD' => 'POST', + 'SCRIPT_FILENAME' => "$dir/index.php", + 'CONTENT_TYPE' => 'application/x-www-form-urlencoded', + 'CONTENT_LENGTH' => (string) strlen($body), +]; +foreach (['PATH', 'USE_ZEND_ALLOC', 'USE_TRACKED_ALLOC', 'ASAN_OPTIONS', 'LSAN_OPTIONS', 'UBSAN_OPTIONS'] as $name) { + if (getenv($name) !== false) { + $env[$name] = getenv($name); + } +} + +/* The first request creates the default stream context, the second one fails to spill its body */ +$proc = proc_open( + [$php, '-n', '-d', 'display_errors=0', '-d', 'log_errors=1', '-d', "sys_temp_dir=$dir/missing", '-T', '2'], + [0 => ['file', "$dir/body", 'r'], 1 => ['pipe', 'w'], 2 => ['pipe', 'w']], + $pipes, + $dir, + $env +); +$stdout = stream_get_contents($pipes[1]); +$stderr = stream_get_contents($pipes[2]); +proc_close($proc); + +var_dump(substr_count($stdout, "ok 0\n")); +echo $stderr; +?> +--CLEAN-- + +--EXPECTF-- +int(2) +PHP Warning: PHP Request Startup: Unable to create temporary file, Check permissions in temporary files directory. in Unknown on line 0 +PHP Warning: PHP Request Startup: POST data can't be buffered; all data discarded in Unknown on line 0 +PHP Warning: PHP Request Startup: Unable to create temporary file, Check permissions in temporary files directory. in Unknown on line 0 +PHP Warning: PHP Request Startup: POST data can't be buffered; all data discarded in Unknown on line 0 + +Elapsed time: %s sec