Skip to content

Commit c54fc7a

Browse files
committed
Handle UAFs
1 parent fc7a720 commit c54fc7a

File tree

8 files changed

+230
-2
lines changed

8 files changed

+230
-2
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
--TEST--
2+
Non rep float string to int conversions should not crash when modified
3+
--FILE--
4+
<?php
5+
set_error_handler(function ($errno, $errstr) {
6+
global $b;
7+
$b = null;
8+
echo $errstr, "\n";
9+
});
10+
11+
$a = "1.0E+" . rand(40,42);
12+
$b = &$a;
13+
var_dump($b | 1);
14+
15+
?>
16+
--EXPECTF--
17+
non-representable float-string 1.0E+4%d was cast to int
18+
Implicit conversion from float-string "1.0E+4%d" to int loses precision
19+
int(9223372036854775807)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--TEST--
2+
Non rep float string to int conversions should not crash when modified
3+
--FILE--
4+
<?php
5+
6+
set_error_handler(function ($errno, $errstr) {
7+
global $ary;
8+
$ary = null;
9+
echo $errstr, "\n";
10+
});
11+
12+
$ary = [rand()];
13+
unset($ary[1.0E+42]);
14+
15+
?>
16+
--EXPECT--
17+
non-representable float 1.0E+42 was cast to int
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
Non rep float string to int conversions should not crash when modified
3+
--FILE--
4+
<?php
5+
6+
set_error_handler(function ($errno, $errstr) {
7+
global $ary;
8+
$ary = null;
9+
echo $errstr, "\n";
10+
});
11+
12+
$ary = [rand()];
13+
var_dump(isset($ary[1.0E+42]));
14+
15+
?>
16+
--EXPECT--
17+
non-representable float 1.0E+42 was cast to int
18+
bool(false)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
Non rep float string to int conversions should not crash when modified
3+
--FILE--
4+
<?php
5+
6+
set_error_handler(function ($errno, $errstr) {
7+
global $ary;
8+
$ary = null;
9+
echo $errstr, "\n";
10+
});
11+
12+
$ary = [rand()];
13+
var_dump(\array_key_exists(1.0E+42, $ary));
14+
15+
?>
16+
--EXPECT--
17+
non-representable float 1.0E+42 was cast to int
18+
bool(false)

Zend/zend_execute.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3241,7 +3241,17 @@ static zend_never_inline zval* ZEND_FASTCALL zend_find_array_dim_slow(HashTable
32413241
zend_ulong hval;
32423242

32433243
if (Z_TYPE_P(offset) == IS_DOUBLE) {
3244+
/* The array may be destroyed while throwing a warning in case the float is not representable as an int.
3245+
* Temporarily increase the refcount to detect this situation. */
3246+
GC_TRY_ADDREF(ht);
32443247
hval = zend_dval_to_lval_safe(Z_DVAL_P(offset));
3248+
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) {
3249+
zend_array_destroy(ht);
3250+
return NULL;
3251+
}
3252+
if (EG(exception)) {
3253+
return NULL;
3254+
}
32453255
num_idx:
32463256
return zend_hash_index_find(ht, hval);
32473257
} else if (Z_TYPE_P(offset) == IS_NULL) {
@@ -3380,7 +3390,17 @@ static zend_never_inline bool ZEND_FASTCALL zend_array_key_exists_fast(HashTable
33803390
key = Z_REFVAL_P(key);
33813391
goto try_again;
33823392
} else if (Z_TYPE_P(key) == IS_DOUBLE) {
3393+
/* The array may be destroyed while throwing a warning in case the float is not representable as an int.
3394+
* Temporarily increase the refcount to detect this situation. */
3395+
GC_TRY_ADDREF(ht);
33833396
hval = zend_dval_to_lval_safe(Z_DVAL_P(key));
3397+
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) {
3398+
zend_array_destroy(ht);
3399+
return false;
3400+
}
3401+
if (EG(exception)) {
3402+
return false;
3403+
}
33843404
goto num_key;
33853405
} else if (Z_TYPE_P(key) == IS_FALSE) {
33863406
hval = 0;

Zend/zend_operators.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,8 @@ static zend_never_inline zend_long ZEND_FASTCALL zendi_try_get_long(const zval *
415415
zend_error(E_WARNING, "A non-numeric value encountered");
416416
if (UNEXPECTED(EG(exception))) {
417417
*failed = 1;
418+
zend_tmp_string_release(op_str);
419+
return 0;
418420
}
419421
}
420422
if (EXPECTED(type == IS_LONG)) {
@@ -425,14 +427,18 @@ static zend_never_inline zend_long ZEND_FASTCALL zendi_try_get_long(const zval *
425427
* We use use saturating conversion to emulate strtol()'s
426428
* behaviour.
427429
*/
430+
if (op_str == NULL) {
431+
/* zend_dval_to_lval_cap() can emit a warning so always do the copy here */
432+
op_str = zend_string_copy(Z_STR_P(op));
433+
}
428434
lval = zend_dval_to_lval_cap(dval);
429435
if (!zend_is_long_compatible(dval, lval)) {
430-
zend_incompatible_string_to_long_error(op_str ? op_str : Z_STR_P(op));
436+
zend_incompatible_string_to_long_error(op_str);
431437
if (UNEXPECTED(EG(exception))) {
432438
*failed = 1;
433439
}
434440
}
435-
zend_tmp_string_release(op_str);
441+
zend_string_release(op_str);
436442
return lval;
437443
}
438444
}

Zend/zend_vm_def.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6751,7 +6751,17 @@ ZEND_VM_C_LABEL(num_index_dim):
67516751
offset = Z_REFVAL_P(offset);
67526752
ZEND_VM_C_GOTO(offset_again);
67536753
} else if (Z_TYPE_P(offset) == IS_DOUBLE) {
6754+
/* The array may be destroyed while throwing a warning in case the float is not representable as an int.
6755+
* Temporarily increase the refcount to detect this situation. */
6756+
GC_TRY_ADDREF(ht);
67546757
hval = zend_dval_to_lval_safe(Z_DVAL_P(offset));
6758+
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) {
6759+
zend_array_destroy(ht);
6760+
break;
6761+
}
6762+
if (EG(exception)) {
6763+
break;
6764+
}
67556765
ZEND_VM_C_GOTO(num_index_dim);
67566766
} else if (Z_TYPE_P(offset) == IS_NULL) {
67576767
key = ZSTR_EMPTY_ALLOC();

Zend/zend_vm_execute.h

Lines changed: 120 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)