diff options
author | Raphael Geissert <geissert@php.net> | 2010-03-06 18:54:55 +0000 |
---|---|---|
committer | Raphael Geissert <geissert@php.net> | 2010-03-06 18:54:55 +0000 |
commit | db01920ad775cf8f25a1d98bd67173b2b820db9e (patch) | |
tree | eed3400a26bb8166ba1d3c1ebf2daccb5a4ebb98 /ext/filter | |
parent | 13e0d47cf34b0af0bcfe0a1ceaad40156920394c (diff) | |
download | php-git-db01920ad775cf8f25a1d98bd67173b2b820db9e.tar.gz |
Detect overflows before they occur in the filter extension (bug #51023)
Thanks to Sean Finney for the patch
Diffstat (limited to 'ext/filter')
-rw-r--r-- | ext/filter/logical_filters.c | 21 | ||||
-rwxr-xr-x | ext/filter/tests/046.phpt | 50 |
2 files changed, 50 insertions, 21 deletions
diff --git a/ext/filter/logical_filters.c b/ext/filter/logical_filters.c index 52dcb504ec..28fae50226 100644 --- a/ext/filter/logical_filters.c +++ b/ext/filter/logical_filters.c @@ -68,7 +68,7 @@ static int php_filter_parse_int(const char *str, unsigned int str_len, long *ret TSRMLS_DC) { /* {{{ */ long ctx_value; - int sign = 0; + int sign = 0, digit = 0; const char *end = str + str_len; switch (*str) { @@ -82,7 +82,7 @@ static int php_filter_parse_int(const char *str, unsigned int str_len, long *ret /* must start with 1..9*/ if (str < end && *str >= '1' && *str <= '9') { - ctx_value = ((*(str++)) - '0'); + ctx_value = ((sign)?-1:1) * ((*(str++)) - '0'); } else { return -1; } @@ -95,19 +95,18 @@ static int php_filter_parse_int(const char *str, unsigned int str_len, long *ret while (str < end) { if (*str >= '0' && *str <= '9') { - ctx_value = (ctx_value * 10) + (*(str++) - '0'); + digit = (*(str++) - '0'); + if ( (!sign) && ctx_value <= (LONG_MAX-digit)/10 ) { + ctx_value = (ctx_value * 10) + digit; + } else if ( sign && ctx_value >= (LONG_MIN+digit)/10) { + ctx_value = (ctx_value * 10) - digit; + } else { + return -1; + } } else { return -1; } } - if (sign) { - ctx_value = -ctx_value; - if (ctx_value > 0) { /* overflow */ - return -1; - } - } else if (ctx_value < 0) { /* overflow */ - return -1; - } *ret = ctx_value; return 1; diff --git a/ext/filter/tests/046.phpt b/ext/filter/tests/046.phpt index 8133289461..bc454420ad 100755 --- a/ext/filter/tests/046.phpt +++ b/ext/filter/tests/046.phpt @@ -4,16 +4,46 @@ Integer overflow <?php if (!extension_loaded("filter")) die("skip"); ?> --FILE-- <?php -$s = sprintf("%d", PHP_INT_MAX); -var_dump(is_long(filter_var($s, FILTER_VALIDATE_INT))); +$max = sprintf("%d", PHP_INT_MAX); +switch($max) { +case "2147483647": /* 32-bit systems */ + $min = "-2147483648"; + $overflow = "2147483648"; + $underflow = "-2147483649"; + break; +case "9223372036854775807": /* 64-bit systems */ + $min = "-9223372036854775808"; + $overflow = "9223372036854775808"; + $underflow = "-9223372036854775809"; + break; +default: + die("failed: unknown value for PHP_MAX_INT"); + break; +} -$s = sprintf("%.0f", PHP_INT_MAX+1); -var_dump(filter_var($s, FILTER_VALIDATE_INT)); +function test_validation($val, $msg) { + $f = filter_var($val, FILTER_VALIDATE_INT); + echo "$msg filtered: "; var_dump($f); // filtered value (or false) + echo "$msg is_long: "; var_dump(is_long($f)); // test validation + echo "$msg equal: "; var_dump($val == $f); // test equality of result +} -$s = sprintf("%d", -PHP_INT_MAX); -var_dump(is_long(filter_var($s, FILTER_VALIDATE_INT))); +// PHP_INT_MAX +test_validation($max, "max"); +test_validation($overflow, "overflow"); +test_validation($min, "min"); +test_validation($underflow, "underflow"); ?> ---EXPECT-- -bool(true) -bool(false) -bool(true) +--EXPECTF-- +max filtered: int(%d) +max is_long: bool(true) +max equal: bool(true) +overflow filtered: bool(false) +overflow is_long: bool(false) +overflow equal: bool(false) +min filtered: int(-%d) +min is_long: bool(true) +min equal: bool(true) +underflow filtered: bool(false) +underflow is_long: bool(false) +underflow equal: bool(false) |