Skip to content

Commit 4066610

Browse files
nielsdosremicollet
authored andcommitted
We should not early-out with success status if we found an ipv6 hostname, we should keep checking the rest of the conditions. Because integrating the if-check of the ipv6 hostname in the "Validate domain" if-check made the code hard to read, I extracted the condition out to a separate function. This also required to make a few pointers const in order to have some clean code.
1 parent 293cd3b commit 4066610

File tree

2 files changed

+61
-15
lines changed

2 files changed

+61
-15
lines changed

ext/filter/logical_filters.c

Lines changed: 20 additions & 15 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, int ip[8]);
92+
static int _php_filter_validate_ipv6(const 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;
@@ -572,6 +572,14 @@ static int is_userinfo_valid(zend_string *str)
572572
return 1;
573573
}
574574

575+
static bool php_filter_is_valid_ipv6_hostname(const char *s, size_t l)
576+
{
577+
const char *e = s + l;
578+
const char *t = e - 1;
579+
580+
return *s == '[' && *t == ']' && _php_filter_validate_ipv6(s + 1, l - 2, NULL);
581+
}
582+
575583
void php_filter_validate_url(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
576584
{
577585
php_url *url;
@@ -592,7 +600,7 @@ void php_filter_validate_url(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
592600

593601
if (url->scheme != NULL &&
594602
(zend_string_equals_literal_ci(url->scheme, "http") || zend_string_equals_literal_ci(url->scheme, "https"))) {
595-
char *e, *s, *t;
603+
const char *s;
596604
size_t l;
597605

598606
if (url->host == NULL) {
@@ -601,17 +609,14 @@ void php_filter_validate_url(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
601609

602610
s = ZSTR_VAL(url->host);
603611
l = ZSTR_LEN(url->host);
604-
e = s + l;
605-
t = e - 1;
606-
607-
/* An IPv6 enclosed by square brackets is a valid hostname */
608-
if (*s == '[' && *t == ']' && _php_filter_validate_ipv6((s + 1), l - 2, NULL)) {
609-
php_url_free(url);
610-
return;
611-
}
612612

613-
// Validate domain
614-
if (!_php_filter_validate_domain(ZSTR_VAL(url->host), l, FILTER_FLAG_HOSTNAME)) {
613+
if (
614+
/* An IPv6 enclosed by square brackets is a valid hostname.*/
615+
!php_filter_is_valid_ipv6_hostname(s, l) &&
616+
/* Validate domain.
617+
* This includes a loose check for an IPv4 address. */
618+
!_php_filter_validate_domain(ZSTR_VAL(url->host), l, FILTER_FLAG_HOSTNAME)
619+
) {
615620
php_url_free(url);
616621
RETURN_VALIDATION_FAILED
617622
}
@@ -745,15 +750,15 @@ static int _php_filter_validate_ipv4(char *str, size_t str_len, int *ip) /* {{{
745750
}
746751
/* }}} */
747752

748-
static int _php_filter_validate_ipv6(char *str, size_t str_len, int ip[8]) /* {{{ */
753+
static int _php_filter_validate_ipv6(const char *str, size_t str_len, int ip[8]) /* {{{ */
749754
{
750755
int compressed_pos = -1;
751756
int blocks = 0;
752757
int num, n, i;
753758
char *ipv4;
754-
char *end;
759+
const char *end;
755760
int ip4elm[4];
756-
char *s = str;
761+
const char *s = str;
757762

758763
if (!memchr(str, ':', str_len)) {
759764
return 0;
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
--TEST--
2+
GHSA-w8qr-v226-r27w
3+
--EXTENSIONS--
4+
filter
5+
--FILE--
6+
<?php
7+
8+
function test(string $input) {
9+
var_dump(filter_var($input, FILTER_VALIDATE_URL));
10+
}
11+
12+
echo "--- These ones should fail ---\n";
13+
test("http://t[[email protected]");
14+
test("http://t[est@[::1]");
15+
test("http://t[est@[::1");
16+
test("http://t[est@::1]");
17+
test("http://php.net\\@aliyun.com/aaa.do");
18+
test("http://test[@2001:db8:3333:4444:5555:6666:1.2.3.4]");
19+
test("http://te[st@2001:db8:3333:4444:5555:6666:1.2.3.4]");
20+
test("http://te[st@2001:db8:3333:4444:5555:6666:1.2.3.4");
21+
22+
echo "--- These ones should work ---\n";
23+
test("http://[email protected]");
24+
test("http://test@[2001:db8:3333:4444:5555:6666:1.2.3.4]");
25+
test("http://test@[::1]");
26+
27+
?>
28+
--EXPECT--
29+
--- These ones should fail ---
30+
bool(false)
31+
bool(false)
32+
bool(false)
33+
bool(false)
34+
bool(false)
35+
bool(false)
36+
bool(false)
37+
bool(false)
38+
--- These ones should work ---
39+
string(21) "http://[email protected]"
40+
string(50) "http://test@[2001:db8:3333:4444:5555:6666:1.2.3.4]"
41+
string(17) "http://test@[::1]"

0 commit comments

Comments
 (0)