/72663.diff Secret
Created
August 2, 2016 08:10
Patch for 72663
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 7eb78025d4df8facdca70d3cadd907bdb67902a2 | |
Author: Stanislav Malyshev <stas@php.net> | |
Date: Tue Aug 2 01:08:42 2016 -0700 | |
Fix bug #72663 - destroy broken object when unserializing | |
diff --git a/ext/standard/tests/strings/bug72663.phpt b/ext/standard/tests/strings/bug72663.phpt | |
new file mode 100644 | |
index 0000000..e61f939 | |
--- /dev/null | |
+++ b/ext/standard/tests/strings/bug72663.phpt | |
@@ -0,0 +1,26 @@ | |
+--TEST-- | |
+Bug #72663: Create an Unexpected Object and Don't Invoke __wakeup() in Deserialization | |
+--FILE-- | |
+<?php | |
+class obj implements Serializable { | |
+ var $data; | |
+ function serialize() { | |
+ return serialize($this->data); | |
+ } | |
+ function unserialize($data) { | |
+ $this->data = unserialize($data); | |
+ } | |
+} | |
+ | |
+$inner = 'a:1:{i:0;O:9:"Exception":2:{s:7:"'."\0".'*'."\0".'file";R:4;}'; | |
+$exploit = 'a:2:{i:0;C:3:"obj":'.strlen($inner).':{'.$inner.'}i:1;R:4;}'; | |
+ | |
+$data = unserialize($exploit); | |
+echo $data[1]; | |
+?> | |
+DONE | |
+--EXPECTF-- | |
+Notice: unserialize(): Unexpected end of serialized data in %sbug72663.php on line %d | |
+ | |
+Notice: unserialize(): Error at offset 46 of 47 bytes in %sbug72663.php on line %d | |
+DONE | |
\ No newline at end of file | |
diff --git a/ext/standard/tests/strings/bug72663_2.phpt b/ext/standard/tests/strings/bug72663_2.phpt | |
new file mode 100644 | |
index 0000000..ac605e9 | |
--- /dev/null | |
+++ b/ext/standard/tests/strings/bug72663_2.phpt | |
@@ -0,0 +1,17 @@ | |
+--TEST-- | |
+Bug #72663: Create an Unexpected Object and Don't Invoke __wakeup() in Deserialization | |
+--FILE-- | |
+<?php | |
+ | |
+ini_set('session.serialize_handler', 'php_serialize'); | |
+session_start(); | |
+$sess = 'O:9:"Exception":2:{s:7:"'."\0".'*'."\0".'file";R:1;}'; | |
+session_decode($sess); | |
+var_dump($_SESSION); | |
+?> | |
+DONE | |
+--EXPECTF-- | |
+Notice: session_decode(): Unexpected end of serialized data in %sbug72663_2.php on line %d | |
+array(0) { | |
+} | |
+DONE | |
\ No newline at end of file | |
diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c | |
index 1e45b03..e4ddecf 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" | |
/* | |
+----------------------------------------------------------------------+ | |
@@ -434,6 +434,9 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, long elements) | |
} | |
if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_OBJPROP_PP(rval), elements, 1)) { | |
+ /* We've got partially constructed object on our hands here. Wipe it */ | |
+ zend_hash_clean(Z_OBJPROP_PP(rval)); | |
+ ZVAL_NULL(*rval); | |
return 0; | |
} | |
@@ -482,7 +485,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) | |
-#line 486 "ext/standard/var_unserializer.c" | |
+#line 489 "ext/standard/var_unserializer.c" | |
{ | |
YYCTYPE yych; | |
static const unsigned char yybm[] = { | |
@@ -542,9 +545,9 @@ yy2: | |
yych = *(YYMARKER = ++YYCURSOR); | |
if (yych == ':') goto yy95; | |
yy3: | |
-#line 851 "ext/standard/var_unserializer.re" | |
+#line 854 "ext/standard/var_unserializer.re" | |
{ return 0; } | |
-#line 548 "ext/standard/var_unserializer.c" | |
+#line 551 "ext/standard/var_unserializer.c" | |
yy4: | |
yych = *(YYMARKER = ++YYCURSOR); | |
if (yych == ':') goto yy89; | |
@@ -587,13 +590,13 @@ yy13: | |
goto yy3; | |
yy14: | |
++YYCURSOR; | |
-#line 845 "ext/standard/var_unserializer.re" | |
+#line 848 "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"); | |
return 0; /* not sure if it should be 0 or 1 here? */ | |
} | |
-#line 597 "ext/standard/var_unserializer.c" | |
+#line 600 "ext/standard/var_unserializer.c" | |
yy16: | |
yych = *++YYCURSOR; | |
goto yy3; | |
@@ -619,11 +622,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 698 "ext/standard/var_unserializer.re" | |
+#line 701 "ext/standard/var_unserializer.re" | |
{ | |
size_t len, len2, len3, maxlen; | |
long elements; | |
@@ -770,7 +774,7 @@ yy20: | |
return object_common2(UNSERIALIZE_PASSTHRU, elements); | |
} | |
-#line 774 "ext/standard/var_unserializer.c" | |
+#line 778 "ext/standard/var_unserializer.c" | |
yy25: | |
yych = *++YYCURSOR; | |
if (yych <= ',') { | |
@@ -795,7 +799,7 @@ yy27: | |
yych = *++YYCURSOR; | |
if (yych != '"') goto yy18; | |
++YYCURSOR; | |
-#line 689 "ext/standard/var_unserializer.re" | |
+#line 692 "ext/standard/var_unserializer.re" | |
{ | |
if (!var_hash) return 0; | |
@@ -804,7 +808,7 @@ yy27: | |
return object_common2(UNSERIALIZE_PASSTHRU, | |
object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR)); | |
} | |
-#line 808 "ext/standard/var_unserializer.c" | |
+#line 812 "ext/standard/var_unserializer.c" | |
yy32: | |
yych = *++YYCURSOR; | |
if (yych == '+') goto yy33; | |
@@ -825,7 +829,7 @@ yy34: | |
yych = *++YYCURSOR; | |
if (yych != '{') goto yy18; | |
++YYCURSOR; | |
-#line 668 "ext/standard/var_unserializer.re" | |
+#line 671 "ext/standard/var_unserializer.re" | |
{ | |
long elements = parse_iv(start + 2); | |
/* use iv() not uiv() in order to check data range */ | |
@@ -846,7 +850,7 @@ yy34: | |
return finish_nested_data(UNSERIALIZE_PASSTHRU); | |
} | |
-#line 850 "ext/standard/var_unserializer.c" | |
+#line 854 "ext/standard/var_unserializer.c" | |
yy39: | |
yych = *++YYCURSOR; | |
if (yych == '+') goto yy40; | |
@@ -867,7 +871,7 @@ yy41: | |
yych = *++YYCURSOR; | |
if (yych != '"') goto yy18; | |
++YYCURSOR; | |
-#line 633 "ext/standard/var_unserializer.re" | |
+#line 636 "ext/standard/var_unserializer.re" | |
{ | |
size_t len, maxlen; | |
char *str; | |
@@ -902,7 +906,7 @@ yy41: | |
ZVAL_STRINGL(*rval, str, len, 0); | |
return 1; | |
} | |
-#line 906 "ext/standard/var_unserializer.c" | |
+#line 910 "ext/standard/var_unserializer.c" | |
yy46: | |
yych = *++YYCURSOR; | |
if (yych == '+') goto yy47; | |
@@ -923,7 +927,7 @@ yy48: | |
yych = *++YYCURSOR; | |
if (yych != '"') goto yy18; | |
++YYCURSOR; | |
-#line 600 "ext/standard/var_unserializer.re" | |
+#line 603 "ext/standard/var_unserializer.re" | |
{ | |
size_t len, maxlen; | |
char *str; | |
@@ -956,7 +960,7 @@ yy48: | |
ZVAL_STRINGL(*rval, str, len, 1); | |
return 1; | |
} | |
-#line 960 "ext/standard/var_unserializer.c" | |
+#line 964 "ext/standard/var_unserializer.c" | |
yy53: | |
yych = *++YYCURSOR; | |
if (yych <= '/') { | |
@@ -1044,7 +1048,7 @@ yy61: | |
} | |
yy63: | |
++YYCURSOR; | |
-#line 590 "ext/standard/var_unserializer.re" | |
+#line 593 "ext/standard/var_unserializer.re" | |
{ | |
#if SIZEOF_LONG == 4 | |
use_double: | |
@@ -1054,7 +1058,7 @@ use_double: | |
ZVAL_DOUBLE(*rval, zend_strtod((const char *)start + 2, NULL)); | |
return 1; | |
} | |
-#line 1058 "ext/standard/var_unserializer.c" | |
+#line 1062 "ext/standard/var_unserializer.c" | |
yy65: | |
yych = *++YYCURSOR; | |
if (yych <= ',') { | |
@@ -1113,7 +1117,7 @@ yy73: | |
yych = *++YYCURSOR; | |
if (yych != ';') goto yy18; | |
++YYCURSOR; | |
-#line 575 "ext/standard/var_unserializer.re" | |
+#line 578 "ext/standard/var_unserializer.re" | |
{ | |
*p = YYCURSOR; | |
INIT_PZVAL(*rval); | |
@@ -1128,7 +1132,7 @@ yy73: | |
return 1; | |
} | |
-#line 1132 "ext/standard/var_unserializer.c" | |
+#line 1136 "ext/standard/var_unserializer.c" | |
yy76: | |
yych = *++YYCURSOR; | |
if (yych == 'N') goto yy73; | |
@@ -1155,7 +1159,7 @@ yy79: | |
if (yych <= '9') goto yy79; | |
if (yych != ';') goto yy18; | |
++YYCURSOR; | |
-#line 548 "ext/standard/var_unserializer.re" | |
+#line 551 "ext/standard/var_unserializer.re" | |
{ | |
#if SIZEOF_LONG == 4 | |
int digits = YYCURSOR - start - 3; | |
@@ -1182,7 +1186,7 @@ yy79: | |
ZVAL_LONG(*rval, parse_iv(start + 2)); | |
return 1; | |
} | |
-#line 1186 "ext/standard/var_unserializer.c" | |
+#line 1190 "ext/standard/var_unserializer.c" | |
yy83: | |
yych = *++YYCURSOR; | |
if (yych <= '/') goto yy18; | |
@@ -1190,24 +1194,24 @@ yy83: | |
yych = *++YYCURSOR; | |
if (yych != ';') goto yy18; | |
++YYCURSOR; | |
-#line 541 "ext/standard/var_unserializer.re" | |
+#line 544 "ext/standard/var_unserializer.re" | |
{ | |
*p = YYCURSOR; | |
INIT_PZVAL(*rval); | |
ZVAL_BOOL(*rval, parse_iv(start + 2)); | |
return 1; | |
} | |
-#line 1201 "ext/standard/var_unserializer.c" | |
+#line 1205 "ext/standard/var_unserializer.c" | |
yy87: | |
++YYCURSOR; | |
-#line 534 "ext/standard/var_unserializer.re" | |
+#line 537 "ext/standard/var_unserializer.re" | |
{ | |
*p = YYCURSOR; | |
INIT_PZVAL(*rval); | |
ZVAL_NULL(*rval); | |
return 1; | |
} | |
-#line 1211 "ext/standard/var_unserializer.c" | |
+#line 1215 "ext/standard/var_unserializer.c" | |
yy89: | |
yych = *++YYCURSOR; | |
if (yych <= ',') { | |
@@ -1230,7 +1234,7 @@ yy91: | |
if (yych <= '9') goto yy91; | |
if (yych != ';') goto yy18; | |
++YYCURSOR; | |
-#line 511 "ext/standard/var_unserializer.re" | |
+#line 514 "ext/standard/var_unserializer.re" | |
{ | |
long id; | |
@@ -1253,7 +1257,7 @@ yy91: | |
return 1; | |
} | |
-#line 1257 "ext/standard/var_unserializer.c" | |
+#line 1261 "ext/standard/var_unserializer.c" | |
yy95: | |
yych = *++YYCURSOR; | |
if (yych <= ',') { | |
@@ -1276,7 +1280,7 @@ yy97: | |
if (yych <= '9') goto yy97; | |
if (yych != ';') goto yy18; | |
++YYCURSOR; | |
-#line 490 "ext/standard/var_unserializer.re" | |
+#line 493 "ext/standard/var_unserializer.re" | |
{ | |
long id; | |
@@ -1297,9 +1301,9 @@ yy97: | |
return 1; | |
} | |
-#line 1301 "ext/standard/var_unserializer.c" | |
+#line 1305 "ext/standard/var_unserializer.c" | |
} | |
-#line 853 "ext/standard/var_unserializer.re" | |
+#line 856 "ext/standard/var_unserializer.re" | |
return 0; | |
diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re | |
index d1d4ef9..c1c18c9 100644 | |
--- a/ext/standard/var_unserializer.re | |
+++ b/ext/standard/var_unserializer.re | |
@@ -438,6 +438,9 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, long elements) | |
} | |
if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_OBJPROP_PP(rval), elements, 1)) { | |
+ /* We've got partially constructed object on our hands here. Wipe it. */ | |
+ zend_hash_clean(Z_OBJPROP_PP(rval)); | |
+ ZVAL_NULL(*rval); | |
return 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment