mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
Fix GH-20352: UAF in php_output_handler_free via re-entrant ob_start() during error deactivation
The problem is that the code is doing `php_output_handler_free` in a loop on the output stack, but prior to freeing the pointer on the stack in `php_output_handler_free` it calls `php_output_handler_dtor` which can run user code that reallocates the stack, resulting in a dangling pointer freed by php_output_handler_free. Furthermore, OG(active) is set when creating a new output handler, but the loop is supposed to clean up all handlers, so OG(active) must be reset as well. Closes GH-20356.
This commit is contained in:
@@ -188,8 +188,12 @@ PHPAPI void php_output_deactivate(void)
|
||||
/* release all output handlers */
|
||||
if (OG(handlers).elements) {
|
||||
while ((handler = zend_stack_top(&OG(handlers)))) {
|
||||
php_output_handler_free(handler);
|
||||
zend_stack_del_top(&OG(handlers));
|
||||
/* It's possible to start a new output handler and mark it as active,
|
||||
* however this loop will destroy all active handlers. */
|
||||
OG(active) = NULL;
|
||||
ZEND_ASSERT(OG(running) == NULL && "output is deactivated therefore running should stay NULL");
|
||||
php_output_handler_free(handler);
|
||||
}
|
||||
}
|
||||
zend_stack_destroy(&OG(handlers));
|
||||
@@ -719,10 +723,11 @@ PHPAPI void php_output_handler_dtor(php_output_handler *handler)
|
||||
* Destroy and free an output handler */
|
||||
PHPAPI void php_output_handler_free(php_output_handler **h)
|
||||
{
|
||||
if (*h) {
|
||||
php_output_handler_dtor(*h);
|
||||
efree(*h);
|
||||
php_output_handler *handler = *h;
|
||||
if (handler) {
|
||||
*h = NULL;
|
||||
php_output_handler_dtor(handler);
|
||||
efree(handler);
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
Reference in New Issue
Block a user