Fix use after free on compound division by zero

We can't destroy the result operand early, because the division
might fail, in which case we need to preserve the original value.
Place the division result in a temporary zval, and only copy it
on success.

Fixes oss-fuzz #35876.
This commit is contained in:
Nikita Popov 2021-07-07 09:36:30 +02:00
parent 52a00fe776
commit 62ecf54f35
2 changed files with 22 additions and 6 deletions

View File

@ -0,0 +1,16 @@
--TEST--
Division by zero in compound assignment with refcounted operand
--FILE--
<?php
$h = "1";
$h .= "2";
try {
$h /= 0;
} catch (DivisionByZeroError $e) {
echo $e->getMessage(), "\n";
}
var_dump($h);
?>
--EXPECT--
Division by zero
string(2) "12"

View File

@ -1314,7 +1314,7 @@ ZEND_API zend_result ZEND_FASTCALL div_function(zval *result, zval *op1, zval *o
ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_DIV);
zval op1_copy, op2_copy;
zval result_copy, op1_copy, op2_copy;
if (UNEXPECTED(zendi_try_convert_scalar_to_number(op1, &op1_copy) == FAILURE)
|| UNEXPECTED(zendi_try_convert_scalar_to_number(op2, &op2_copy) == FAILURE)) {
zend_binop_error("/", op1, op2);
@ -1324,12 +1324,12 @@ ZEND_API zend_result ZEND_FASTCALL div_function(zval *result, zval *op1, zval *o
return FAILURE;
}
if (result == op1) {
zval_ptr_dtor(result);
}
retval = div_function_base(result, &op1_copy, &op2_copy);
retval = div_function_base(&result_copy, &op1_copy, &op2_copy);
if (retval == SUCCESS) {
if (result == op1) {
zval_ptr_dtor(result);
}
ZVAL_COPY_VALUE(result, &result_copy);
return SUCCESS;
}