Skip to content

Commit

Permalink
Fix GH-11876: ini_parse_quantity() accepts invalid quantities
Browse files Browse the repository at this point in the history
Closes GH-11910
  • Loading branch information
Girgias committed Aug 30, 2023
1 parent d5f7ffb commit d229a48
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 0 deletions.
2 changes: 2 additions & 0 deletions NEWS
Expand Up @@ -6,6 +6,8 @@ PHP NEWS
. Fixed bug GH-11937 (Constant ASTs containing objects). (ilutov)
. Fixed bug GH-11790 (On riscv64 require libatomic if actually needed).
(Jeremie Courreges-Anglas)
. Fixed bug GH-11876: ini_parse_quantity() accepts invalid quantities.
(Girgias)

- DOM:
. Fix memory leak when setting an invalid DOMDocument encoding. (nielsdos)
Expand Down
51 changes: 51 additions & 0 deletions Zend/tests/zend_ini/gh11876.phpt
@@ -0,0 +1,51 @@
--TEST--
Invalid INI quantities, base prefix followed by stuff eaten by strtoull()
--EXTENSIONS--
zend_test
--FILE--
<?php

var_dump(zend_test_zend_ini_parse_quantity('0x0x12'));

var_dump(zend_test_zend_ini_parse_quantity('0b+10'));
var_dump(zend_test_zend_ini_parse_quantity('0o+10'));
var_dump(zend_test_zend_ini_parse_quantity('0x+10'));

var_dump(zend_test_zend_ini_parse_quantity('0b 10'));
var_dump(zend_test_zend_ini_parse_quantity('0o 10'));
var_dump(zend_test_zend_ini_parse_quantity('0x 10'));

var_dump(zend_test_zend_ini_parse_quantity('0g10'));
var_dump(zend_test_zend_ini_parse_quantity('0m10'));
var_dump(zend_test_zend_ini_parse_quantity('0k10'));

--EXPECTF--
Warning: Invalid quantity "0x0x12": no digits after base prefix, interpreting as "0" for backwards compatibility in %s on line %d
int(0)

Warning: Invalid quantity "0b+10": no digits after base prefix, interpreting as "0" for backwards compatibility in %s on line %d
int(0)

Warning: Invalid quantity "0o+10": no digits after base prefix, interpreting as "0" for backwards compatibility in %s on line %d
int(0)

Warning: Invalid quantity "0x+10": no digits after base prefix, interpreting as "0" for backwards compatibility in %s on line %d
int(0)

Warning: Invalid quantity "0b 10": no digits after base prefix, interpreting as "0" for backwards compatibility in %s on line %d
int(0)

Warning: Invalid quantity "0o 10": no digits after base prefix, interpreting as "0" for backwards compatibility in %s on line %d
int(0)

Warning: Invalid quantity "0x 10": no digits after base prefix, interpreting as "0" for backwards compatibility in %s on line %d
int(0)

Warning: Invalid quantity "0g10": unknown multiplier "0", interpreting as "0" for backwards compatibility in %s on line %d
int(0)

Warning: Invalid quantity "0m10": unknown multiplier "0", interpreting as "0" for backwards compatibility in %s on line %d
int(0)

Warning: Invalid quantity "0k10": unknown multiplier "0", interpreting as "0" for backwards compatibility in %s on line %d
int(0)
40 changes: 40 additions & 0 deletions Zend/zend_ini.c
Expand Up @@ -547,6 +547,34 @@ typedef enum {
ZEND_INI_PARSE_QUANTITY_UNSIGNED,
} zend_ini_parse_quantity_signed_result_t;

static const char *zend_ini_consume_quantity_prefix(const char *const digits, const char *const str_end) {
const char *digits_consumed = digits;
/* Ignore leading whitespace. */
while (digits_consumed < str_end && zend_is_whitespace(*digits_consumed)) {++digits_consumed;}
if (digits_consumed[0] == '+' || digits_consumed[0] == '-') {
++digits_consumed;
}

if (digits_consumed[0] == '0' && !isdigit(digits_consumed[1])) {
/* Value is just 0 */
if ((digits_consumed+1) == str_end) {
return digits;
}

switch (digits_consumed[1]) {
case 'x':
case 'X':
case 'o':
case 'O':
case 'b':
case 'B':
digits_consumed += 2;
break;
}
}
return digits_consumed;
}

static zend_ulong zend_ini_parse_quantity_internal(zend_string *value, zend_ini_parse_quantity_signed_result_t signed_result, zend_string **errstr) /* {{{ */
{
char *digits_end = NULL;
Expand Down Expand Up @@ -634,6 +662,18 @@ static zend_ulong zend_ini_parse_quantity_internal(zend_string *value, zend_ini_
smart_str_append_escaped(&invalid, ZSTR_VAL(value), ZSTR_LEN(value));
smart_str_0(&invalid);

*errstr = zend_strpprintf(0, "Invalid quantity \"%s\": no digits after base prefix, interpreting as \"0\" for backwards compatibility",
ZSTR_VAL(invalid.s));

smart_str_free(&invalid);
return 0;
}
if (UNEXPECTED(digits != zend_ini_consume_quantity_prefix(digits, str_end))) {
/* Escape the string to avoid null bytes and to make non-printable chars
* visible */
smart_str_append_escaped(&invalid, ZSTR_VAL(value), ZSTR_LEN(value));
smart_str_0(&invalid);

*errstr = zend_strpprintf(0, "Invalid quantity \"%s\": no digits after base prefix, interpreting as \"0\" for backwards compatibility",
ZSTR_VAL(invalid.s));

Expand Down

0 comments on commit d229a48

Please sign in to comment.