summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS4
-rw-r--r--ext/standard/tests/serialize/bug70213.phpt30
-rw-r--r--ext/standard/var_unserializer.c32
-rw-r--r--ext/standard/var_unserializer.re2
4 files changed, 53 insertions, 15 deletions
diff --git a/NEWS b/NEWS
index e957009839..0bb1e67723 100644
--- a/NEWS
+++ b/NEWS
@@ -13,6 +13,10 @@ PHP NEWS
. Reverted fix for bug #73530 (Unsetting result set may reset other result
set). (cmb)
+- Standard:
+ . Fixed bug #70213 (Unserialize context shared on double class lookup).
+ (Taoguang Chen)
+
08 Dec 2016, PHP 5.6.29
- Mbstring:
diff --git a/ext/standard/tests/serialize/bug70213.phpt b/ext/standard/tests/serialize/bug70213.phpt
new file mode 100644
index 0000000000..c01d362be0
--- /dev/null
+++ b/ext/standard/tests/serialize/bug70213.phpt
@@ -0,0 +1,30 @@
+--TEST--
+Bug #70213: Unserialize context shared on double class lookup
+--FILE--
+<?php
+
+ini_set('unserialize_callback_func', 'evil');
+
+function evil() {
+ function __autoload($arg) {
+ var_dump(unserialize('R:1;'));
+ }
+}
+
+var_dump(unserialize('a:2:{i:0;i:42;i:1;O:4:"evil":0:{}}'));
+
+?>
+--EXPECTF--
+Notice: unserialize(): Error at offset 4 of 4 bytes in %s on line %d
+bool(false)
+
+Warning: unserialize(): Function evil() hasn't defined the class it was called for in %s on line %d
+array(2) {
+ [0]=>
+ int(42)
+ [1]=>
+ object(__PHP_Incomplete_Class)#1 (1) {
+ ["__PHP_Incomplete_Class_Name"]=>
+ string(4) "evil"
+ }
+}
diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c
index efb0942b05..79d98e5a24 100644
--- a/ext/standard/var_unserializer.c
+++ b/ext/standard/var_unserializer.c
@@ -557,7 +557,7 @@ yy2:
yych = *(YYMARKER = ++YYCURSOR);
if (yych == ':') goto yy95;
yy3:
-#line 875 "ext/standard/var_unserializer.re"
+#line 877 "ext/standard/var_unserializer.re"
{ return 0; }
#line 563 "ext/standard/var_unserializer.c"
yy4:
@@ -602,7 +602,7 @@ yy13:
goto yy3;
yy14:
++YYCURSOR;
-#line 869 "ext/standard/var_unserializer.re"
+#line 871 "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");
@@ -750,6 +750,7 @@ yy20:
}
/* The callback function may have defined the class */
+ BG(serialize_lock)++;
if (zend_lookup_class(class_name, len2, &pce TSRMLS_CC) == SUCCESS) {
ce = *pce;
} else {
@@ -757,6 +758,7 @@ yy20:
incomplete_class = 1;
ce = PHP_IC_ENTRY;
}
+ BG(serialize_lock)--;
zval_ptr_dtor(&user_func);
zval_ptr_dtor(&arg_func_name);
@@ -791,7 +793,7 @@ yy20:
return object_common2(UNSERIALIZE_PASSTHRU, elements);
}
-#line 795 "ext/standard/var_unserializer.c"
+#line 797 "ext/standard/var_unserializer.c"
yy25:
yych = *++YYCURSOR;
if (yych <= ',') {
@@ -829,7 +831,7 @@ yy27:
}
return object_common2(UNSERIALIZE_PASSTHRU, elements);
}
-#line 833 "ext/standard/var_unserializer.c"
+#line 835 "ext/standard/var_unserializer.c"
yy32:
yych = *++YYCURSOR;
if (yych == '+') goto yy33;
@@ -871,7 +873,7 @@ yy34:
return finish_nested_data(UNSERIALIZE_PASSTHRU);
}
-#line 875 "ext/standard/var_unserializer.c"
+#line 877 "ext/standard/var_unserializer.c"
yy39:
yych = *++YYCURSOR;
if (yych == '+') goto yy40;
@@ -927,7 +929,7 @@ yy41:
ZVAL_STRINGL(*rval, str, len, 0);
return 1;
}
-#line 931 "ext/standard/var_unserializer.c"
+#line 933 "ext/standard/var_unserializer.c"
yy46:
yych = *++YYCURSOR;
if (yych == '+') goto yy47;
@@ -981,7 +983,7 @@ yy48:
ZVAL_STRINGL(*rval, str, len, 1);
return 1;
}
-#line 985 "ext/standard/var_unserializer.c"
+#line 987 "ext/standard/var_unserializer.c"
yy53:
yych = *++YYCURSOR;
if (yych <= '/') {
@@ -1079,7 +1081,7 @@ use_double:
ZVAL_DOUBLE(*rval, zend_strtod((const char *)start + 2, NULL));
return 1;
}
-#line 1083 "ext/standard/var_unserializer.c"
+#line 1085 "ext/standard/var_unserializer.c"
yy65:
yych = *++YYCURSOR;
if (yych <= ',') {
@@ -1153,7 +1155,7 @@ yy73:
return 1;
}
-#line 1157 "ext/standard/var_unserializer.c"
+#line 1159 "ext/standard/var_unserializer.c"
yy76:
yych = *++YYCURSOR;
if (yych == 'N') goto yy73;
@@ -1207,7 +1209,7 @@ yy79:
ZVAL_LONG(*rval, parse_iv(start + 2));
return 1;
}
-#line 1211 "ext/standard/var_unserializer.c"
+#line 1213 "ext/standard/var_unserializer.c"
yy83:
yych = *++YYCURSOR;
if (yych <= '/') goto yy18;
@@ -1222,7 +1224,7 @@ yy83:
ZVAL_BOOL(*rval, parse_iv(start + 2));
return 1;
}
-#line 1226 "ext/standard/var_unserializer.c"
+#line 1228 "ext/standard/var_unserializer.c"
yy87:
++YYCURSOR;
#line 549 "ext/standard/var_unserializer.re"
@@ -1232,7 +1234,7 @@ yy87:
ZVAL_NULL(*rval);
return 1;
}
-#line 1236 "ext/standard/var_unserializer.c"
+#line 1238 "ext/standard/var_unserializer.c"
yy89:
yych = *++YYCURSOR;
if (yych <= ',') {
@@ -1278,7 +1280,7 @@ yy91:
return 1;
}
-#line 1282 "ext/standard/var_unserializer.c"
+#line 1284 "ext/standard/var_unserializer.c"
yy95:
yych = *++YYCURSOR;
if (yych <= ',') {
@@ -1322,9 +1324,9 @@ yy97:
return 1;
}
-#line 1326 "ext/standard/var_unserializer.c"
+#line 1328 "ext/standard/var_unserializer.c"
}
-#line 877 "ext/standard/var_unserializer.re"
+#line 879 "ext/standard/var_unserializer.re"
return 0;
diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re
index 4cdf313735..7fbab9f2f0 100644
--- a/ext/standard/var_unserializer.re
+++ b/ext/standard/var_unserializer.re
@@ -824,6 +824,7 @@ object ":" uiv ":" ["] {
}
/* The callback function may have defined the class */
+ BG(serialize_lock)++;
if (zend_lookup_class(class_name, len2, &pce TSRMLS_CC) == SUCCESS) {
ce = *pce;
} else {
@@ -831,6 +832,7 @@ object ":" uiv ":" ["] {
incomplete_class = 1;
ce = PHP_IC_ENTRY;
}
+ BG(serialize_lock)--;
zval_ptr_dtor(&user_func);
zval_ptr_dtor(&arg_func_name);