Skip to content

Instantly share code, notes, and snippets.

@nikic
Created June 25, 2017 19:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nikic/46c6ce2005c5d5a0f62cc17fc1dddd96 to your computer and use it in GitHub Desktop.
Save nikic/46c6ce2005c5d5a0f62cc17fc1dddd96 to your computer and use it in GitHub Desktop.
From af336c11afdc6bc116530320cdbad9408e46971d Mon Sep 17 00:00:00 2001
From: Nikita Popov <nikita.ppv@gmail.com>
Date: Sun, 25 Jun 2017 21:15:26 +0200
Subject: [PATCH] Fixed bug #74111
---
ext/standard/tests/serialize/bug25378.phpt | 2 +-
ext/standard/tests/serialize/bug74111.phpt | 10 +++++
ext/standard/var_unserializer.c | 71 +++++++++++++++---------------
ext/standard/var_unserializer.re | 11 +++--
4 files changed, 51 insertions(+), 43 deletions(-)
create mode 100644 ext/standard/tests/serialize/bug74111.phpt
diff --git a/ext/standard/tests/serialize/bug25378.phpt b/ext/standard/tests/serialize/bug25378.phpt
index e865b96..e95a427 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/tests/serialize/bug74111.phpt b/ext/standard/tests/serialize/bug74111.phpt
new file mode 100644
index 0000000..62922be
--- /dev/null
+++ b/ext/standard/tests/serialize/bug74111.phpt
@@ -0,0 +1,10 @@
+--TEST--
+Bug #74111: Heap buffer overread (READ: 1) finish_nested_data from unserialize
+--FILE--
+<?php
+$s = 'O:8:"stdClass":00000000';
+var_dump(unserialize($s));
+?>
+--EXPECTF--
+Notice: unserialize(): Error at offset 25 of 23 bytes in %s on line %d
+bool(false)
diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c
index 76688b9..49fb183 100644
--- a/ext/standard/var_unserializer.c
+++ b/ext/standard/var_unserializer.c
@@ -428,13 +428,12 @@ string_key:
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)
@@ -578,7 +577,7 @@ static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER)
start = cursor;
-#line 582 "ext/standard/var_unserializer.c"
+#line 581 "ext/standard/var_unserializer.c"
{
YYCTYPE yych;
static const unsigned char yybm[] = {
@@ -636,9 +635,9 @@ static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER)
yy2:
++YYCURSOR;
yy3:
-#line 959 "ext/standard/var_unserializer.re"
+#line 958 "ext/standard/var_unserializer.re"
{ return 0; }
-#line 642 "ext/standard/var_unserializer.c"
+#line 641 "ext/standard/var_unserializer.c"
yy4:
yych = *(YYMARKER = ++YYCURSOR);
if (yych == ':') goto yy17;
@@ -685,13 +684,13 @@ yy14:
goto yy3;
yy15:
++YYCURSOR;
-#line 953 "ext/standard/var_unserializer.re"
+#line 952 "ext/standard/var_unserializer.re"
{
/* this is the case where we have less data than planned */
php_error_docref(NULL, E_NOTICE, "Unexpected end of serialized data");
return 0; /* not sure if it should be 0 or 1 here? */
}
-#line 695 "ext/standard/var_unserializer.c"
+#line 694 "ext/standard/var_unserializer.c"
yy17:
yych = *++YYCURSOR;
if (yybm[0+yych] & 128) {
@@ -703,13 +702,13 @@ yy18:
goto yy3;
yy19:
++YYCURSOR;
-#line 637 "ext/standard/var_unserializer.re"
+#line 636 "ext/standard/var_unserializer.re"
{
*p = YYCURSOR;
ZVAL_NULL(rval);
return 1;
}
-#line 713 "ext/standard/var_unserializer.c"
+#line 712 "ext/standard/var_unserializer.c"
yy21:
yych = *++YYCURSOR;
if (yych <= ',') {
@@ -959,7 +958,7 @@ yy62:
goto yy18;
yy63:
++YYCURSOR;
-#line 586 "ext/standard/var_unserializer.re"
+#line 585 "ext/standard/var_unserializer.re"
{
zend_long id;
@@ -985,7 +984,7 @@ yy63:
return 1;
}
-#line 989 "ext/standard/var_unserializer.c"
+#line 988 "ext/standard/var_unserializer.c"
yy65:
yych = *++YYCURSOR;
if (yych == '"') goto yy84;
@@ -996,13 +995,13 @@ yy66:
goto yy18;
yy67:
++YYCURSOR;
-#line 643 "ext/standard/var_unserializer.re"
+#line 642 "ext/standard/var_unserializer.re"
{
*p = YYCURSOR;
ZVAL_BOOL(rval, parse_iv(start + 2));
return 1;
}
-#line 1006 "ext/standard/var_unserializer.c"
+#line 1005 "ext/standard/var_unserializer.c"
yy69:
++YYCURSOR;
if ((YYLIMIT - YYCURSOR) < 4) YYFILL(4);
@@ -1022,7 +1021,7 @@ yy69:
}
yy71:
++YYCURSOR;
-#line 691 "ext/standard/var_unserializer.re"
+#line 690 "ext/standard/var_unserializer.re"
{
#if SIZEOF_ZEND_LONG == 4
use_double:
@@ -1031,7 +1030,7 @@ use_double:
ZVAL_DOUBLE(rval, zend_strtod((const char *)start + 2, NULL));
return 1;
}
-#line 1035 "ext/standard/var_unserializer.c"
+#line 1034 "ext/standard/var_unserializer.c"
yy73:
yych = *++YYCURSOR;
if (yych <= ',') {
@@ -1053,7 +1052,7 @@ yy75:
goto yy18;
yy76:
++YYCURSOR;
-#line 649 "ext/standard/var_unserializer.re"
+#line 648 "ext/standard/var_unserializer.re"
{
#if SIZEOF_ZEND_LONG == 4
int digits = YYCURSOR - start - 3;
@@ -1079,14 +1078,14 @@ yy76:
ZVAL_LONG(rval, parse_iv(start + 2));
return 1;
}
-#line 1083 "ext/standard/var_unserializer.c"
+#line 1082 "ext/standard/var_unserializer.c"
yy78:
yych = *++YYCURSOR;
if (yych == '"') goto yy92;
goto yy18;
yy79:
++YYCURSOR;
-#line 612 "ext/standard/var_unserializer.re"
+#line 611 "ext/standard/var_unserializer.re"
{
zend_long id;
@@ -1111,14 +1110,14 @@ yy79:
return 1;
}
-#line 1115 "ext/standard/var_unserializer.c"
+#line 1114 "ext/standard/var_unserializer.c"
yy81:
yych = *++YYCURSOR;
if (yych == '"') goto yy94;
goto yy18;
yy82:
++YYCURSOR;
-#line 801 "ext/standard/var_unserializer.re"
+#line 800 "ext/standard/var_unserializer.re"
{
size_t len, len2, len3, maxlen;
zend_long elements;
@@ -1270,10 +1269,10 @@ yy82:
return object_common2(UNSERIALIZE_PASSTHRU, elements);
}
-#line 1274 "ext/standard/var_unserializer.c"
+#line 1273 "ext/standard/var_unserializer.c"
yy84:
++YYCURSOR;
-#line 732 "ext/standard/var_unserializer.re"
+#line 731 "ext/standard/var_unserializer.re"
{
size_t len, maxlen;
zend_string *str;
@@ -1307,10 +1306,10 @@ yy84:
ZVAL_STR(rval, str);
return 1;
}
-#line 1311 "ext/standard/var_unserializer.c"
+#line 1310 "ext/standard/var_unserializer.c"
yy86:
++YYCURSOR;
-#line 766 "ext/standard/var_unserializer.re"
+#line 765 "ext/standard/var_unserializer.re"
{
zend_long elements = parse_iv(start + 2);
/* use iv() not uiv() in order to check data range */
@@ -1334,7 +1333,7 @@ yy86:
return finish_nested_data(UNSERIALIZE_PASSTHRU);
}
-#line 1338 "ext/standard/var_unserializer.c"
+#line 1337 "ext/standard/var_unserializer.c"
yy88:
yych = *++YYCURSOR;
if (yych <= ',') {
@@ -1359,7 +1358,7 @@ yy91:
goto yy18;
yy92:
++YYCURSOR;
-#line 790 "ext/standard/var_unserializer.re"
+#line 789 "ext/standard/var_unserializer.re"
{
long elements;
if (!var_hash) return 0;
@@ -1370,10 +1369,10 @@ yy92:
}
return object_common2(UNSERIALIZE_PASSTHRU, elements);
}
-#line 1374 "ext/standard/var_unserializer.c"
+#line 1373 "ext/standard/var_unserializer.c"
yy94:
++YYCURSOR;
-#line 700 "ext/standard/var_unserializer.re"
+#line 699 "ext/standard/var_unserializer.re"
{
size_t len, maxlen;
char *str;
@@ -1405,7 +1404,7 @@ yy94:
ZVAL_STRINGL(rval, str, len);
return 1;
}
-#line 1409 "ext/standard/var_unserializer.c"
+#line 1408 "ext/standard/var_unserializer.c"
yy96:
yych = *++YYCURSOR;
if (yych <= '/') goto yy18;
@@ -1413,7 +1412,7 @@ yy96:
goto yy18;
yy97:
++YYCURSOR;
-#line 675 "ext/standard/var_unserializer.re"
+#line 674 "ext/standard/var_unserializer.re"
{
*p = YYCURSOR;
@@ -1429,9 +1428,9 @@ yy97:
return 1;
}
-#line 1433 "ext/standard/var_unserializer.c"
+#line 1432 "ext/standard/var_unserializer.c"
}
-#line 961 "ext/standard/var_unserializer.re"
+#line 960 "ext/standard/var_unserializer.re"
return 0;
diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re
index b5f459a..761ab4f 100644
--- a/ext/standard/var_unserializer.re
+++ b/ext/standard/var_unserializer.re
@@ -432,13 +432,12 @@ string_key:
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.7.4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment