From 0743a1eadcf2166c9c50adaa37a06ba91dc58381 Mon Sep 17 00:00:00 2001 From: OracleNep <3377457402@qq.com> Date: Thu, 4 Jun 2026 04:41:11 +0000 Subject: [PATCH] Warn on negative request_parse_body() max_input_vars option --- NEWS | 3 ++ UPGRADING | 3 ++ ext/standard/http.c | 22 +++++++++-- ...ipart_options_negative_max_input_vars.phpt | 38 +++++++++++++++++++ 4 files changed, 62 insertions(+), 4 deletions(-) create mode 100644 ext/standard/tests/http/request_parse_body/multipart_options_negative_max_input_vars.phpt diff --git a/NEWS b/NEWS index 3c4d6993f46c..41888fa5690a 100644 --- a/NEWS +++ b/NEWS @@ -226,6 +226,9 @@ PHP NEWS contains null bytes. (Weilin Du) . parse_str() now raises a ValueError when the $string argument contains null bytes. (Weilin Du) + . request_parse_body() now emits a warning and falls back to the + max_input_vars ini setting for negative max_input_vars option values. + (Xu Chen) . proc_open() now raises a ValueError when the $cwd argument contains null bytes. (Weilin Du) . ini_get_all() now includes the built-in default value in the details. diff --git a/UPGRADING b/UPGRADING index 95299dd5117f..2f4ef479e041 100644 --- a/UPGRADING +++ b/UPGRADING @@ -142,6 +142,9 @@ PHP 8.6 UPGRADE NOTES contains null bytes. . parse_str() now raises a ValueError when the $string argument contains null bytes. + . request_parse_body() now emits a warning and falls back to the + max_input_vars ini setting when the $options argument contains a negative + max_input_vars value. . linkinfo() now raises a ValueError when the $path argument is empty. . pathinfo() now raises a ValueError when an invalid $flag argument value is passed. diff --git a/ext/standard/http.c b/ext/standard/http.c index 99509e7ceb04..e21273268f95 100644 --- a/ext/standard/http.c +++ b/ext/standard/http.c @@ -247,7 +247,7 @@ PHP_FUNCTION(http_build_query) } /* }}} */ -static zend_result cache_request_parse_body_option(HashTable *options, zval *option, int cache_offset) +static zend_result cache_request_parse_body_option(zval *option, int cache_offset, const char *non_negative_option_name) { if (option) { zend_long result; @@ -265,6 +265,11 @@ static zend_result cache_request_parse_body_option(HashTable *options, zval *opt zend_value_error("Invalid %s value in $options argument", zend_zval_value_name(option)); return FAILURE; } + if (non_negative_option_name && result < 0) { + zend_error(E_WARNING, "\"%s\" option in $options argument must be greater than or equal to 0", non_negative_option_name); + SG(request_parse_body_context).options_cache[cache_offset].set = false; + return SUCCESS; + } SG(request_parse_body_context).options_cache[cache_offset].set = true; SG(request_parse_body_context).options_cache[cache_offset].value = result; } else { @@ -290,7 +295,15 @@ static zend_result cache_request_parse_body_options(HashTable *options) #define CHECK_OPTION(name) \ if (zend_string_equals_literal_ci(key, #name)) { \ - if (cache_request_parse_body_option(options, value, REQUEST_PARSE_BODY_OPTION_ ## name) == FAILURE) { \ + if (cache_request_parse_body_option(value, REQUEST_PARSE_BODY_OPTION_ ## name, NULL) == FAILURE) { \ + return FAILURE; \ + } \ + continue; \ + } + +#define CHECK_NON_NEGATIVE_OPTION(name) \ + if (zend_string_equals_literal_ci(key, #name)) { \ + if (cache_request_parse_body_option(value, REQUEST_PARSE_BODY_OPTION_ ## name, #name) == FAILURE) { \ return FAILURE; \ } \ continue; \ @@ -300,7 +313,7 @@ static zend_result cache_request_parse_body_options(HashTable *options) case 'm': case 'M': CHECK_OPTION(max_file_uploads); - CHECK_OPTION(max_input_vars); + CHECK_NON_NEGATIVE_OPTION(max_input_vars); CHECK_OPTION(max_multipart_body_parts); break; case 'p': @@ -317,7 +330,8 @@ static zend_result cache_request_parse_body_options(HashTable *options) return FAILURE; } ZEND_HASH_FOREACH_END(); -#undef CACHE_OPTION +#undef CHECK_OPTION +#undef CHECK_NON_NEGATIVE_OPTION return SUCCESS; } diff --git a/ext/standard/tests/http/request_parse_body/multipart_options_negative_max_input_vars.phpt b/ext/standard/tests/http/request_parse_body/multipart_options_negative_max_input_vars.phpt new file mode 100644 index 000000000000..8563eb36737e --- /dev/null +++ b/ext/standard/tests/http/request_parse_body/multipart_options_negative_max_input_vars.phpt @@ -0,0 +1,38 @@ +--TEST-- +request_parse_body() negative max_input_vars option falls back to ini setting +--INI-- +max_input_vars=1 +--ENV-- +REQUEST_METHOD=PUT +--POST_RAW-- +Content-Type: multipart/form-data; boundary=---------------------------84000087610663814162942123332 +-----------------------------84000087610663814162942123332 +Content-Disposition: form-data; name="field1" + +post field data +-----------------------------84000087610663814162942123332 +Content-Disposition: form-data; name="field2" + +post field data +-----------------------------84000087610663814162942123332-- +--FILE-- + -1, + ]); +} catch (Throwable $e) { + echo get_class($e), ': ', $e->getMessage(), "\n"; +} + +var_dump($_POST, $_FILES); + +?> +--EXPECTF-- +Warning: "max_input_vars" option in $options argument must be greater than or equal to 0 in %s on line %d +RequestParseBodyException: Input variables exceeded 1. To increase the limit change max_input_vars in php.ini. +array(0) { +} +array(0) { +}