[Pkg-php-commits] [php/debian-sid] Fix improper signed overflow detection in filter extension

Sean Finney seanius at debian.org
Thu Feb 25 21:42:20 UTC 2010


The existing filter code relied on detecting invalid long integers by
examining computed values for wraparound.  This is not defined behavior
in any C standard, and in fact recent versions of gcc will optimize out
such checks resulting in invalid code.

This patch therefore changes how the overflow/underflow conditions are
detected, using more reliable arithmetic.  It also fixes another bug, that
the minimum integer value (-PHP_INT_MAX)-1 could not be detected properly.

This patch also includes an update to the test case that detects such
overflows, adding much more thorough and descriptive checking.

Closes: #570287
---
 debian/patches/filter_validate_int.patch |  124 ++++++++++++++++++++++++++++++
 debian/patches/series                    |    1 +
 2 files changed, 125 insertions(+), 0 deletions(-)
 create mode 100644 debian/patches/filter_validate_int.patch

diff --git a/debian/patches/filter_validate_int.patch b/debian/patches/filter_validate_int.patch
new file mode 100644
index 0000000..8c33995
--- /dev/null
+++ b/debian/patches/filter_validate_int.patch
@@ -0,0 +1,124 @@
+From: Sean Finney <seanius at debian.org>
+Subject: Fix improper signed overflow detection in filter extension
+
+The existing filter code relied on detecting invalid long integers by
+examining computed values for wraparound.  This is not defined behavior
+in any C standard, and in fact recent versions of gcc will optimize out
+such checks resulting in invalid code.
+
+This patch therefore changes how the overflow/underflow conditions are
+detected, using more reliable arithmetic.  It also fixes another bug, that
+the minimum integer value (-PHP_INT_MAX)-1 could not be detected properly.
+
+This patch also includes an update to the test case that detects such
+overflows, adding much more thorough and descriptive checking.
+
+Bug: http://bugs.php.net/bug.php?id=51023
+Bug-Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=570287
+--- php.orig/ext/filter/logical_filters.c
++++ php/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 ch
+ 
+ 	/* 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 ch
+ 
+ 	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;
+--- php.orig/ext/filter/tests/046.phpt
++++ php/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)
diff --git a/debian/patches/series b/debian/patches/series
index 097fa4a..e7c1a45 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -44,3 +44,4 @@ dont-gitclean-in-build.patch
 broken_5.3_test-posix_uname.patch
 shtool_mkdir_-p_-race-condition.patch
 qdbm-is-usr_include_qdbm.patch
+filter_validate_int.patch
-- 
1.6.3.3




More information about the Pkg-php-commits mailing list