summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRemi Collet <remi@remirepo.net>2021-01-04 14:40:02 +0100
committerRemi Collet <remi@remirepo.net>2021-01-04 14:40:02 +0100
commit986f60d859ab5c31fa877c302bbbb2056c20c1ea (patch)
treea3580705993e5c5df908e88d40dd78380132b78e
parent7b20869557afb0fb1c1006ea1e614372cefc5310 (diff)
Fix #77423 FILTER_VALIDATE_URL accepts URLs with invalid userinfo
CVE-2020-7071
-rw-r--r--failed.txt11
-rw-r--r--php-bug77423.patch196
-rw-r--r--php.spec12
3 files changed, 212 insertions, 7 deletions
diff --git a/failed.txt b/failed.txt
index 4efc109..3332857 100644
--- a/failed.txt
+++ b/failed.txt
@@ -1,16 +1,17 @@
-===== 7.2.34 (2020-10-01)
+===== 7.2.34-2 (2021-01-04)
$ grep -ar 'Tests failed' /var/lib/mock/scl72*/build.log
-/var/lib/mock/scl72el6x/build.log:Tests failed : 0
/var/lib/mock/scl72el7x/build.log:Tests failed : 0
/var/lib/mock/scl72el8x/build.log:Tests failed : 17
-/var/lib/mock/scl72fc31x/build.log:Tests failed : 1
-/var/lib/mock/scl72fc32x/build.log:Tests failed : 1
-/var/lib/mock/scl72fc33x/build.log:Tests failed : 16
+/var/lib/mock/scl72fc31x/build.log:Tests failed : 2
+/var/lib/mock/scl72fc32x/build.log:Tests failed : 2
+/var/lib/mock/scl72fc33x/build.log:Tests failed : 17
fc31x, fc32x, fc33x:
+ Bug #48097 (date_timezone_set function produces wrong datetime result) [ext/date/tests/bug48097.phpt]
+fc31x, fc32x, fc33x:
3 TLS server rate-limits client-initiated renegotiation [ext/openssl/tests/stream_server_reneg_limit.phpt]
el8x, fc33x:
3 buildroot issue with strict openssl policy (fixed in 7.4)
diff --git a/php-bug77423.patch b/php-bug77423.patch
new file mode 100644
index 0000000..ced3680
--- /dev/null
+++ b/php-bug77423.patch
@@ -0,0 +1,196 @@
+From 2d3d72412a6734e19a38ed10f385227a6238e4a6 Mon Sep 17 00:00:00 2001
+From: "Christoph M. Becker" <cmbecker69@gmx.de>
+Date: Wed, 13 May 2020 09:36:52 +0200
+Subject: [PATCH] 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.
+---
+ 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 +-
+ .../tests/url/parse_url_unterminated.phpt | 6 ++--
+ ext/standard/url.c | 21 +++++++++++++
+ 7 files changed, 59 insertions(+), 14 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 79ff3bc4a8e3..f564f59f0632 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 000000000000..be03fe95e24e
+--- /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--
++<?php
++$urls = array(
++ "http://php.net\@aliyun.com/aaa.do",
++ "https://example.com\uFF03@bing.com",
++);
++foreach ($urls as $url) {
++ var_dump(filter_var($url, FILTER_VALIDATE_URL));
++ var_dump(parse_url($url));
++}
++?>
++--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 4606849c5781..51010991326c 100644
+--- a/ext/standard/tests/url/parse_url_basic_001.phpt
++++ b/ext/standard/tests/url/parse_url_basic_001.phpt
+@@ -506,15 +506,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 3d5a4a344afd..7968fd3f09fd 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 aefb33964bc4..ba778bf9035d 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/tests/url/parse_url_unterminated.phpt b/ext/standard/tests/url/parse_url_unterminated.phpt
+index 912b6a5641e8..875d93a10948 100644
+--- a/ext/standard/tests/url/parse_url_unterminated.phpt
++++ b/ext/standard/tests/url/parse_url_unterminated.phpt
+@@ -508,15 +508,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/url.c b/ext/standard/url.c
+index 1dd073e2bb42..8d155bb9846c 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,
diff --git a/php.spec b/php.spec
index 5400c19..1770701 100644
--- a/php.spec
+++ b/php.spec
@@ -65,7 +65,7 @@
%else
%ifarch x86_64
-%global oraclever 19.8
+%global oraclever 19.9
%else
%global oraclever 19.6
%endif
@@ -140,7 +140,7 @@
Summary: PHP scripting language for creating dynamic web sites
Name: %{?scl_prefix}php
Version: %{upver}%{?rcver:~%{rcver}}
-Release: 1%{?dist}
+Release: 2%{?dist}
# All files licensed under PHP version 3.01, except
# Zend is licensed under Zend
# TSRM is licensed under BSD
@@ -203,6 +203,7 @@ Patch91: php-7.2.0-oci8conf.patch
# Upstream fixes (100+)
# Security fixes (200+)
+Patch200: php-bug77423.patch
# Fixes for tests (300+)
# Factory is droped from system tzdata
@@ -237,6 +238,7 @@ BuildRequires: bzip2
BuildRequires: perl
BuildRequires: autoconf
BuildRequires: automake
+BuildRequires: make
BuildRequires: %{?dtsprefix}gcc
BuildRequires: %{?dtsprefix}gcc-c++
BuildRequires: libtool
@@ -421,6 +423,7 @@ Requires: %{?scl_prefix}php-cli%{?_isa} = %{version}-%{release}
# always needed to build extension
Requires: autoconf
Requires: automake
+Requires: make
Requires: gcc
Requires: gcc-c++
Requires: libtool
@@ -962,6 +965,7 @@ sed -e 's/php-devel/%{?scl_prefix}php-devel/' -i scripts/phpize.in
# upstream patches
# security patches
+%patch200 -p1 -b .bug77423
# Fixes for tests
%patch300 -p1 -b .datetests
@@ -1920,6 +1924,10 @@ fi
%changelog
+* Mon Jan 4 2021 Remi Collet <remi@remirepo.net> - 7.2.34-2
+- Fix #77423 FILTER_VALIDATE_URL accepts URLs with invalid userinfo
+ CVE-2020-7071
+
* Wed Sep 30 2020 Remi Collet <remi@remirepo.net> - 7.2.34-1
- Update to 7.2.34 - http://www.php.net/releases/7_2_34.php