You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

142 lines
3.7 KiB

From 16b3003ffc6393e250f069aa28a78dc5a2c064b2 Mon Sep 17 00:00:00 2001
From: Stanislav Malyshev <stas@php.net>
Date: Fri, 30 Dec 2016 16:59:46 -0800
Subject: [PATCH] CVE-2016-10161
Fix bug #73825 - Heap out of bounds read on unserialize in finish_nested_data()
[roberto@debian.org: backported to 5.4.45]
Bug: https://bugs.php.net/bug.php?id=73825
Origin: backport, http://git.php.net/?p=php-src.git;a=commitdiff;h=16b3003ffc6393e250f069aa28a78dc5a2c064b2
---
ext/standard/tests/serialize/bug73825.phpt | 12 +++++
ext/standard/var_unserializer.c | 80 ++++++++++++++++++------------
ext/standard/var_unserializer.re | 20 ++++++--
3 files changed, 76 insertions(+), 36 deletions(-)
create mode 100644 ext/standard/tests/serialize/bug73825.phpt
--- /dev/null
+++ php5.git/ext/standard/tests/serialize/bug73825.phpt
@@ -0,0 +1,12 @@
+--TEST--
+Bug #73825 Heap out of bounds read on unserialize in finish_nested_data()
+--FILE--
+<?php
+$obj = unserialize('O:8:"00000000":');
+var_dump($obj);
+?>
+--EXPECTF--
+Warning: Bad unserialize data in %sbug73825.php on line %d
+
+Notice: unserialize(): Error at offset 13 of 15 bytes in %sbug73825.php on line %d
+bool(false)
--- php5.git.orig/ext/standard/var_unserializer.c
+++ php5.git/ext/standard/var_unserializer.c
@@ -404,6 +404,11 @@
{
long elements;
+ if( *p >= max - 2) {
+ zend_error(E_WARNING, "Bad unserialize data");
+ return -1;
+ }
+
elements = parse_iv2((*p) + 2, p);
(*p) += 2;
@@ -418,7 +423,7 @@
/* If this class implements Serializable, it should not land here but in object_custom(). The passed string
obviously doesn't descend from the regular serializer. */
zend_error(E_WARNING, "Erroneous data format for unserializing '%s'", ce->name);
- return 0;
+ return -1;
}
return elements;
@@ -771,6 +776,11 @@
elements = object_common1(UNSERIALIZE_PASSTHRU, ce);
+ if (elements < 0) {
+ efree(class_name);
+ return 0;
+ }
+
if (incomplete_class) {
php_store_class_name(*rval, class_name, len2);
}
@@ -803,12 +813,16 @@
if (yych != '"') goto yy18;
++YYCURSOR;
{
+ long elements;
if (!var_hash) return 0;
INIT_PZVAL(*rval);
- return object_common2(UNSERIALIZE_PASSTHRU,
- object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR));
+ elements = object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR);
+ if (elements < 0) {
+ return 0;
+ }
+ return object_common2(UNSERIALIZE_PASSTHRU, elements);
}
yy32:
yych = *++YYCURSOR;
--- php5.git.orig/ext/standard/var_unserializer.re
+++ php5.git/ext/standard/var_unserializer.re
@@ -410,6 +410,11 @@
{
long elements;
+ if( *p >= max - 2) {
+ zend_error(E_WARNING, "Bad unserialize data");
+ return -1;
+ }
+
elements = parse_iv2((*p) + 2, p);
(*p) += 2;
@@ -424,7 +429,7 @@
/* If this class implements Serializable, it should not land here but in object_custom(). The passed string
obviously doesn't descend from the regular serializer. */
zend_error(E_WARNING, "Erroneous data format for unserializing '%s'", ce->name);
- return 0;
+ return -1;
}
return elements;
@@ -691,12 +696,16 @@
}
"o:" iv ":" ["] {
+ long elements;
if (!var_hash) return 0;
INIT_PZVAL(*rval);
- return object_common2(UNSERIALIZE_PASSTHRU,
- object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR));
+ elements = object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR);
+ if (elements < 0) {
+ return 0;
+ }
+ return object_common2(UNSERIALIZE_PASSTHRU, elements);
}
object ":" uiv ":" ["] {
@@ -838,6 +847,11 @@
elements = object_common1(UNSERIALIZE_PASSTHRU, ce);
+ if (elements < 0) {
+ efree(class_name);
+ return 0;
+ }
+
if (incomplete_class) {
php_store_class_name(*rval, class_name, len2);
}