Skip to content

Commit fbc922d

Browse files
committed
Merge branch 'PHP-7.4' into PHP-8.0
* PHP-7.4: Fix #61700: FILTER_FLAG_IPV6/FILTER_FLAG_NO_PRIV|RES_RANGE failing
2 parents 1b33da5 + 288c25f commit fbc922d

File tree

4 files changed

+82
-54
lines changed

4 files changed

+82
-54
lines changed

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ PHP NEWS
1717
- Fileinfo:
1818
. Fixed bug #78987 (High memory usage during encoding detection). (Anatol)
1919

20+
- Filter:
21+
. Fixed bug #61700 (FILTER_FLAG_IPV6/FILTER_FLAG_NO_PRIV|RES_RANGE failing).
22+
(cmb, Nikita)
23+
2024
- PCRE:
2125
. Fixed bug #81424 (PCRE2 10.35 JIT performance regression). (cmb)
2226

ext/filter/logical_filters.c

Lines changed: 59 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@
8989
#define FORMAT_IPV4 4
9090
#define FORMAT_IPV6 6
9191

92-
static int _php_filter_validate_ipv6(char *str, size_t str_len);
92+
static int _php_filter_validate_ipv6(char *str, size_t str_len, int ip[8]);
9393

9494
static int php_filter_parse_int(const char *str, size_t str_len, zend_long *ret) { /* {{{ */
9595
zend_long ctx_value;
@@ -605,7 +605,7 @@ void php_filter_validate_url(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
605605
t = e - 1;
606606

607607
/* An IPv6 enclosed by square brackets is a valid hostname */
608-
if (*s == '[' && *t == ']' && _php_filter_validate_ipv6((s + 1), l - 2)) {
608+
if (*s == '[' && *t == ']' && _php_filter_validate_ipv6((s + 1), l - 2, NULL)) {
609609
php_url_free(url);
610610
return;
611611
}
@@ -745,11 +745,11 @@ static int _php_filter_validate_ipv4(char *str, size_t str_len, int *ip) /* {{{
745745
}
746746
/* }}} */
747747

748-
static int _php_filter_validate_ipv6(char *str, size_t str_len) /* {{{ */
748+
static int _php_filter_validate_ipv6(char *str, size_t str_len, int ip[8]) /* {{{ */
749749
{
750-
int compressed = 0;
750+
int compressed_pos = -1;
751751
int blocks = 0;
752-
int n;
752+
int num, n, i;
753753
char *ipv4;
754754
char *end;
755755
int ip4elm[4];
@@ -792,35 +792,67 @@ static int _php_filter_validate_ipv6(char *str, size_t str_len) /* {{{ */
792792
return 0;
793793
}
794794
if (*str == ':') {
795-
if (compressed) {
795+
if (compressed_pos >= 0) {
796796
return 0;
797797
}
798-
blocks++; /* :: means 1 or more 16-bit 0 blocks */
799-
compressed = 1;
800-
798+
if (ip && blocks < 8) {
799+
ip[blocks] = -1;
800+
}
801+
compressed_pos = blocks++; /* :: means 1 or more 16-bit 0 blocks */
801802
if (++str == end) {
802-
return (blocks <= 8);
803+
if (blocks > 8) {
804+
return 0;
805+
}
806+
goto fixup_ip;
803807
}
804808
} else if ((str - 1) == s) {
805809
/* don't allow leading : without another : following */
806810
return 0;
807811
}
808812
}
809-
n = 0;
810-
while ((str < end) &&
811-
((*str >= '0' && *str <= '9') ||
812-
(*str >= 'a' && *str <= 'f') ||
813-
(*str >= 'A' && *str <= 'F'))) {
813+
num = n = 0;
814+
while (str < end) {
815+
if (*str >= '0' && *str <= '9') {
816+
num = 16 * num + (*str - '0');
817+
} else if (*str >= 'a' && *str <= 'f') {
818+
num = 16 * num + (*str - 'a') + 10;
819+
} else if (*str >= 'A' && *str <= 'F') {
820+
num = 16 * num + (*str - 'A') + 10;
821+
} else {
822+
break;
823+
}
814824
n++;
815825
str++;
816826
}
827+
if (ip && blocks < 8) {
828+
ip[blocks] = num;
829+
}
817830
if (n < 1 || n > 4) {
818831
return 0;
819832
}
820833
if (++blocks > 8)
821834
return 0;
822835
}
823-
return ((compressed && blocks <= 8) || blocks == 8);
836+
837+
fixup_ip:
838+
if (ip && ipv4) {
839+
for (i = 0; i < 5; i++) {
840+
ip[i] = 0;
841+
}
842+
ip[i++] = 0xffff;
843+
ip[i++] = 256 * ip4elm[0] + ip4elm[1];
844+
ip[i++] = 256 * ip4elm[2] + ip4elm[3];
845+
} else if (ip && compressed_pos >= 0 && blocks <= 8) {
846+
int offset = 8 - blocks;
847+
for (i = 7; i > compressed_pos + offset; i--) {
848+
ip[i] = ip[i - offset];
849+
}
850+
for (i = compressed_pos + offset; i >= compressed_pos; i--) {
851+
ip[i] = 0;
852+
}
853+
}
854+
855+
return (compressed_pos >= 0 && blocks <= 8) || blocks == 8;
824856
}
825857
/* }}} */
826858

@@ -831,7 +863,7 @@ void php_filter_validate_ip(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
831863
* allow_ipv4 and allow_ipv6 flags flag are used, then the first dot or
832864
* colon determine the format */
833865

834-
int ip[4];
866+
int ip[8];
835867
int mode;
836868

837869
if (memchr(Z_STRVAL_P(value), ':', Z_STRLEN_P(value))) {
@@ -882,49 +914,25 @@ void php_filter_validate_ip(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
882914
case FORMAT_IPV6:
883915
{
884916
int res = 0;
885-
res = _php_filter_validate_ipv6(Z_STRVAL_P(value), Z_STRLEN_P(value));
917+
res = _php_filter_validate_ipv6(Z_STRVAL_P(value), Z_STRLEN_P(value), ip);
886918
if (res < 1) {
887919
RETURN_VALIDATION_FAILED
888920
}
889921
/* Check flags */
890922
if (flags & FILTER_FLAG_NO_PRIV_RANGE) {
891-
if (Z_STRLEN_P(value) >=2 && (!strncasecmp("FC", Z_STRVAL_P(value), 2) || !strncasecmp("FD", Z_STRVAL_P(value), 2))) {
923+
if (ip[0] >= 0xfc00 && ip[0] <= 0xfdff) {
892924
RETURN_VALIDATION_FAILED
893925
}
894926
}
895927
if (flags & FILTER_FLAG_NO_RES_RANGE) {
896-
switch (Z_STRLEN_P(value)) {
897-
case 1: case 0:
898-
break;
899-
case 2:
900-
if (!strcmp("::", Z_STRVAL_P(value))) {
901-
RETURN_VALIDATION_FAILED
902-
}
903-
break;
904-
case 3:
905-
if (!strcmp("::1", Z_STRVAL_P(value)) || !strcmp("5f:", Z_STRVAL_P(value))) {
906-
RETURN_VALIDATION_FAILED
907-
}
908-
break;
909-
default:
910-
if (Z_STRLEN_P(value) >= 5) {
911-
if (
912-
!strncasecmp("fe8", Z_STRVAL_P(value), 3) ||
913-
!strncasecmp("fe9", Z_STRVAL_P(value), 3) ||
914-
!strncasecmp("fea", Z_STRVAL_P(value), 3) ||
915-
!strncasecmp("feb", Z_STRVAL_P(value), 3)
916-
) {
917-
RETURN_VALIDATION_FAILED
918-
}
919-
}
920-
if (
921-
(Z_STRLEN_P(value) >= 9 && !strncasecmp("2001:0db8", Z_STRVAL_P(value), 9)) ||
922-
(Z_STRLEN_P(value) >= 2 && !strncasecmp("5f", Z_STRVAL_P(value), 2)) ||
923-
(Z_STRLEN_P(value) >= 4 && !strncasecmp("3ff3", Z_STRVAL_P(value), 4)) ||
924-
(Z_STRLEN_P(value) >= 8 && !strncasecmp("2001:001", Z_STRVAL_P(value), 8))
925-
) {
926-
RETURN_VALIDATION_FAILED
927-
}
928+
if ((ip[0] == 0 && ip[1] == 0 && ip[2] == 0 && ip[3] == 0
929+
&& ip[4] == 0 && ip[5] == 0 && ip[6] == 0 && (ip[7] == 0 || ip[7] == 1))
930+
|| (ip[0] == 0x5f)
931+
|| (ip[0] >= 0xfe80 && ip[0] <= 0xfebf)
932+
|| ((ip[0] == 0x2001 && ip[1] == 0x0db8) || (ip[1] >= 0x0010 && ip[1] <= 0x001f))
933+
|| (ip[0] == 0x3ff3)
934+
) {
935+
RETURN_VALIDATION_FAILED
928936
}
929937
}
930938
}

ext/filter/tests/bug47435.phpt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ var_dump(filter_var("::", FILTER_VALIDATE_IP, FILTER_FLAG_IPV6));
1010
var_dump(filter_var("::", FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 | FILTER_FLAG_NO_RES_RANGE));
1111
var_dump(filter_var("::1", FILTER_VALIDATE_IP, FILTER_FLAG_IPV6));
1212
var_dump(filter_var("::1", FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 | FILTER_FLAG_NO_RES_RANGE));
13-
var_dump(filter_var("fe8:5:6::1", FILTER_VALIDATE_IP, FILTER_FLAG_IPV6));
14-
var_dump(filter_var("fe8:5:6::1", FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 | FILTER_FLAG_NO_RES_RANGE));
13+
var_dump(filter_var("fe80:5:6::1", FILTER_VALIDATE_IP, FILTER_FLAG_IPV6));
14+
var_dump(filter_var("fe80:5:6::1", FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 | FILTER_FLAG_NO_RES_RANGE));
1515
var_dump(filter_var("2001:0db8::1", FILTER_VALIDATE_IP, FILTER_FLAG_IPV6));
1616
var_dump(filter_var("2001:0db8::1", FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 | FILTER_FLAG_NO_RES_RANGE));
1717
var_dump(filter_var("5f::1", FILTER_VALIDATE_IP, FILTER_FLAG_IPV6));
@@ -26,7 +26,7 @@ string(2) "::"
2626
bool(false)
2727
string(3) "::1"
2828
bool(false)
29-
string(10) "fe8:5:6::1"
29+
string(11) "fe80:5:6::1"
3030
bool(false)
3131
string(12) "2001:0db8::1"
3232
bool(false)

ext/filter/tests/bug61700.phpt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
--TEST--
2+
Bug #61700 (FILTER_FLAG_IPV6/FILTER_FLAG_NO_PRIV|RES_RANGE failing)
3+
--SKIPIF--
4+
<?php
5+
if (!extension_loaded("filter")) die("skip filter extension not available");
6+
?>
7+
--FILE--
8+
<?php
9+
var_dump(filter_var('::ffff:192.168.1.1', FILTER_VALIDATE_IP, FILTER_FLAG_IPV4));
10+
var_dump(filter_var('::ffff:192.168.1.1', FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE));
11+
var_dump(filter_var('0:0:0:0:0:0:0:1', FILTER_VALIDATE_IP, FILTER_FLAG_NO_RES_RANGE));
12+
?>
13+
--EXPECT--
14+
bool(false)
15+
string(18) "::ffff:192.168.1.1"
16+
bool(false)

0 commit comments

Comments
 (0)