Skip to content

Commit 49f44e7

Browse files
committed
JIT: Fixed use-after-free caused by shift by negative number
Fixes oss-fuzz #41192
1 parent 179030d commit 49f44e7

File tree

2 files changed

+61
-0
lines changed

2 files changed

+61
-0
lines changed

ext/opcache/jit/zend_jit_x86.dasc

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3906,6 +3906,15 @@ static int zend_jit_load_var(dasm_State **Dst, uint32_t info, int var, zend_reg
39063906
return zend_jit_load_reg(Dst, src, dst, info);
39073907
}
39083908

3909+
static int zend_jit_invalidate_var_if_necessary(dasm_State **Dst, zend_uchar op_type, zend_jit_addr addr, znode_op op)
3910+
{
3911+
if ((op_type & (IS_TMP_VAR|IS_VAR)) && Z_MODE(addr) == IS_REG && !Z_LOAD(addr) && !Z_STORE(addr)) {
3912+
zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op.var);
3913+
| SET_ZVAL_TYPE_INFO dst, IS_UNDEF
3914+
}
3915+
return 1;
3916+
}
3917+
39093918
static int zend_jit_update_regs(dasm_State **Dst, uint32_t var, zend_jit_addr src, zend_jit_addr dst, uint32_t info)
39103919
{
39113920
if (!zend_jit_same_addr(src, dst)) {
@@ -5024,6 +5033,8 @@ static int zend_jit_long_math_helper(dasm_State **Dst,
50245033
if (EXPECTED(op2_lval > 0)) {
50255034
| xor Ra(result_reg), Ra(result_reg)
50265035
} else {
5036+
zend_jit_invalidate_var_if_necessary(Dst, op1_type, op1_addr, op1);
5037+
zend_jit_invalidate_var_if_necessary(Dst, op2_type, op2_addr, op2);
50275038
| SET_EX_OPLINE opline, r0
50285039
| jmp ->negative_shift
50295040
}
@@ -5047,6 +5058,8 @@ static int zend_jit_long_math_helper(dasm_State **Dst,
50475058
| cmp r1, 0
50485059
| mov Ra(result_reg), 0
50495060
| jg >1
5061+
zend_jit_invalidate_var_if_necessary(Dst, op1_type, op1_addr, op1);
5062+
zend_jit_invalidate_var_if_necessary(Dst, op2_type, op2_addr, op2);
50505063
| SET_EX_OPLINE opline, r0
50515064
| jmp ->negative_shift
50525065
|.code
@@ -5064,6 +5077,8 @@ static int zend_jit_long_math_helper(dasm_State **Dst,
50645077
if (EXPECTED(op2_lval > 0)) {
50655078
| sar Ra(result_reg), (SIZEOF_ZEND_LONG * 8) - 1
50665079
} else {
5080+
zend_jit_invalidate_var_if_necessary(Dst, op1_type, op1_addr, op1);
5081+
zend_jit_invalidate_var_if_necessary(Dst, op2_type, op2_addr, op2);
50675082
| SET_EX_OPLINE opline, r0
50685083
| jmp ->negative_shift
50695084
}
@@ -5084,6 +5099,8 @@ static int zend_jit_long_math_helper(dasm_State **Dst,
50845099
| cmp r1, 0
50855100
| mov r1, (SIZEOF_ZEND_LONG * 8) - 1
50865101
| jg >1
5102+
zend_jit_invalidate_var_if_necessary(Dst, op1_type, op1_addr, op1);
5103+
zend_jit_invalidate_var_if_necessary(Dst, op2_type, op2_addr, op2);
50875104
| SET_EX_OPLINE opline, r0
50885105
| jmp ->negative_shift
50895106
|.code
@@ -5096,6 +5113,8 @@ static int zend_jit_long_math_helper(dasm_State **Dst,
50965113
zend_long op2_lval = Z_LVAL_P(Z_ZV(op2_addr));
50975114

50985115
if (op2_lval == 0) {
5116+
zend_jit_invalidate_var_if_necessary(Dst, op1_type, op1_addr, op1);
5117+
zend_jit_invalidate_var_if_necessary(Dst, op2_type, op2_addr, op2);
50995118
| SET_EX_OPLINE opline, r0
51005119
| jmp ->mod_by_zero
51015120
} else if (zend_long_is_power_of_two(op2_lval) && op1_range && op1_range->min >= 0) {
@@ -5135,6 +5154,8 @@ static int zend_jit_long_math_helper(dasm_State **Dst,
51355154
| jz >1
51365155
|.cold_code
51375156
|1:
5157+
zend_jit_invalidate_var_if_necessary(Dst, op1_type, op1_addr, op1);
5158+
zend_jit_invalidate_var_if_necessary(Dst, op2_type, op2_addr, op2);
51385159
| SET_EX_OPLINE opline, r0
51395160
| jmp ->mod_by_zero
51405161
|.code
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
--TEST--
2+
JIT Shift Right: 004
3+
--INI--
4+
opcache.enable=1
5+
opcache.enable_cli=1
6+
opcache.file_update_protection=0
7+
opcache.jit_buffer_size=1M
8+
opcache.protect_memory=1
9+
--FILE--
10+
<?php
11+
function test() {
12+
$j = 2;
13+
for ($i = 0; $i < 10;
14+
$i + $b = $a + $a = $a + $a = $a +
15+
$a = !$a +
16+
$c[0] .= 0xfff0001/34028236692903846346336*6) {
17+
$a =!$a + $a &= 74444444 - 444 >> 4 - $j++;
18+
if ($j > 14) break;
19+
}
20+
}
21+
test();
22+
?>
23+
--EXPECTF--
24+
Warning: Undefined variable $a in %sshift_right_004.php on line 8
25+
26+
Warning: Undefined variable $a in %sshift_right_004.php on line 8
27+
28+
Warning: Undefined variable $c in %sshift_right_004.php on line 7
29+
30+
Warning: Undefined array key 0 in %sshift_right_004.php on line 7
31+
32+
Warning: A non-numeric value encountered in %sshift_right_004.php on line 7
33+
34+
Warning: A non-numeric value encountered in %sshift_right_004.php on line 7
35+
36+
Fatal error: Uncaught ArithmeticError: Bit shift by negative number in %sshift_right_004.php:8
37+
Stack trace:
38+
#0 %sshift_right_004.php(12): test()
39+
#1 {main}
40+
thrown in %sshift_right_004.php on line 8

0 commit comments

Comments
 (0)