summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaphael Geissert <geissert@php.net>2010-03-06 18:54:55 +0000
committerRaphael Geissert <geissert@php.net>2010-03-06 18:54:55 +0000
commitf2ff225bee590223690f8d132036572921da3a2a (patch)
tree11c5ce27cc1ae26148c9ca2b097fa58507d6929f
parentf8e412ae5142ed5482a7f955c1923aabf9b59b63 (diff)
downloadphp-git-f2ff225bee590223690f8d132036572921da3a2a.tar.gz
Detect overflows before they occur in the filter extension (bug #51023)
Thanks to Sean Finney for the patch
-rw-r--r--ext/filter/logical_filters.c21
-rwxr-xr-xext/filter/tests/046.phpt50
2 files changed, 50 insertions, 21 deletions
diff --git a/ext/filter/logical_filters.c b/ext/filter/logical_filters.c
index 61f5bc0b4e..8b4f58b51a 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)