-
-
Save smalyshev/ed63468e63bc008ba314 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
commit bcd64a9bdd8afcf7f91a12e700d12d12eedc136b | |
Author: Stanislav Malyshev <stas@php.net> | |
Date: Sun Jan 17 17:53:03 2016 -0800 | |
Fixed bug #71311: Use-after-free vulnerability in SPL(ArrayObject, unserialize) | |
diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c | |
index 1f4cad1..67d2ccb 100644 | |
--- a/ext/spl/spl_array.c | |
+++ b/ext/spl/spl_array.c | |
@@ -1778,6 +1778,7 @@ SPL_METHOD(Array, unserialize) | |
intern->ar_flags &= ~SPL_ARRAY_CLONE_MASK; | |
intern->ar_flags |= flags & SPL_ARRAY_CLONE_MASK; | |
zval_ptr_dtor(&intern->array); | |
+ ZVAL_UNDEF(&intern->array); | |
if (!php_var_unserialize(&intern->array, &p, s + buf_len, &var_hash)) { | |
goto outexcept; | |
} | |
diff --git a/ext/standard/tests/serialize/bug71311.phpt b/ext/standard/tests/serialize/bug71311.phpt | |
new file mode 100644 | |
index 0000000..9cd1373 | |
--- /dev/null | |
+++ b/ext/standard/tests/serialize/bug71311.phpt | |
@@ -0,0 +1,16 @@ | |
+--TEST-- | |
+Bug #71311 Use-after-free vulnerability in SPL(ArrayObject, unserialize) | |
+--FILE-- | |
+<?php | |
+$data = unserialize("C:11:\"ArrayObject\":11:{x:i:0;r:3;XX"); | |
+var_dump($data); | |
+?> | |
+--EXPECTF-- | |
+Fatal error: Uncaught UnexpectedValueException: Error at offset 10 of 11 bytes in %s/bug71311.php:2 | |
+Stack trace: | |
+#0 [internal function]: ArrayObject->unserialize('x:i:0;r:3;X') | |
+#1 %s/bug71311.php(2): unserialize('%s') | |
+#2 {main} | |
+ thrown in %s/bug71311.php on line 2 | |
+ | |
+ | |
diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c | |
index 20709ee..12a15c3 100644 | |
--- a/ext/standard/var_unserializer.c | |
+++ b/ext/standard/var_unserializer.c | |
@@ -1,4 +1,4 @@ | |
-/* Generated by re2c 0.13.5 */ | |
+/* Generated by re2c 0.13.7.5 */ | |
#line 1 "ext/standard/var_unserializer.re" | |
/* | |
+----------------------------------------------------------------------+ | |
@@ -574,7 +574,7 @@ yy2: | |
yych = *(YYMARKER = ++YYCURSOR); | |
if (yych == ':') goto yy95; | |
yy3: | |
-#line 869 "ext/standard/var_unserializer.re" | |
+#line 873 "ext/standard/var_unserializer.re" | |
{ return 0; } | |
#line 580 "ext/standard/var_unserializer.c" | |
yy4: | |
@@ -619,7 +619,7 @@ yy13: | |
goto yy3; | |
yy14: | |
++YYCURSOR; | |
-#line 863 "ext/standard/var_unserializer.re" | |
+#line 867 "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"); | |
@@ -651,11 +651,12 @@ yy20: | |
if (yybm[0+yych] & 128) { | |
goto yy20; | |
} | |
- if (yych != ':') goto yy18; | |
+ if (yych <= '/') goto yy18; | |
+ if (yych >= ';') goto yy18; | |
yych = *++YYCURSOR; | |
if (yych != '"') goto yy18; | |
++YYCURSOR; | |
-#line 718 "ext/standard/var_unserializer.re" | |
+#line 722 "ext/standard/var_unserializer.re" | |
{ | |
size_t len, len2, len3, maxlen; | |
zend_long elements; | |
@@ -800,7 +801,7 @@ yy20: | |
return object_common2(UNSERIALIZE_PASSTHRU, elements); | |
} | |
-#line 804 "ext/standard/var_unserializer.c" | |
+#line 805 "ext/standard/var_unserializer.c" | |
yy25: | |
yych = *++YYCURSOR; | |
if (yych <= ',') { | |
@@ -825,14 +826,14 @@ yy27: | |
yych = *++YYCURSOR; | |
if (yych != '"') goto yy18; | |
++YYCURSOR; | |
-#line 711 "ext/standard/var_unserializer.re" | |
+#line 715 "ext/standard/var_unserializer.re" | |
{ | |
if (!var_hash) return 0; | |
return object_common2(UNSERIALIZE_PASSTHRU, | |
object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR)); | |
} | |
-#line 836 "ext/standard/var_unserializer.c" | |
+#line 837 "ext/standard/var_unserializer.c" | |
yy32: | |
yych = *++YYCURSOR; | |
if (yych == '+') goto yy33; | |
@@ -853,7 +854,7 @@ yy34: | |
yych = *++YYCURSOR; | |
if (yych != '{') goto yy18; | |
++YYCURSOR; | |
-#line 687 "ext/standard/var_unserializer.re" | |
+#line 691 "ext/standard/var_unserializer.re" | |
{ | |
zend_long elements = parse_iv(start + 2); | |
/* use iv() not uiv() in order to check data range */ | |
@@ -877,7 +878,7 @@ yy34: | |
return finish_nested_data(UNSERIALIZE_PASSTHRU); | |
} | |
-#line 881 "ext/standard/var_unserializer.c" | |
+#line 882 "ext/standard/var_unserializer.c" | |
yy39: | |
yych = *++YYCURSOR; | |
if (yych == '+') goto yy40; | |
@@ -898,7 +899,7 @@ yy41: | |
yych = *++YYCURSOR; | |
if (yych != '"') goto yy18; | |
++YYCURSOR; | |
-#line 659 "ext/standard/var_unserializer.re" | |
+#line 663 "ext/standard/var_unserializer.re" | |
{ | |
size_t len, maxlen; | |
zend_string *str; | |
@@ -926,7 +927,7 @@ yy41: | |
ZVAL_STR(rval, str); | |
return 1; | |
} | |
-#line 930 "ext/standard/var_unserializer.c" | |
+#line 931 "ext/standard/var_unserializer.c" | |
yy46: | |
yych = *++YYCURSOR; | |
if (yych == '+') goto yy47; | |
@@ -947,7 +948,7 @@ yy48: | |
yych = *++YYCURSOR; | |
if (yych != '"') goto yy18; | |
++YYCURSOR; | |
-#line 632 "ext/standard/var_unserializer.re" | |
+#line 636 "ext/standard/var_unserializer.re" | |
{ | |
size_t len, maxlen; | |
char *str; | |
@@ -974,7 +975,7 @@ yy48: | |
ZVAL_STRINGL(rval, str, len); | |
return 1; | |
} | |
-#line 978 "ext/standard/var_unserializer.c" | |
+#line 979 "ext/standard/var_unserializer.c" | |
yy53: | |
yych = *++YYCURSOR; | |
if (yych <= '/') { | |
@@ -1062,7 +1063,7 @@ yy61: | |
} | |
yy63: | |
++YYCURSOR; | |
-#line 623 "ext/standard/var_unserializer.re" | |
+#line 627 "ext/standard/var_unserializer.re" | |
{ | |
#if SIZEOF_ZEND_LONG == 4 | |
use_double: | |
@@ -1071,7 +1072,7 @@ use_double: | |
ZVAL_DOUBLE(rval, zend_strtod((const char *)start + 2, NULL)); | |
return 1; | |
} | |
-#line 1075 "ext/standard/var_unserializer.c" | |
+#line 1076 "ext/standard/var_unserializer.c" | |
yy65: | |
yych = *++YYCURSOR; | |
if (yych <= ',') { | |
@@ -1130,7 +1131,7 @@ yy73: | |
yych = *++YYCURSOR; | |
if (yych != ';') goto yy18; | |
++YYCURSOR; | |
-#line 607 "ext/standard/var_unserializer.re" | |
+#line 611 "ext/standard/var_unserializer.re" | |
{ | |
*p = YYCURSOR; | |
@@ -1146,7 +1147,7 @@ yy73: | |
return 1; | |
} | |
-#line 1150 "ext/standard/var_unserializer.c" | |
+#line 1151 "ext/standard/var_unserializer.c" | |
yy76: | |
yych = *++YYCURSOR; | |
if (yych == 'N') goto yy73; | |
@@ -1173,7 +1174,7 @@ yy79: | |
if (yych <= '9') goto yy79; | |
if (yych != ';') goto yy18; | |
++YYCURSOR; | |
-#line 581 "ext/standard/var_unserializer.re" | |
+#line 585 "ext/standard/var_unserializer.re" | |
{ | |
#if SIZEOF_ZEND_LONG == 4 | |
int digits = YYCURSOR - start - 3; | |
@@ -1199,7 +1200,7 @@ yy79: | |
ZVAL_LONG(rval, parse_iv(start + 2)); | |
return 1; | |
} | |
-#line 1203 "ext/standard/var_unserializer.c" | |
+#line 1204 "ext/standard/var_unserializer.c" | |
yy83: | |
yych = *++YYCURSOR; | |
if (yych <= '/') goto yy18; | |
@@ -1207,22 +1208,22 @@ yy83: | |
yych = *++YYCURSOR; | |
if (yych != ';') goto yy18; | |
++YYCURSOR; | |
-#line 575 "ext/standard/var_unserializer.re" | |
+#line 579 "ext/standard/var_unserializer.re" | |
{ | |
*p = YYCURSOR; | |
ZVAL_BOOL(rval, parse_iv(start + 2)); | |
return 1; | |
} | |
-#line 1217 "ext/standard/var_unserializer.c" | |
+#line 1218 "ext/standard/var_unserializer.c" | |
yy87: | |
++YYCURSOR; | |
-#line 569 "ext/standard/var_unserializer.re" | |
+#line 573 "ext/standard/var_unserializer.re" | |
{ | |
*p = YYCURSOR; | |
ZVAL_NULL(rval); | |
return 1; | |
} | |
-#line 1226 "ext/standard/var_unserializer.c" | |
+#line 1227 "ext/standard/var_unserializer.c" | |
yy89: | |
yych = *++YYCURSOR; | |
if (yych <= ',') { | |
@@ -1257,6 +1258,10 @@ yy91: | |
return 0; | |
} | |
+ if (rval_ref == rval) { | |
+ return 0; | |
+ } | |
+ | |
if (Z_ISUNDEF_P(rval_ref) || (Z_ISREF_P(rval_ref) && Z_ISUNDEF_P(Z_REFVAL_P(rval_ref)))) { | |
ZVAL_UNDEF(rval); | |
return 1; | |
@@ -1266,7 +1271,7 @@ yy91: | |
return 1; | |
} | |
-#line 1270 "ext/standard/var_unserializer.c" | |
+#line 1275 "ext/standard/var_unserializer.c" | |
yy95: | |
yych = *++YYCURSOR; | |
if (yych <= ',') { | |
@@ -1315,9 +1320,9 @@ yy97: | |
return 1; | |
} | |
-#line 1319 "ext/standard/var_unserializer.c" | |
+#line 1324 "ext/standard/var_unserializer.c" | |
} | |
-#line 871 "ext/standard/var_unserializer.re" | |
+#line 875 "ext/standard/var_unserializer.re" | |
return 0; | |
diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re | |
index 18e3cb3..e4db909 100644 | |
--- a/ext/standard/var_unserializer.re | |
+++ b/ext/standard/var_unserializer.re | |
@@ -556,6 +556,10 @@ PHPAPI int php_var_unserialize_ex(UNSERIALIZE_PARAMETER) | |
return 0; | |
} | |
+ if (rval_ref == rval) { | |
+ return 0; | |
+ } | |
+ | |
if (Z_ISUNDEF_P(rval_ref) || (Z_ISREF_P(rval_ref) && Z_ISUNDEF_P(Z_REFVAL_P(rval_ref)))) { | |
ZVAL_UNDEF(rval); | |
return 1; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment