Skip to content

Commit 0743a1e

Browse files
author
OracleNep
committed
Warn on negative request_parse_body() max_input_vars option
1 parent 425cd3d commit 0743a1e

4 files changed

Lines changed: 62 additions & 4 deletions

File tree

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,9 @@ PHP NEWS
226226
contains null bytes. (Weilin Du)
227227
. parse_str() now raises a ValueError when the $string argument contains
228228
null bytes. (Weilin Du)
229+
. request_parse_body() now emits a warning and falls back to the
230+
max_input_vars ini setting for negative max_input_vars option values.
231+
(Xu Chen)
229232
. proc_open() now raises a ValueError when the $cwd argument contains
230233
null bytes. (Weilin Du)
231234
. ini_get_all() now includes the built-in default value in the details.

UPGRADING

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,9 @@ PHP 8.6 UPGRADE NOTES
142142
contains null bytes.
143143
. parse_str() now raises a ValueError when the $string argument contains
144144
null bytes.
145+
. request_parse_body() now emits a warning and falls back to the
146+
max_input_vars ini setting when the $options argument contains a negative
147+
max_input_vars value.
145148
. linkinfo() now raises a ValueError when the $path argument is empty.
146149
. pathinfo() now raises a ValueError when an invalid $flag
147150
argument value is passed.

ext/standard/http.c

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ PHP_FUNCTION(http_build_query)
247247
}
248248
/* }}} */
249249

250-
static zend_result cache_request_parse_body_option(HashTable *options, zval *option, int cache_offset)
250+
static zend_result cache_request_parse_body_option(zval *option, int cache_offset, const char *non_negative_option_name)
251251
{
252252
if (option) {
253253
zend_long result;
@@ -265,6 +265,11 @@ static zend_result cache_request_parse_body_option(HashTable *options, zval *opt
265265
zend_value_error("Invalid %s value in $options argument", zend_zval_value_name(option));
266266
return FAILURE;
267267
}
268+
if (non_negative_option_name && result < 0) {
269+
zend_error(E_WARNING, "\"%s\" option in $options argument must be greater than or equal to 0", non_negative_option_name);
270+
SG(request_parse_body_context).options_cache[cache_offset].set = false;
271+
return SUCCESS;
272+
}
268273
SG(request_parse_body_context).options_cache[cache_offset].set = true;
269274
SG(request_parse_body_context).options_cache[cache_offset].value = result;
270275
} else {
@@ -290,7 +295,15 @@ static zend_result cache_request_parse_body_options(HashTable *options)
290295

291296
#define CHECK_OPTION(name) \
292297
if (zend_string_equals_literal_ci(key, #name)) { \
293-
if (cache_request_parse_body_option(options, value, REQUEST_PARSE_BODY_OPTION_ ## name) == FAILURE) { \
298+
if (cache_request_parse_body_option(value, REQUEST_PARSE_BODY_OPTION_ ## name, NULL) == FAILURE) { \
299+
return FAILURE; \
300+
} \
301+
continue; \
302+
}
303+
304+
#define CHECK_NON_NEGATIVE_OPTION(name) \
305+
if (zend_string_equals_literal_ci(key, #name)) { \
306+
if (cache_request_parse_body_option(value, REQUEST_PARSE_BODY_OPTION_ ## name, #name) == FAILURE) { \
294307
return FAILURE; \
295308
} \
296309
continue; \
@@ -300,7 +313,7 @@ static zend_result cache_request_parse_body_options(HashTable *options)
300313
case 'm':
301314
case 'M':
302315
CHECK_OPTION(max_file_uploads);
303-
CHECK_OPTION(max_input_vars);
316+
CHECK_NON_NEGATIVE_OPTION(max_input_vars);
304317
CHECK_OPTION(max_multipart_body_parts);
305318
break;
306319
case 'p':
@@ -317,7 +330,8 @@ static zend_result cache_request_parse_body_options(HashTable *options)
317330
return FAILURE;
318331
} ZEND_HASH_FOREACH_END();
319332

320-
#undef CACHE_OPTION
333+
#undef CHECK_OPTION
334+
#undef CHECK_NON_NEGATIVE_OPTION
321335

322336
return SUCCESS;
323337
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
--TEST--
2+
request_parse_body() negative max_input_vars option falls back to ini setting
3+
--INI--
4+
max_input_vars=1
5+
--ENV--
6+
REQUEST_METHOD=PUT
7+
--POST_RAW--
8+
Content-Type: multipart/form-data; boundary=---------------------------84000087610663814162942123332
9+
-----------------------------84000087610663814162942123332
10+
Content-Disposition: form-data; name="field1"
11+
12+
post field data
13+
-----------------------------84000087610663814162942123332
14+
Content-Disposition: form-data; name="field2"
15+
16+
post field data
17+
-----------------------------84000087610663814162942123332--
18+
--FILE--
19+
<?php
20+
21+
try {
22+
[$_POST, $_FILES] = request_parse_body([
23+
'max_input_vars' => -1,
24+
]);
25+
} catch (Throwable $e) {
26+
echo get_class($e), ': ', $e->getMessage(), "\n";
27+
}
28+
29+
var_dump($_POST, $_FILES);
30+
31+
?>
32+
--EXPECTF--
33+
Warning: "max_input_vars" option in $options argument must be greater than or equal to 0 in %s on line %d
34+
RequestParseBodyException: Input variables exceeded 1. To increase the limit change max_input_vars in php.ini.
35+
array(0) {
36+
}
37+
array(0) {
38+
}

0 commit comments

Comments
 (0)