Patch max_input_vars.patch for *General Issues Bug #60655
Patch version 2012-01-05 05:04 UTC
Return to Bug #60655
| Download this patch
Patch Revisions:
2012-01-05 05:04 UTC | 2012-01-05 05:03 UTC | 2012-01-05 05:02 UTC | 2012-01-05 04:17 UTC | 2012-01-05 04:08 UTCDeveloper: laruence@php.net
-Warning: unserialize() expects exactly 1 parameter, 2 given in %s on line 21
+Notice: unserialize(): Error at offset 0 of 1 bytes in %sserialization_error_001.php on line %d
bool(false)
Done
Index: trunk/ext/standard/tests/serialize/unserialize_max_vars.phpt
===================================================================
--- trunk/ext/standard/tests/serialize/unserialize_max_vars.phpt (revision 0)
+++ trunk/ext/standard/tests/serialize/unserialize_max_vars.phpt (revision 0)
@@ -0,0 +1,57 @@
+--TEST--
+Test unserialize() functions with max_input_vars
+--FILE--
+<?php
+$str = serialize(array(1,2,3)); // there will be 4 items, array, and 1, 2, 3
+
+print_r(unserialize($str, 3));
+print_r(unserialize($str, 4));
+
+$str = serialize(array(array(),array(2,3))); // there will be 5 items, array, and array, array, 2, 3
+print_r(unserialize($str, 3));
+print_r(unserialize($str, 5));
+
+$obj = (object)(array(array(),array(2,3)));
+$str = serialize($obj);
+
+print_r(unserialize($str, 3));
+print_r(unserialize($str, 5));
+?>
+--EXPECTF--
+Warning: unserialize(): Unserialized variables exceeded 3 in %sunserialize_max_vars.php on line %d
+Array
+(
+ [0] => 1
+ [1] => 2
+ [2] => 3
+)
+
+Warning: unserialize(): Unserialized variables exceeded 3 in %sunserialize_max_vars.php on line %d
+Array
+(
+ [0] => Array
+ (
+ )
+
+ [1] => Array
+ (
+ [0] => 2
+ [1] => 3
+ )
+
+)
+
+Warning: unserialize(): Unserialized variables exceeded 3 in %sunserialize_max_vars.php on line %d
+stdClass Object
+(
+ [0] => Array
+ (
+ )
+
+ [1] => Array
+ (
+ [0] => 2
+ [1] => 3
+ )
+
+)
Index: trunk/ext/standard/var_unserializer.c
===================================================================
--- trunk/ext/standard/var_unserializer.c (revision 321767)
+++ trunk/ext/standard/var_unserializer.c (working copy)
yy14:
++YYCURSOR;
-#line 741 "ext/standard/var_unserializer.re"
+#line 760 "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? */
}
{
long elements = parse_iv(start + 2);
/* use iv() not uiv() in order to check data range */
@@ -747,13 +756,14 @@
array_init_size(*rval, elements);
+ ++(BG(unserialize).num_vars);
if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL_PP(rval), elements, 0)) {
return 0;
}
array_init_size(*rval, elements);
+ ++(BG(unserialize).num_vars);
if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL_PP(rval), elements, 0)) {
return 0;
}
return finish_nested_data(UNSERIALIZE_PASSTHRU);
}
-#line 757 "ext/standard/var_unserializer.c"
+#line 767 "ext/standard/var_unserializer.c"
{
size_t len, maxlen;
char *str;
@@ -801,9 +811,10 @@
INIT_PZVAL(*rval);
INIT_PZVAL(*rval);
ZVAL_STRINGL(*rval, str, len, 0);
+ ++(BG(unserialize).num_vars);
return 1;
}
yy63:
++YYCURSOR;
-#line 529 "ext/standard/var_unserializer.re"
+#line 541 "ext/standard/var_unserializer.re"
{
#if SIZEOF_LONG == 4
{
#if SIZEOF_LONG == 4
use_double:
@@ -948,9 +960,10 @@
*p = YYCURSOR;
INIT_PZVAL(*rval);
yych = *++YYCURSOR;
if (yych == 'N') goto yy73;
@@ -1051,7 +1065,7 @@
if (yych <= '9') goto yy79;
if (yych != ';') goto yy18;
if (yych != ';') goto yy18;
++YYCURSOR;
-#line 487 "ext/standard/var_unserializer.re"
+#line 497 "ext/standard/var_unserializer.re"
{
if (yych != ';') goto yy18;
++YYCURSOR;
-#line 450 "ext/standard/var_unserializer.re"
+#line 457 "ext/standard/var_unserializer.re"
{
{
long id;
@@ -1147,9 +1164,10 @@
Z_ADDREF_PP(rval);
+ long max_vars = PG(max_input_vars);
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &buf, &buf_len) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &buf, &buf_len, &max_vars) == FAILURE) {
RETURN_FALSE;
RETURN_FALSE;
}
@@ -939,10 +940,13 @@
/*!re2c
"R:" iv ";" {
@@ -444,6 +450,7 @@
Z_ADDREF_PP(rval);
Z_SET_ISREF_PP(rval);
+ ++(BG(unserialize).num_vars);
return 1;
}
@@ -467,6 +474,7 @@
Z_ADDREF_PP(rval);
Z_UNSET_ISREF_PP(rval);
+ ++(BG(unserialize).num_vars);
return 1;
}
Z_ADDREF_PP(rval);
Z_SET_ISREF_PP(rval);
+ ++(BG(unserialize).num_vars);
return 1;
}
@@ -467,6 +474,7 @@
Z_ADDREF_PP(rval);
Z_UNSET_ISREF_PP(rval);
+ ++(BG(unserialize).num_vars);
return 1;
}
@@ -474,6 +482,7 @@
*p = YYCURSOR;
INIT_PZVAL(*rval);
+$x = json_decode($json, false, 512, 1000, JSON_BIGINT_AS_STRING);
var_dump($x->largenum);
echo "Done\n";
?>
Index: trunk/ext/json/tests/max_input_vars.phpt
===================================================================
--- trunk/ext/json/tests/max_input_vars.phpt (revision 0)
+++ trunk/ext/json/tests/max_input_vars.phpt (revision 0)
@@ -0,0 +1,40 @@
+--TEST--
+json_decode() with max_input_vars
+--SKIPIF--
+<?php if (!extension_loaded("json")) print "skip"; ?>
+--FILE--
+<?php
+
+$a = array(1,2,3,4); //an array, and 1,2,3,4 total 5 elements
+$str = json_encode($a);
+
+print_r(json_decode($str, false, 512, 4));
+var_dump(json_last_error() == JSON_ERROR_MAX_VARS);
+print_r(json_decode($str, false, 512, 5));
+
+$a = array(1,array(1),3); //an array, 1, an array, 1, 3 total 5 elements
+$str = json_encode($a);
+print_r(json_decode($str, true, 512, 4));
+var_dump(json_last_error() == JSON_ERROR_MAX_VARS);
+print_r(json_decode($str, true, 512, 5));
+?>
+--EXPECT--
+bool(true)
+Array
+(
+ [0] => 1
+ [1] => 2
+ [2] => 3
+ [3] => 4
+)
+bool(true)
+Array
+(
+ [0] => 1
+ [1] => Array
+ (
+ [0] => 1
+ )
+
+ [2] => 3
+)
Index: trunk/ext/json/tests/json_decode_error.phpt
===================================================================
--- trunk/ext/json/tests/json_decode_error.phpt (revision 321767)
+++ trunk/ext/json/tests/json_decode_error.phpt (working copy)
JSON_RESET_TYPE();
}
@@ -615,6 +629,7 @@
if (jp->top > 1) {
attach_zval(jp, jp->top - 1, jp->top, &key, assoc TSRMLS_CC);
+ ++num_vars;
}
static inline void php_json_decode(zval *return_value, char *str, int str_len, zend_bool assoc, long depth TSRMLS_DC)
{
- php_json_decode_ex(return_value, str, str_len, assoc ? PHP_JSON_OBJECT_AS_ARRAY : 0, depth TSRMLS_CC);
+ php_json_decode_ex(return_value, str, str_len, assoc ? PHP_JSON_OBJECT_AS_ARRAY : 0, depth, 0 TSRMLS_CC);
}
}
Index: trunk/ext/json/JSON_parser.h
===================================================================
--- trunk/ext/json/JSON_parser.h (revision 321767)
+++ trunk/ext/json/JSON_parser.h (working copy)
+ ++(BG(unserialize).num_vars);
return object_common2(UNSERIALIZE_PASSTHRU, elements);
}
Index: branches/PHP_5_3/ext/json/json.c
===================================================================
--- branches/PHP_5_3/ext/json/json.c (revision 321767)
+++ branches/PHP_5_3/ext/json/json.c (working copy)
@@ -76,6 +76,7 @@
REGISTER_LONG_CONSTANT("JSON_ERROR_NONE", PHP_JSON_ERROR_NONE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("JSON_ERROR_DEPTH", PHP_JSON_ERROR_DEPTH, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("JSON_ERROR_MAX_VARS", PHP_JSON_ERROR_MAX_VARS, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("JSON_ERROR_STATE_MISMATCH", PHP_JSON_ERROR_STATE_MISMATCH, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("JSON_ERROR_CTRL_CHAR", PHP_JSON_ERROR_CTRL_CHAR, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("JSON_ERROR_SYNTAX", PHP_JSON_ERROR_SYNTAX, CONST_CS | CONST_PERSISTENT);
@@ -485,7 +486,7 @@
}
/* }}} */
-PHP_JSON_API void php_json_decode(zval *return_value, char *str, int str_len, zend_bool assoc, long depth TSRMLS_DC) /* {{{ */
+PHP_JSON_API void php_json_decode_ex(zval *return_value, char *str, int str_len, zend_bool assoc, long depth, long max_vars TSRMLS_DC) /* {{{ */
{
int utf16_len;
zval *z;
@@ -510,7 +511,7 @@
}
ALLOC_INIT_ZVAL(z);
- jp = new_JSON_parser(depth);
+ jp = new_JSON_parser(depth, max_vars);
if (parse_JSON(jp, z, utf16, utf16_len, assoc TSRMLS_CC)) {
*return_value = *z;
}
@@ -584,8 +585,9 @@
int str_len;
zend_bool assoc = 0; /* return JS objects as PHP objects by default */
long depth = JSON_PARSER_DEFAULT_DEPTH;
+ long max_vars = PG(max_input_vars);
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|bl", &str, &str_len, &assoc, &depth) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|bll", &str, &str_len, &assoc, &depth, &max_vars) == FAILURE) {
return;
}
@@ -595,7 +597,7 @@
RETURN_NULL();
}
- php_json_decode(return_value, str, str_len, assoc, depth TSRMLS_CC);
+ php_json_decode_ex(return_value, str, str_len, assoc, depth, max_vars TSRMLS_CC);
}
/* }}} */
Index: branches/PHP_5_3/ext/json/tests/json_decode_error.phpt
===================================================================
--- branches/PHP_5_3/ext/json/tests/json_decode_error.phpt (revision 321767)
+++ branches/PHP_5_3/ext/json/tests/json_decode_error.phpt (working copy)
@@ -20,7 +20,7 @@
echo "\n-- Testing json_decode() function with more than expected no. of arguments --\n";
$extra_arg = 10;
-var_dump( json_decode('"abc"', TRUE, 512, $extra_arg) );
+var_dump( json_decode('"abc"', TRUE, 512, 1000, $extra_arg) );
?>
===Done===
@@ -34,6 +34,6 @@
-- Testing json_decode() function with more than expected no. of arguments --
-Warning: json_decode() expects at most 3 parameters, 4 given in %s on line %d
+Warning: json_decode() expects at most 4 parameters, 5 given in %s on line %d
NULL
===Done===
Index: branches/PHP_5_3/ext/json/JSON_parser.c
===================================================================
--- branches/PHP_5_3/ext/json/JSON_parser.c (revision 321767)
+++ branches/PHP_5_3/ext/json/JSON_parser.c (working copy)
@@ -239,11 +239,12 @@
JSON_checker_char will delete the JSON_checker object if it sees an error.
*/
JSON_parser
-new_JSON_parser(int depth)
+new_JSON_parser(int depth, long max_vars)
{
JSON_parser jp = (JSON_parser)emalloc(sizeof(struct JSON_parser_struct));
jp->state = GO;
jp->depth = depth;
+ jp->max_vars = max_vars;
jp->top = -1;
jp->error_code = PHP_JSON_ERROR_NONE;
jp->stack = (int*)ecalloc(depth, sizeof(int));
@@ -426,6 +427,7 @@
int next_class; /* the next character class */
int next_state; /* the next state */
int the_index;
+ long num_vars = 1; /* the container is also counted in */
smart_str buf = {0};
smart_str key = {0};
@@ -436,6 +438,11 @@
JSON_RESET_TYPE();
for (the_index = 0; the_index < length; the_index += 1) {
+ if (jp->max_vars && num_vars >= jp->max_vars) {
+ jp->error_code = PHP_JSON_ERROR_MAX_VARS;
+ FREE_BUFFERS();
+ return false;
+ }
next_char = utf16_json[the_index];
if (next_char >= 128) {
next_class = C_ETC;
@@ -540,6 +547,7 @@
}
key.len = 0;
buf.len = 0;
+ ++num_vars;
JSON_RESET_TYPE();
}
@@ -561,6 +569,7 @@
json_create_zval(&mval, &buf, type);
add_next_index_zval(jp->the_zstack[jp->top], mval);
buf.len = 0;
+ ++num_vars;
JSON_RESET_TYPE();
}
@@ -585,6 +594,7 @@
if (jp->top == 1) {
obj = z;
} else {
+ ++num_vars;
ALLOC_INIT_ZVAL(obj);
}
@@ -626,6 +636,7 @@
if (jp->top > 1) {
attach_zval(jp, jp->top - 1, jp->top, &key, assoc TSRMLS_CC);
+ ++num_vars;
}
JSON_RESET_TYPE();
@@ -683,6 +694,7 @@
} else {
add_assoc_zval_ex(jp->the_zstack[jp->top], (key.len ? key.c : ""), (key.len ? (key.len + 1) : sizeof("")), mval);
}
+ ++num_vars;
key.len = 0;
}
jp->state = KE;
@@ -691,6 +703,7 @@
case MODE_ARRAY:
if (type != -1) {
add_next_index_zval(jp->the_zstack[jp->top], mval);
+ ++num_vars;
}
jp->state = VA;
break;
Index: branches/PHP_5_3/ext/json/php_json.h
===================================================================
--- branches/PHP_5_3/ext/json/php_json.h (revision 321767)
+++ branches/PHP_5_3/ext/json/php_json.h (working copy)
@@ -48,7 +48,11 @@
#endif
PHP_JSON_API void php_json_encode(smart_str *buf, zval *val, int options TSRMLS_DC);
-PHP_JSON_API void php_json_decode(zval *return_value, char *str, int str_len, zend_bool assoc, long depth TSRMLS_DC);
+PHP_JSON_API void php_json_decode_ex(zval *return_value, char *str, int str_len, zend_bool assoc, long depth, long max_vars TSRMLS_DC);
+static inline void php_json_decode(zval *return_value, char *str, int str_len, zend_bool assoc, long depth TSRMLS_DC)
+{
+ php_json_decode_ex(return_value, str, str_len, assoc, depth, 0 TSRMLS_CC);
+}
#define PHP_JSON_HEX_TAG (1<<0)
#define PHP_JSON_HEX_AMP (1<<1)
Index: branches/PHP_5_3/ext/json/JSON_parser.h
===================================================================
--- branches/PHP_5_3/ext/json/JSON_parser.h (revision 321767)
+++ branches/PHP_5_3/ext/json/JSON_parser.h (working copy)
@@ -14,6 +14,7 @@
int top;
int error_code;
int* stack;
+ long max_vars;
zval **the_zstack;
zval *the_static_zstack[JSON_PARSER_DEFAULT_DEPTH];
} * JSON_parser;
@@ -24,10 +25,11 @@
PHP_JSON_ERROR_STATE_MISMATCH,
PHP_JSON_ERROR_CTRL_CHAR,
PHP_JSON_ERROR_SYNTAX,
- PHP_JSON_ERROR_UTF8
+ PHP_JSON_ERROR_UTF8,
+ PHP_JSON_ERROR_MAX_VARS
};
-extern JSON_parser new_JSON_parser(int depth);
+extern JSON_parser new_JSON_parser(int depth, long max_vars);
extern int parse_JSON(JSON_parser jp, zval *z, unsigned short utf16_json[], int length, int assoc TSRMLS_DC);
extern int free_JSON_parser(JSON_parser jp);
#endif
Index: branches/PHP_5_3/main/rfc1867.c
===================================================================
--- branches/PHP_5_3/main/rfc1867.c (revision 321767)
+++ branches/PHP_5_3/main/rfc1867.c (working copy)
+++ branches/PHP_5_4/ext/standard/tests/serialize/serialization_error_001.phpt (working copy)
@@ -28,15 +28,15 @@
--EXPECTF--
*** Testing serialize()/unserialize() : error conditions ***
-Warning: serialize() expects exactly 1 parameter, 0 given in %s on line 16
+Warning: serialize() expects exactly 1 parameter, 0 given in %sserialization_error_001.php on line %d
NULL
NULL
-Warning: unserialize() expects exactly 1 parameter, 0 given in %s on line 17
+Warning: unserialize() expects at least 1 parameter, 0 given in %sserialization_error_001.php on line %d
bool(false)
bool(false)
-Warning: serialize() expects exactly 1 parameter, 2 given in %s on line 20
+Warning: serialize() expects exactly 1 parameter, 2 given in %sserialization_error_001.php on line %d
NULL
-Warning: unserialize() expects exactly 1 parameter, 2 given in %s on line 21
+Notice: unserialize(): Error at offset 0 of 1 bytes in %sserialization_error_001.php on line %d
bool(false)
Done
Index: branches/PHP_5_4/ext/standard/tests/serialize/unserialize_max_vars.phpt
===================================================================
--- branches/PHP_5_4/ext/standard/tests/serialize/unserialize_max_vars.phpt (revision 0)
+++ branches/PHP_5_4/ext/standard/tests/serialize/unserialize_max_vars.phpt (revision 0)
@@ -0,0 +1,57 @@
+--TEST--
+Test unserialize() functions with max_input_vars
+--FILE--
+<?php
+$str = serialize(array(1,2,3)); // there will be 4 items, array, and 1, 2, 3
+
+print_r(unserialize($str, 3));
+print_r(unserialize($str, 4));
+
+$str = serialize(array(array(),array(2,3))); // there will be 5 items, array, and array, array, 2, 3
+print_r(unserialize($str, 3));
+print_r(unserialize($str, 5));
+
+$obj = (object)(array(array(),array(2,3)));
+$str = serialize($obj);
+
+print_r(unserialize($str, 3));
+print_r(unserialize($str, 5));
+?>
+--EXPECTF--
+Warning: unserialize(): Unserialized variables exceeded 3 in %sunserialize_max_vars.php on line %d
+Array
+(
+ [0] => 1
+ [1] => 2
+ [2] => 3
+)
+
+Warning: unserialize(): Unserialized variables exceeded 3 in %sunserialize_max_vars.php on line %d
+Array
+(
+ [0] => Array
+ (
+ )
+
+ [1] => Array
+ (
+ [0] => 2
+ [1] => 3
+ )
+
+)
+
+Warning: unserialize(): Unserialized variables exceeded 3 in %sunserialize_max_vars.php on line %d
+stdClass Object
+(
+ [0] => Array
+ (
+ )
+
+ [1] => Array
+ (
+ [0] => 2
+ [1] => 3
+ )
+
+)
Index: branches/PHP_5_4/ext/standard/var_unserializer.c
===================================================================
--- branches/PHP_5_4/ext/standard/var_unserializer.c (revision 321767)
+++ branches/PHP_5_4/ext/standard/var_unserializer.c (working copy)
|