Skip to content

Commit 1fdcfa4

Browse files
iluuu1994ramsey
authored andcommitted
Fix use-after-free of name in var-var with malicious error handler
Fixes oss-fuzz #54325 Closes phpGH-12732
1 parent 55e0748 commit 1fdcfa4

File tree

4 files changed

+51
-0
lines changed

4 files changed

+51
-0
lines changed

NEWS

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ PHP NEWS
22
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
33
?? ??? ????, PHP 8.1.27
44

5+
- Core:
6+
. Fixed oss-fuzz #54325 (Use-after-free of name in var-var with malicious
7+
error handler). (ilutov)
8+
59
- DOM:
610
. Fixed bug GH-12616 (DOM: Removing XMLNS namespace node results in invalid
711
default: prefix). (nielsdos)

Zend/tests/oss_fuzz_54325.phpt

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
--TEST--
2+
oss-fuzz #54325: Fix use-after-free of name in var-var with malicious error handler
3+
--FILE--
4+
<?php
5+
set_error_handler(function ($errno, $errstr) {
6+
var_dump($errstr);
7+
global $x;
8+
$x = new stdClass;
9+
});
10+
11+
// Needs to be non-interned string
12+
$x = strrev('foo');
13+
$$x++;
14+
var_dump($x);
15+
?>
16+
--EXPECT--
17+
string(23) "Undefined variable $oof"
18+
object(stdClass)#2 (0) {
19+
}

Zend/zend_vm_def.h

+7
Original file line numberDiff line numberDiff line change
@@ -1748,13 +1748,20 @@ ZEND_VM_C_LABEL(fetch_this):
17481748
} else if (type == BP_VAR_IS || type == BP_VAR_UNSET) {
17491749
retval = &EG(uninitialized_zval);
17501750
} else {
1751+
if (OP1_TYPE == IS_CV) {
1752+
/* Keep name alive in case an error handler tries to free it. */
1753+
zend_string_addref(name);
1754+
}
17511755
zend_error(E_WARNING, "Undefined %svariable $%s",
17521756
(opline->extended_value & ZEND_FETCH_GLOBAL ? "global " : ""), ZSTR_VAL(name));
17531757
if (type == BP_VAR_RW && !EG(exception)) {
17541758
retval = zend_hash_update(target_symbol_table, name, &EG(uninitialized_zval));
17551759
} else {
17561760
retval = &EG(uninitialized_zval);
17571761
}
1762+
if (OP1_TYPE == IS_CV) {
1763+
zend_string_release(name);
1764+
}
17581765
}
17591766
/* GLOBAL or $$name variable may be an INDIRECT pointer to CV */
17601767
} else if (Z_TYPE_P(retval) == IS_INDIRECT) {

Zend/zend_vm_execute.h

+21
Original file line numberDiff line numberDiff line change
@@ -9755,13 +9755,20 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_ad
97559755
} else if (type == BP_VAR_IS || type == BP_VAR_UNSET) {
97569756
retval = &EG(uninitialized_zval);
97579757
} else {
9758+
if (IS_CONST == IS_CV) {
9759+
/* Keep name alive in case an error handler tries to free it. */
9760+
zend_string_addref(name);
9761+
}
97589762
zend_error(E_WARNING, "Undefined %svariable $%s",
97599763
(opline->extended_value & ZEND_FETCH_GLOBAL ? "global " : ""), ZSTR_VAL(name));
97609764
if (type == BP_VAR_RW && !EG(exception)) {
97619765
retval = zend_hash_update(target_symbol_table, name, &EG(uninitialized_zval));
97629766
} else {
97639767
retval = &EG(uninitialized_zval);
97649768
}
9769+
if (IS_CONST == IS_CV) {
9770+
zend_string_release(name);
9771+
}
97659772
}
97669773
/* GLOBAL or $$name variable may be an INDIRECT pointer to CV */
97679774
} else if (Z_TYPE_P(retval) == IS_INDIRECT) {
@@ -17560,13 +17567,20 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_ad
1756017567
} else if (type == BP_VAR_IS || type == BP_VAR_UNSET) {
1756117568
retval = &EG(uninitialized_zval);
1756217569
} else {
17570+
if ((IS_TMP_VAR|IS_VAR) == IS_CV) {
17571+
/* Keep name alive in case an error handler tries to free it. */
17572+
zend_string_addref(name);
17573+
}
1756317574
zend_error(E_WARNING, "Undefined %svariable $%s",
1756417575
(opline->extended_value & ZEND_FETCH_GLOBAL ? "global " : ""), ZSTR_VAL(name));
1756517576
if (type == BP_VAR_RW && !EG(exception)) {
1756617577
retval = zend_hash_update(target_symbol_table, name, &EG(uninitialized_zval));
1756717578
} else {
1756817579
retval = &EG(uninitialized_zval);
1756917580
}
17581+
if ((IS_TMP_VAR|IS_VAR) == IS_CV) {
17582+
zend_string_release(name);
17583+
}
1757017584
}
1757117585
/* GLOBAL or $$name variable may be an INDIRECT pointer to CV */
1757217586
} else if (Z_TYPE_P(retval) == IS_INDIRECT) {
@@ -47008,13 +47022,20 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_ad
4700847022
} else if (type == BP_VAR_IS || type == BP_VAR_UNSET) {
4700947023
retval = &EG(uninitialized_zval);
4701047024
} else {
47025+
if (IS_CV == IS_CV) {
47026+
/* Keep name alive in case an error handler tries to free it. */
47027+
zend_string_addref(name);
47028+
}
4701147029
zend_error(E_WARNING, "Undefined %svariable $%s",
4701247030
(opline->extended_value & ZEND_FETCH_GLOBAL ? "global " : ""), ZSTR_VAL(name));
4701347031
if (type == BP_VAR_RW && !EG(exception)) {
4701447032
retval = zend_hash_update(target_symbol_table, name, &EG(uninitialized_zval));
4701547033
} else {
4701647034
retval = &EG(uninitialized_zval);
4701747035
}
47036+
if (IS_CV == IS_CV) {
47037+
zend_string_release(name);
47038+
}
4701847039
}
4701947040
/* GLOBAL or $$name variable may be an INDIRECT pointer to CV */
4702047041
} else if (Z_TYPE_P(retval) == IS_INDIRECT) {

0 commit comments

Comments
 (0)