cataphract                               Mon, 08 Nov 2010 04:36:15 +0000

Revision: http://svn.php.net/viewvc?view=revision&revision=305186

Log:
- Fixed the filter extension accepting IPv4 octets with a leading 0 as that
  belongs to the unsupported "dotted octal" representation.
- Fixed bug #53236 (problems in the validation of IPv6 addresses with leading
  and trailing :: in the filter extension).
- Fixed bug #50117 (problems in the validation of IPv6 addresses with IPv4
  addresses and ::).

Bugs: http://bugs.php.net/53236 (Open) IPv6 address validation error
      http://bugs.php.net/50117 (Open) IPv6 validation errors
      
Changed paths:
    U   php/php-src/branches/PHP_5_3/NEWS
    U   php/php-src/branches/PHP_5_3/ext/filter/logical_filters.c
    U   php/php-src/branches/PHP_5_3/ext/filter/tests/030.phpt
    U   php/php-src/trunk/ext/filter/logical_filters.c
    U   php/php-src/trunk/ext/filter/tests/030.phpt

Modified: php/php-src/branches/PHP_5_3/NEWS
===================================================================
--- php/php-src/branches/PHP_5_3/NEWS	2010-11-08 02:55:04 UTC (rev 305185)
+++ php/php-src/branches/PHP_5_3/NEWS	2010-11-08 04:36:15 UTC (rev 305186)
@@ -52,11 +52,15 @@
 - Fixed ReflectionProperty::isDefault() giving a wrong result for properties
   obtained with ReflectionClass::getProperties(). (Gustavo)
 - Fixed covariance of return-by-ref constraints. (Etienne)
+- Fixed the filter extension accepting IPv4 octets with a leading 0 as that
+  belongs to the unsupported "dotted octal" representation. (Gustavo)

 - Fixed bug #53248 (rawurlencode RFC 3986 EBCDIC support misses tilde char).
   (Justin Martin)
 - Fixed bug #53241 (stream casting that relies on fdopen/fopencookie fails
   with streams opened with, inter alia, the 'xb' mode). (Gustavo)
+- Fixed bug #53236 (problems in the validation of IPv6 addresses with leading
+  and trailing :: in the filter extension). (Gustavo)
 - Fixed bug #53226 (file_exists fails on big filenames). (Adam)
 - Fixed bug #53198 (changing INI setting "from" with ini_set did not have any
   effect). (Gustavo)
@@ -177,6 +181,8 @@
   other platforms). (Pierre)
 - Fixed bug #50345 (nanosleep not detected properly on some solaris versions).
   (Ulf, Tony)
+- Fixed bug #50117 (problems in the validation of IPv6 addresses with IPv4
+  addresses and ::). (Gustavo)
 - Fixed bug #49687 (utf8_decode vulnerabilities and deficiencies in the number
   of reported malformed sequences). (CVE-2010-3870) (Gustavo)
 - Fixed bug #49407 (get_html_translation_table doesn't handle UTF-8). (Gustavo)

Modified: php/php-src/branches/PHP_5_3/ext/filter/logical_filters.c
===================================================================
--- php/php-src/branches/PHP_5_3/ext/filter/logical_filters.c	2010-11-08 02:55:04 UTC (rev 305185)
+++ php/php-src/branches/PHP_5_3/ext/filter/logical_filters.c	2010-11-08 04:36:15 UTC (rev 305186)
@@ -557,9 +557,11 @@
 	int n = 0;

 	while (str < end) {
+		int leading_zero;
 		if (*str < '0' || *str > '9') {
 			return 0;
 		}
+		leading_zero = (*str == '0');
 		m = 1;
 		num = ((*(str++)) - '0');
 		while (str < end && (*str >= '0' && *str <= '9')) {
@@ -568,6 +570,10 @@
 				return 0;
 			}
 		}
