mirror of
https://github.com/php/php-src.git
synced 2025-08-16 22:18:50 +02:00
Fixed bug #67072 Echoing unserialized "SplFileObject" crash
The actual issue lays in the unserializer code which doesn't honor the unserialize callback. By contrast, the serialize callback is respected. This leads to the situation that even if a class has disabled the serialization explicitly, user could still construct a vulnerable string which would result bad things when trying to unserialize. This conserns also the classes implementing Serializable as well as some core classes disabling serialize/unserialize callbacks explicitly (PDO, SimpleXML, SplFileInfo and co). As of now, the flow is first to call the unserialize callback (if available), then call __wakeup. If the unserialize callback returns with no success, no object is instantiated. This makes the scheme used by internal classes effective, to disable unserialize just assign zend_class_unserialize_deny as callback.
This commit is contained in:
parent
7a5f1663c6
commit
5328d42899
5 changed files with 70 additions and 34 deletions
4
NEWS
4
NEWS
|
@ -6,6 +6,10 @@ PHP NEWS
|
||||||
. Fixed bug #67081 (DOMDocumentType->internalSubset returns entire DOCTYPE tag,
|
. Fixed bug #67081 (DOMDocumentType->internalSubset returns entire DOCTYPE tag,
|
||||||
not only the subset). (Anatol)
|
not only the subset). (Anatol)
|
||||||
|
|
||||||
|
- Standard:
|
||||||
|
. Fixed bug #67072 (Echoing unserialized "SplFileObject" crash). (Anatol)
|
||||||
|
|
||||||
|
|
||||||
?? ??? 2014, PHP 5.4.28
|
?? ??? 2014, PHP 5.4.28
|
||||||
|
|
||||||
- Core:
|
- Core:
|
||||||
|
|
|
@ -156,6 +156,7 @@ object(TestNAOld)#%d (0) {
|
||||||
}
|
}
|
||||||
===NANew===
|
===NANew===
|
||||||
unserializer(TestNANew)
|
unserializer(TestNANew)
|
||||||
|
TestNew::unserialize()
|
||||||
TestNew::__wakeup()
|
TestNew::__wakeup()
|
||||||
object(TestNANew)#%d (0) {
|
object(TestNANew)#%d (0) {
|
||||||
}
|
}
|
||||||
|
|
13
ext/standard/tests/serialize/bug67072.phpt
Normal file
13
ext/standard/tests/serialize/bug67072.phpt
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
--TEST--
|
||||||
|
Bug #67072 Echoing unserialized "SplFileObject" crash
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
echo unserialize('O:13:"SplFileObject":1:{s:9:"*filename";s:15:"/home/flag/flag";}');
|
||||||
|
?>
|
||||||
|
===DONE==
|
||||||
|
--EXPECTF--
|
||||||
|
Fatal error: Uncaught exception 'Exception' with message 'Unserialization of 'SplFileObject' is not allowed' in %sbug67072.php:2
|
||||||
|
Stack trace:
|
||||||
|
#0 %sbug67072.php(2): unserialize('O:13:"SplFileOb...')
|
||||||
|
#1 {main}
|
||||||
|
thrown in %sbug67072.php on line 2
|
|
@ -1,10 +1,10 @@
|
||||||
/* Generated by re2c 0.13.5 on Mon Jul 29 17:57:26 2013 */
|
/* Generated by re2c 0.13.5 on Thu Apr 17 10:03:26 2014 */
|
||||||
#line 1 "ext/standard/var_unserializer.re"
|
#line 1 "ext/standard/var_unserializer.re"
|
||||||
/*
|
/*
|
||||||
+----------------------------------------------------------------------+
|
+----------------------------------------------------------------------+
|
||||||
| PHP Version 5 |
|
| PHP Version 5 |
|
||||||
+----------------------------------------------------------------------+
|
+----------------------------------------------------------------------+
|
||||||
| Copyright (c) 1997-2014 The PHP Group |
|
| Copyright (c) 1997-2013 The PHP Group |
|
||||||
+----------------------------------------------------------------------+
|
+----------------------------------------------------------------------+
|
||||||
| This source file is subject to version 3.01 of the PHP license, |
|
| This source file is subject to version 3.01 of the PHP license, |
|
||||||
| that is bundled with this package in the file LICENSE, and is |
|
| that is bundled with this package in the file LICENSE, and is |
|
||||||
|
@ -396,7 +396,12 @@ static inline long object_common1(UNSERIALIZE_PARAMETER, zend_class_entry *ce)
|
||||||
|
|
||||||
(*p) += 2;
|
(*p) += 2;
|
||||||
|
|
||||||
object_init_ex(*rval, ce);
|
if (ce->unserialize == NULL) {
|
||||||
|
object_init_ex(*rval, ce);
|
||||||
|
} else if (ce->unserialize(rval, ce, (const unsigned char*)*p, elements, (zend_unserialize_data *)var_hash TSRMLS_CC) != SUCCESS) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return elements;
|
return elements;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -408,6 +413,10 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, long elements)
|
||||||
zval *retval_ptr = NULL;
|
zval *retval_ptr = NULL;
|
||||||
zval fname;
|
zval fname;
|
||||||
|
|
||||||
|
if (Z_TYPE_PP(rval) != IS_OBJECT) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_OBJPROP_PP(rval), elements, 1)) {
|
if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_OBJPROP_PP(rval), elements, 1)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -457,7 +466,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#line 461 "ext/standard/var_unserializer.c"
|
#line 470 "ext/standard/var_unserializer.c"
|
||||||
{
|
{
|
||||||
YYCTYPE yych;
|
YYCTYPE yych;
|
||||||
static const unsigned char yybm[] = {
|
static const unsigned char yybm[] = {
|
||||||
|
@ -517,9 +526,9 @@ yy2:
|
||||||
yych = *(YYMARKER = ++YYCURSOR);
|
yych = *(YYMARKER = ++YYCURSOR);
|
||||||
if (yych == ':') goto yy95;
|
if (yych == ':') goto yy95;
|
||||||
yy3:
|
yy3:
|
||||||
#line 812 "ext/standard/var_unserializer.re"
|
#line 821 "ext/standard/var_unserializer.re"
|
||||||
{ return 0; }
|
{ return 0; }
|
||||||
#line 523 "ext/standard/var_unserializer.c"
|
#line 532 "ext/standard/var_unserializer.c"
|
||||||
yy4:
|
yy4:
|
||||||
yych = *(YYMARKER = ++YYCURSOR);
|
yych = *(YYMARKER = ++YYCURSOR);
|
||||||
if (yych == ':') goto yy89;
|
if (yych == ':') goto yy89;
|
||||||
|
@ -562,13 +571,13 @@ yy13:
|
||||||
goto yy3;
|
goto yy3;
|
||||||
yy14:
|
yy14:
|
||||||
++YYCURSOR;
|
++YYCURSOR;
|
||||||
#line 806 "ext/standard/var_unserializer.re"
|
#line 815 "ext/standard/var_unserializer.re"
|
||||||
{
|
{
|
||||||
/* this is the case where we have less data than planned */
|
/* this is the case where we have less data than planned */
|
||||||
php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unexpected end of serialized data");
|
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? */
|
return 0; /* not sure if it should be 0 or 1 here? */
|
||||||
}
|
}
|
||||||
#line 572 "ext/standard/var_unserializer.c"
|
#line 581 "ext/standard/var_unserializer.c"
|
||||||
yy16:
|
yy16:
|
||||||
yych = *++YYCURSOR;
|
yych = *++YYCURSOR;
|
||||||
goto yy3;
|
goto yy3;
|
||||||
|
@ -598,7 +607,7 @@ yy20:
|
||||||
yych = *++YYCURSOR;
|
yych = *++YYCURSOR;
|
||||||
if (yych != '"') goto yy18;
|
if (yych != '"') goto yy18;
|
||||||
++YYCURSOR;
|
++YYCURSOR;
|
||||||
#line 660 "ext/standard/var_unserializer.re"
|
#line 669 "ext/standard/var_unserializer.re"
|
||||||
{
|
{
|
||||||
size_t len, len2, len3, maxlen;
|
size_t len, len2, len3, maxlen;
|
||||||
long elements;
|
long elements;
|
||||||
|
@ -744,7 +753,7 @@ yy20:
|
||||||
|
|
||||||
return object_common2(UNSERIALIZE_PASSTHRU, elements);
|
return object_common2(UNSERIALIZE_PASSTHRU, elements);
|
||||||
}
|
}
|
||||||
#line 748 "ext/standard/var_unserializer.c"
|
#line 757 "ext/standard/var_unserializer.c"
|
||||||
yy25:
|
yy25:
|
||||||
yych = *++YYCURSOR;
|
yych = *++YYCURSOR;
|
||||||
if (yych <= ',') {
|
if (yych <= ',') {
|
||||||
|
@ -769,7 +778,7 @@ yy27:
|
||||||
yych = *++YYCURSOR;
|
yych = *++YYCURSOR;
|
||||||
if (yych != '"') goto yy18;
|
if (yych != '"') goto yy18;
|
||||||
++YYCURSOR;
|
++YYCURSOR;
|
||||||
#line 652 "ext/standard/var_unserializer.re"
|
#line 661 "ext/standard/var_unserializer.re"
|
||||||
{
|
{
|
||||||
|
|
||||||
INIT_PZVAL(*rval);
|
INIT_PZVAL(*rval);
|
||||||
|
@ -777,7 +786,7 @@ yy27:
|
||||||
return object_common2(UNSERIALIZE_PASSTHRU,
|
return object_common2(UNSERIALIZE_PASSTHRU,
|
||||||
object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR));
|
object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR));
|
||||||
}
|
}
|
||||||
#line 781 "ext/standard/var_unserializer.c"
|
#line 790 "ext/standard/var_unserializer.c"
|
||||||
yy32:
|
yy32:
|
||||||
yych = *++YYCURSOR;
|
yych = *++YYCURSOR;
|
||||||
if (yych == '+') goto yy33;
|
if (yych == '+') goto yy33;
|
||||||
|
@ -798,7 +807,7 @@ yy34:
|
||||||
yych = *++YYCURSOR;
|
yych = *++YYCURSOR;
|
||||||
if (yych != '{') goto yy18;
|
if (yych != '{') goto yy18;
|
||||||
++YYCURSOR;
|
++YYCURSOR;
|
||||||
#line 632 "ext/standard/var_unserializer.re"
|
#line 641 "ext/standard/var_unserializer.re"
|
||||||
{
|
{
|
||||||
long elements = parse_iv(start + 2);
|
long elements = parse_iv(start + 2);
|
||||||
/* use iv() not uiv() in order to check data range */
|
/* use iv() not uiv() in order to check data range */
|
||||||
|
@ -818,7 +827,7 @@ yy34:
|
||||||
|
|
||||||
return finish_nested_data(UNSERIALIZE_PASSTHRU);
|
return finish_nested_data(UNSERIALIZE_PASSTHRU);
|
||||||
}
|
}
|
||||||
#line 822 "ext/standard/var_unserializer.c"
|
#line 831 "ext/standard/var_unserializer.c"
|
||||||
yy39:
|
yy39:
|
||||||
yych = *++YYCURSOR;
|
yych = *++YYCURSOR;
|
||||||
if (yych == '+') goto yy40;
|
if (yych == '+') goto yy40;
|
||||||
|
@ -839,7 +848,7 @@ yy41:
|
||||||
yych = *++YYCURSOR;
|
yych = *++YYCURSOR;
|
||||||
if (yych != '"') goto yy18;
|
if (yych != '"') goto yy18;
|
||||||
++YYCURSOR;
|
++YYCURSOR;
|
||||||
#line 603 "ext/standard/var_unserializer.re"
|
#line 612 "ext/standard/var_unserializer.re"
|
||||||
{
|
{
|
||||||
size_t len, maxlen;
|
size_t len, maxlen;
|
||||||
char *str;
|
char *str;
|
||||||
|
@ -868,7 +877,7 @@ yy41:
|
||||||
ZVAL_STRINGL(*rval, str, len, 0);
|
ZVAL_STRINGL(*rval, str, len, 0);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#line 872 "ext/standard/var_unserializer.c"
|
#line 881 "ext/standard/var_unserializer.c"
|
||||||
yy46:
|
yy46:
|
||||||
yych = *++YYCURSOR;
|
yych = *++YYCURSOR;
|
||||||
if (yych == '+') goto yy47;
|
if (yych == '+') goto yy47;
|
||||||
|
@ -889,7 +898,7 @@ yy48:
|
||||||
yych = *++YYCURSOR;
|
yych = *++YYCURSOR;
|
||||||
if (yych != '"') goto yy18;
|
if (yych != '"') goto yy18;
|
||||||
++YYCURSOR;
|
++YYCURSOR;
|
||||||
#line 575 "ext/standard/var_unserializer.re"
|
#line 584 "ext/standard/var_unserializer.re"
|
||||||
{
|
{
|
||||||
size_t len, maxlen;
|
size_t len, maxlen;
|
||||||
char *str;
|
char *str;
|
||||||
|
@ -917,7 +926,7 @@ yy48:
|
||||||
ZVAL_STRINGL(*rval, str, len, 1);
|
ZVAL_STRINGL(*rval, str, len, 1);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#line 921 "ext/standard/var_unserializer.c"
|
#line 930 "ext/standard/var_unserializer.c"
|
||||||
yy53:
|
yy53:
|
||||||
yych = *++YYCURSOR;
|
yych = *++YYCURSOR;
|
||||||
if (yych <= '/') {
|
if (yych <= '/') {
|
||||||
|
@ -1005,7 +1014,7 @@ yy61:
|
||||||
}
|
}
|
||||||
yy63:
|
yy63:
|
||||||
++YYCURSOR;
|
++YYCURSOR;
|
||||||
#line 565 "ext/standard/var_unserializer.re"
|
#line 574 "ext/standard/var_unserializer.re"
|
||||||
{
|
{
|
||||||
#if SIZEOF_LONG == 4
|
#if SIZEOF_LONG == 4
|
||||||
use_double:
|
use_double:
|
||||||
|
@ -1015,7 +1024,7 @@ use_double:
|
||||||
ZVAL_DOUBLE(*rval, zend_strtod((const char *)start + 2, NULL));
|
ZVAL_DOUBLE(*rval, zend_strtod((const char *)start + 2, NULL));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#line 1019 "ext/standard/var_unserializer.c"
|
#line 1028 "ext/standard/var_unserializer.c"
|
||||||
yy65:
|
yy65:
|
||||||
yych = *++YYCURSOR;
|
yych = *++YYCURSOR;
|
||||||
if (yych <= ',') {
|
if (yych <= ',') {
|
||||||
|
@ -1074,7 +1083,7 @@ yy73:
|
||||||
yych = *++YYCURSOR;
|
yych = *++YYCURSOR;
|
||||||
if (yych != ';') goto yy18;
|
if (yych != ';') goto yy18;
|
||||||
++YYCURSOR;
|
++YYCURSOR;
|
||||||
#line 550 "ext/standard/var_unserializer.re"
|
#line 559 "ext/standard/var_unserializer.re"
|
||||||
{
|
{
|
||||||
*p = YYCURSOR;
|
*p = YYCURSOR;
|
||||||
INIT_PZVAL(*rval);
|
INIT_PZVAL(*rval);
|
||||||
|
@ -1089,7 +1098,7 @@ yy73:
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#line 1093 "ext/standard/var_unserializer.c"
|
#line 1102 "ext/standard/var_unserializer.c"
|
||||||
yy76:
|
yy76:
|
||||||
yych = *++YYCURSOR;
|
yych = *++YYCURSOR;
|
||||||
if (yych == 'N') goto yy73;
|
if (yych == 'N') goto yy73;
|
||||||
|
@ -1116,7 +1125,7 @@ yy79:
|
||||||
if (yych <= '9') goto yy79;
|
if (yych <= '9') goto yy79;
|
||||||
if (yych != ';') goto yy18;
|
if (yych != ';') goto yy18;
|
||||||
++YYCURSOR;
|
++YYCURSOR;
|
||||||
#line 523 "ext/standard/var_unserializer.re"
|
#line 532 "ext/standard/var_unserializer.re"
|
||||||
{
|
{
|
||||||
#if SIZEOF_LONG == 4
|
#if SIZEOF_LONG == 4
|
||||||
int digits = YYCURSOR - start - 3;
|
int digits = YYCURSOR - start - 3;
|
||||||
|
@ -1143,7 +1152,7 @@ yy79:
|
||||||
ZVAL_LONG(*rval, parse_iv(start + 2));
|
ZVAL_LONG(*rval, parse_iv(start + 2));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#line 1147 "ext/standard/var_unserializer.c"
|
#line 1156 "ext/standard/var_unserializer.c"
|
||||||
yy83:
|
yy83:
|
||||||
yych = *++YYCURSOR;
|
yych = *++YYCURSOR;
|
||||||
if (yych <= '/') goto yy18;
|
if (yych <= '/') goto yy18;
|
||||||
|
@ -1151,24 +1160,24 @@ yy83:
|
||||||
yych = *++YYCURSOR;
|
yych = *++YYCURSOR;
|
||||||
if (yych != ';') goto yy18;
|
if (yych != ';') goto yy18;
|
||||||
++YYCURSOR;
|
++YYCURSOR;
|
||||||
#line 516 "ext/standard/var_unserializer.re"
|
#line 525 "ext/standard/var_unserializer.re"
|
||||||
{
|
{
|
||||||
*p = YYCURSOR;
|
*p = YYCURSOR;
|
||||||
INIT_PZVAL(*rval);
|
INIT_PZVAL(*rval);
|
||||||
ZVAL_BOOL(*rval, parse_iv(start + 2));
|
ZVAL_BOOL(*rval, parse_iv(start + 2));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#line 1162 "ext/standard/var_unserializer.c"
|
#line 1171 "ext/standard/var_unserializer.c"
|
||||||
yy87:
|
yy87:
|
||||||
++YYCURSOR;
|
++YYCURSOR;
|
||||||
#line 509 "ext/standard/var_unserializer.re"
|
#line 518 "ext/standard/var_unserializer.re"
|
||||||
{
|
{
|
||||||
*p = YYCURSOR;
|
*p = YYCURSOR;
|
||||||
INIT_PZVAL(*rval);
|
INIT_PZVAL(*rval);
|
||||||
ZVAL_NULL(*rval);
|
ZVAL_NULL(*rval);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#line 1172 "ext/standard/var_unserializer.c"
|
#line 1181 "ext/standard/var_unserializer.c"
|
||||||
yy89:
|
yy89:
|
||||||
yych = *++YYCURSOR;
|
yych = *++YYCURSOR;
|
||||||
if (yych <= ',') {
|
if (yych <= ',') {
|
||||||
|
@ -1191,7 +1200,7 @@ yy91:
|
||||||
if (yych <= '9') goto yy91;
|
if (yych <= '9') goto yy91;
|
||||||
if (yych != ';') goto yy18;
|
if (yych != ';') goto yy18;
|
||||||
++YYCURSOR;
|
++YYCURSOR;
|
||||||
#line 486 "ext/standard/var_unserializer.re"
|
#line 495 "ext/standard/var_unserializer.re"
|
||||||
{
|
{
|
||||||
long id;
|
long id;
|
||||||
|
|
||||||
|
@ -1214,7 +1223,7 @@ yy91:
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#line 1218 "ext/standard/var_unserializer.c"
|
#line 1227 "ext/standard/var_unserializer.c"
|
||||||
yy95:
|
yy95:
|
||||||
yych = *++YYCURSOR;
|
yych = *++YYCURSOR;
|
||||||
if (yych <= ',') {
|
if (yych <= ',') {
|
||||||
|
@ -1237,7 +1246,7 @@ yy97:
|
||||||
if (yych <= '9') goto yy97;
|
if (yych <= '9') goto yy97;
|
||||||
if (yych != ';') goto yy18;
|
if (yych != ';') goto yy18;
|
||||||
++YYCURSOR;
|
++YYCURSOR;
|
||||||
#line 465 "ext/standard/var_unserializer.re"
|
#line 474 "ext/standard/var_unserializer.re"
|
||||||
{
|
{
|
||||||
long id;
|
long id;
|
||||||
|
|
||||||
|
@ -1258,9 +1267,9 @@ yy97:
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#line 1262 "ext/standard/var_unserializer.c"
|
#line 1271 "ext/standard/var_unserializer.c"
|
||||||
}
|
}
|
||||||
#line 814 "ext/standard/var_unserializer.re"
|
#line 823 "ext/standard/var_unserializer.re"
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -400,7 +400,12 @@ static inline long object_common1(UNSERIALIZE_PARAMETER, zend_class_entry *ce)
|
||||||
|
|
||||||
(*p) += 2;
|
(*p) += 2;
|
||||||
|
|
||||||
object_init_ex(*rval, ce);
|
if (ce->unserialize == NULL) {
|
||||||
|
object_init_ex(*rval, ce);
|
||||||
|
} else if (ce->unserialize(rval, ce, (const unsigned char*)*p, elements, (zend_unserialize_data *)var_hash TSRMLS_CC) != SUCCESS) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return elements;
|
return elements;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -412,6 +417,10 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, long elements)
|
||||||
zval *retval_ptr = NULL;
|
zval *retval_ptr = NULL;
|
||||||
zval fname;
|
zval fname;
|
||||||
|
|
||||||
|
if (Z_TYPE_PP(rval) != IS_OBJECT) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_OBJPROP_PP(rval), elements, 1)) {
|
if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_OBJPROP_PP(rval), elements, 1)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue