From 886c3c68ff81f54577ecc66753c1d946dfc44c8e Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Mon, 4 Jan 2021 16:15:22 +0100 Subject: Fix #77423 FILTER_VALIDATE_URL accepts URLs with invalid userinfo CVE-2020-7071 --- php-bug77423.patch | 209 +++++++++++++++++++++++++++++++++++++++++++++++++++++ php70.spec | 14 +++- 2 files changed, 219 insertions(+), 4 deletions(-) create mode 100644 php-bug77423.patch diff --git a/php-bug77423.patch b/php-bug77423.patch new file mode 100644 index 0000000..4520be4 --- /dev/null +++ b/php-bug77423.patch @@ -0,0 +1,209 @@ +From 6d88ee38ec98c500c4a596307ce6b3e83becd0e9 Mon Sep 17 00:00:00 2001 +From: "Christoph M. Becker" +Date: Wed, 13 May 2020 09:36:52 +0200 +Subject: [PATCH 1/2] Fix #77423: parse_url() will deliver a wrong host to user + +To avoid that `parse_url()` returns an erroneous host, which would be +valid for `FILTER_VALIDATE_URL`, we make sure that only userinfo which +is valid according to RFC 3986 is treated as such. + +For consistency with the existing url parsing code, we use ctype +functions, although that is not necessarily correct. + +(cherry picked from commit 2d3d72412a6734e19a38ed10f385227a6238e4a6) +(cherry picked from commit 31459f94f2780e748e15d5c2951ba20adbba2366) +--- + ext/standard/tests/strings/url_t.phpt | 6 ++-- + ext/standard/tests/url/bug77423.phpt | 30 +++++++++++++++++++ + .../tests/url/parse_url_basic_001.phpt | 6 ++-- + .../tests/url/parse_url_basic_003.phpt | 2 +- + .../tests/url/parse_url_basic_005.phpt | 2 +- + ext/standard/url.c | 21 +++++++++++++ + 6 files changed, 57 insertions(+), 10 deletions(-) + create mode 100644 ext/standard/tests/url/bug77423.phpt + +diff --git a/ext/standard/tests/strings/url_t.phpt b/ext/standard/tests/strings/url_t.phpt +index e172061ec2..80e164a08e 100644 +--- a/ext/standard/tests/strings/url_t.phpt ++++ b/ext/standard/tests/strings/url_t.phpt +@@ -575,15 +575,13 @@ $sample_urls = array ( + string(16) "some_page_ref123" + } + +---> http://secret@hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123: array(7) { ++--> http://secret@hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123: array(6) { + ["scheme"]=> + string(4) "http" + ["host"]=> +- string(11) "www.php.net" ++ string(26) "secret@hideout@www.php.net" + ["port"]=> + int(80) +- ["user"]=> +- string(14) "secret@hideout" + ["path"]=> + string(10) "/index.php" + ["query"]=> +diff --git a/ext/standard/tests/url/bug77423.phpt b/ext/standard/tests/url/bug77423.phpt +new file mode 100644 +index 0000000000..be03fe95e2 +--- /dev/null ++++ b/ext/standard/tests/url/bug77423.phpt +@@ -0,0 +1,30 @@ ++--TEST-- ++Bug #77423 (parse_url() will deliver a wrong host to user) ++--FILE-- ++ ++--EXPECT-- ++bool(false) ++array(3) { ++ ["scheme"]=> ++ string(4) "http" ++ ["host"]=> ++ string(19) "php.net\@aliyun.com" ++ ["path"]=> ++ string(7) "/aaa.do" ++} ++bool(false) ++array(2) { ++ ["scheme"]=> ++ string(5) "https" ++ ["host"]=> ++ string(26) "example.com\uFF03@bing.com" ++} +diff --git a/ext/standard/tests/url/parse_url_basic_001.phpt b/ext/standard/tests/url/parse_url_basic_001.phpt +index e468066a42..c9e9d32de0 100644 +--- a/ext/standard/tests/url/parse_url_basic_001.phpt ++++ b/ext/standard/tests/url/parse_url_basic_001.phpt +@@ -507,15 +507,13 @@ echo "Done"; + string(16) "some_page_ref123" + } + +---> http://secret@hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123: array(7) { ++--> http://secret@hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123: array(6) { + ["scheme"]=> + string(4) "http" + ["host"]=> +- string(11) "www.php.net" ++ string(26) "secret@hideout@www.php.net" + ["port"]=> + int(80) +- ["user"]=> +- string(14) "secret@hideout" + ["path"]=> + string(10) "/index.php" + ["query"]=> +diff --git a/ext/standard/tests/url/parse_url_basic_003.phpt b/ext/standard/tests/url/parse_url_basic_003.phpt +index 70dc4bb90b..431de27009 100644 +--- a/ext/standard/tests/url/parse_url_basic_003.phpt ++++ b/ext/standard/tests/url/parse_url_basic_003.phpt +@@ -68,7 +68,7 @@ echo "Done"; + --> http://secret:@www.php.net/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123 : string(11) "www.php.net" + --> http://:hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123 : string(11) "www.php.net" + --> http://secret:hideout@www.php.net/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123 : string(11) "www.php.net" +---> http://secret@hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123 : string(11) "www.php.net" ++--> http://secret@hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123 : string(26) "secret@hideout@www.php.net" + --> http://secret:hid:out@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123 : string(11) "www.php.net" + --> nntp://news.php.net : string(12) "news.php.net" + --> ftp://ftp.gnu.org/gnu/glic/glibc.tar.gz : string(11) "ftp.gnu.org" +diff --git a/ext/standard/tests/url/parse_url_basic_005.phpt b/ext/standard/tests/url/parse_url_basic_005.phpt +index b2ca06ff96..b2c1a1d6dd 100644 +--- a/ext/standard/tests/url/parse_url_basic_005.phpt ++++ b/ext/standard/tests/url/parse_url_basic_005.phpt +@@ -68,7 +68,7 @@ echo "Done"; + --> http://secret:@www.php.net/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123 : string(6) "secret" + --> http://:hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123 : string(0) "" + --> http://secret:hideout@www.php.net/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123 : string(6) "secret" +---> http://secret@hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123 : string(14) "secret@hideout" ++--> http://secret@hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123 : NULL + --> http://secret:hid:out@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123 : string(6) "secret" + --> nntp://news.php.net : NULL + --> ftp://ftp.gnu.org/gnu/glic/glibc.tar.gz : NULL +diff --git a/ext/standard/url.c b/ext/standard/url.c +index a9cc06b1c0..3bb62c7da3 100644 +--- a/ext/standard/url.c ++++ b/ext/standard/url.c +@@ -92,6 +92,22 @@ PHPAPI php_url *php_url_parse(char const *str) + return php_url_parse_ex(str, strlen(str)); + } + ++static int is_userinfo_valid(const char *str, size_t len) ++{ ++ char *valid = "-._~!$&'()*+,;=:"; ++ char *p = str; ++ while (p - str < len) { ++ if (isalpha(*p) || isdigit(*p) || strchr(valid, *p)) { ++ p++; ++ } else if (*p == '%' && p - str <= len - 3 && isdigit(*(p+1)) && isxdigit(*(p+2))) { ++ p += 3; ++ } else { ++ return 0; ++ } ++ } ++ return 1; ++} ++ + /* {{{ php_url_parse + */ + PHPAPI php_url *php_url_parse_ex(char const *str, size_t length) +@@ -235,13 +251,18 @@ PHPAPI php_url *php_url_parse_ex(char const *str, size_t length) + ret->pass = estrndup(pp, (p-pp)); + php_replace_controlchars_ex(ret->pass, (p-pp)); + } else { ++ if (!is_userinfo_valid(s, p-s)) { ++ goto check_port; ++ } + ret->user = estrndup(s, (p-s)); + php_replace_controlchars_ex(ret->user, (p-s)); ++ + } + + s = p + 1; + } + ++check_port: + /* check for port */ + if (s < ue && *s == '[' && *(e-1) == ']') { + /* Short circuit portscan, +-- +2.29.2 + +From 745ba68440670440bdddd6cfb7e0f02eacef0f29 Mon Sep 17 00:00:00 2001 +From: Remi Collet +Date: Mon, 4 Jan 2021 14:20:55 +0100 +Subject: [PATCH 2/2] NEWS + +(cherry picked from commit c784479182b92b9b3b96a7be42aa86a6c6d0b693) +--- + NEWS | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/NEWS b/NEWS +index 47848d24b7..e328fd39c0 100644 +--- a/NEWS ++++ b/NEWS +@@ -1,6 +1,12 @@ + PHP NEWS + ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| + ++Backported from 7.3.26 ++ ++- Standard: ++ . Fixed bug #77423 (FILTER_VALIDATE_URL accepts URLs with invalid userinfo). ++ (CVE-2020-7071) (cmb) ++ + Backported from 7.2.34 + + - Core: +-- +2.29.2 + diff --git a/php70.spec b/php70.spec index 533ab92..58a1e1d 100644 --- a/php70.spec +++ b/php70.spec @@ -36,7 +36,7 @@ %else %ifarch x86_64 -%global oraclever 19.8 +%global oraclever 19.9 %else %global oraclever 19.6 %endif @@ -123,7 +123,7 @@ Summary: PHP scripting language for creating dynamic web sites Name: php Version: %{upver}%{?rcver:~%{rcver}} -Release: 23%{?dist} +Release: 24%{?dist} # All files licensed under PHP version 3.01, except # Zend is licensed under Zend # TSRM is licensed under BSD @@ -229,6 +229,7 @@ Patch243: php-bug78876.patch Patch244: php-bug79797.patch Patch245: php-bug79877.patch Patch246: php-bug79699.patch +Patch247: php-bug77423.patch # Fixes for tests (300+) # Factory is droped from system tzdata @@ -459,7 +460,7 @@ package and the php-cli package. %package devel Group: Development/Libraries Summary: Files needed for building PHP extensions -Requires: php-cli%{?_isa} = %{version}-%{release}, autoconf, automake +Requires: php-cli%{?_isa} = %{version}-%{release}, autoconf, automake, make # see "php-config --libs" Requires: krb5-devel%{?_isa} Requires: libedit-devel%{?_isa} @@ -1134,6 +1135,7 @@ echo CIBLE = %{name}-%{version}-%{release} oci8=%{with_oci8} libzip=%{with_libzi %patch244 -p1 -b .bug79797 %patch245 -p1 -b .bug79877 %patch246 -p1 -b .bug79699 +%patch247 -p1 -b .bug77423 # Fixes for tests %if 0%{?fedora} >= 21 || 0%{?rhel} >= 5 @@ -1931,7 +1933,7 @@ cat << EOF WARNING : PHP 7.0 have reached its "End of Life" in December 2018. Even, if this package includes some of - the important security fix, backported from 7.2, the + the important security fix, backported from 7.3, the UPGRADE to a maintained version is very strongly RECOMMENDED. ===================================================================== @@ -2171,6 +2173,10 @@ fi %changelog +* Mon Jan 4 2021 Remi Collet - 7.0.33-24 +- Fix #77423 FILTER_VALIDATE_URL accepts URLs with invalid userinfo + CVE-2020-7071 + * Tue Sep 29 2020 Remi Collet - 7.0.33-23 - Core: Fix #79699 PHP parses encoded cookie names so malicious `__Host-` cookies can be sent -- cgit