summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2018-07-02 17:28:45 +0200
committerNikita Popov <nikita.ppv@gmail.com>2018-07-02 17:29:32 +0200
commit09bb2527e96bcefa79ae5d5d93038f2a0cc80d0a (patch)
treec19721a3c63f378a4bc66113a41188bf992ed03c /ext
parent26a33a96fa5a85bcc74e33c1b8103d3841e11bad (diff)
parentc793885b7624be4e2a95c69a2b8b3fee969b312f (diff)
downloadphp-git-09bb2527e96bcefa79ae5d5d93038f2a0cc80d0a.tar.gz
Merge branch 'PHP-7.1' into PHP-7.2
Diffstat (limited to 'ext')
-rw-r--r--ext/gmp/bug74670.phpt10
-rw-r--r--ext/gmp/tests/serialize.phpt2
-rw-r--r--ext/standard/tests/serialize/bug71311.phpt2
-rw-r--r--ext/standard/tests/serialize/bug73341.phpt4
-rw-r--r--ext/standard/var_unserializer.c74
-rw-r--r--ext/standard/var_unserializer.re12
6 files changed, 63 insertions, 41 deletions
diff --git a/ext/gmp/bug74670.phpt b/ext/gmp/bug74670.phpt
new file mode 100644
index 0000000000..a28640b5c6
--- /dev/null
+++ b/ext/gmp/bug74670.phpt
@@ -0,0 +1,10 @@
+--TEST--
+Bug #74670: Integer Underflow when unserializing GMP and possible other classes
+--FILE--
+<?php
+$str = 'C:3:"GMP":4:{s:6666666666:""}';
+var_dump(unserialize($str));
+?>
+--EXPECTF--
+Notice: unserialize(): Error at offset 13 of 29 bytes in %s on line %d
+bool(false)
diff --git a/ext/gmp/tests/serialize.phpt b/ext/gmp/tests/serialize.phpt
index 5e308fa14e..e9b9bb549f 100644
--- a/ext/gmp/tests/serialize.phpt
+++ b/ext/gmp/tests/serialize.phpt
@@ -18,7 +18,7 @@ try {
} catch (Exception $e) { var_dump($e->getMessage()); }
try {
- unserialize('C:3:"GMP":8:{s:2:"42";}');
+ unserialize('C:3:"GMP":9:{s:2:"42";}');
} catch (Exception $e) { var_dump($e->getMessage()); }
?>
diff --git a/ext/standard/tests/serialize/bug71311.phpt b/ext/standard/tests/serialize/bug71311.phpt
index 3c70783d37..70267c5b0b 100644
--- a/ext/standard/tests/serialize/bug71311.phpt
+++ b/ext/standard/tests/serialize/bug71311.phpt
@@ -2,7 +2,7 @@
Bug #71311 Use-after-free vulnerability in SPL(ArrayObject, unserialize)
--FILE--
<?php
-$data = unserialize("C:11:\"ArrayObject\":11:{x:i:0;r:3;XX");
+$data = unserialize("C:11:\"ArrayObject\":11:{x:i:0;r:3;X}");
var_dump($data);
?>
--EXPECTF--
diff --git a/ext/standard/tests/serialize/bug73341.phpt b/ext/standard/tests/serialize/bug73341.phpt
index 55423217c3..86fd457c60 100644
--- a/ext/standard/tests/serialize/bug73341.phpt
+++ b/ext/standard/tests/serialize/bug73341.phpt
@@ -3,7 +3,7 @@ Bug #73144 (Use-afte-free in ArrayObject Deserialization)
--FILE--
<?php
try {
-$token = 'a:2:{i:0;O:1:"0":2:0s:1:"0";i:0;s:1:"0";a:1:{i:0;C:11:"ArrayObject":7:0x:i:0;r0';
+$token = 'a:2:{i:0;O:1:"0":2:0s:1:"0";i:0;s:1:"0";a:1:{i:0;C:11:"ArrayObject":7:{x:i:0;r}';
$obj = unserialize($token);
} catch(Exception $e) {
echo $e->getMessage()."\n";
@@ -21,4 +21,4 @@ unserialize($exploit);
Error at offset 6 of 7 bytes
Notice: ArrayObject::unserialize(): Unexpected end of serialized data in %sbug73341.php on line %d
-Error at offset 24 of 34 bytes \ No newline at end of file
+Error at offset 24 of 34 bytes
diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c
index 108887580f..8c16a555fd 100644
--- a/ext/standard/var_unserializer.c
+++ b/ext/standard/var_unserializer.c
@@ -1,4 +1,4 @@
-/* Generated by re2c 0.16 */
+/* Generated by re2c 1.0.1 */
#line 1 "ext/standard/var_unserializer.re"
/*
+----------------------------------------------------------------------+
@@ -519,6 +519,13 @@ static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce)
return 0;
}
+ /* Check that '}' is present before calling ce->unserialize() to mitigate issues
+ * with unserialize reading past the end of the passed buffer if the string is not
+ * appropriately terminated (usually NUL terminated, but '}' is also sufficient.) */
+ if ((*p)[datalen] != '}') {
+ return 0;
+ }
+
if (ce->unserialize == NULL) {
zend_error(E_WARNING, "Class %s has no unserializer", ZSTR_VAL(ce->name));
object_init_ex(rval, ce);
@@ -526,9 +533,8 @@ static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce)
return 0;
}
- (*p) += datalen;
-
- return finish_nested_data(UNSERIALIZE_PASSTHRU);
+ (*p) += datalen + 1; /* +1 for '}' */
+ return 1;
}
static inline zend_long object_common1(UNSERIALIZE_PARAMETER, zend_class_entry *ce)
@@ -645,7 +651,7 @@ static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER)
start = cursor;
-#line 649 "ext/standard/var_unserializer.c"
+#line 655 "ext/standard/var_unserializer.c"
{
YYCTYPE yych;
static const unsigned char yybm[] = {
@@ -703,9 +709,9 @@ static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER)
yy2:
++YYCURSOR;
yy3:
-#line 1036 "ext/standard/var_unserializer.re"
+#line 1042 "ext/standard/var_unserializer.re"
{ return 0; }
-#line 709 "ext/standard/var_unserializer.c"
+#line 715 "ext/standard/var_unserializer.c"
yy4:
yych = *(YYMARKER = ++YYCURSOR);
if (yych == ':') goto yy17;
@@ -752,13 +758,13 @@ yy14:
goto yy3;
yy15:
++YYCURSOR;
-#line 1030 "ext/standard/var_unserializer.re"
+#line 1036 "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 762 "ext/standard/var_unserializer.c"
+#line 768 "ext/standard/var_unserializer.c"
yy17:
yych = *++YYCURSOR;
if (yybm[0+yych] & 128) {
@@ -769,13 +775,13 @@ yy18:
goto yy3;
yy19:
++YYCURSOR;
-#line 702 "ext/standard/var_unserializer.re"
+#line 708 "ext/standard/var_unserializer.re"
{
*p = YYCURSOR;
ZVAL_NULL(rval);
return 1;
}
-#line 779 "ext/standard/var_unserializer.c"
+#line 785 "ext/standard/var_unserializer.c"
yy21:
yych = *++YYCURSOR;
if (yych <= '/') goto yy18;
@@ -974,7 +980,7 @@ yy55:
goto yy18;
yy56:
++YYCURSOR;
-#line 653 "ext/standard/var_unserializer.re"
+#line 659 "ext/standard/var_unserializer.re"
{
zend_long id;
@@ -999,7 +1005,7 @@ yy56:
return 1;
}
-#line 1003 "ext/standard/var_unserializer.c"
+#line 1009 "ext/standard/var_unserializer.c"
yy58:
yych = *++YYCURSOR;
if (yych == '"') goto yy77;
@@ -1010,13 +1016,13 @@ yy59:
goto yy18;
yy60:
++YYCURSOR;
-#line 708 "ext/standard/var_unserializer.re"
+#line 714 "ext/standard/var_unserializer.re"
{
*p = YYCURSOR;
ZVAL_BOOL(rval, parse_iv(start + 2));
return 1;
}
-#line 1020 "ext/standard/var_unserializer.c"
+#line 1026 "ext/standard/var_unserializer.c"
yy62:
++YYCURSOR;
if ((YYLIMIT - YYCURSOR) < 3) YYFILL(3);
@@ -1036,7 +1042,7 @@ yy62:
}
yy64:
++YYCURSOR;
-#line 756 "ext/standard/var_unserializer.re"
+#line 762 "ext/standard/var_unserializer.re"
{
#if SIZEOF_ZEND_LONG == 4
use_double:
@@ -1045,7 +1051,7 @@ use_double:
ZVAL_DOUBLE(rval, zend_strtod((const char *)start + 2, NULL));
return 1;
}
-#line 1049 "ext/standard/var_unserializer.c"
+#line 1055 "ext/standard/var_unserializer.c"
yy66:
yych = *++YYCURSOR;
if (yych <= ',') {
@@ -1067,7 +1073,7 @@ yy68:
goto yy18;
yy69:
++YYCURSOR;
-#line 714 "ext/standard/var_unserializer.re"
+#line 720 "ext/standard/var_unserializer.re"
{
#if SIZEOF_ZEND_LONG == 4
int digits = YYCURSOR - start - 3;
@@ -1093,14 +1099,14 @@ yy69:
ZVAL_LONG(rval, parse_iv(start + 2));
return 1;
}
-#line 1097 "ext/standard/var_unserializer.c"
+#line 1103 "ext/standard/var_unserializer.c"
yy71:
yych = *++YYCURSOR;
if (yych == '"') goto yy85;
goto yy18;
yy72:
++YYCURSOR;
-#line 678 "ext/standard/var_unserializer.re"
+#line 684 "ext/standard/var_unserializer.re"
{
zend_long id;
@@ -1124,14 +1130,14 @@ yy72:
return 1;
}
-#line 1128 "ext/standard/var_unserializer.c"
+#line 1134 "ext/standard/var_unserializer.c"
yy74:
yych = *++YYCURSOR;
if (yych == '"') goto yy87;
goto yy18;
yy75:
++YYCURSOR;
-#line 878 "ext/standard/var_unserializer.re"
+#line 884 "ext/standard/var_unserializer.re"
{
size_t len, len2, len3, maxlen;
zend_long elements;
@@ -1283,10 +1289,10 @@ yy75:
return object_common2(UNSERIALIZE_PASSTHRU, elements);
}
-#line 1287 "ext/standard/var_unserializer.c"
+#line 1293 "ext/standard/var_unserializer.c"
yy77:
++YYCURSOR;
-#line 803 "ext/standard/var_unserializer.re"
+#line 809 "ext/standard/var_unserializer.re"
{
size_t len, maxlen;
zend_string *str;
@@ -1320,10 +1326,10 @@ yy77:
ZVAL_STR(rval, str);
return 1;
}
-#line 1324 "ext/standard/var_unserializer.c"
+#line 1330 "ext/standard/var_unserializer.c"
yy79:
++YYCURSOR;
-#line 837 "ext/standard/var_unserializer.re"
+#line 843 "ext/standard/var_unserializer.re"
{
zend_long elements = parse_iv(start + 2);
/* use iv() not uiv() in order to check data range */
@@ -1353,7 +1359,7 @@ yy79:
return finish_nested_data(UNSERIALIZE_PASSTHRU);
}
-#line 1357 "ext/standard/var_unserializer.c"
+#line 1363 "ext/standard/var_unserializer.c"
yy81:
yych = *++YYCURSOR;
if (yych <= '/') goto yy18;
@@ -1372,7 +1378,7 @@ yy84:
goto yy18;
yy85:
++YYCURSOR;
-#line 867 "ext/standard/var_unserializer.re"
+#line 873 "ext/standard/var_unserializer.re"
{
zend_long elements;
if (!var_hash) return 0;
@@ -1383,10 +1389,10 @@ yy85:
}
return object_common2(UNSERIALIZE_PASSTHRU, elements);
}
-#line 1387 "ext/standard/var_unserializer.c"
+#line 1393 "ext/standard/var_unserializer.c"
yy87:
++YYCURSOR;
-#line 765 "ext/standard/var_unserializer.re"
+#line 771 "ext/standard/var_unserializer.re"
{
size_t len, maxlen;
char *str;
@@ -1424,10 +1430,10 @@ yy87:
}
return 1;
}
-#line 1428 "ext/standard/var_unserializer.c"
+#line 1434 "ext/standard/var_unserializer.c"
yy89:
++YYCURSOR;
-#line 740 "ext/standard/var_unserializer.re"
+#line 746 "ext/standard/var_unserializer.re"
{
*p = YYCURSOR;
@@ -1443,9 +1449,9 @@ yy89:
return 1;
}
-#line 1447 "ext/standard/var_unserializer.c"
+#line 1453 "ext/standard/var_unserializer.c"
}
-#line 1038 "ext/standard/var_unserializer.re"
+#line 1044 "ext/standard/var_unserializer.re"
return 0;
diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re
index af42222677..3d23925657 100644
--- a/ext/standard/var_unserializer.re
+++ b/ext/standard/var_unserializer.re
@@ -523,6 +523,13 @@ static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce)
return 0;
}
+ /* Check that '}' is present before calling ce->unserialize() to mitigate issues
+ * with unserialize reading past the end of the passed buffer if the string is not
+ * appropriately terminated (usually NUL terminated, but '}' is also sufficient.) */
+ if ((*p)[datalen] != '}') {
+ return 0;
+ }
+
if (ce->unserialize == NULL) {
zend_error(E_WARNING, "Class %s has no unserializer", ZSTR_VAL(ce->name));
object_init_ex(rval, ce);
@@ -530,9 +537,8 @@ static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce)
return 0;
}
- (*p) += datalen;
-
- return finish_nested_data(UNSERIALIZE_PASSTHRU);
+ (*p) += datalen + 1; /* +1 for '}' */
+ return 1;
}
static inline zend_long object_common1(UNSERIALIZE_PARAMETER, zend_class_entry *ce)