summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStanislav Malyshev <stas@php.net>2015-09-01 12:05:02 -0700
committerFerenc Kovacs <tyrael@php.net>2015-09-03 01:51:19 +0200
commit4d7bb43b9f399d20af45124906384d82afbd10f7 (patch)
treed80c74e887736e2d7decf845c27c49e252e00371
parent55ddcbca0f8c95e28a8a828ec4635cbc792d9807 (diff)
downloadphp-git-4d7bb43b9f399d20af45124906384d82afbd10f7.tar.gz
Merge branch '70284' into PHP-5.6
* 70284: Fix bug ##70284 (Use after free vulnerability in unserialize() with GMP)
-rw-r--r--ext/gmp/gmp.c10
-rw-r--r--ext/gmp/tests/bug70284.phpt50
2 files changed, 55 insertions, 5 deletions
diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c
index 575dab8a5b..c7cdef736f 100644
--- a/ext/gmp/gmp.c
+++ b/ext/gmp/gmp.c
@@ -630,7 +630,7 @@ static int gmp_unserialize(zval **object, zend_class_entry *ce, const unsigned c
{
mpz_ptr gmpnum;
const unsigned char *p, *max;
- zval zv, *zv_ptr = &zv;
+ zval *zv_ptr;
int retval = FAILURE;
php_unserialize_data_t unserialize_data = (php_unserialize_data_t) data;
@@ -640,7 +640,7 @@ static int gmp_unserialize(zval **object, zend_class_entry *ce, const unsigned c
p = buf;
max = buf + buf_len;
- INIT_ZVAL(zv);
+ ALLOC_INIT_ZVAL(zv_ptr);
if (!php_var_unserialize(&zv_ptr, &p, max, &unserialize_data TSRMLS_CC)
|| Z_TYPE_P(zv_ptr) != IS_STRING
|| convert_to_gmp(gmpnum, zv_ptr, 10 TSRMLS_CC) == FAILURE
@@ -648,9 +648,9 @@ static int gmp_unserialize(zval **object, zend_class_entry *ce, const unsigned c
zend_throw_exception(NULL, "Could not unserialize number", 0 TSRMLS_CC);
goto exit;
}
- zval_dtor(&zv);
+ var_push_dtor_no_addref(&unserialize_data, &zv_ptr);
- INIT_ZVAL(zv);
+ ALLOC_INIT_ZVAL(zv_ptr);
if (!php_var_unserialize(&zv_ptr, &p, max, &unserialize_data TSRMLS_CC)
|| Z_TYPE_P(zv_ptr) != IS_ARRAY
) {
@@ -667,7 +667,7 @@ static int gmp_unserialize(zval **object, zend_class_entry *ce, const unsigned c
retval = SUCCESS;
exit:
- zval_dtor(&zv);
+ var_push_dtor_no_addref(&unserialize_data, &zv_ptr);
PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data);
return retval;
}
diff --git a/ext/gmp/tests/bug70284.phpt b/ext/gmp/tests/bug70284.phpt
new file mode 100644
index 0000000000..ab17c0fc1c
--- /dev/null
+++ b/ext/gmp/tests/bug70284.phpt
@@ -0,0 +1,50 @@
+--TEST--
+Bug #70284 (Use after free vulnerability in unserialize() with GMP)
+--SKIPIF--
+<?php if (!extension_loaded("gmp")) print "skip"; ?>
+--FILE--
+<?php
+
+$inner = 'r:2;a:1:{i:0;a:1:{i:0;r:4;}}';
+$exploit = 'a:2:{i:0;s:1:"1";i:1;C:3:"GMP":'.strlen($inner).':{'.$inner.'}}';
+
+$data = unserialize($exploit);
+
+$fakezval = ptr2str(1122334455);
+$fakezval .= ptr2str(0);
+$fakezval .= "\x00\x00\x00\x00";
+$fakezval .= "\x01";
+$fakezval .= "\x00";
+$fakezval .= "\x00\x00";
+
+for ($i = 0; $i < 5; $i++) {
+ $v[$i] = $fakezval.$i;
+}
+
+var_dump($data);
+
+function ptr2str($ptr)
+{
+$out = '';
+ for ($i = 0; $i < 8; $i++) {
+ $out .= chr($ptr & 0xff);
+ $ptr >>= 8;
+ }
+ return $out;
+}
+?>
+--EXPECTF--
+array(2) {
+ [0]=>
+ string(1) "1"
+ [1]=>
+ object(GMP)#%d (2) {
+ [0]=>
+ array(1) {
+ [0]=>
+ NULL
+ }
+ ["num"]=>
+ string(1) "1"
+ }
+}