From 08be64e40197fc12dca5f802d16748d9c3cb4cb4 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Wed, 22 May 2024 22:25:02 +0200 Subject: [PATCH 1/2] Fix GHSA-w8qr-v226-r27w 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. (cherry picked from commit 4066610b47e22c24cbee91be434a94357056a479) --- ext/filter/logical_filters.c | 35 ++++++++++--------- ext/filter/tests/ghsa-w8qr-v226-r27w.phpt | 41 +++++++++++++++++++++++ 2 files changed, 61 insertions(+), 15 deletions(-) create mode 100644 ext/filter/tests/ghsa-w8qr-v226-r27w.phpt diff --git a/ext/filter/logical_filters.c b/ext/filter/logical_filters.c index e5e87c01568..9c86ad072cc 100644 --- a/ext/filter/logical_filters.c +++ b/ext/filter/logical_filters.c @@ -91,7 +91,7 @@ #define FORMAT_IPV4 4 #define FORMAT_IPV6 6 -static int _php_filter_validate_ipv6(char *str, size_t str_len, int ip[8]); +static int _php_filter_validate_ipv6(const char *str, size_t str_len, int ip[8]); static int php_filter_parse_int(const char *str, size_t str_len, zend_long *ret) { /* {{{ */ zend_long ctx_value; @@ -571,6 +571,14 @@ static int is_userinfo_valid(zend_string *str) return 1; } +static zend_bool php_filter_is_valid_ipv6_hostname(const char *s, size_t l) +{ + const char *e = s + l; + const char *t = e - 1; + + return *s == '[' && *t == ']' && _php_filter_validate_ipv6(s + 1, l - 2, NULL); +} + void php_filter_validate_url(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */ { php_url *url; @@ -596,7 +604,7 @@ void php_filter_validate_url(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */ if (url->scheme != NULL && (zend_string_equals_literal_ci(url->scheme, "http") || zend_string_equals_literal_ci(url->scheme, "https"))) { - char *e, *s, *t; + const char *s; size_t l; if (url->host == NULL) { @@ -605,17 +613,14 @@ void php_filter_validate_url(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */ s = ZSTR_VAL(url->host); l = ZSTR_LEN(url->host); - e = s + l; - t = e - 1; - - /* An IPv6 enclosed by square brackets is a valid hostname */ - if (*s == '[' && *t == ']' && _php_filter_validate_ipv6((s + 1), l - 2, NULL)) { - php_url_free(url); - return; - } - // Validate domain - if (!_php_filter_validate_domain(ZSTR_VAL(url->host), l, FILTER_FLAG_HOSTNAME)) { + if ( + /* An IPv6 enclosed by square brackets is a valid hostname.*/ + !php_filter_is_valid_ipv6_hostname(s, l) && + /* Validate domain. + * This includes a loose check for an IPv4 address. */ + !_php_filter_validate_domain(ZSTR_VAL(url->host), l, FILTER_FLAG_HOSTNAME) + ) { php_url_free(url); RETURN_VALIDATION_FAILED } @@ -749,15 +754,15 @@ static int _php_filter_validate_ipv4(char *str, size_t str_len, int *ip) /* {{{ } /* }}} */ -static int _php_filter_validate_ipv6(char *str, size_t str_len, int ip[8]) /* {{{ */ +static int _php_filter_validate_ipv6(const char *str, size_t str_len, int ip[8]) /* {{{ */ { int compressed_pos = -1; int blocks = 0; int num, n, i; char *ipv4; - char *end; + const char *end; int ip4elm[4]; - char *s = str; + const char *s = str; if (!memchr(str, ':', str_len)) { return 0; diff --git a/ext/filter/tests/ghsa-w8qr-v226-r27w.phpt b/ext/filter/tests/ghsa-w8qr-v226-r27w.phpt new file mode 100644 index 00000000000..0092408ee5a --- /dev/null +++ b/ext/filter/tests/ghsa-w8qr-v226-r27w.phpt @@ -0,0 +1,41 @@ +--TEST-- +GHSA-w8qr-v226-r27w +--EXTENSIONS-- +filter +--FILE-- + +--EXPECT-- +--- These ones should fail --- +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +--- These ones should work --- +string(21) "http://test@127.0.0.1" +string(50) "http://test@[2001:db8:3333:4444:5555:6666:1.2.3.4]" +string(17) "http://test@[::1]" -- 2.45.1 From ec1d5e6468479e64acc7fb8cb955f053b64ea9a0 Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Tue, 4 Jun 2024 16:48:08 +0200 Subject: [PATCH 2/2] NEWS (cherry picked from commit a1ff81b786bd519597e770795be114f5171f0648) --- NEWS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/NEWS b/NEWS index 8058eff0256..34ad33cf5c4 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,12 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| +Backported from 8.1.29 + +- Filter: + . Fixed bug GHSA-w8qr-v226-r27w (Filter bypass in filter_var FILTER_VALIDATE_URL). + (CVE-2024-5458) (nielsdos) + Backported from 8.1.28 - Standard: -- 2.45.1