175 lines
5.4 KiB
Diff
175 lines
5.4 KiB
Diff
|
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);
|
||
|
}
|
||
|
|