+		/* don't allow a leading 0; that introduces octal numbers,
+		 * which we don't support */
+		if (leading_zero && (num != 0 || m > 1))
+			return 0;
 		ip[n++] = num;
 		if (n == 4) {
 			return str == end;
@@ -582,7 +588,7 @@
 static int _php_filter_validate_ipv6(char *str, int str_len TSRMLS_DC) /* {{{ */
 {
 	int compressed = 0;
-	int blocks = 8;
+	int blocks = 0;
 	int n;
 	char *ipv4;
 	char *end;
@@ -603,32 +609,40 @@
 		if (!_php_filter_validate_ipv4(ipv4, (str_len - (ipv4 - str)), ip4elm)) {
 			return 0;
 		}
-		str_len = (ipv4 - str) - 1;
-		if (str_len == 1) {
-			return *str == ':';
+
+		str_len = ipv4 - str; /* length excluding ipv4 */
+		if (str_len < 2) {
+			return 0;
 		}
-		blocks = 6;
+
+		if (ipv4[-2] != ':') {
+			/* don't include : before ipv4 unless it's a :: */
+			str_len--;
+		}
+
+		blocks = 2;
 	}

 	end = str + str_len;

 	while (str < end) {
 		if (*str == ':') {
-			if (--blocks == 0) {
-				return 0;
-			}
 			if (++str >= end) {
+				/* cannot end in : without previous : */
 				return 0;
 			}
 			if (*str == ':') {
-				if (compressed || --blocks == 0) {
+				if (compressed) {
 					return 0;
-				}
+				}
+				blocks++; /* :: means 1 or more 16-bit 0 blocks */
+				compressed = 1;
+
 				if (++str == end) {
-					return 1;
+					return (blocks <= 8);
 				}
-				compressed = 1;
 			} else if ((str - 1) == s) {
+				/* dont allow leading : without another : following */
 				return 0;
 			}
 		}
@@ -643,8 +657,10 @@
 		if (n < 1 || n > 4) {
 			return 0;
 		}
+		if (++blocks > 8)
+			return 0;
 	}
-	return (compressed || blocks == 1);
+	return ((compressed && blocks <= 8) || blocks == 8);
 }
 /* }}} */


Modified: php/php-src/branches/PHP_5_3/ext/filter/tests/030.phpt
===================================================================
--- php/php-src/branches/PHP_5_3/ext/filter/tests/030.phpt	2010-11-08 02:55:04 UTC (rev 305185)
+++ php/php-src/branches/PHP_5_3/ext/filter/tests/030.phpt	2010-11-08 04:36:15 UTC (rev 305186)
@@ -5,35 +5,56 @@
 --FILE--
 <?php
 $ipv6_test = array(
-	"::127.0.0.1"				=> true,
-	"FF01::101:127.0.1" 		=> false,
-	"FF01:0:0:0:101:127.0.1.1"  => false,
-	"FF01:0:0:0:237:101:127.0.1.1"  => true,
-	"FF01::101"					=> true,
-	"A1080::8:800:200C:417A"	=> false,
-	"1080::8:Z00:200C:417A"		=> false,
-	"FF01::101::1"				=> false,
-	"1080::8:800:200C:417A"		=> true,
-	"1080:0:0:0:8:800:200C:417A" => true,
+	"::127.0.0.1"					=> true,
+	"FF01::101:127.0.1" 			=> false,
+	"FF01:0:0:0:101:127.0.1.1"		=> false,
+	"FF01:0:0:0:237:101:127.0.1.1"	=> true,
+	"FF01::101"						=> true,
+	"A1080::8:800:200C:417A"		=> false,
+	"1080::8:Z00:200C:417A"			=> false,
+	"FF01::101::1"					=> false,
+	"1080::8:800:200C:417A"			=> true,
+	"1080:0:0:0:8:800:200C:417A"	=> true,
 	"2001:ec8:1:1:1:1:1:1"			=> true,
 	"ffff::FFFF:129.144.52.38"		=> true,
 	"::ffff:1.2.3.4"				=> true,
-	"0:0:0:0:0:FFFF:129.144.52.38" => true,
-	"0:0:0:0:0:0:13.1.68.3"		=> true,
-	"::13.1.68.3"				=> true,
-    "::FFFF:129.144.52.38"		=> true,
+	"0:0:0:0:0:FFFF:129.144.52.38"	=> true,
+	"0:0:0:0:0:0:13.1.68.3"			=> true,
+    "0:0:0:0:0:0:0:13.1.68.3"		=> false,
+	"::13.1.68.3"					=> true,
+    "::FFFF:129.144.52.38"			=> true,
+
     "1:2:3:4:5:6::129.144.52.38"	=> false,
     "::1:2:3:4:5:6:129.144.52.38"	=> false,
     "1:2:3::4:5:6:129.144.52.38"	=> false,
+
+    "1:2:3:4::5:6:7:8"				=> false,
+    "::1:2:3:4:5:6:7"				=> true,
+    "::1:2:3:4:5:6:7:8"				=> false,
+    "1:2:3:4:5:6:7::"				=> true,
     "1:2:3:4:5:6:7:8::"				=> false,
-    "::1:2:3:4:5:6:7:8"				=> false,
-    "1:2:3:4::5:6:7:8"				=> false,
+    "1:2:3:4:5:6:7::8"				=> false,
+
+    "1:2:3:4:5:6:7:8g"				=> false,
+    "1:2:3:4:5:6:7:g"				=> false,
+    "1:2:3:4:5g:6:7:8"				=> false,
+
+    'a:b:c:d:e::1.2.3.4'			=> true,
+    '::0:a:b:c:d:e:f'				=> true,
+    '0:a:b:c:d:e:f::'				=> true,
+    ':::1.2.3.4'					=> false,
+    '8:::1.2.3.4'					=> false,
+    '::01.02.03.04'					=> false,
+    '::1.00.3.4'					=> false,
+    '0:0:0:255.255.255.255'			=> false,
+    '0:0:0::255.255.255.255'		=> true,
 );
 foreach ($ipv6_test as $ip => $exp) {
 	$out = filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6);
 	$out = (int) ($out === false ? 0 : 1);
 	if ($exp != $out) {
-		echo "$ip failed\n";
+		echo "$ip failed (expected ", $exp?"true":"false", ", got ",
+            $out?"true":"false", ")\n";
 	}
 }


