components/php/php56/patches/70284.patch
author Michael Nestler <Michael.Nestler@Oracle.COM>
Thu, 19 Nov 2015 22:52:15 -0800
changeset 5116 867d838118ad
permissions -rw-r--r--
22244227 problem in UTILITY/PHP 21577672 problem in UTILITY/PHP 22244239 problem in UTILITY/PHP 22244245 problem in UTILITY/PHP 22244247 problem in UTILITY/PHP 22244253 problem in UTILITY/PHP 22244256 problem in UTILITY/PHP 22244261 problem in UTILITY/PHP 22244265 problem in UTILITY/PHP 22244270 problem in UTILITY/PHP 22244277 problem in UTILITY/PHP 22244286 problem in UTILITY/PHP

# Source: upstream
# https://github.com/php/php-src/commit/d735957cb5f8fee8d13ae68cf75300306c84374f.patch
# https://bugs.php.net/bug.php?id=70284
# Security

From d735957cb5f8fee8d13ae68cf75300306c84374f Mon Sep 17 00:00:00 2001
From: Stanislav Malyshev <[email protected]>
Date: Sun, 23 Aug 2015 13:46:19 -0700
Subject: [PATCH] Fix bug ##70284 (Use after free vulnerability in
 unserialize() with GMP)

---
 ext/gmp/gmp.c               | 10 ++++-----
 ext/gmp/tests/bug70284.phpt | 50 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 55 insertions(+), 5 deletions(-)
 create mode 100644 ext/gmp/tests/bug70284.phpt

diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c
index 575dab8..c7cdef7 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 0000000..ab17c0f
--- /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"
+  }
+}