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.
 
 

217 lines
5.6 KiB

From a7ddf7b792796da9636e474e0ce514c1b566c1a8 Mon Sep 17 00:00:00 2001
From: Lucas Kanashiro <kanashiro@debian.org>
Date: Tue, 29 Aug 2017 17:32:01 -0300
Subject: [PATCH] Fix buffer over-read in finish_nested_data
The finish_nested_data function in ext/standard/var_unserializer.re in
PHP is prone to a buffer over-read while unserializing untrusted data.
Exploitation of this issue can have an unspecified impact on the
integrity of PHP.
This is an adaptation of this upstream commit: 61ba5f84774938617f78d65c06e5933cff2d8af3
Fixes CVE-2017-12933
Bug: https://bugs.php.net/bug.php?id=74111
---
ext/standard/tests/serialize/bug25378.phpt | 2 +-
ext/standard/var_unserializer.c | 41 +++++++++++++++---------------
ext/standard/var_unserializer.re | 11 ++++----
3 files changed, 26 insertions(+), 28 deletions(-)
diff --git a/ext/standard/tests/serialize/bug25378.phpt b/ext/standard/tests/serialize/bug25378.phpt
index e865b96e..e95a4270 100644
--- a/ext/standard/tests/serialize/bug25378.phpt
+++ b/ext/standard/tests/serialize/bug25378.phpt
@@ -42,7 +42,7 @@ bool(false)
Notice: unserialize(): Error at offset 17 of 33 bytes in %sbug25378.php on line %d
bool(false)
-Notice: unserialize(): Error at offset 33 of 32 bytes in %sbug25378.php on line %d
+Notice: unserialize(): Error at offset 32 of 32 bytes in %sbug25378.php on line %d
bool(false)
Notice: unserialize(): Error at offset 2 of 13 bytes in %sbug25378.php on line %d
diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c
index 22594ad5..0fba6130 100644
--- a/ext/standard/var_unserializer.c
+++ b/ext/standard/var_unserializer.c
@@ -407,13 +407,12 @@ static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, long
static inline int finish_nested_data(UNSERIALIZE_PARAMETER)
{
- if (*((*p)++) == '}')
- return 1;
+ if (*p >= max || **p != '}') {
+ return 0;
+ }
-#if SOMETHING_NEW_MIGHT_LEAD_TO_CRASH_ENABLE_IF_YOU_ARE_BRAVE
- zval_ptr_dtor(rval);
-#endif
- return 0;
+ (*p)++;
+ return 1;
}
static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce)
@@ -563,7 +562,7 @@ yy2:
default: goto yy3;
}
yy3:
-#line 901 "ext/standard/var_unserializer.re"
+#line 900 "ext/standard/var_unserializer.re"
{ return 0; }
#line 569 "<stdout>"
yy4:
@@ -628,7 +627,7 @@ yy13:
}
yy14:
++YYCURSOR;
-#line 895 "ext/standard/var_unserializer.re"
+#line 894 "ext/standard/var_unserializer.re"
{
/* this is the case where we have less data than planned */
php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unexpected end of serialized data");
@@ -698,7 +697,7 @@ yy22:
}
yy23:
++YYCURSOR;
-#line 743 "ext/standard/var_unserializer.re"
+#line 742 "ext/standard/var_unserializer.re"
{
size_t len, len2, len3, maxlen;
long elements;
@@ -909,7 +908,7 @@ yy29:
}
yy30:
++YYCURSOR;
-#line 730 "ext/standard/var_unserializer.re"
+#line 729 "ext/standard/var_unserializer.re"
{
long elements;
if (!var_hash) return 0;
@@ -980,7 +979,7 @@ yy36:
}
yy37:
++YYCURSOR;
-#line 709 "ext/standard/var_unserializer.re"
+#line 708 "ext/standard/var_unserializer.re"
{
long elements = parse_iv(start + 2);
/* use iv() not uiv() in order to check data range */
@@ -1059,7 +1058,7 @@ yy43:
}
yy44:
++YYCURSOR;
-#line 680 "ext/standard/var_unserializer.re"
+#line 679 "ext/standard/var_unserializer.re"
{
size_t len, maxlen;
char *str;
@@ -1146,7 +1145,7 @@ yy50:
}
yy51:
++YYCURSOR;
-#line 652 "ext/standard/var_unserializer.re"
+#line 651 "ext/standard/var_unserializer.re"
{
size_t len, maxlen;
char *str;
@@ -1298,7 +1297,7 @@ yy61:
}
yy63:
++YYCURSOR;
-#line 642 "ext/standard/var_unserializer.re"
+#line 641 "ext/standard/var_unserializer.re"
{
#if SIZEOF_LONG == 4
use_double:
@@ -1410,7 +1409,7 @@ yy73:
}
yy74:
++YYCURSOR;
-#line 627 "ext/standard/var_unserializer.re"
+#line 626 "ext/standard/var_unserializer.re"
{
*p = YYCURSOR;
INIT_PZVAL(*rval);
@@ -1484,7 +1483,7 @@ yy79:
}
yy81:
++YYCURSOR;
-#line 600 "ext/standard/var_unserializer.re"
+#line 599 "ext/standard/var_unserializer.re"
{
#if SIZEOF_LONG == 4
int digits = YYCURSOR - start - 3;
@@ -1527,7 +1526,7 @@ yy84:
}
yy85:
++YYCURSOR;
-#line 593 "ext/standard/var_unserializer.re"
+#line 592 "ext/standard/var_unserializer.re"
{
*p = YYCURSOR;
INIT_PZVAL(*rval);
@@ -1537,7 +1536,7 @@ yy85:
#line 1538 "<stdout>"
yy87:
++YYCURSOR;
-#line 586 "ext/standard/var_unserializer.re"
+#line 585 "ext/standard/var_unserializer.re"
{
*p = YYCURSOR;
INIT_PZVAL(*rval);
@@ -1597,7 +1596,7 @@ yy91:
}
yy93:
++YYCURSOR;
-#line 563 "ext/standard/var_unserializer.re"
+#line 562 "ext/standard/var_unserializer.re"
{
long id;
@@ -1673,7 +1672,7 @@ yy97:
}
yy99:
++YYCURSOR;
-#line 542 "ext/standard/var_unserializer.re"
+#line 541 "ext/standard/var_unserializer.re"
{
long id;
@@ -1696,7 +1695,7 @@ yy99:
}
#line 1698 "<stdout>"
}
-#line 903 "ext/standard/var_unserializer.re"
+#line 902 "ext/standard/var_unserializer.re"
return 0;
diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re
index d4d5622b..b161fe26 100644
--- a/ext/standard/var_unserializer.re
+++ b/ext/standard/var_unserializer.re
@@ -411,13 +411,12 @@ static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, long
static inline int finish_nested_data(UNSERIALIZE_PARAMETER)
{
- if (*((*p)++) == '}')
- return 1;
+ if (*p >= max || **p != '}') {
+ return 0;
+ }
-#if SOMETHING_NEW_MIGHT_LEAD_TO_CRASH_ENABLE_IF_YOU_ARE_BRAVE
- zval_ptr_dtor(rval);
-#endif
- return 0;
+ (*p)++;
+ return 1;
}
static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce)
--
2.14.1