Skip to content

Commit 45e7e79

Browse files
committed
Merge branch '70284' into PHP-5.6
* 70284: Fix bug ##70284 (Use after free vulnerability in unserialize() with GMP)
2 parents 9da99d8 + d735957 commit 45e7e79

File tree

2 files changed

+55
-5
lines changed

2 files changed

+55
-5
lines changed

ext/gmp/gmp.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -630,7 +630,7 @@ static int gmp_unserialize(zval **object, zend_class_entry *ce, const unsigned c
630630
{
631631
mpz_ptr gmpnum;
632632
const unsigned char *p, *max;
633-
zval zv, *zv_ptr = &zv;
633+
zval *zv_ptr;
634634
int retval = FAILURE;
635635
php_unserialize_data_t unserialize_data = (php_unserialize_data_t) data;
636636

@@ -640,17 +640,17 @@ static int gmp_unserialize(zval **object, zend_class_entry *ce, const unsigned c
640640
p = buf;
641641
max = buf + buf_len;
642642

643-
INIT_ZVAL(zv);
643+
ALLOC_INIT_ZVAL(zv_ptr);
644644
if (!php_var_unserialize(&zv_ptr, &p, max, &unserialize_data TSRMLS_CC)
645645
|| Z_TYPE_P(zv_ptr) != IS_STRING
646646
|| convert_to_gmp(gmpnum, zv_ptr, 10 TSRMLS_CC) == FAILURE
647647
) {
648648
zend_throw_exception(NULL, "Could not unserialize number", 0 TSRMLS_CC);
649649
goto exit;
650650
}
651-
zval_dtor(&zv);
651+
var_push_dtor_no_addref(&unserialize_data, &zv_ptr);
652652

653-
INIT_ZVAL(zv);
653+
ALLOC_INIT_ZVAL(zv_ptr);
654654
if (!php_var_unserialize(&zv_ptr, &p, max, &unserialize_data TSRMLS_CC)
655655
|| Z_TYPE_P(zv_ptr) != IS_ARRAY
656656
) {
@@ -667,7 +667,7 @@ static int gmp_unserialize(zval **object, zend_class_entry *ce, const unsigned c
667667

668668
retval = SUCCESS;
669669
exit:
670-
zval_dtor(&zv);
670+
var_push_dtor_no_addref(&unserialize_data, &zv_ptr);
671671
PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data);
672672
return retval;
673673
}

ext/gmp/tests/bug70284.phpt

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
--TEST--
2+
Bug #70284 (Use after free vulnerability in unserialize() with GMP)
3+
--SKIPIF--
4+
<?php if (!extension_loaded("gmp")) print "skip"; ?>
5+
--FILE--
6+
<?php
7+
8+
$inner = 'r:2;a:1:{i:0;a:1:{i:0;r:4;}}';
9+
$exploit = 'a:2:{i:0;s:1:"1";i:1;C:3:"GMP":'.strlen($inner).':{'.$inner.'}}';
10+
11+
$data = unserialize($exploit);
12+
13+
$fakezval = ptr2str(1122334455);
14+
$fakezval .= ptr2str(0);
15+
$fakezval .= "\x00\x00\x00\x00";
16+
$fakezval .= "\x01";
17+
$fakezval .= "\x00";
18+
$fakezval .= "\x00\x00";
19+
20+
for ($i = 0; $i < 5; $i++) {
21+
$v[$i] = $fakezval.$i;
22+
}
23+
24+
var_dump($data);
25+
26+
function ptr2str($ptr)
27+
{
28+
$out = '';
29+
for ($i = 0; $i < 8; $i++) {
30+
$out .= chr($ptr & 0xff);
31+
$ptr >>= 8;
32+
}
33+
return $out;
34+
}
35+
?>
36+
--EXPECTF--
37+
array(2) {
38+
[0]=>
39+
string(1) "1"
40+
[1]=>
41+
object(GMP)#%d (2) {
42+
[0]=>
43+
array(1) {
44+
[0]=>
45+
NULL
46+
}
47+
["num"]=>
48+
string(1) "1"
49+
}
50+
}

0 commit comments

Comments
 (0)