php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Return to Bug #60655
Patch rand_hash_resize.patch revision 2012-01-05 08:09 UTC by laruence@php.net
Patch max_input_vars.patch revision 2012-01-05 05:04 UTC by laruence@php.net
revision 2012-01-05 05:03 UTC by laruence@php.net
revision 2012-01-05 05:02 UTC by laruence@php.net
revision 2012-01-05 04:17 UTC by laruence@php.net
revision 2012-01-05 04:08 UTC by laruence@php.net

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 UTC

Developer: 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)


   			FREE_ZVAL(key);
   			return 0;
   		}
  +        --(BG(unserialize).num_vars);
  
  
   		if (Z_TYPE_P(key) != IS_LONG && Z_TYPE_P(key) != IS_STRING) {
   			zval_dtor(key);
  @@ -297,12 +298,14 @@
   			switch (Z_TYPE_P(key)) {


  +    }
   	
   	if (var_hash && cursor[0] != 'R') {
   		var_push(var_hash, rval);
  	}
  
  	}
  
   	start = cursor;
  -
   	
  -	


   	if (yych != '"') goto yy18;
   	++YYCURSOR;
  -#line 616 "ext/standard/var_unserializer.re"
  +#line 632 "ext/standard/var_unserializer.re"
  	{
  
  	INIT_PZVAL(*rval);
  	
 +    ++(BG(unserialize).num_vars);
  	{
  
  	INIT_PZVAL(*rval);
  	
 +    ++(BG(unserialize).num_vars);
   	return object_common2(UNSERIALIZE_PASSTHRU,
   			object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR));
   }
  -#line 716 "ext/standard/var_unserializer.c"


  Index: trunk/ext/standard/php_var.h
  ===================================================================
  --- trunk/ext/standard/php_var.h	(revision 321767)
  +++ trunk/ext/standard/php_var.h	(working copy)
 @@ -95,9 +95,12 @@
 @@ -95,9 +95,13 @@
   	} else { \
   		(var_hash_ptr) = (php_serialize_data_t)BG(unserialize).var_hash; \
   		++BG(unserialize).level; \
  -	} \
  +	}	\
  +	BG(unserialize).num_vars = 0; \
 +	BG(unserialize).max_vars = 0; \
   } while (0)
   
  +#define PHP_VAR_UNSERIALIZE_MAX_VARS(max_vars)  BG(unserialize).max_vars = max_vars;
  +


   	return 1;
   }
   
  @@ -533,6 +545,7 @@
  	*p = YYCURSOR;
  	INIT_PZVAL(*rval);
  	ZVAL_DOUBLE(*rval, zend_strtod((const char *)start + 2, NULL));
 +    ++(BG(unserialize).num_vars);
  	return 1;
  }
  
 @@ -561,6 +574,7 @@
  
  	INIT_PZVAL(*rval);
  	ZVAL_STRINGL(*rval, str, len, 1);
 +    ++(BG(unserialize).num_vars);
  	return 1;
  }
  
 @@ -590,6 +604,7 @@
  	*p = YYCURSOR;
  	INIT_PZVAL(*rval);
  	ZVAL_DOUBLE(*rval, zend_strtod((const char *)start + 2, NULL));
 +    ++(BG(unserialize).num_vars);
  	return 1;
  }
  
 @@ -561,6 +574,7 @@
  
  	INIT_PZVAL(*rval);
  	ZVAL_STRINGL(*rval, str, len, 1);
 +    ++(BG(unserialize).num_vars);
  	return 1;
  }
  
 @@ -590,6 +604,7 @@
   
   	INIT_PZVAL(*rval);
   	ZVAL_STRINGL(*rval, str, len, 0);
  +    ++(BG(unserialize).num_vars);


   {
   	int utf16_len;
   	zval *z;
  @@ -627,7 +628,7 @@
  	}
  
  	}
  
   	ALLOC_INIT_ZVAL(z);
  -	jp = new_JSON_parser(depth);
  +	jp = new_JSON_parser(depth, max_vars);
   	if (parse_JSON_ex(jp, z, utf16, utf16_len, options TSRMLS_CC)) {


  +$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)


   echo "\n-- Testing json_decode() function with more than expected no. of arguments --\n";
   $extra_arg = 10;
  -var_dump( json_decode('"abc"', TRUE, 512, 0, $extra_arg) );
  +var_dump( json_decode('"abc"', TRUE, 512, 0, 1000, $extra_arg) );
  
  ?>
  ===Done===
 @@ -34,6 +34,6 @@
  
  
  ?>
  ===Done===
 @@ -34,6 +34,6 @@
  
   -- Testing json_decode() function with more than expected no. of arguments --
   
  -Warning: json_decode() expects at most 4 parameters, 5 given in %s on line %d
  +Warning: json_decode() expects at most 5 parameters, 6 given in %s on line %d


   
                       if (jp->top > 1) {
                           attach_zval(jp, jp->top - 1, jp->top, &key, assoc TSRMLS_CC);
  +						++num_vars;
                      }
                      }
   
                       JSON_RESET_TYPE();
  @@ -643,6 +658,7 @@
   


   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)
  @@ -15,20 +15,22 @@
      int top;
  	int error_code;
      int* stack;
 +	long max_vars;
      zval **the_zstack;
      zval *the_static_zstack[JSON_PARSER_DEFAULT_DEPTH];
  } * JSON_parser;
  
      int top;
  	int error_code;
      int* stack;
 +	long max_vars;
      zval **the_zstack;
      zval *the_static_zstack[JSON_PARSER_DEFAULT_DEPTH];
  } * JSON_parser;
  
   enum error_codes {
   	PHP_JSON_ERROR_NONE = 0,
  -    PHP_JSON_ERROR_DEPTH, 
  +    PHP_JSON_ERROR_DEPTH,


       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 JSON_parser new_JSON_parser(int depth);
 +extern JSON_parser new_JSON_parser(int depth, long max_vars);
   extern int parse_JSON_ex(JSON_parser jp, zval *z, unsigned short utf16_json[], int length, int options TSRMLS_DC);
   extern int free_JSON_parser(JSON_parser jp);
   
  Index: trunk/main/rfc1867.c


   				continue;
   			}
   
  Index: trunk/main/php_variables.c
 ===================================================================
 ===================================================================
  --- trunk/main/php_variables.c	(revision 321767)
  +++ trunk/main/php_variables.c	(working copy)
  @@ -178,15 +178,10 @@
   			} else {


  -						}
  -						MAKE_STD_ZVAL(gpc_element);
  -						array_init(gpc_element);
  -						zend_symtable_update(symtable1, escaped_index, index_len + 1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p);
 -					}
 -					}
  +						|| Z_TYPE_PP(gpc_element_p) != IS_ARRAY) {
  +					MAKE_STD_ZVAL(gpc_element);
  +					array_init(gpc_element);
  +					zend_symtable_update(symtable1, escaped_index, index_len + 1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p);


   {
   	char *var, *val, *e, *s, *p;
   	zval *array_ptr = (zval *) arg;
  +	long num_vars = 0;
  
  
   	if (SG(request_info).post_data == NULL) {
  		return;
  		return;
  @@ -270,6 +259,11 @@
   			}
   			efree(val);
  		}
  		}
  +		++num_vars;
  +		if (PG(max_input_vars) && num_vars >= PG(max_input_vars)) {
  +			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Post variables exceeded %ld. To increase the limit change max_input_vars in php.ini.", PG(max_input_vars));
  +			return;
 +		}
 +		}
   		s = p + 1;
  	}
  	}
   	if (s < e) {
 Index: branches/PHP_5_3/ext/standard/basic_functions.h
 ===================================================================
 --- branches/PHP_5_3/ext/standard/basic_functions.h	(revision 321767)
 +++ branches/PHP_5_3/ext/standard/basic_functions.h	(working copy)
 @@ -208,6 +208,10 @@
  
  	/* var.c */
  	zend_class_entry *incomplete_class;
 +	struct {
 +		long max_vars;
 +		long num_vars;
 +	} unserialize;
  
  	/* url_scanner_ex.re */
  	url_adapt_state_ex_t url_adapt_state_ex;
 Index: branches/PHP_5_3/ext/standard/var.c
 ===================================================================
 --- branches/PHP_5_3/ext/standard/var.c	(revision 321767)
 +++ branches/PHP_5_3/ext/standard/var.c	(working copy)
 @@ -923,8 +923,9 @@
  	int buf_len;
  	const unsigned char *p;
  	php_unserialize_data_t var_hash;
 +	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;
  	}
  
 @@ -934,10 +935,13 @@
  
  	p = (const unsigned char*) buf;
  	PHP_VAR_UNSERIALIZE_INIT(var_hash);
 +	PHP_VAR_UNSERIALIZE_MAX_VARS(max_vars);
  	if (!php_var_unserialize(&return_value, &p, p + buf_len, &var_hash TSRMLS_CC)) {
  		PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
  		zval_dtor(return_value);
 -		php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Error at offset %ld of %d bytes", (long)((char*)p - buf), buf_len);
 +		if (!BG(unserialize).max_vars || BG(unserialize).num_vars < BG(unserialize).max_vars) {
 +			php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Error at offset %ld of %d bytes", (long)((char*)p - buf), buf_len);
 +		}
  		RETURN_FALSE;
  	}
  	PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
 Index: branches/PHP_5_3/ext/standard/php_var.h
 ===================================================================
 --- branches/PHP_5_3/ext/standard/php_var.h	(revision 321767)
 +++ branches/PHP_5_3/ext/standard/php_var.h	(working copy)
 @@ -21,6 +21,7 @@
  #ifndef PHP_VAR_H
  #define PHP_VAR_H
  
 +#include "ext/standard/basic_functions.h"
  #include "ext/standard/php_smart_str_public.h"
  
  PHP_FUNCTION(var_dump);
 @@ -57,10 +58,15 @@
  
  #define PHP_VAR_UNSERIALIZE_INIT(var_hash) \
  	(var_hash).first = 0; \
 -	(var_hash).first_dtor = 0
 +	(var_hash).first_dtor = 0; \
 +    BG(unserialize).num_vars = 0; \
 +    BG(unserialize).max_vars = 0
 +   
  #define PHP_VAR_UNSERIALIZE_DESTROY(var_hash) \
  	var_destroy(&(var_hash))
  
 +#define PHP_VAR_UNSERIALIZE_MAX_VARS(max_vars) BG(unserialize).max_vars = max_vars
 +
  PHPAPI void var_replace(php_unserialize_data_t *var_hash, zval *ozval, zval **nzval);
  PHPAPI void var_push_dtor(php_unserialize_data_t *var_hash, zval **val);
  PHPAPI void var_destroy(php_unserialize_data_t *var_hash);
 Index: branches/PHP_5_3/ext/standard/var_unserializer.re
 ===================================================================
 --- branches/PHP_5_3/ext/standard/var_unserializer.re	(revision 321767)
 +++ branches/PHP_5_3/ext/standard/var_unserializer.re	(working copy)
 @@ -269,6 +269,7 @@
  			FREE_ZVAL(key);
  			return 0;
  		}
 +	    --(BG(unserialize).num_vars);
  
  		if (Z_TYPE_P(key) != IS_LONG && Z_TYPE_P(key) != IS_STRING) {
  			zval_dtor(key);
 @@ -398,6 +399,11 @@
  
  	limit = cursor = *p;
  	
 +    if (BG(unserialize).max_vars && BG(unserialize).num_vars >= BG(unserialize).max_vars) {
 +	    php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unserialized variables exceeded %ld", BG(unserialize).max_vars);
 +        return 0;
 +    }
 +
  	if (var_hash && cursor[0] != 'R') {
  		var_push(var_hash, rval);
  	}
 @@ -425,7 +431,7 @@
  	*rval = *rval_ref;
  	Z_ADDREF_PP(rval);
  	Z_SET_ISREF_PP(rval);
 -	
 +	++(BG(unserialize).num_vars);
  	return 1;
  }
  
 @@ -449,6 +455,7 @@
  	Z_ADDREF_PP(rval);
  	Z_UNSET_ISREF_PP(rval);
  	
 +	++(BG(unserialize).num_vars);
  	return 1;
  }
  
 @@ -456,6 +463,7 @@
  	*p = YYCURSOR;
  	INIT_PZVAL(*rval);
  	ZVAL_NULL(*rval);
 +	++(BG(unserialize).num_vars);
  	return 1;
  }
  
 @@ -463,6 +471,7 @@
  	*p = YYCURSOR;
  	INIT_PZVAL(*rval);
  	ZVAL_BOOL(*rval, parse_iv(start + 2));
 +	++(BG(unserialize).num_vars);
  	return 1;
  }
  
 @@ -490,6 +499,7 @@
  	*p = YYCURSOR;
  	INIT_PZVAL(*rval);
  	ZVAL_LONG(*rval, parse_iv(start + 2));
 +	++(BG(unserialize).num_vars);
  	return 1;
  }
  
 @@ -505,6 +515,7 @@
  		ZVAL_DOUBLE(*rval, -php_get_inf());
  	}
  
 +	++(BG(unserialize).num_vars);
  	return 1;
  }
  
 @@ -515,6 +526,7 @@
  	*p = YYCURSOR;
  	INIT_PZVAL(*rval);
  	ZVAL_DOUBLE(*rval, zend_strtod((const char *)start + 2, NULL));
 +	++(BG(unserialize).num_vars);
  	return 1;
  }
  
 @@ -543,6 +555,7 @@
  
  	INIT_PZVAL(*rval);
  	ZVAL_STRINGL(*rval, str, len, 1);
 +	++(BG(unserialize).num_vars);
  	return 1;
  }
  
 @@ -572,6 +585,7 @@
  
  	INIT_PZVAL(*rval);
  	ZVAL_STRINGL(*rval, str, len, 0);
 +	++(BG(unserialize).num_vars);
  	return 1;
  }
  
 @@ -588,6 +602,7 @@
  
  	array_init_size(*rval, elements);
  
 +	++(BG(unserialize).num_vars);
  	if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL_PP(rval), elements, 0)) {
  		return 0;
  	}
 @@ -599,6 +614,7 @@
  
  	INIT_PZVAL(*rval);
  	
 +	++(BG(unserialize).num_vars);
  	return object_common2(UNSERIALIZE_PASSTHRU,
  			object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR));
  }
 @@ -701,6 +717,7 @@
  	*p = YYCURSOR;
  
  	if (custom_object) {
 +	    ++(BG(unserialize).num_vars);
  		int ret = object_custom(UNSERIALIZE_PASSTHRU, ce);
  
  		if (ret && incomplete_class) {
 @@ -717,6 +734,7 @@
  	}
  	efree(class_name);
  
 +	++(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)


  -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)


  Index: branches/PHP_5_4/ext/standard/php_var.h
  ===================================================================
  --- branches/PHP_5_4/ext/standard/php_var.h	(revision 321767)
  +++ branches/PHP_5_4/ext/standard/php_var.h	(working copy)
 @@ -95,9 +95,12 @@
 @@ -95,9 +95,13 @@
   	} else { \
   		(var_hash_ptr) = (php_serialize_data_t)BG(unserialize).var_hash; \
   		++BG(unserialize).level; \
  -	} \
  +	}	\
  +	BG(unserialize).num_vars = 0; \
 +	BG(unserialize).max_vars = 0; \
   } while (0)
   
  +#define PHP_VAR_UNSERIALIZE_MAX_VARS(max_vars)  BG(unserialize).max_vars = max_vars;
  +
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Mar 29 09:01:28 2024 UTC