Modified: php/php-src/trunk/ext/filter/logical_filters.c
===================================================================
--- php/php-src/trunk/ext/filter/logical_filters.c	2010-11-08 02:55:04 UTC (rev 305185)
+++ php/php-src/trunk/ext/filter/logical_filters.c	2010-11-08 04:36:15 UTC (rev 305186)
@@ -557,9 +557,11 @@
 	int n = 0;

 	while (str < end) {
+		int leading_zero;
 		if (*str < '0' || *str > '9') {
 			return 0;
 		}
+		leading_zero = (*str == '0');
 		m = 1;
 		num = ((*(str++)) - '0');
 		while (str < end && (*str >= '0' && *str <= '9')) {
@@ -568,6 +570,10 @@
 				return 0;
 			}
 		}
+		/* don't allow a leading 0; that introduces octal numbers,
+		 * which we don't support */
+		if (leading_zero && (num != 0 || m > 1))
+			return 0;
 		ip[n++] = num;
 		if (n == 4) {
 			return str == end;
@@ -582,7 +588,7 @@
 static int _php_filter_validate_ipv6(char *str, int str_len TSRMLS_DC) /* {{{ */
 {
 	int compressed = 0;
-	int blocks = 8;
+	int blocks = 0;
 	int n;
 	char *ipv4;
 	char *end;
@@ -603,32 +609,40 @@
 		if (!_php_filter_validate_ipv4(ipv4, (str_len - (ipv4 - str)), ip4elm)) {
 			return 0;
 		}
-		str_len = (ipv4 - str) - 1;
-		if (str_len == 1) {
-			return *str == ':';
+
+		str_len = ipv4 - str; /* length excluding ipv4 */
+		if (str_len < 2) {
+			return 0;
 		}
-		blocks = 6;
+
+		if (ipv4[-2] != ':') {
+			/* don't include : before ipv4 unless it's a :: */
+			str_len--;
+		}
+
+		blocks = 2;
 	}

 	end = str + str_len;

 	while (str < end) {
 		if (*str == ':') {
-			if (--blocks == 0) {
-				return 0;
-			}
 			if (++str >= end) {
+				/* cannot end in : without previous : */
 				return 0;
 			}
 			if (*str == ':') {
-				if (compressed || --blocks == 0) {
+				if (compressed) {
 					return 0;
-				}
+				}
+				blocks++; /* :: means 1 or more 16-bit 0 blocks */
+				compressed = 1;
+
 				if (++str == end) {
-					return 1;
+					return (blocks <= 8);
 				}
-				compressed = 1;
 			} else if ((str - 1) == s) {
+				/* dont allow leading : without another : following */
 				return 0;
 			}
 		}
@@ -643,8 +657,10 @@
 		if (n < 1 || n > 4) {
 			return 0;
 		}
+		if (++blocks > 8)
+			return 0;
 	}
-	return (compressed || blocks == 1);
+	return ((compressed && blocks <= 8) || blocks == 8);
 }
 /* }}} */


Modified: php/php-src/trunk/ext/filter/tests/030.phpt
===================================================================
--- php/php-src/trunk/ext/filter/tests/030.phpt	2010-11-08 02:55:04 UTC (rev 305185)
+++ php/php-src/trunk/ext/filter/tests/030.phpt	2010-11-08 04:36:15 UTC (rev 305186)
@@ -5,35 +5,56 @@
 --FILE--
 <?php
 $ipv6_test = array(
-	"::127.0.0.1"				=> true,
-	"FF01::101:127.0.1" 		=> false,
-	"FF01:0:0:0:101:127.0.1.1"  => false,
-	"FF01:0:0:0:237:101:127.0.1.1"  => true,
-	"FF01::101"					=> true,
-	"A1080::8:800:200C:417A"	=> false,
-	"1080::8:Z00:200C:417A"		=> false,
-	"FF01::101::1"				=> false,
-	"1080::8:800:200C:417A"		=> true,
-	"1080:0:0:0:8:800:200C:417A" => true,
+	"::127.0.0.1"					=> true,
+	"FF01::101:127.0.1" 			=> false,
+	"FF01:0:0:0:101:127.0.1.1"		=> false,
+	"FF01:0:0:0:237:101:127.0.1.1"	=> true,
+	"FF01::101"						=> true,
+	"A1080::8:800:200C:417A"		=> false,
+	"1080::8:Z00:200C:417A"			=> false,
+	"FF01::101::1"					=> false,
+	"1080::8:800:200C:417A"			=> true,
+	"1080:0:0:0:8:800:200C:417A"	=> true,
 	"2001:ec8:1:1:1:1:1:1"			=> true,
 	"ffff::FFFF:129.144.52.38"		=> true,
 	"::ffff:1.2.3.4"				=> true,
-	"0:0:0:0:0:FFFF:129.144.52.38" => true,
-	"0:0:0:0:0:0:13.1.68.3"		=> true,
-	"::13.1.68.3"				=> true,
-    "::FFFF:129.144.52.38"		=> true,
+	"0:0:0:0:0:FFFF:129.144.52.38"	=> true,
+	"0:0:0:0:0:0:13.1.68.3"			=> true,
+    "0:0:0:0:0:0:0:13.1.68.3"		=> false,
+	"::13.1.68.3"					=> true,
+    "::FFFF:129.144.52.38"			=> true,
+
     "1:2:3:4:5:6::129.144.52.38"	=> false,
     "::1:2:3:4:5:6:129.144.52.38"	=> false,
     "1:2:3::4:5:6:129.144.52.38"	=> false,
+
+    "1:2:3:4::5:6:7:8"				=> false,
+    "::1:2:3:4:5:6:7"				=> true,
+    "::1:2:3:4:5:6:7:8"				=> false,
+    "1:2:3:4:5:6:7::"				=> true,
     "1:2:3:4:5:6:7:8::"				=> false,
-    "::1:2:3:4:5:6:7:8"				=> false,
-    "1:2:3:4::5:6:7:8"				=> false,
+    "1:2:3:4:5:6:7::8"				=> false,
+
+    "1:2:3:4:5:6:7:8g"				=> false,
+    "1:2:3:4:5:6:7:g"				=> false,
+    "1:2:3:4:5g:6:7:8"				=> false,
+
+    'a:b:c:d:e::1.2.3.4'			=> true,
+    '::0:a:b:c:d:e:f'				=> true,
+    '0:a:b:c:d:e:f::'				=> true,
+    ':::1.2.3.4'					=> false,
+    '8:::1.2.3.4'					=> false,
+    '::01.02.03.04'					=> false,
+    '::1.00.3.4'					=> false,
+    '0:0:0:255.255.255.255'			=> false,
+    '0:0:0::255.255.255.255'		=> true,
 );
 foreach ($ipv6_test as $ip => $exp) {
 	$out = filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6);
 	$out = (int) ($out === false ? 0 : 1);
 	if ($exp != $out) {
-		echo "$ip failed\n";
+		echo "$ip failed (expected ", $exp?"true":"false", ", got ",
+            $out?"true":"false", ")\n";
 	}
 }

-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to