You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
gentoo-overlay/dev-lang/php/files/php-7.2.34-use-after-free-b...

175 lines
5.4 KiB

Backport of https://git.php.net/?p=php-src.git;a=commit;h=ef1e4891b47949c8dc0f9482eef9454a0ecdfa1d
--- a/Zend/tests/bug52361.phpt
+++ b/Zend/tests/bug52361.phpt
@@ -25,9 +25,8 @@ try {
--EXPECTF--
1. Exception: aaa in %sbug52361.php:5
Stack trace:
-#0 %sbug52361.php(13): aaa->__destruct()
-#1 %sbug52361.php(16): bbb()
-#2 {main}
+#0 %sbug52361.php(16): aaa->__destruct()
+#1 {main}
2. Exception: bbb in %sbug52361.php:13
Stack trace:
#0 %sbug52361.php(16): bbb()
--- /dev/null
+++ b/Zend/tests/bug76047.phpt
@@ -0,0 +1,68 @@
+--TEST--
+Bug #76047: Use-after-free when accessing already destructed backtrace arguments
+--FILE--
+<?php
+
+class Vuln {
+ public $a;
+ public function __destruct() {
+ unset($this->a);
+ $backtrace = (new Exception)->getTrace();
+ var_dump($backtrace);
+ }
+}
+
+function test($arg) {
+ $arg = str_shuffle(str_repeat('A', 79));
+ $vuln = new Vuln();
+ $vuln->a = $arg;
+}
+
+function test2($arg) {
+ $$arg = 1; // Trigger symbol table
+ $arg = str_shuffle(str_repeat('A', 79));
+ $vuln = new Vuln();
+ $vuln->a = $arg;
+}
+
+test('x');
+test2('x');
+
+?>
+--EXPECTF--
+array(1) {
+ [0]=>
+ array(6) {
+ ["file"]=>
+ string(%d) "%s"
+ ["line"]=>
+ int(%d)
+ ["function"]=>
+ string(10) "__destruct"
+ ["class"]=>
+ string(4) "Vuln"
+ ["type"]=>
+ string(2) "->"
+ ["args"]=>
+ array(0) {
+ }
+ }
+}
+array(1) {
+ [0]=>
+ array(6) {
+ ["file"]=>
+ string(%d) "%s"
+ ["line"]=>
+ int(%d)
+ ["function"]=>
+ string(10) "__destruct"
+ ["class"]=>
+ string(4) "Vuln"
+ ["type"]=>
+ string(2) "->"
+ ["args"]=>
+ array(0) {
+ }
+ }
+}
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -2366,9 +2366,9 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
uint32_t call_info = EX_CALL_INFO();
if (EXPECTED((call_info & (ZEND_CALL_CODE|ZEND_CALL_TOP|ZEND_CALL_HAS_SYMBOL_TABLE|ZEND_CALL_FREE_EXTRA_ARGS|ZEND_CALL_ALLOCATED)) == 0)) {
+ EG(current_execute_data) = EX(prev_execute_data);
i_free_compiled_variables(execute_data);
- EG(current_execute_data) = EX(prev_execute_data);
if (UNEXPECTED(call_info & ZEND_CALL_RELEASE_THIS)) {
zend_object *object = Z_OBJ(execute_data->This);
#if 0
@@ -2394,12 +2394,12 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
LOAD_NEXT_OPLINE();
ZEND_VM_LEAVE();
} else if (EXPECTED((call_info & (ZEND_CALL_CODE|ZEND_CALL_TOP)) == 0)) {
+ EG(current_execute_data) = EX(prev_execute_data);
i_free_compiled_variables(execute_data);
if (UNEXPECTED(call_info & ZEND_CALL_HAS_SYMBOL_TABLE)) {
zend_clean_and_cache_symbol_table(EX(symbol_table));
}
- EG(current_execute_data) = EX(prev_execute_data);
/* Free extra args before releasing the closure,
* as that may free the op_array. */
@@ -2449,6 +2449,7 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
ZEND_VM_LEAVE();
} else {
if (EXPECTED((call_info & ZEND_CALL_CODE) == 0)) {
+ EG(current_execute_data) = EX(prev_execute_data);
i_free_compiled_variables(execute_data);
if (UNEXPECTED(call_info & (ZEND_CALL_HAS_SYMBOL_TABLE|ZEND_CALL_FREE_EXTRA_ARGS))) {
if (UNEXPECTED(call_info & ZEND_CALL_HAS_SYMBOL_TABLE)) {
@@ -2456,7 +2457,6 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
}
zend_vm_stack_free_extra_args_ex(call_info, execute_data);
}
- EG(current_execute_data) = EX(prev_execute_data);
if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
OBJ_RELEASE((zend_object*)EX(func)->op_array.prototype);
}
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@ -434,9 +434,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_
uint32_t call_info = EX_CALL_INFO();
if (EXPECTED((call_info & (ZEND_CALL_CODE|ZEND_CALL_TOP|ZEND_CALL_HAS_SYMBOL_TABLE|ZEND_CALL_FREE_EXTRA_ARGS|ZEND_CALL_ALLOCATED)) == 0)) {
+ EG(current_execute_data) = EX(prev_execute_data);
i_free_compiled_variables(execute_data);
- EG(current_execute_data) = EX(prev_execute_data);
if (UNEXPECTED(call_info & ZEND_CALL_RELEASE_THIS)) {
zend_object *object = Z_OBJ(execute_data->This);
#if 0
@@ -462,12 +462,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_
LOAD_NEXT_OPLINE();
ZEND_VM_LEAVE();
} else if (EXPECTED((call_info & (ZEND_CALL_CODE|ZEND_CALL_TOP)) == 0)) {
+ EG(current_execute_data) = EX(prev_execute_data);
i_free_compiled_variables(execute_data);
if (UNEXPECTED(call_info & ZEND_CALL_HAS_SYMBOL_TABLE)) {
zend_clean_and_cache_symbol_table(EX(symbol_table));
}
- EG(current_execute_data) = EX(prev_execute_data);
/* Free extra args before releasing the closure,
* as that may free the op_array. */
@@ -517,6 +517,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_
ZEND_VM_LEAVE();
} else {
if (EXPECTED((call_info & ZEND_CALL_CODE) == 0)) {
+ EG(current_execute_data) = EX(prev_execute_data);
i_free_compiled_variables(execute_data);
if (UNEXPECTED(call_info & (ZEND_CALL_HAS_SYMBOL_TABLE|ZEND_CALL_FREE_EXTRA_ARGS))) {
if (UNEXPECTED(call_info & ZEND_CALL_HAS_SYMBOL_TABLE)) {
@@ -524,7 +525,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_
}
zend_vm_stack_free_extra_args_ex(call_info, execute_data);
}
- EG(current_execute_data) = EX(prev_execute_data);
if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
OBJ_RELEASE((zend_object*)EX(func)->op_array.prototype);
}