diff options
50 files changed, 6390 insertions, 83 deletions
@@ -1,2 +1,3 @@ +clog php-*.tar.xz php-*.src.rpm @@ -1,14 +1,12 @@ -===== 7.1.30 (2019-05-30) +===== 7.1.33-28 (2024-04-11) $ grep -r 'Tests failed' /var/lib/mock/*/build.log -/var/lib/mock/el6i/build.log:Tests failed : 0 -/var/lib/mock/el6x/build.log:Tests failed : 0 -/var/lib/mock/el7x/build.log:Tests failed : 0 -/var/lib/mock/fc27i/build.log:Tests failed : 0 -/var/lib/mock/fc27x/build.log:Tests failed : 0 +/var/lib/mock/el7x/build.log:Tests failed : 20 +el7x: + 2 related to tzdata, expired test cert and openssl policy 1 proc_open give erratic test results :( @@ -18,4 +18,8 @@ %__php %{_bindir}/php %__ztsphp %{_bindir}/zts-php +%__phpize %{_bindir}/phpize +%__ztsphpize %{_bindir}/zts-phpize +%__phpconfig %{_bindir}/php-config +%__ztsphpconfig %{_bindir}/zts-php-config diff --git a/php-5.6.3-oci8conf.patch b/php-5.6.3-oci8conf.patch index f2d8f99..0f923f7 100644 --- a/php-5.6.3-oci8conf.patch +++ b/php-5.6.3-oci8conf.patch @@ -10,28 +10,29 @@ diff -up php5.3-201104170830/ext/ldap/php_ldap.h.remi-oci8 php5.3-201104170830/e extern zend_module_entry ldap_module_entry; #define ldap_module_ptr &ldap_module_entry -diff -up php5.3-201104170830/ext/oci8/config.m4.remi-oci8 php5.3-201104170830/ext/oci8/config.m4 ---- php5.3-201104170830/ext/oci8/config.m4.remi-oci8 2011-03-30 00:35:22.000000000 +0200 -+++ php5.3-201104170830/ext/oci8/config.m4 2011-04-17 11:55:25.628871315 +0200 -@@ -376,6 +376,7 @@ if test "$PHP_OCI8" != "no"; then - - dnl Header directory for Instant Client SDK RPM install - OCISDKRPMINC=`echo "$PHP_OCI8_INSTANT_CLIENT" | $PHP_OCI8_SED -e 's!^/usr/lib/oracle/\(.*\)/client\('${PHP_OCI8_IC_LIBDIR_SUFFIX}'\)*/lib[/]*$!/usr/include/oracle/\1/client\2!'` -+ OCISDKRPMINC=`echo "$PHP_OCI8_INSTANT_CLIENT" | $PHP_OCI8_SED -e 's!^/usr/\(lib64\|lib\)/oracle/\(.*\)/\(client64\|client\)/lib[/]*$!/usr/include/oracle/\2/\3!'` - - dnl Header directory for Instant Client SDK zip file install - OCISDKZIPINC=$PHP_OCI8_INSTANT_CLIENT/sdk/include -diff -up php5.3-201104170830/ext/pdo_oci/config.m4.remi-oci8 php5.3-201104170830/ext/pdo_oci/config.m4 ---- php5.3-201104170830/ext/pdo_oci/config.m4.remi-oci8 2011-04-02 04:35:24.000000000 +0200 -+++ php5.3-201104170830/ext/pdo_oci/config.m4 2011-04-17 12:02:42.837194120 +0200 -@@ -104,8 +104,10 @@ You need to tell me where to find your O +diff -up ./ext/pdo_oci/config.m4.remi-oci8 ./ext/pdo_oci/config.m4 +--- ./ext/pdo_oci/config.m4.remi-oci8 2019-10-22 18:59:47.000000000 +0200 ++++ ./ext/pdo_oci/config.m4 2023-09-22 09:49:00.888471382 +0200 +@@ -104,7 +104,10 @@ You need to tell me where to find your O + fi + fi + AC_MSG_CHECKING([for oci.h]) +- if test -f $PDO_OCI_IC_PREFIX/include/oracle/$PDO_OCI_IC_VERS/$PDO_OCI_CLIENT_DIR/oci.h ; then ++ if test -f $PDO_OCI_IC_PREFIX/include/oracle/$PDO_OCI_IC_MAJ_VER/$PDO_OCI_CLIENT_DIR/oci.h ; then ++ PHP_ADD_INCLUDE($PDO_OCI_IC_PREFIX/include/oracle/$PDO_OCI_IC_MAJ_VER/$PDO_OCI_CLIENT_DIR) ++ AC_MSG_RESULT($PDO_OCI_IC_PREFIX/include/oracle/$PDO_OCI_IC_MAJ_VER/$PDO_OCI_CLIENT_DIR) ++ elif test -f $PDO_OCI_IC_PREFIX/include/oracle/$PDO_OCI_IC_VERS/$PDO_OCI_CLIENT_DIR/oci.h ; then + PHP_ADD_INCLUDE($PDO_OCI_IC_PREFIX/include/oracle/$PDO_OCI_IC_VERS/$PDO_OCI_CLIENT_DIR) + AC_MSG_RESULT($PDO_OCI_IC_PREFIX/include/oracle/$PDO_OCI_IC_VERS/$PDO_OCI_CLIENT_DIR) + elif test -f $PDO_OCI_IC_PREFIX/lib/oracle/$PDO_OCI_IC_VERS/$PDO_OCI_CLIENT_DIR/include/oci.h ; then +@@ -119,8 +122,10 @@ You need to tell me where to find your O else AC_MSG_ERROR([I'm too dumb to figure out where the include dir is in your Instant Client install]) fi - if test -f "$PDO_OCI_IC_PREFIX/lib/oracle/$PDO_OCI_IC_VERS/$PDO_OCI_CLIENT_DIR/lib/libclntsh.$SHLIB_SUFFIX_NAME" ; then - PDO_OCI_LIB_DIR="$PDO_OCI_IC_PREFIX/lib/oracle/$PDO_OCI_IC_VERS/$PDO_OCI_CLIENT_DIR/lib" -+ if test -f "$PDO_OCI_IC_PREFIX/lib64/oracle/$PDO_OCI_IC_VERS/$PDO_OCI_CLIENT_DIR/lib/libclntsh.$SHLIB_SUFFIX_NAME" ; then -+ PDO_OCI_LIB_DIR="$PDO_OCI_IC_PREFIX/lib64/oracle/$PDO_OCI_IC_VERS/$PDO_OCI_CLIENT_DIR/lib" ++ if test -f "$PDO_OCI_IC_PREFIX/lib/oracle/$PDO_OCI_IC_MAJ_VER/$PDO_OCI_CLIENT_DIR/lib/libclntsh.$SHLIB_SUFFIX_NAME" ; then ++ PDO_OCI_LIB_DIR="$PDO_OCI_IC_PREFIX/lib/oracle/$PDO_OCI_IC_MAJ_VER/$PDO_OCI_CLIENT_DIR/lib" + elif test -f "$PDO_OCI_IC_PREFIX/lib/oracle/$PDO_OCI_IC_VERS/$PDO_OCI_CLIENT_DIR/lib/libclntsh.$SHLIB_SUFFIX_NAME" ; then + PDO_OCI_LIB_DIR="$PDO_OCI_IC_PREFIX/lib/oracle/$PDO_OCI_IC_VERS/$PDO_OCI_CLIENT_DIR/lib" elif test -f "$PDO_OCI_IC_PREFIX/$PDO_OCI_CLIENT_DIR/lib/libclntsh.$SHLIB_SUFFIX_NAME" ; then diff --git a/php-7.1.0-systzdata-v14.patch b/php-7.1.0-systzdata-v14.patch index bd73a4b..1ab782b 100644 --- a/php-7.1.0-systzdata-v14.patch +++ b/php-7.1.0-systzdata-v14.patch @@ -392,7 +392,7 @@ diff -up php-7.1.0RC4/ext/date/lib/parse_tz.c.systzdata php-7.1.0RC4/ext/date/li + size_t n; + char *data, *p; + -+ data = malloc(3 * sysdb->index_size + 7); ++ data = malloc(3 * sysdb->index_size + sizeof(FAKE_HEADER) - 1); + + p = mempcpy(data, FAKE_HEADER, sizeof(FAKE_HEADER) - 1); + diff --git a/php-7.1.33-intl.patch b/php-7.1.33-intl.patch new file mode 100644 index 0000000..961fd89 --- /dev/null +++ b/php-7.1.33-intl.patch @@ -0,0 +1,13 @@ +diff -up ./ext/intl/collator/collator_sort.c.old ./ext/intl/collator/collator_sort.c +diff -up ./ext/intl/config.m4.old ./ext/intl/config.m4 +--- ./ext/intl/config.m4.old 2021-09-07 07:38:38.698104692 +0200 ++++ ./ext/intl/config.m4 2021-09-07 07:38:42.909098288 +0200 +@@ -9,7 +9,7 @@ if test "$PHP_INTL" != "no"; then + PHP_SETUP_ICU(INTL_SHARED_LIBADD) + PHP_SUBST(INTL_SHARED_LIBADD) + PHP_REQUIRE_CXX() +- INTL_COMMON_FLAGS="$ICU_INCS -Wno-write-strings -D__STDC_LIMIT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1" ++ INTL_COMMON_FLAGS="$ICU_INCS -Wno-write-strings -DU_DEFINE_FALSE_AND_TRUE=1 -D__STDC_LIMIT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1" + if test "$icu_version" -ge "4002"; then + icu_spoof_src=" spoofchecker/spoofchecker_class.c \ + spoofchecker/spoofchecker.c\ diff --git a/php-bug76450.patch b/php-bug76450.patch new file mode 100644 index 0000000..86594a6 --- /dev/null +++ b/php-bug76450.patch @@ -0,0 +1,209 @@ +From dea5f0e827021b24581e735e2998fed07036acb7 Mon Sep 17 00:00:00 2001 +From: "Christoph M. Becker" <cmbecker69@gmx.de> +Date: Wed, 5 May 2021 12:42:17 +0200 +Subject: [PATCH 3/7] Fix #76452: Crash while parsing blob data in + firebird_fetch_blob + +We need to prevent integer overflow when calling `erealloc()` with +`len+1`. + +(cherry picked from commit 286162e9b03071c4308e7e92597bca4239f49d89) +--- + ext/pdo_firebird/firebird_statement.c | 5 +++++ + ext/pdo_firebird/tests/bug_76452.data | Bin 0 -> 856 bytes + ext/pdo_firebird/tests/bug_76452.phpt | 31 ++++++++++++++++++++++++++ + 3 files changed, 36 insertions(+) + create mode 100644 ext/pdo_firebird/tests/bug_76452.data + create mode 100644 ext/pdo_firebird/tests/bug_76452.phpt + +diff --git a/ext/pdo_firebird/firebird_statement.c b/ext/pdo_firebird/firebird_statement.c +index 1c0f5b6071..c5e6b684c3 100644 +--- a/ext/pdo_firebird/firebird_statement.c ++++ b/ext/pdo_firebird/firebird_statement.c +@@ -294,6 +294,11 @@ static int firebird_fetch_blob(pdo_stmt_t *stmt, int colno, char **ptr, /* {{{ * + unsigned short seg_len; + ISC_STATUS stat; + ++ /* prevent overflow */ ++ if (*len == ZEND_ULONG_MAX) { ++ result = 0; ++ goto fetch_blob_end; ++ } + *ptr = S->fetch_buf[colno] = erealloc(S->fetch_buf[colno], *len+1); + + for (cur_len = stat = 0; (!stat || stat == isc_segment) && cur_len < *len; cur_len += seg_len) { + +From 9543fdf49a36d4d7d341dd8065b341c55680acc6 Mon Sep 17 00:00:00 2001 +From: "Christoph M. Becker" <cmbecker69@gmx.de> +Date: Fri, 30 Apr 2021 14:10:50 +0200 +Subject: [PATCH 4/7] Fix #76450: SIGSEGV in firebird_stmt_execute + +We need to verify that the `result_size` is not larger than our buffer, +and also should make sure that the `len` which is passed to +`isc_vax_integer()` has a permissible value; otherwise we bail out. + +(cherry picked from commit bcbf8aa0c96d8d9e81ec3428232485555fae0b37) +--- + ext/pdo_firebird/firebird_statement.c | 7 +++++++ + ext/pdo_firebird/tests/bug_76450.data | Bin 0 -> 464 bytes + ext/pdo_firebird/tests/bug_76450.phpt | 29 ++++++++++++++++++++++++++ + 3 files changed, 36 insertions(+) + create mode 100644 ext/pdo_firebird/tests/bug_76450.data + create mode 100644 ext/pdo_firebird/tests/bug_76450.phpt + +diff --git a/ext/pdo_firebird/firebird_statement.c b/ext/pdo_firebird/firebird_statement.c +index c5e6b684c3..bdde6c7cf2 100644 +--- a/ext/pdo_firebird/firebird_statement.c ++++ b/ext/pdo_firebird/firebird_statement.c +@@ -133,8 +133,14 @@ static int firebird_stmt_execute(pdo_stmt_t *stmt) /* {{{ */ + } + if (result[0] == isc_info_sql_records) { + unsigned i = 3, result_size = isc_vax_integer(&result[1], 2); ++ if (result_size > sizeof(result)) { ++ goto error; ++ } + while (result[i] != isc_info_end && i < result_size) { + short len = (short) isc_vax_integer(&result[i + 1], 2); ++ if (len != 1 && len != 2 && len != 4) { ++ goto error; ++ } + if (result[i] != isc_info_req_select_count) { + affected_rows += isc_vax_integer(&result[i + 3], len); + } +@@ -158,6 +164,7 @@ static int firebird_stmt_execute(pdo_stmt_t *stmt) /* {{{ */ + return 1; + } while (0); + ++error: + RECORD_ERROR(stmt); + + return 0; + +From bced1923e48355048fd6a05484244b7163467342 Mon Sep 17 00:00:00 2001 +From: "Christoph M. Becker" <cmbecker69@gmx.de> +Date: Fri, 30 Apr 2021 13:53:21 +0200 +Subject: [PATCH 5/7] Fix #76449: SIGSEGV in firebird_handle_doer + +We need to verify that the `result_size` is not larger than our buffer, +and also should make sure that the `len` which is passed to +`isc_vax_integer()` has a permissible value; otherwise we bail out. + +(cherry picked from commit 08da7c73726f7b86b67d6f0ff87c73c585a7834a) +--- + ext/pdo_firebird/firebird_driver.c | 9 +++++++++ + ext/pdo_firebird/tests/bug_76449.data | Bin 0 -> 464 bytes + ext/pdo_firebird/tests/bug_76449.phpt | 23 +++++++++++++++++++++++ + 3 files changed, 32 insertions(+) + create mode 100644 ext/pdo_firebird/tests/bug_76449.data + create mode 100644 ext/pdo_firebird/tests/bug_76449.phpt + +diff --git a/ext/pdo_firebird/firebird_driver.c b/ext/pdo_firebird/firebird_driver.c +index 3b39cc6c8b..62caf86631 100644 +--- a/ext/pdo_firebird/firebird_driver.c ++++ b/ext/pdo_firebird/firebird_driver.c +@@ -253,8 +253,17 @@ static zend_long firebird_handle_doer(pdo_dbh_t *dbh, const char *sql, size_t sq + if (result[0] == isc_info_sql_records) { + unsigned i = 3, result_size = isc_vax_integer(&result[1],2); + ++ if (result_size > sizeof(result)) { ++ ret = -1; ++ goto free_statement; ++ } + while (result[i] != isc_info_end && i < result_size) { + short len = (short)isc_vax_integer(&result[i+1],2); ++ /* bail out on bad len */ ++ if (len != 1 && len != 2 && len != 4) { ++ ret = -1; ++ goto free_statement; ++ } + if (result[i] != isc_info_req_select_count) { + ret += isc_vax_integer(&result[i+3],len); + } + +From eec3aaecf00b5a418a03c0531351a34260e11427 Mon Sep 17 00:00:00 2001 +From: "Christoph M. Becker" <cmbecker69@gmx.de> +Date: Thu, 29 Apr 2021 15:26:22 +0200 +Subject: [PATCH 6/7] Fix #76448: Stack buffer overflow in firebird_info_cb + +We ensure not to overflow the stack allocated buffer by using `strlcat`. + +(cherry picked from commit 67afa32541ebc4abbf633cb1e7e879b2fbb616ad) +--- + ext/pdo_firebird/firebird_driver.c | 8 +++++--- + ext/pdo_firebird/tests/bug_76448.data | Bin 0 -> 749 bytes + ext/pdo_firebird/tests/bug_76448.phpt | 23 +++++++++++++++++++++++ + 3 files changed, 28 insertions(+), 3 deletions(-) + create mode 100644 ext/pdo_firebird/tests/bug_76448.data + create mode 100644 ext/pdo_firebird/tests/bug_76448.phpt + +diff --git a/ext/pdo_firebird/firebird_driver.c b/ext/pdo_firebird/firebird_driver.c +index 62caf86631..f9ec0eb847 100644 +--- a/ext/pdo_firebird/firebird_driver.c ++++ b/ext/pdo_firebird/firebird_driver.c +@@ -556,14 +556,16 @@ static int firebird_handle_set_attribute(pdo_dbh_t *dbh, zend_long attr, zval *v + } + /* }}} */ + ++#define INFO_BUF_LEN 512 ++ + /* callback to used to report database server info */ + static void firebird_info_cb(void *arg, char const *s) /* {{{ */ + { + if (arg) { + if (*(char*)arg) { /* second call */ +- strcat(arg, " "); ++ strlcat(arg, " ", INFO_BUF_LEN); + } +- strcat(arg, s); ++ strlcat(arg, s, INFO_BUF_LEN); + } + } + /* }}} */ +@@ -574,7 +576,7 @@ static int firebird_handle_get_attribute(pdo_dbh_t *dbh, zend_long attr, zval *v + pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data; + + switch (attr) { +- char tmp[512]; ++ char tmp[INFO_BUF_LEN]; + + case PDO_ATTR_AUTOCOMMIT: + ZVAL_LONG(val,dbh->auto_commit); + +From 21368561ec3949872822e4f24659d91ab590ec69 Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Sun, 20 Jun 2021 22:20:38 -0700 +Subject: [PATCH 7/7] Update NEWS + +(cherry picked from commit c68a687566591e2268f35d124a90c7d556ce968b) +(cherry picked from commit 7598733c51af30611aa64e456c9a777069d2efb9) +--- + NEWS | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/NEWS b/NEWS +index 63295d3b76..b1b31e5dd0 100644 +--- a/NEWS ++++ b/NEWS +@@ -1,6 +1,19 @@ + PHP NEWS + ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| + ++Backported from 7.3.29 ++ ++- Core: ++ . Fixed #81122: SSRF bypass in FILTER_VALIDATE_URL. (CVE-2021-21705) (cmb) ++ ++- PDO_Firebird: ++ . Fixed #76448: Stack buffer overflow in firebird_info_cb. (CVE-2021-21704) ++ (cmb) ++ . Fixed #76449: SIGSEGV in firebird_handle_doer. (CVE-2021-21704) (cmb) ++ . Fixed #76450: SIGSEGV in firebird_stmt_execute. (CVE-2021-21704) (cmb) ++ . Fixed #76452: Crash while parsing blob data in firebird_fetch_blob. ++ (CVE-2021-21704) (cmb) ++ + Backported from 7.3.28 + + - Imap: +-- +2.31.1 + diff --git a/php-bug77423.patch b/php-bug77423.patch new file mode 100644 index 0000000..0f6f64c --- /dev/null +++ b/php-bug77423.patch @@ -0,0 +1,428 @@ +From 31459f94f2780e748e15d5c2951ba20adbba2366 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 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) +--- + 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 79ff3bc4a8..f564f59f06 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-- ++<?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 4606849c57..5101099132 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 3d5a4a344a..7968fd3f09 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 aefb33964b..ba778bf903 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 4cc1f77aec..d56dc24dc6 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 c784479182b92b9b3b96a7be42aa86a6c6d0b693 Mon Sep 17 00:00:00 2001 +From: Remi Collet <remi@remirepo.net> +Date: Mon, 4 Jan 2021 14:20:55 +0100 +Subject: [PATCH 2/2] NEWS + +--- + NEWS | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/NEWS b/NEWS +index bc49257774..1f538b891d 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 + +From b5d4f109bab648c0d07273d2a52a5f2560e7832b Mon Sep 17 00:00:00 2001 +From: "Christoph M. Becker" <cmbecker69@gmx.de> +Date: Tue, 19 Jan 2021 11:23:25 +0100 +Subject: [PATCH] Alternative fix for bug 77423 + +That bug report originally was about `parse_url()` misbehaving, but the +security aspect was actually only regarding `FILTER_VALIDATE_URL`. +Since the changes to `parse_url_ex()` apparently affect userland code +which is relying on the sloppy URL parsing[1], this alternative +restores the old parsing behavior, but ensures that the userinfo is +checked for correctness for `FILTER_VALIDATE_URL`. + +[1] <https://github.com/php/php-src/commit/5174de7cd33c3d4fa591c9c93859ff9989b07e8c#commitcomment-45967652> + +(cherry picked from commit 4a89e726bd4d0571991dc22a9a1ad4509e8fe347) +(cherry picked from commit 9c673083cd46ee2a954a62156acbe4b6e657c048) +(cherry picked from commit 356f7008f36da60ec9794d48c55d117f1dd31903) +--- + ext/filter/logical_filters.c | 25 +++++++++++++++++++ + .../tests/url => filter/tests}/bug77423.phpt | 15 ----------- + ext/standard/tests/strings/url_t.phpt | 6 +++-- + .../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 ---------------- + 7 files changed, 35 insertions(+), 42 deletions(-) + rename ext/{standard/tests/url => filter/tests}/bug77423.phpt (53%) + +diff --git a/ext/filter/logical_filters.c b/ext/filter/logical_filters.c +index 52c9e285c4..1c51e6d2ef 100644 +--- a/ext/filter/logical_filters.c ++++ b/ext/filter/logical_filters.c +@@ -514,6 +514,24 @@ void php_filter_validate_domain(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */ + } + /* }}} */ + ++static int is_userinfo_valid(char *str) ++{ ++ const char *valid = "-._~!$&'()*+,;=:"; ++ const char *p = str; ++ size_t len = strlen(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; ++} ++ + void php_filter_validate_url(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */ + { + php_url *url; +@@ -568,6 +586,13 @@ bad_url: + php_url_free(url); + RETURN_VALIDATION_FAILED + } ++ ++ if (url->user != NULL && !is_userinfo_valid(url->user)) { ++ php_url_free(url); ++ RETURN_VALIDATION_FAILED ++ ++ } ++ + php_url_free(url); + } + /* }}} */ +diff --git a/ext/standard/tests/url/bug77423.phpt b/ext/filter/tests/bug77423.phpt +similarity index 53% +rename from ext/standard/tests/url/bug77423.phpt +rename to ext/filter/tests/bug77423.phpt +index be03fe95e2..761c7c359a 100644 +--- a/ext/standard/tests/url/bug77423.phpt ++++ b/ext/filter/tests/bug77423.phpt +@@ -8,23 +8,8 @@ $urls = array( + ); + 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/strings/url_t.phpt b/ext/standard/tests/strings/url_t.phpt +index f564f59f06..79ff3bc4a8 100644 +--- a/ext/standard/tests/strings/url_t.phpt ++++ b/ext/standard/tests/strings/url_t.phpt +@@ -575,13 +575,15 @@ $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(6) { ++--> http://secret@hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123: array(7) { + ["scheme"]=> + string(4) "http" + ["host"]=> +- string(26) "secret@hideout@www.php.net" ++ string(11) "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_001.phpt b/ext/standard/tests/url/parse_url_basic_001.phpt +index 5101099132..4606849c57 100644 +--- a/ext/standard/tests/url/parse_url_basic_001.phpt ++++ b/ext/standard/tests/url/parse_url_basic_001.phpt +@@ -506,13 +506,15 @@ 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(6) { ++--> http://secret@hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123: array(7) { + ["scheme"]=> + string(4) "http" + ["host"]=> +- string(26) "secret@hideout@www.php.net" ++ string(11) "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 7968fd3f09..3d5a4a344a 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(26) "secret@hideout@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: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 ba778bf903..aefb33964b 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 : NULL ++--> http://secret@hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123 : string(14) "secret@hideout" + --> 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 d56dc24dc6..4cc1f77aec 100644 +--- a/ext/standard/url.c ++++ b/ext/standard/url.c +@@ -92,22 +92,6 @@ 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) +@@ -251,18 +235,13 @@ 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 + diff --git a/php-bug77569.patch b/php-bug77569.patch new file mode 100644 index 0000000..459372a --- /dev/null +++ b/php-bug77569.patch @@ -0,0 +1,100 @@ +From 2ee92db814827e4484d997c91b75034995e6f99e Mon Sep 17 00:00:00 2001 +From: "Christoph M. Becker" <cmbecker69@gmx.de> +Date: Thu, 13 Feb 2020 15:13:26 +0100 +Subject: [PATCH] Fix #77569: Write Acess Violation in DomImplementation + +We must not assume that the zval IS_STRING. + +(cherry picked from commit cec8b24c848bab8562c82422f3692c193f0afcdb) +--- + NEWS | 6 ++++++ + ext/dom/document.c | 2 +- + ext/dom/tests/bug77569.phpt | 14 ++++++++++++++ + 3 files changed, 21 insertions(+), 1 deletion(-) + create mode 100644 ext/dom/tests/bug77569.phpt + +diff --git a/NEWS b/NEWS +index e311fc78cc..0743c78268 100644 +--- a/NEWS ++++ b/NEWS +@@ -1,6 +1,12 @@ + PHP NEWS + ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| + ++Backported from 7.2.28 ++ ++- DOM: ++ . Fixed bug #77569: (Write Acess Violation in DomImplementation). (Nikita, ++ cmb) ++ + Backported from 7.2.27 + + - Mbstring: +diff --git a/ext/dom/document.c b/ext/dom/document.c +index c9e1802f78..11ef4aa818 100644 +--- a/ext/dom/document.c ++++ b/ext/dom/document.c +@@ -341,7 +341,7 @@ int dom_document_encoding_write(dom_object *obj, zval *newval) + + str = zval_get_string(newval); + +- handler = xmlFindCharEncodingHandler(Z_STRVAL_P(newval)); ++ handler = xmlFindCharEncodingHandler(ZSTR_VAL(str)); + + if (handler != NULL) { + xmlCharEncCloseFunc(handler); +diff --git a/ext/dom/tests/bug77569.phpt b/ext/dom/tests/bug77569.phpt +new file mode 100644 +index 0000000000..f0f3566708 +--- /dev/null ++++ b/ext/dom/tests/bug77569.phpt +@@ -0,0 +1,14 @@ ++--TEST-- ++Bug #77569 (Write Acess Violation in DomImplementation) ++--SKIPIF-- ++<?php ++if (!extension_loaded('dom')) die('skip dom extension not available'); ++?> ++--FILE-- ++<?php ++$imp = new DOMImplementation; ++$dom = $imp->createDocument("", ""); ++$dom->encoding = null; ++?> ++--EXPECTF-- ++Warning: main(): Invalid Document Encoding in %s on line %d +From 08374ddcc45940dc341afc68de505599f1839e64 Mon Sep 17 00:00:00 2001 +From: "Christoph M. Becker" <cmbecker69@gmx.de> +Date: Fri, 14 Feb 2020 09:21:13 +0100 +Subject: [PATCH] Fix typo in recent bugfix + +(cherry picked from commit 8308196c97418ba4c8381bed0962ae160623027a) +--- + NEWS | 2 +- + ext/dom/tests/bug77569.phpt | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/NEWS b/NEWS +index 0743c78268..7e220aae24 100644 +--- a/NEWS ++++ b/NEWS +@@ -4,7 +4,7 @@ PHP NEWS + Backported from 7.2.28 + + - DOM: +- . Fixed bug #77569: (Write Acess Violation in DomImplementation). (Nikita, ++ . Fixed bug #77569: (Write Access Violation in DomImplementation). (Nikita, + cmb) + + Backported from 7.2.27 +diff --git a/ext/dom/tests/bug77569.phpt b/ext/dom/tests/bug77569.phpt +index f0f3566708..9eef2af65a 100644 +--- a/ext/dom/tests/bug77569.phpt ++++ b/ext/dom/tests/bug77569.phpt +@@ -1,5 +1,5 @@ + --TEST-- +-Bug #77569 (Write Acess Violation in DomImplementation) ++Bug #77569 (Write Access Violation in DomImplementation) + --SKIPIF-- + <?php + if (!extension_loaded('dom')) die('skip dom extension not available'); diff --git a/php-bug78793.patch b/php-bug78793.patch new file mode 100644 index 0000000..c34da4d --- /dev/null +++ b/php-bug78793.patch @@ -0,0 +1,62 @@ +From 020d208284f3bfa87b3b983f59a6a2eb7d4dae87 Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Mon, 16 Dec 2019 01:14:38 -0800 +Subject: [PATCH] Fix bug #78793 + +(cherry picked from commit c14eb8de974fc8a4d74f3515424c293bc7a40fba) +--- + NEWS | 4 ++++ + ext/exif/exif.c | 5 +++-- + ext/exif/tests/bug78793.phpt | 12 ++++++++++++ + 3 files changed, 19 insertions(+), 2 deletions(-) + create mode 100644 ext/exif/tests/bug78793.phpt + +diff --git a/NEWS b/NEWS +index 6477dd620f..20bbff880e 100644 +--- a/NEWS ++++ b/NEWS +@@ -13,6 +13,10 @@ Backported from 7.2.26 + . Fixed bug #78863 (DirectoryIterator class silently truncates after a null + byte). (CVE-2019-11045). (cmb) + ++- EXIF: ++ . Fixed bug #78793 (Use-after-free in exif parsing under memory sanitizer). ++ (CVE-2019-11050). (Nikita) ++ + 24 Oct 2019, PHP 7.1.33 + + - FPM: +diff --git a/ext/exif/exif.c b/ext/exif/exif.c +index 77e4427b48..c9ebaa7b78 100644 +--- a/ext/exif/exif.c ++++ b/ext/exif/exif.c +@@ -2821,8 +2821,9 @@ static int exif_process_IFD_in_MAKERNOTE(image_info_type *ImageInfo, char * valu + } + + for (de=0;de<NumDirEntries;de++) { +- if (!exif_process_IFD_TAG(ImageInfo, dir_start + 2 + 12 * de, +- offset_base, data_len, displacement, section_index, 0, maker_note->tag_table)) { ++ size_t offset = 2 + 12 * de; ++ if (!exif_process_IFD_TAG(ImageInfo, dir_start + offset, ++ offset_base, data_len - offset, displacement, section_index, 0, maker_note->tag_table)) { + return FALSE; + } + } +diff --git a/ext/exif/tests/bug78793.phpt b/ext/exif/tests/bug78793.phpt +new file mode 100644 +index 0000000000..033f255ace +--- /dev/null ++++ b/ext/exif/tests/bug78793.phpt +@@ -0,0 +1,12 @@ ++--TEST-- ++Bug #78793: Use-after-free in exif parsing under memory sanitizer ++--FILE-- ++<?php ++$f = "ext/exif/tests/bug77950.tiff"; ++for ($i = 0; $i < 10; $i++) { ++ @exif_read_data($f); ++} ++?> ++===DONE=== ++--EXPECT-- ++===DONE=== diff --git a/php-bug78862.patch b/php-bug78862.patch new file mode 100644 index 0000000..cf9a338 --- /dev/null +++ b/php-bug78862.patch @@ -0,0 +1,68 @@ +From 4a9f72a29b086f40ff6529bbd28b843b5e902ebd Mon Sep 17 00:00:00 2001 +From: "Christoph M. Becker" <cmbecker69@gmx.de> +Date: Tue, 17 Dec 2019 10:57:12 +0100 +Subject: [PATCH] Fix #78862: link() silently truncates after a null byte on + Windows + +Since link() is supposed to accepts paths (i.e. strings without NUL +bytes), we must not accept arbitrary strings. + +(cherry picked from commit 0e6c0654ed06751ced134515f7629c40bd979d7f) +--- + NEWS | 4 ++++ + ext/standard/link_win32.c | 2 +- + .../tests/file/windows_links/bug78862.phpt | 17 +++++++++++++++++ + 3 files changed, 22 insertions(+), 1 deletion(-) + create mode 100644 ext/standard/tests/file/windows_links/bug78862.phpt + +diff --git a/NEWS b/NEWS +index ec0247e1f1..93f18b9c8e 100644 +--- a/NEWS ++++ b/NEWS +@@ -7,6 +7,10 @@ Backported from 7.2.26 + . Fixed bug #78878 (Buffer underflow in bc_shift_addsub). (CVE-2019-11046). + (cmb) + ++- Core: ++ . Fixed bug #78862 (link() silently truncates after a null byte on Windows). ++ (CVE-2019-11044). (cmb) ++ + 24 Oct 2019, PHP 7.1.33 + + - FPM: +diff --git a/ext/standard/link_win32.c b/ext/standard/link_win32.c +index b46dee6a26..0197ec02af 100644 +--- a/ext/standard/link_win32.c ++++ b/ext/standard/link_win32.c +@@ -211,7 +211,7 @@ PHP_FUNCTION(link) + + /*First argument to link function is the target and hence should go to frompath + Second argument to link function is the link itself and hence should go to topath */ +- if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &frompath, &frompath_len, &topath, &topath_len) == FAILURE) { ++ if (zend_parse_parameters(ZEND_NUM_ARGS(), "pp", &frompath, &frompath_len, &topath, &topath_len) == FAILURE) { + return; + } + +diff --git a/ext/standard/tests/file/windows_links/bug78862.phpt b/ext/standard/tests/file/windows_links/bug78862.phpt +new file mode 100644 +index 0000000000..33b4b49293 +--- /dev/null ++++ b/ext/standard/tests/file/windows_links/bug78862.phpt +@@ -0,0 +1,17 @@ ++--TEST-- ++Bug #78862 (link() silently truncates after a null byte on Windows) ++--FILE-- ++<?php ++file_put_contents(__DIR__ . '/bug78862.target', 'foo'); ++var_dump(link(__DIR__ . "/bug78862.target\0more", __DIR__ . "/bug78862.link\0more")); ++var_dump(file_exists(__DIR__ . '/bug78862.link')); ++?> ++--EXPECTF-- ++Warning: link() expects parameter 1 to be a valid path, string given in %s on line %d ++NULL ++bool(false) ++--CLEAN-- ++<?php ++unlink(__DIR__ . '/bug78862.target'); ++unlink(__DIR__ . '/bug78862.link'); ++?> diff --git a/php-bug78863.patch b/php-bug78863.patch new file mode 100644 index 0000000..69f5e43 --- /dev/null +++ b/php-bug78863.patch @@ -0,0 +1,85 @@ +From e7d893348f02c662b6b3283ec77eb3c3cbc9a46e Mon Sep 17 00:00:00 2001 +From: "Christoph M. Becker" <cmbecker69@gmx.de> +Date: Mon, 25 Nov 2019 16:56:34 +0100 +Subject: [PATCH] Fix #78863: DirectoryIterator class silently truncates after + a null byte + +Since the constructor of DirectoryIterator and friends is supposed to +accepts paths (i.e. strings without NUL bytes), we must not accept +arbitrary strings. + +(cherry picked from commit a5a15965da23c8e97657278fc8dfbf1dfb20c016) +--- + NEWS | 2 ++ + ext/spl/spl_directory.c | 4 ++-- + ext/spl/tests/bug78863.phpt | 31 +++++++++++++++++++++++++++++++ + 3 files changed, 35 insertions(+), 2 deletions(-) + create mode 100644 ext/spl/tests/bug78863.phpt + +diff --git a/NEWS b/NEWS +index 93f18b9c8e..6477dd620f 100644 +--- a/NEWS ++++ b/NEWS +@@ -10,6 +10,8 @@ Backported from 7.2.26 + - Core: + . Fixed bug #78862 (link() silently truncates after a null byte on Windows). + (CVE-2019-11044). (cmb) ++ . Fixed bug #78863 (DirectoryIterator class silently truncates after a null ++ byte). (CVE-2019-11045). (cmb) + + 24 Oct 2019, PHP 7.1.33 + +diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c +index 748b1549b5..636e26a521 100644 +--- a/ext/spl/spl_directory.c ++++ b/ext/spl/spl_directory.c +@@ -685,10 +685,10 @@ void spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAMETERS, zend_long cto + + if (SPL_HAS_FLAG(ctor_flags, DIT_CTOR_FLAGS)) { + flags = SPL_FILE_DIR_KEY_AS_PATHNAME|SPL_FILE_DIR_CURRENT_AS_FILEINFO; +- parsed = zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &path, &len, &flags); ++ parsed = zend_parse_parameters(ZEND_NUM_ARGS(), "p|l", &path, &len, &flags); + } else { + flags = SPL_FILE_DIR_KEY_AS_PATHNAME|SPL_FILE_DIR_CURRENT_AS_SELF; +- parsed = zend_parse_parameters(ZEND_NUM_ARGS(), "s", &path, &len); ++ parsed = zend_parse_parameters(ZEND_NUM_ARGS(), "p", &path, &len); + } + if (SPL_HAS_FLAG(ctor_flags, SPL_FILE_DIR_SKIPDOTS)) { + flags |= SPL_FILE_DIR_SKIPDOTS; +diff --git a/ext/spl/tests/bug78863.phpt b/ext/spl/tests/bug78863.phpt +new file mode 100644 +index 0000000000..dc88d98dee +--- /dev/null ++++ b/ext/spl/tests/bug78863.phpt +@@ -0,0 +1,31 @@ ++--TEST-- ++Bug #78863 (DirectoryIterator class silently truncates after a null byte) ++--FILE-- ++<?php ++$dir = __DIR__ . '/bug78863'; ++mkdir($dir); ++touch("$dir/bad"); ++mkdir("$dir/sub"); ++touch("$dir/sub/good"); ++ ++$it = new DirectoryIterator(__DIR__ . "/bug78863\0/sub"); ++foreach ($it as $fileinfo) { ++ if (!$fileinfo->isDot()) { ++ var_dump($fileinfo->getFilename()); ++ } ++} ++?> ++--EXPECTF-- ++Fatal error: Uncaught UnexpectedValueException: DirectoryIterator::__construct() expects parameter 1 to be a valid path, string given in %s:%d ++Stack trace: ++#0 %s(%d): DirectoryIterator->__construct('%s') ++#1 {main} ++ thrown in %s on line %d ++--CLEAN-- ++<?php ++$dir = __DIR__ . '/bug78863'; ++unlink("$dir/sub/good"); ++rmdir("$dir/sub"); ++unlink("$dir/bad"); ++rmdir($dir); ++?> diff --git a/php-bug78875.patch b/php-bug78875.patch new file mode 100644 index 0000000..aa04cee --- /dev/null +++ b/php-bug78875.patch @@ -0,0 +1,38 @@ +From d856f7b27eef0249abc6fd2f87cca379b48b815e Mon Sep 17 00:00:00 2001 +From: "Christoph M. Becker" <cmbecker69@gmx.de> +Date: Wed, 18 Mar 2020 10:26:53 +0100 +Subject: [PATCH] Fix #78875: Long filenames cause OOM and temp files are not + cleaned + +We must not cast `size_t` to `int` (unless the `size_t` value is +guaranteed to be less than or equal to `INT_MAX`). In this case we can +declare `array_len` as `size_t` in the first place. + +(cherry picked from commit 1c9bd513ac5c7c1d13d7f0dfa7c16a7ad2ce0f87) +--- + main/rfc1867.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/main/rfc1867.c b/main/rfc1867.c +index b930e07ad1..14ffbea9f4 100644 +--- a/main/rfc1867.c ++++ b/main/rfc1867.c +@@ -692,7 +692,8 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */ + char *boundary, *s = NULL, *boundary_end = NULL, *start_arr = NULL, *array_index = NULL; + char *lbuf = NULL, *abuf = NULL; + zend_string *temp_filename = NULL; +- int boundary_len = 0, cancel_upload = 0, is_arr_upload = 0, array_len = 0; ++ int boundary_len = 0, cancel_upload = 0, is_arr_upload = 0; ++ size_t array_len = 0; + int64_t total_bytes = 0, max_file_size = 0; + int skip_upload = 0, anonindex = 0, is_anonymous; + HashTable *uploaded_files = NULL; +@@ -1126,7 +1127,7 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */ + is_arr_upload = (start_arr = strchr(param,'[')) && (param[strlen(param)-1] == ']'); + + if (is_arr_upload) { +- array_len = (int)strlen(start_arr); ++ array_len = strlen(start_arr); + if (array_index) { + efree(array_index); + } diff --git a/php-bug78876.patch b/php-bug78876.patch new file mode 100644 index 0000000..0afab9c --- /dev/null +++ b/php-bug78876.patch @@ -0,0 +1,73 @@ +From 29b3876a0aad27a65e853fd0be4bdc7647dee444 Mon Sep 17 00:00:00 2001 +From: "Christoph M. Becker" <cmbecker69@gmx.de> +Date: Wed, 18 Mar 2020 10:57:42 +0100 +Subject: [PATCH] Fix #78876: Long variables cause OOM and temp files are not + cleaned + +We use the proper type for size calculations, which is `size_t`. + +(cherry picked from commit 3c8582ca4b8e84e5647220b647914876d2c3b124) +--- + main/rfc1867.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/main/rfc1867.c b/main/rfc1867.c +index 14ffbea9f4..1742b9c0a9 100644 +--- a/main/rfc1867.c ++++ b/main/rfc1867.c +@@ -616,7 +616,7 @@ static void *php_ap_memstr(char *haystack, int haystacklen, char *needle, int ne + } + + /* read until a boundary condition */ +-static int multipart_buffer_read(multipart_buffer *self, char *buf, size_t bytes, int *end) ++static size_t multipart_buffer_read(multipart_buffer *self, char *buf, size_t bytes, int *end) + { + size_t len, max; + char *bound; +@@ -655,7 +655,7 @@ static int multipart_buffer_read(multipart_buffer *self, char *buf, size_t bytes + self->buf_begin += len; + } + +- return (int)len; ++ return len; + } + + /* +@@ -665,7 +665,7 @@ static int multipart_buffer_read(multipart_buffer *self, char *buf, size_t bytes + static char *multipart_buffer_read_body(multipart_buffer *self, size_t *len) + { + char buf[FILLUNIT], *out=NULL; +- int total_bytes=0, read_bytes=0; ++ size_t total_bytes=0, read_bytes=0; + + while((read_bytes = multipart_buffer_read(self, buf, sizeof(buf), NULL))) { + out = erealloc(out, total_bytes + read_bytes + 1); +From f1a89efe27650b62d58fceb77252480b19da6555 Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Mon, 11 May 2020 14:28:51 -0700 +Subject: [PATCH] Update NEWS + +(cherry picked from commit b4afd21428e09133228fd84bf048157526c2c705) +--- + NEWS | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/NEWS b/NEWS +index cc1e992229..19fbb3adf2 100644 +--- a/NEWS ++++ b/NEWS +@@ -1,6 +1,14 @@ + PHP NEWS + ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| + ++Backported from 7.2.31 ++ ++- Core: ++ . Fixed bug #78875 (Long filenames cause OOM and temp files are not cleaned). ++ (CVE-2019-11048) (cmb) ++ . Fixed bug #78876 (Long variables in multipart/form-data cause OOM and temp ++ files are not cleaned). (CVE-2019-11048) (cmb) ++ + Backported from 7.2.30 + + - Standard: diff --git a/php-bug78878.patch b/php-bug78878.patch new file mode 100644 index 0000000..1b9f6fe --- /dev/null +++ b/php-bug78878.patch @@ -0,0 +1,68 @@ +From fc9982062527b1a58206d826449273dd2bd850cf Mon Sep 17 00:00:00 2001 +From: "Christoph M. Becker" <cmbecker69@gmx.de> +Date: Tue, 17 Dec 2019 10:46:45 +0100 +Subject: [PATCH] Fix #78878: Buffer underflow in bc_shift_addsub + +We must not rely on `isdigit()` to detect digits, since we only support +decimal ASCII digits in the following processing. + +(cherry picked from commit eb23c6008753b1cdc5359dead3a096dce46c9018) +--- + NEWS | 6 ++++++ + ext/bcmath/libbcmath/src/str2num.c | 4 ++-- + ext/bcmath/tests/bug78878.phpt | 13 +++++++++++++ + 3 files changed, 21 insertions(+), 2 deletions(-) + create mode 100644 ext/bcmath/tests/bug78878.phpt + +diff --git a/NEWS b/NEWS +index 0fd96d0c91..ec0247e1f1 100644 +--- a/NEWS ++++ b/NEWS +@@ -1,5 +1,12 @@ + PHP NEWS + ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ++ ++Backported from 7.2.26 ++ ++- Bcmath: ++ . Fixed bug #78878 (Buffer underflow in bc_shift_addsub). (CVE-2019-11046). ++ (cmb) ++ + 24 Oct 2019, PHP 7.1.33 + + - FPM: +diff --git a/ext/bcmath/libbcmath/src/str2num.c b/ext/bcmath/libbcmath/src/str2num.c +index f38d341570..03aec15930 100644 +--- a/ext/bcmath/libbcmath/src/str2num.c ++++ b/ext/bcmath/libbcmath/src/str2num.c +@@ -57,9 +57,9 @@ bc_str2num (bc_num *num, char *str, int scale) + zero_int = FALSE; + if ( (*ptr == '+') || (*ptr == '-')) ptr++; /* Sign */ + while (*ptr == '0') ptr++; /* Skip leading zeros. */ +- while (isdigit((int)*ptr)) ptr++, digits++; /* digits */ ++ while (*ptr >= '0' && *ptr <= '9') ptr++, digits++; /* digits */ + if (*ptr == '.') ptr++; /* decimal point */ +- while (isdigit((int)*ptr)) ptr++, strscale++; /* digits */ ++ while (*ptr >= '0' && *ptr <= '9') ptr++, strscale++; /* digits */ + if ((*ptr != '\0') || (digits+strscale == 0)) + { + *num = bc_copy_num (BCG(_zero_)); +diff --git a/ext/bcmath/tests/bug78878.phpt b/ext/bcmath/tests/bug78878.phpt +new file mode 100644 +index 0000000000..2c9d72b946 +--- /dev/null ++++ b/ext/bcmath/tests/bug78878.phpt +@@ -0,0 +1,13 @@ ++--TEST-- ++Bug #78878 (Buffer underflow in bc_shift_addsub) ++--SKIPIF-- ++<?php ++if (!extension_loaded('bcmath')) die('skip bcmath extension not available'); ++?> ++--FILE-- ++<?php ++print @bcmul("\xB26483605105519922841849335928742092", bcpowmod(2, 65535, -4e-4)); ++?> ++--EXPECT-- ++bc math warning: non-zero scale in modulus ++0 diff --git a/php-bug78910.patch b/php-bug78910.patch new file mode 100644 index 0000000..81e793d --- /dev/null +++ b/php-bug78910.patch @@ -0,0 +1,120 @@ +From e5c13f8716507a1210bd0ed6550c3b29fb8b2117 Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Mon, 16 Dec 2019 00:10:39 -0800 +Subject: [PATCH] Fixed bug #78910 + +(cherry picked from commit d348cfb96f2543565691010ade5e0346338be5a7) +--- + NEWS | 2 ++ + ext/exif/exif.c | 3 ++- + ext/exif/tests/bug78910.phpt | 17 +++++++++++++++++ + 3 files changed, 21 insertions(+), 1 deletion(-) + create mode 100644 ext/exif/tests/bug78910.phpt + +diff --git a/NEWS b/NEWS +index 20bbff880e..25d352f784 100644 +--- a/NEWS ++++ b/NEWS +@@ -16,6 +16,8 @@ Backported from 7.2.26 + - EXIF: + . Fixed bug #78793 (Use-after-free in exif parsing under memory sanitizer). + (CVE-2019-11050). (Nikita) ++ . Fixed bug #78910 (Heap-buffer-overflow READ in exif). (CVE-2019-11047). ++ (Nikita) + + 24 Oct 2019, PHP 7.1.33 + +diff --git a/ext/exif/exif.c b/ext/exif/exif.c +index c9ebaa7b78..406fee4ff4 100644 +--- a/ext/exif/exif.c ++++ b/ext/exif/exif.c +@@ -2749,7 +2749,8 @@ static int exif_process_IFD_in_MAKERNOTE(image_info_type *ImageInfo, char * valu + continue; + if (maker_note->model && (!ImageInfo->model || strcmp(maker_note->model, ImageInfo->model))) + continue; +- if (maker_note->id_string && strncmp(maker_note->id_string, value_ptr, maker_note->id_string_len)) ++ if (maker_note->id_string && value_len >= maker_note->id_string_len ++ && strncmp(maker_note->id_string, value_ptr, maker_note->id_string_len)) + continue; + break; + } +diff --git a/ext/exif/tests/bug78910.phpt b/ext/exif/tests/bug78910.phpt +new file mode 100644 +index 0000000000..f5b1c32c1b +--- /dev/null ++++ b/ext/exif/tests/bug78910.phpt +@@ -0,0 +1,17 @@ ++--TEST-- ++Bug #78910: Heap-buffer-overflow READ in exif (OSS-Fuzz #19044) ++--FILE-- ++<?php ++ ++var_dump(exif_read_data('data:image/jpg;base64,TU0AKgAAAAwgICAgAAIBDwAEAAAAAgAAACKSfCAgAAAAAEZVSklGSUxN')); ++ ++?> ++--EXPECTF-- ++Notice: exif_read_data(): Read from TIFF: tag(0x927C, MakerNote ): Illegal format code 0x2020, switching to BYTE in %s on line %d ++ ++Warning: exif_read_data(): Process tag(x927C=MakerNote ): Illegal format code 0x2020, suppose BYTE in %s on line %d ++ ++Warning: exif_read_data(): IFD data too short: 0x0000 offset 0x000C in %s on line %d ++ ++Warning: exif_read_data(): Invalid TIFF file in %s on line %d ++bool(false) +From 0d68020ffa1eef58df2bf845f8638646e840a86f Mon Sep 17 00:00:00 2001 +From: Remi Collet <remi@remirepo.net> +Date: Tue, 17 Dec 2019 15:07:18 +0100 +Subject: [PATCH] relax tests + +--- + ext/exif/tests/bug76557.phpt | 2 +- + ext/exif/tests/bug78910.phpt | 8 ++++---- + ext/spl/tests/bug54291.phpt | 2 +- + 3 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/ext/exif/tests/bug76557.phpt b/ext/exif/tests/bug76557.phpt +index 4553b62772..08bd2d73a7 100644 +--- a/ext/exif/tests/bug76557.phpt ++++ b/ext/exif/tests/bug76557.phpt +@@ -70,7 +70,7 @@ Warning: exif_read_data(bug76557.jpg): Process tag(x3030=UndefinedTa): Illegal f + + Warning: exif_read_data(bug76557.jpg): Process tag(x3030=UndefinedTa): Illegal format code 0x3030, suppose BYTE in %sbug76557.php on line %d + +-Warning: exif_read_data(bug76557.jpg): Process tag(x3030=UndefinedTa): Illegal pointer offset(x30303030 + x30303030 = x60606060 > x00EE) in %sbug76557.php on line %d ++Warning: exif_read_data(bug76557.jpg): Process tag(x3030=UndefinedTa): Illegal pointer offset(x30303030 + x30303030 = x60606060 > x%s) in %sbug76557.php on line %d + + Warning: exif_read_data(bug76557.jpg): File structure corrupted in %sbug76557.php on line %d + +diff --git a/ext/exif/tests/bug78910.phpt b/ext/exif/tests/bug78910.phpt +index f5b1c32c1b..7770df5129 100644 +--- a/ext/exif/tests/bug78910.phpt ++++ b/ext/exif/tests/bug78910.phpt +@@ -7,11 +7,11 @@ var_dump(exif_read_data('data:image/jpg;base64,TU0AKgAAAAwgICAgAAIBDwAEAAAAAgAAA + + ?> + --EXPECTF-- +-Notice: exif_read_data(): Read from TIFF: tag(0x927C, MakerNote ): Illegal format code 0x2020, switching to BYTE in %s on line %d ++Notice: exif_read_data(%s): Read from TIFF: tag(0x927C, MakerNote ): Illegal format code 0x2020, switching to BYTE in %s on line %d + +-Warning: exif_read_data(): Process tag(x927C=MakerNote ): Illegal format code 0x2020, suppose BYTE in %s on line %d ++Warning: exif_read_data(%s): Process tag(x927C=MakerNote ): Illegal format code 0x2020, suppose BYTE in %s on line %d + +-Warning: exif_read_data(): IFD data too short: 0x0000 offset 0x000C in %s on line %d ++Warning: exif_read_data(%s): IFD data too short: 0x0000 offset 0x000C in %s on line %d + +-Warning: exif_read_data(): Invalid TIFF file in %s on line %d ++Warning: exif_read_data(%s): Invalid TIFF file in %s on line %d + bool(false) +diff --git a/ext/spl/tests/bug54291.phpt b/ext/spl/tests/bug54291.phpt +index b15a3723d4..655291fde4 100644 +--- a/ext/spl/tests/bug54291.phpt ++++ b/ext/spl/tests/bug54291.phpt +@@ -5,7 +5,7 @@ Bug #54291 (Crash iterating DirectoryIterator for dir name starting with \0) + $dir = new DirectoryIterator("\x00/abc"); + $dir->isFile(); + --EXPECTF-- +-Fatal error: Uncaught UnexpectedValueException: Failed to open directory "" in %s:%d ++Fatal error: Uncaught UnexpectedValueException: %s in %s:%d + Stack trace: + #0 %s(%d): DirectoryIterator->__construct('\x00/abc') + #1 {main} diff --git a/php-bug79037.patch b/php-bug79037.patch new file mode 100644 index 0000000..d488065 --- /dev/null +++ b/php-bug79037.patch @@ -0,0 +1,96 @@ +From 6639124e6e1fbfe81a6afe5ee9f0a1fee24d0856 Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Mon, 20 Jan 2020 21:42:44 -0800 +Subject: [PATCH] Fix bug #79037 (global buffer-overflow in + `mbfl_filt_conv_big5_wchar`) + +(cherry picked from commit 2bcbc95f033c31b00595ed39f79c3a99b4ed0501) +--- + ext/mbstring/libmbfl/filters/mbfilter_big5.c | 17 ++++++++++++----- + ext/mbstring/tests/bug79037.phpt | 10 ++++++++++ + 2 files changed, 22 insertions(+), 5 deletions(-) + create mode 100644 ext/mbstring/tests/bug79037.phpt + +diff --git a/ext/mbstring/libmbfl/filters/mbfilter_big5.c b/ext/mbstring/libmbfl/filters/mbfilter_big5.c +index f5ab8809ce..5e1ca815da 100644 +--- a/ext/mbstring/libmbfl/filters/mbfilter_big5.c ++++ b/ext/mbstring/libmbfl/filters/mbfilter_big5.c +@@ -138,6 +138,17 @@ static unsigned short cp950_pua_tbl[][4] = { + {0xf70f,0xf848,0xc740,0xc8fe}, + }; + ++static inline int is_in_cp950_pua(int c1, int c) { ++ if ((c1 >= 0xfa && c1 <= 0xfe) || (c1 >= 0x8e && c1 <= 0xa0) || ++ (c1 >= 0x81 && c1 <= 0x8d) || (c1 >= 0xc7 && c1 <= 0xc8)) { ++ return (c >=0x40 && c <= 0x7e) || (c >= 0xa1 && c <= 0xfe); ++ } ++ if (c1 == 0xc6) { ++ return c >= 0xa1 && c <= 0xfe; ++ } ++ return 0; ++} ++ + /* + * Big5 => wchar + */ +@@ -186,11 +197,7 @@ mbfl_filt_conv_big5_wchar(int c, mbfl_convert_filter *filter) + + if (filter->from->no_encoding == mbfl_no_encoding_cp950) { + /* PUA for CP950 */ +- if (w <= 0 && +- (((c1 >= 0xfa && c1 <= 0xfe) || (c1 >= 0x8e && c1 <= 0xa0) || +- (c1 >= 0x81 && c1 <= 0x8d) ||(c1 >= 0xc7 && c1 <= 0xc8)) +- && ((c > 0x39 && c < 0x7f) || (c > 0xa0 && c < 0xff))) || +- ((c1 == 0xc6) && (c > 0xa0 && c < 0xff))) { ++ if (w <= 0 && is_in_cp950_pua(c1, c)) { + c2 = c1 << 8 | c; + for (k = 0; k < sizeof(cp950_pua_tbl)/(sizeof(unsigned short)*4); k++) { + if (c2 >= cp950_pua_tbl[k][2] && c2 <= cp950_pua_tbl[k][3]) { +diff --git a/ext/mbstring/tests/bug79037.phpt b/ext/mbstring/tests/bug79037.phpt +new file mode 100644 +index 0000000000..94ff01a4a1 +--- /dev/null ++++ b/ext/mbstring/tests/bug79037.phpt +@@ -0,0 +1,10 @@ ++--TEST-- ++Bug #79037: global buffer-overflow in `mbfl_filt_conv_big5_wchar` ++--FILE-- ++<?php ++ ++var_dump(mb_convert_encoding("\x81\x3a", "UTF-8", "CP950")); ++ ++?> ++--EXPECT-- ++string(1) "?" +From 18d8f6f9033a35b33e4bbf8590cd6e653b45b6d7 Mon Sep 17 00:00:00 2001 +From: Remi Collet <remi@remirepo.net> +Date: Tue, 21 Jan 2020 09:06:34 +0100 +Subject: [PATCH] update NEWS + +--- + NEWS | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/NEWS b/NEWS +index 25d352f784..e311fc78cc 100644 +--- a/NEWS ++++ b/NEWS +@@ -1,6 +1,18 @@ + PHP NEWS + ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| + ++Backported from 7.2.27 ++ ++- Mbstring: ++ . Fixed bug #79037 (global buffer-overflow in `mbfl_filt_conv_big5_wchar`). ++ (CVE-2020-7060) (Nikita) ++ ++- Session: ++ . Fixed bug #79091 (heap use-after-free in session_create_id()). (cmb, Nikita) ++ ++- Standard: ++ . Fixed bug #79099 (OOB read in php_strip_tags_ex). (CVE-2020-7059). (cmb) ++ + Backported from 7.2.26 + + - Bcmath: diff --git a/php-bug79082.patch b/php-bug79082.patch new file mode 100644 index 0000000..5ad894a --- /dev/null +++ b/php-bug79082.patch @@ -0,0 +1,146 @@ +From d1b4f9477f43c55cfb631e7c60d5b3568bdc889c Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Sat, 15 Feb 2020 22:17:14 -0800 +Subject: [PATCH] Fix bug #79082 - Files added to tar with + Phar::buildFromIterator have all-access permissions + +(cherry picked from commit e5c95234d87fcb8f6b7569a96a89d1e1544749a6) +--- + ext/phar/phar_object.c | 11 +++++ + ext/phar/tests/bug79082.phpt | 52 ++++++++++++++++++++ + ext/phar/tests/test79082/test79082-testfile | 1 + + ext/phar/tests/test79082/test79082-testfile2 | 1 + + 4 files changed, 65 insertions(+) + create mode 100644 ext/phar/tests/bug79082.phpt + create mode 100644 ext/phar/tests/test79082/test79082-testfile + create mode 100644 ext/phar/tests/test79082/test79082-testfile2 + +diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c +index c1ba97a195..b22a6acf90 100644 +--- a/ext/phar/phar_object.c ++++ b/ext/phar/phar_object.c +@@ -1439,6 +1439,7 @@ static int phar_build(zend_object_iterator *iter, void *puser) /* {{{ */ + char *str_key; + zend_class_entry *ce = p_obj->c; + phar_archive_object *phar_obj = p_obj->p; ++ php_stream_statbuf ssb; + + value = iter->funcs->get_current_data(iter); + +@@ -1718,6 +1719,16 @@ static int phar_build(zend_object_iterator *iter, void *puser) /* {{{ */ + php_stream_copy_to_stream_ex(fp, p_obj->fp, PHP_STREAM_COPY_ALL, &contents_len); + data->internal_file->uncompressed_filesize = data->internal_file->compressed_filesize = + php_stream_tell(p_obj->fp) - data->internal_file->offset; ++ if (php_stream_stat(fp, &ssb) != -1) { ++ data->internal_file->flags = ssb.sb.st_mode & PHAR_ENT_PERM_MASK ; ++ } else { ++#ifndef _WIN32 ++ mode_t mask; ++ mask = umask(0); ++ umask(mask); ++ data->internal_file->flags &= ~mask; ++#endif ++ } + } + + if (close_fp) { +diff --git a/ext/phar/tests/bug79082.phpt b/ext/phar/tests/bug79082.phpt +new file mode 100644 +index 0000000000..ca453d1b57 +--- /dev/null ++++ b/ext/phar/tests/bug79082.phpt +@@ -0,0 +1,52 @@ ++--TEST-- ++Phar: Bug #79082: Files added to tar with Phar::buildFromIterator have all-access permissions ++--SKIPIF-- ++<?php ++if (!extension_loaded("phar")) die("skip"); ++if (defined("PHP_WINDOWS_VERSION_MAJOR")) die("skip not for Windows") ++?> ++--FILE-- ++<?php ++umask(022); ++var_dump(decoct(umask())); ++chmod(__DIR__ . '/test79082/test79082-testfile', 0644); ++chmod(__DIR__ . '/test79082/test79082-testfile2', 0400); ++ ++foreach([Phar::TAR => 'tar', Phar::ZIP => 'zip'] as $mode => $ext) { ++ clearstatcache(); ++ $phar = new PharData(__DIR__ . '/test79082.' . $ext, null, null, $mode); ++ $phar->buildFromIterator(new \RecursiveDirectoryIterator(__DIR__ . '/test79082', \FilesystemIterator::SKIP_DOTS), __DIR__ . '/test79082'); ++ $phar->extractTo(__DIR__); ++ var_dump(decoct(stat(__DIR__ . '/test79082-testfile')['mode'])); ++ var_dump(decoct(stat(__DIR__ . '/test79082-testfile2')['mode'])); ++ unlink(__DIR__ . '/test79082-testfile'); ++ unlink(__DIR__ . '/test79082-testfile2'); ++} ++foreach([Phar::TAR => 'tar', Phar::ZIP => 'zip'] as $mode => $ext) { ++ clearstatcache(); ++ $phar = new PharData(__DIR__ . '/test79082-d.' . $ext, null, null, $mode); ++ $phar->buildFromDirectory(__DIR__ . '/test79082'); ++ $phar->extractTo(__DIR__); ++ var_dump(decoct(stat(__DIR__ . '/test79082-testfile')['mode'])); ++ var_dump(decoct(stat(__DIR__ . '/test79082-testfile2')['mode'])); ++ unlink(__DIR__ . '/test79082-testfile'); ++ unlink(__DIR__ . '/test79082-testfile2'); ++} ++?> ++--CLEAN-- ++<? ++unlink(__DIR__ . '/test79082.tar'); ++unlink(__DIR__ . '/test79082.zip'); ++unlink(__DIR__ . '/test79082-d.tar'); ++unlink(__DIR__ . '/test79082-d.zip'); ++?> ++--EXPECT-- ++string(2) "22" ++string(6) "100644" ++string(6) "100400" ++string(6) "100644" ++string(6) "100400" ++string(6) "100644" ++string(6) "100400" ++string(6) "100644" ++string(6) "100400" +diff --git a/ext/phar/tests/test79082/test79082-testfile b/ext/phar/tests/test79082/test79082-testfile +new file mode 100644 +index 0000000000..9daeafb986 +--- /dev/null ++++ b/ext/phar/tests/test79082/test79082-testfile +@@ -0,0 +1 @@ ++test +diff --git a/ext/phar/tests/test79082/test79082-testfile2 b/ext/phar/tests/test79082/test79082-testfile2 +new file mode 100644 +index 0000000000..9daeafb986 +--- /dev/null ++++ b/ext/phar/tests/test79082/test79082-testfile2 +@@ -0,0 +1 @@ ++test +From f59b90d7c7d5b593fdde3fda1195490125d0f170 Mon Sep 17 00:00:00 2001 +From: Remi Collet <remi@remirepo.net> +Date: Tue, 18 Feb 2020 06:34:16 +0100 +Subject: [PATCH] NEWS + +--- + NEWS | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/NEWS b/NEWS +index 7e220aae24..4233a530c1 100644 +--- a/NEWS ++++ b/NEWS +@@ -7,6 +7,14 @@ Backported from 7.2.28 + . Fixed bug #77569: (Write Access Violation in DomImplementation). (Nikita, + cmb) + ++- Phar: ++ . Fixed bug #79082 (Files added to tar with Phar::buildFromIterator have ++ all-access permissions). (CVE-2020-7063) (stas) ++ ++- Session: ++ . Fixed bug #79221 (Null Pointer Dereference in PHP Session Upload Progress). ++ (CVE-2020-7062) (stas) ++ + Backported from 7.2.27 + + - Mbstring: diff --git a/php-bug79091.patch b/php-bug79091.patch new file mode 100644 index 0000000..ad3a5cc --- /dev/null +++ b/php-bug79091.patch @@ -0,0 +1,99 @@ +From 35c8a53c098cd828413a80ed7964146d50161c6c Mon Sep 17 00:00:00 2001 +From: "Christoph M. Becker" <cmbecker69@gmx.de> +Date: Mon, 20 Jan 2020 18:05:00 +0100 +Subject: [PATCH] Fix #79091: heap use-after-free in session_create_id() + +If the `new_id` is released, we must not use it again. + +(cherry picked from commit f79c7742746907d676989cb7f97fb4f7cd26789f) +--- + ext/session/session.c | 1 + + ext/session/tests/bug79091.phpt | 67 +++++++++++++++++++++++++++++++++ + 2 files changed, 68 insertions(+) + create mode 100644 ext/session/tests/bug79091.phpt + +diff --git a/ext/session/session.c b/ext/session/session.c +index 8d60ac249a..44ecb85f74 100644 +--- a/ext/session/session.c ++++ b/ext/session/session.c +@@ -2049,6 +2049,7 @@ static PHP_FUNCTION(session_create_id) + /* Detect collision and retry */ + if (PS(mod)->s_validate_sid(&PS(mod_data), new_id) == FAILURE) { + zend_string_release(new_id); ++ new_id = NULL; + continue; + } + break; +diff --git a/ext/session/tests/bug79091.phpt b/ext/session/tests/bug79091.phpt +new file mode 100644 +index 0000000000..1d14427159 +--- /dev/null ++++ b/ext/session/tests/bug79091.phpt +@@ -0,0 +1,67 @@ ++--TEST-- ++Bug #79091 (heap use-after-free in session_create_id()) ++--SKIPIF-- ++<?php ++if (!extension_loaded('session')) die('skip session extension not available'); ++?> ++--FILE-- ++<?php ++class MySessionHandler implements SessionHandlerInterface, SessionIdInterface, SessionUpdateTimestampHandlerInterface ++{ ++ public function close() ++ { ++ return true; ++ } ++ ++ public function destroy($session_id) ++ { ++ return true; ++ } ++ ++ public function gc($maxlifetime) ++ { ++ return true; ++ } ++ ++ public function open($save_path, $session_name) ++ { ++ return true; ++ } ++ ++ public function read($session_id) ++ { ++ return ''; ++ } ++ ++ public function write($session_id, $session_data) ++ { ++ return true; ++ } ++ ++ public function create_sid() ++ { ++ return uniqid(); ++ } ++ ++ public function updateTimestamp($key, $val) ++ { ++ return true; ++ } ++ ++ public function validateId($key) ++ { ++ return false; ++ } ++} ++ ++ob_start(); ++var_dump(session_set_save_handler(new MySessionHandler())); ++var_dump(session_start()); ++ob_flush(); ++session_create_id(); ++?> ++--EXPECTF-- ++bool(true) ++bool(true) ++ ++Warning: session_create_id(): Failed to create new ID in %s on line %d diff --git a/php-bug79099.patch b/php-bug79099.patch new file mode 100644 index 0000000..5bdd647 --- /dev/null +++ b/php-bug79099.patch @@ -0,0 +1,113 @@ +From f18f20c032482e34d5f94d747da16f8ae029a017 Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Mon, 20 Jan 2020 21:33:17 -0800 +Subject: [PATCH] Fix #79099: OOB read in php_strip_tags_ex + +(cherry picked from commit 0f79b1bf301f455967676b5129240140c5c45b09) +--- + ext/standard/string.c | 6 ++--- + ext/standard/tests/file/bug79099.phpt | 32 +++++++++++++++++++++++++++ + 2 files changed, 35 insertions(+), 3 deletions(-) + create mode 100644 ext/standard/tests/file/bug79099.phpt + +diff --git a/ext/standard/string.c b/ext/standard/string.c +index 922d4fceaf..c88135da6f 100644 +--- a/ext/standard/string.c ++++ b/ext/standard/string.c +@@ -4781,7 +4781,7 @@ PHPAPI size_t php_strip_tags_ex(char *rbuf, size_t len, int *stateptr, const cha + if (state == 4) { + /* Inside <!-- comment --> */ + break; +- } else if (state == 2 && *(p-1) != '\\') { ++ } else if (state == 2 && p >= buf + 1 && *(p-1) != '\\') { + if (lc == c) { + lc = '\0'; + } else if (lc != '\\') { +@@ -4808,7 +4808,7 @@ PHPAPI size_t php_strip_tags_ex(char *rbuf, size_t len, int *stateptr, const cha + + case '!': + /* JavaScript & Other HTML scripting languages */ +- if (state == 1 && *(p-1) == '<') { ++ if (state == 1 && p >= buf + 1 && *(p-1) == '<') { + state = 3; + lc = c; + } else { +@@ -4835,7 +4835,7 @@ PHPAPI size_t php_strip_tags_ex(char *rbuf, size_t len, int *stateptr, const cha + + case '?': + +- if (state == 1 && *(p-1) == '<') { ++ if (state == 1 && p >= buf + 1 && *(p-1) == '<') { + br=0; + state=2; + break; +diff --git a/ext/standard/tests/file/bug79099.phpt b/ext/standard/tests/file/bug79099.phpt +new file mode 100644 +index 0000000000..7c842f4654 +--- /dev/null ++++ b/ext/standard/tests/file/bug79099.phpt +@@ -0,0 +1,32 @@ ++--TEST-- ++Bug #79099 (OOB read in php_strip_tags_ex) ++--FILE-- ++<?php ++$stream = fopen('php://memory', 'w+'); ++fputs($stream, "<?\n\"\n"); ++rewind($stream); ++var_dump(fgetss($stream)); ++var_dump(fgetss($stream)); ++fclose($stream); ++ ++$stream = fopen('php://memory', 'w+'); ++fputs($stream, "<\0\n!\n"); ++rewind($stream); ++var_dump(fgetss($stream)); ++var_dump(fgetss($stream)); ++fclose($stream); ++ ++$stream = fopen('php://memory', 'w+'); ++fputs($stream, "<\0\n?\n"); ++rewind($stream); ++var_dump(fgetss($stream)); ++var_dump(fgetss($stream)); ++fclose($stream); ++?> ++--EXPECT-- ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" +From a9620f5c7f2d55ca90552d3eb44d0980f10deec3 Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Wed, 22 Jan 2020 22:36:53 -0800 +Subject: [PATCH] More checks for php_strip_tags_ex + +(cherry picked from commit 2dc170e25d86a725fefd4c08f2bd8378820b28f5) +--- + ext/standard/string.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/ext/standard/string.c b/ext/standard/string.c +index c88135da6f..018e919cbf 100644 +--- a/ext/standard/string.c ++++ b/ext/standard/string.c +@@ -4731,7 +4731,7 @@ PHPAPI size_t php_strip_tags_ex(char *rbuf, size_t len, int *stateptr, const cha + switch (state) { + case 1: /* HTML/XML */ + lc = '>'; +- if (is_xml && *(p -1) == '-') { ++ if (is_xml && p >= buf + 1 && *(p-1) == '-') { + break; + } + in_q = state = is_xml = 0; +@@ -4752,7 +4752,7 @@ PHPAPI size_t php_strip_tags_ex(char *rbuf, size_t len, int *stateptr, const cha + break; + + case 2: /* PHP */ +- if (!br && lc != '\"' && *(p-1) == '?') { ++ if (!br && lc != '\"' && p >= buf + 1 && *(p-1) == '?') { + in_q = state = 0; + tp = tbuf; + } diff --git a/php-bug79221.patch b/php-bug79221.patch new file mode 100644 index 0000000..f687d40 --- /dev/null +++ b/php-bug79221.patch @@ -0,0 +1,83 @@ +From 4438b2844e80d9533587d558f4411f29d17de2c1 Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Sat, 15 Feb 2020 20:52:19 -0800 +Subject: [PATCH] Fix bug #79221 - Null Pointer Dereference in PHP Session + Upload Progress + +(cherry picked from commit d76f7c6c636b8240e06a1fa29eebb98ad005008a) +--- + ext/session/session.c | 8 +++--- + ext/session/tests/bug79221.phpt | 45 +++++++++++++++++++++++++++++++++ + 2 files changed, 50 insertions(+), 3 deletions(-) + create mode 100644 ext/session/tests/bug79221.phpt + +diff --git a/ext/session/session.c b/ext/session/session.c +index 44ecb85f74..ee52d24fcc 100644 +--- a/ext/session/session.c ++++ b/ext/session/session.c +@@ -2999,9 +2999,11 @@ static int php_session_rfc1867_callback(unsigned int event, void *event_data, vo + if (PS(rfc1867_cleanup)) { + php_session_rfc1867_cleanup(progress); + } else { +- add_assoc_bool_ex(&progress->data, "done", sizeof("done") - 1, 1); +- Z_LVAL_P(progress->post_bytes_processed) = data->post_bytes_processed; +- php_session_rfc1867_update(progress, 1); ++ if (!Z_ISUNDEF(progress->data)) { ++ add_assoc_bool_ex(&progress->data, "done", sizeof("done") - 1, 1); ++ Z_LVAL_P(progress->post_bytes_processed) = data->post_bytes_processed; ++ php_session_rfc1867_update(progress, 1); ++ } + } + php_rshutdown_session_globals(); + } +diff --git a/ext/session/tests/bug79221.phpt b/ext/session/tests/bug79221.phpt +new file mode 100644 +index 0000000000..b0972c4697 +--- /dev/null ++++ b/ext/session/tests/bug79221.phpt +@@ -0,0 +1,45 @@ ++--TEST-- ++Null Pointer Dereference in PHP Session Upload Progress ++--INI-- ++error_reporting=0 ++file_uploads=1 ++upload_max_filesize=1024 ++session.save_path= ++session.name=PHPSESSID ++session.serialize_handler=php ++session.use_strict_mode=0 ++session.use_cookies=1 ++session.use_only_cookies=0 ++session.upload_progress.enabled=1 ++session.upload_progress.cleanup=0 ++session.upload_progress.prefix=upload_progress_ ++session.upload_progress.name=PHP_SESSION_UPLOAD_PROGRESS ++session.upload_progress.freq=1% ++session.upload_progress.min_freq=0.000000001 ++--COOKIE-- ++PHPSESSID=session-upload ++--POST_RAW-- ++Content-Type: multipart/form-data; boundary=---------------------------20896060251896012921717172737 ++-----------------------------20896060251896012921717172737 ++Content-Disposition: form-data; name="PHPSESSID" ++ ++session-upload ++-----------------------------20896060251896012921717172737 ++Content-Disposition: form-data; name="PHP_SESSION_UPLOAD_PROGRESS" ++ ++ryat ++-----------------------------20896060251896012921717172737 ++Content-Disposition: form-data; file="file"; ryat="filename" ++ ++1 ++-----------------------------20896060251896012921717172737-- ++--FILE-- ++<?php ++ ++session_start(); ++var_dump($_SESSION); ++session_destroy(); ++ ++--EXPECTF-- ++array(0) { ++} diff --git a/php-bug79282.patch b/php-bug79282.patch new file mode 100644 index 0000000..0ea2bae --- /dev/null +++ b/php-bug79282.patch @@ -0,0 +1,107 @@ +From 8577fa5891220dac40d42b2f745fa159dcd871ad Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Sun, 15 Mar 2020 17:26:00 -0700 +Subject: [PATCH] Fixed bug #79282 + +(cherry picked from commit 41f66e2a2cfd611e35be5ac3bf747f0b56161216) +--- + ext/exif/exif.c | 7 ++++++- + ext/exif/tests/bug79282.phpt | 15 +++++++++++++++ + 2 files changed, 21 insertions(+), 1 deletion(-) + create mode 100644 ext/exif/tests/bug79282.phpt + +diff --git a/ext/exif/exif.c b/ext/exif/exif.c +index 406fee4ff4..9130ceaf6d 100644 +--- a/ext/exif/exif.c ++++ b/ext/exif/exif.c +@@ -3243,6 +3243,11 @@ static void exif_process_TIFF_in_JPEG(image_info_type *ImageInfo, char *CharBuf, + { + unsigned exif_value_2a, offset_of_ifd; + ++ if (length < 2) { ++ exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "Missing TIFF alignment marker"); ++ return; ++ } ++ + /* set the thumbnail stuff to nothing so we can test to see if they get set up */ + if (memcmp(CharBuf, "II", 2) == 0) { + ImageInfo->motorola_intel = 0; +@@ -3395,7 +3400,7 @@ static int exif_scan_JPEG_header(image_info_type *ImageInfo) + return FALSE; + } + +- sn = exif_file_sections_add(ImageInfo, marker, itemlen+1, NULL); ++ sn = exif_file_sections_add(ImageInfo, marker, itemlen, NULL); + Data = ImageInfo->file.list[sn].data; + + /* Store first two pre-read bytes. */ +diff --git a/ext/exif/tests/bug79282.phpt b/ext/exif/tests/bug79282.phpt +new file mode 100644 +index 0000000000..7b7e365657 +--- /dev/null ++++ b/ext/exif/tests/bug79282.phpt +@@ -0,0 +1,15 @@ ++--TEST-- ++Bug #79282: Use-of-uninitialized-value in exif ++--FILE-- ++<?php ++ ++var_dump(exif_read_data('data://image/jpeg;base64,/9jhAAlFeGlmAAAg')); ++ ++?> ++--EXPECTF-- ++Warning: exif_read_data(): Invalid TIFF alignment marker in %s on line %d ++ ++Warning: exif_read_data(): File structure corrupted in %s on line %d ++ ++Warning: exif_read_data(): Invalid JPEG file in %s on line %d ++bool(false) +From ad05ad4dbafc29dd23828760d4bfa2be12ccbb1c Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Sun, 15 Mar 2020 17:55:28 -0700 +Subject: [PATCH] Fix test + +(cherry picked from commit 2c081b7e269d0f63cd9d60a40997f18b5cf793be) +--- + ext/exif/tests/bug79282.phpt | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ext/exif/tests/bug79282.phpt b/ext/exif/tests/bug79282.phpt +index 7b7e365657..df91127c9c 100644 +--- a/ext/exif/tests/bug79282.phpt ++++ b/ext/exif/tests/bug79282.phpt +@@ -7,7 +7,7 @@ var_dump(exif_read_data('data://image/jpeg;base64,/9jhAAlFeGlmAAAg')); + + ?> + --EXPECTF-- +-Warning: exif_read_data(): Invalid TIFF alignment marker in %s on line %d ++Warning: exif_read_data(): Missing TIFF alignment marker in %s on line %d + + Warning: exif_read_data(): File structure corrupted in %s on line %d + +From b42b6d0ff774fdced1155cb0c721d91914d619f5 Mon Sep 17 00:00:00 2001 +From: Remi Collet <remi@remirepo.net> +Date: Tue, 17 Mar 2020 07:23:32 +0100 +Subject: [PATCH] fix test + +--- + ext/exif/tests/bug79282.phpt | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/ext/exif/tests/bug79282.phpt b/ext/exif/tests/bug79282.phpt +index df91127c9c..142cf28a6c 100644 +--- a/ext/exif/tests/bug79282.phpt ++++ b/ext/exif/tests/bug79282.phpt +@@ -7,9 +7,9 @@ var_dump(exif_read_data('data://image/jpeg;base64,/9jhAAlFeGlmAAAg')); + + ?> + --EXPECTF-- +-Warning: exif_read_data(): Missing TIFF alignment marker in %s on line %d ++Warning: exif_read_data(%s): Missing TIFF alignment marker in %s on line %d + +-Warning: exif_read_data(): File structure corrupted in %s on line %d ++Warning: exif_read_data(%s): File structure corrupted in %s on line %d + +-Warning: exif_read_data(): Invalid JPEG file in %s on line %d ++Warning: exif_read_data(%s): Invalid JPEG file in %s on line %d + bool(false) diff --git a/php-bug79329.patch b/php-bug79329.patch new file mode 100644 index 0000000..1dedb01 --- /dev/null +++ b/php-bug79329.patch @@ -0,0 +1,54 @@ +From b7b9302660a23a67285e204bc3d7fcf6ba7f6533 Mon Sep 17 00:00:00 2001 +From: Remi Collet <remi@remirepo.net> +Date: Tue, 17 Mar 2020 07:25:12 +0100 +Subject: [PATCH] Fix bug #79329 - get_headers should not accept \0 + +From 0d139c5b94a5f485a66901919e51faddb0371c43 +--- + ext/standard/url.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ext/standard/url.c b/ext/standard/url.c +index 0eac03ee0a..39e5b1b2c2 100644 +--- a/ext/standard/url.c ++++ b/ext/standard/url.c +@@ -660,7 +660,7 @@ PHP_FUNCTION(get_headers) + zval *zcontext = NULL; + php_stream_context *context; + +- if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|lr!", &url, &url_len, &format, &zcontext) == FAILURE) { ++ if (zend_parse_parameters(ZEND_NUM_ARGS(), "p|lr!", &url, &url_len, &format, &zcontext) == FAILURE) { + return; + } + +From 03471e31c9b467d1d8d944e44fa009ef247e81bd Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Sun, 15 Mar 2020 19:35:26 -0700 +Subject: [PATCH] [ci skip] Update NEWS + +(cherry picked from commit c8d21d7728109b0f911033c098cfaeb7438ba1d5) +--- + NEWS | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/NEWS b/NEWS +index 4233a530c1..f0bec6aa69 100644 +--- a/NEWS ++++ b/NEWS +@@ -1,6 +1,16 @@ + PHP NEWS + ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| + ++Backported from 7.2.29 ++ ++- Core: ++ . Fixed bug #79329 (get_headers() silently truncates after a null byte) ++ (CVE-2020-7066) (cmb) ++ ++- EXIF: ++ . Fixed bug #79282 (Use-of-uninitialized-value in exif) (CVE-2020-7064) ++ (Nikita) ++ + Backported from 7.2.28 + + - DOM: diff --git a/php-bug79330.patch b/php-bug79330.patch new file mode 100644 index 0000000..4698880 --- /dev/null +++ b/php-bug79330.patch @@ -0,0 +1,31 @@ +From edd1ff390be461e9ae5c69237358beddee4655a4 Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Mon, 13 Apr 2020 21:00:44 -0700 +Subject: [PATCH] Fix bug #79330 - make all execution modes consistent in + rejecting \0 + +(cherry picked from commit 14fcc813948254b84f382ff537247d8a7e5e0e62) +--- + ext/standard/exec.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/ext/standard/exec.c b/ext/standard/exec.c +index 8af11801ad..02d9539f73 100644 +--- a/ext/standard/exec.c ++++ b/ext/standard/exec.c +@@ -524,6 +524,15 @@ PHP_FUNCTION(shell_exec) + return; + } + ++ if (!command_len) { ++ php_error_docref(NULL, E_WARNING, "Cannot execute a blank command"); ++ RETURN_FALSE; ++ } ++ if (strlen(command) != command_len) { ++ php_error_docref(NULL, E_WARNING, "NULL byte detected. Possible attack"); ++ RETURN_FALSE; ++ } ++ + #ifdef PHP_WIN32 + if ((in=VCWD_POPEN(command, "rt"))==NULL) { + #else diff --git a/php-bug79465.patch b/php-bug79465.patch new file mode 100644 index 0000000..9dd39ab --- /dev/null +++ b/php-bug79465.patch @@ -0,0 +1,58 @@ +From 3a81a8f4d47c1b628da3b3a2db433d8cc7146bba Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Mon, 13 Apr 2020 21:07:04 -0700 +Subject: [PATCH] Fix bug #79465 - use unsigneds as indexes. + +(cherry picked from commit 9d6bf8221b05f86ce5875832f0f646c4c1f218be) +--- + ext/standard/url.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/ext/standard/url.c b/ext/standard/url.c +index 39e5b1b2c2..4cc1f77aec 100644 +--- a/ext/standard/url.c ++++ b/ext/standard/url.c +@@ -540,7 +540,7 @@ PHPAPI size_t php_url_decode(char *str, size_t len) + #ifndef CHARSET_EBCDIC + *dest = (char) php_htoi(data + 1); + #else +- *dest = os_toebcdic[(char) php_htoi(data + 1)]; ++ *dest = os_toebcdic[(unsigned char) php_htoi(data + 1)]; + #endif + data += 2; + len -= 2; +@@ -632,7 +632,7 @@ PHPAPI size_t php_raw_url_decode(char *str, size_t len) + #ifndef CHARSET_EBCDIC + *dest = (char) php_htoi(data + 1); + #else +- *dest = os_toebcdic[(char) php_htoi(data + 1)]; ++ *dest = os_toebcdic[(unsigned char) php_htoi(data + 1)]; + #endif + data += 2; + len -= 2; +From bd4a5ebe653f36ea7705fbc95a6ec4842d7f86fc Mon Sep 17 00:00:00 2001 +From: Remi Collet <remi@remirepo.net> +Date: Tue, 14 Apr 2020 08:02:28 +0200 +Subject: [PATCH] NEWS + +--- + NEWS | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/NEWS b/NEWS +index f0bec6aa69..cc1e992229 100644 +--- a/NEWS ++++ b/NEWS +@@ -1,6 +1,12 @@ + PHP NEWS + ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| + ++Backported from 7.2.30 ++ ++- Standard: ++ . Fixed bug #79330 (shell_exec silently truncates after a null byte). (stas) ++ . Fixed bug #79465 (OOB Read in urldecode). (CVE-2020-7067) (stas) ++ + Backported from 7.2.29 + + - Core: diff --git a/php-bug79601.patch b/php-bug79601.patch new file mode 100644 index 0000000..b377887 --- /dev/null +++ b/php-bug79601.patch @@ -0,0 +1,217 @@ +From 3528f51fe33944ba7bab263a47c49dd1d7dd12e3 Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Sat, 26 Sep 2020 22:08:52 -0700 +Subject: [PATCH] Fix bug #79601 (Wrong ciphertext/tag in AES-CCM encryption + for a 12 bytes IV) + +(cherry picked from commit 0216630ea2815a5789a24279a1211ac398d4de79) +--- + ext/openssl/openssl.c | 10 ++++----- + ext/openssl/tests/cipher_tests.inc | 21 +++++++++++++++++ + ext/openssl/tests/openssl_decrypt_ccm.phpt | 22 +++++++++++------- + ext/openssl/tests/openssl_encrypt_ccm.phpt | 26 ++++++++++++++-------- + 4 files changed, 57 insertions(+), 22 deletions(-) + +diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c +index 39b6a20473..21c5367f72 100644 +--- a/ext/openssl/openssl.c ++++ b/ext/openssl/openssl.c +@@ -6216,11 +6216,6 @@ static int php_openssl_validate_iv(char **piv, size_t *piv_len, size_t iv_requir + { + char *iv_new; + +- /* Best case scenario, user behaved */ +- if (*piv_len == iv_required_len) { +- return SUCCESS; +- } +- + if (mode->is_aead) { + if (EVP_CIPHER_CTX_ctrl(cipher_ctx, mode->aead_ivlen_flag, *piv_len, NULL) != 1) { + php_error_docref(NULL, E_WARNING, "Setting of IV length for AEAD mode failed"); +@@ -6229,6 +6224,11 @@ static int php_openssl_validate_iv(char **piv, size_t *piv_len, size_t iv_requir + return SUCCESS; + } + ++ /* Best case scenario, user behaved */ ++ if (*piv_len == iv_required_len) { ++ return SUCCESS; ++ } ++ + iv_new = ecalloc(1, iv_required_len + 1); + + if (*piv_len == 0) { +diff --git a/ext/openssl/tests/cipher_tests.inc b/ext/openssl/tests/cipher_tests.inc +index b1e46b411e..779bfa8515 100644 +--- a/ext/openssl/tests/cipher_tests.inc ++++ b/ext/openssl/tests/cipher_tests.inc +@@ -1,5 +1,26 @@ + <?php + $php_openssl_cipher_tests = array( ++ 'aes-128-ccm' => array( ++ array( ++ 'key' => '404142434445464748494a4b4c4d4e4f', ++ 'iv' => '1011121314151617', ++ 'aad' => '000102030405060708090a0b0c0d0e0f', ++ 'tag' => '1fc64fbfaccd', ++ 'pt' => '202122232425262728292a2b2c2d2e2f', ++ 'ct' => 'd2a1f0e051ea5f62081a7792073d593d', ++ ), ++ array( ++ 'key' => '404142434445464748494a4b4c4d4e4f', ++ 'iv' => '101112131415161718191a1b', ++ 'aad' => '000102030405060708090a0b0c0d0e0f' . ++ '10111213', ++ 'tag' => '484392fbc1b09951', ++ 'pt' => '202122232425262728292a2b2c2d2e2f' . ++ '3031323334353637', ++ 'ct' => 'e3b201a9f5b71a7a9b1ceaeccd97e70b' . ++ '6176aad9a4428aa5', ++ ), ++ ), + 'aes-256-ccm' => array( + array( + 'key' => '1bde3251d41a8b5ea013c195ae128b21' . +diff --git a/ext/openssl/tests/openssl_decrypt_ccm.phpt b/ext/openssl/tests/openssl_decrypt_ccm.phpt +index 87b6d4b264..479114719a 100644 +--- a/ext/openssl/tests/openssl_decrypt_ccm.phpt ++++ b/ext/openssl/tests/openssl_decrypt_ccm.phpt +@@ -10,14 +10,16 @@ if (!in_array('aes-256-ccm', openssl_get_cipher_methods())) + --FILE-- + <?php + require_once __DIR__ . "/cipher_tests.inc"; +-$method = 'aes-256-ccm'; +-$tests = openssl_get_cipher_tests($method); ++$methods = ['aes-128-ccm', 'aes-256-ccm']; + +-foreach ($tests as $idx => $test) { +- echo "TEST $idx\n"; +- $pt = openssl_decrypt($test['ct'], $method, $test['key'], OPENSSL_RAW_DATA, +- $test['iv'], $test['tag'], $test['aad']); +- var_dump($test['pt'] === $pt); ++foreach ($methods as $method) { ++ $tests = openssl_get_cipher_tests($method); ++ foreach ($tests as $idx => $test) { ++ echo "$method - TEST $idx\n"; ++ $pt = openssl_decrypt($test['ct'], $method, $test['key'], OPENSSL_RAW_DATA, ++ $test['iv'], $test['tag'], $test['aad']); ++ var_dump($test['pt'] === $pt); ++ } + } + + // no IV +@@ -32,7 +34,11 @@ var_dump(openssl_decrypt($test['ct'], $method, $test['key'], OPENSSL_RAW_DATA, + + ?> + --EXPECTF-- +-TEST 0 ++aes-128-ccm - TEST 0 ++bool(true) ++aes-128-ccm - TEST 1 ++bool(true) ++aes-256-ccm - TEST 0 + bool(true) + + Warning: openssl_decrypt(): Setting of IV length for AEAD mode failed in %s on line %d +diff --git a/ext/openssl/tests/openssl_encrypt_ccm.phpt b/ext/openssl/tests/openssl_encrypt_ccm.phpt +index c8610bc96b..64a3b758e2 100644 +--- a/ext/openssl/tests/openssl_encrypt_ccm.phpt ++++ b/ext/openssl/tests/openssl_encrypt_ccm.phpt +@@ -10,15 +10,17 @@ if (!in_array('aes-256-ccm', openssl_get_cipher_methods())) + --FILE-- + <?php + require_once __DIR__ . "/cipher_tests.inc"; +-$method = 'aes-256-ccm'; +-$tests = openssl_get_cipher_tests($method); ++$methods = ['aes-128-ccm', 'aes-256-ccm']; + +-foreach ($tests as $idx => $test) { +- echo "TEST $idx\n"; +- $ct = openssl_encrypt($test['pt'], $method, $test['key'], OPENSSL_RAW_DATA, +- $test['iv'], $tag, $test['aad'], strlen($test['tag'])); +- var_dump($test['ct'] === $ct); +- var_dump($test['tag'] === $tag); ++foreach ($methods as $method) { ++ $tests = openssl_get_cipher_tests($method); ++ foreach ($tests as $idx => $test) { ++ echo "$method - TEST $idx\n"; ++ $ct = openssl_encrypt($test['pt'], $method, $test['key'], OPENSSL_RAW_DATA, ++ $test['iv'], $tag, $test['aad'], strlen($test['tag'])); ++ var_dump($test['ct'] === $ct); ++ var_dump($test['tag'] === $tag); ++ } + } + + // Empty IV error +@@ -29,7 +31,13 @@ var_dump(openssl_encrypt('data', $method, 'password', 0, str_repeat('x', 10), $t + var_dump(strlen($tag)); + ?> + --EXPECTF-- +-TEST 0 ++aes-128-ccm - TEST 0 ++bool(true) ++bool(true) ++aes-128-ccm - TEST 1 ++bool(true) ++bool(true) ++aes-256-ccm - TEST 0 + bool(true) + bool(true) + +From 74495ac743e1896c3b33c954fcef54b412f87ac9 Mon Sep 17 00:00:00 2001 +From: Jakub Zelenka <bukka@php.net> +Date: Sun, 2 Jun 2019 19:10:56 +0100 +Subject: [PATCH] Fix bug #78079 (openssl_encrypt_ccm.phpt fails with OpenSSL + 1.1.1c) + +It also fixes invalid setting of tag length + +(cherry picked from commit 2e025794745e09f7d0c72822ad0238bf6d67b2e8) +--- + ext/openssl/openssl.c | 5 ++++- + ext/openssl/tests/openssl_encrypt_ccm.phpt | 12 +++++++++--- + 2 files changed, 13 insertions(+), 4 deletions(-) + +diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c +index 21c5367f72..72db9941d4 100644 +--- a/ext/openssl/openssl.c ++++ b/ext/openssl/openssl.c +@@ -6289,7 +6289,10 @@ static int php_openssl_cipher_init(const EVP_CIPHER *cipher_type, + return FAILURE; + } + if (mode->is_single_run_aead && enc) { +- EVP_CIPHER_CTX_ctrl(cipher_ctx, mode->aead_set_tag_flag, tag_len, NULL); ++ if (!EVP_CIPHER_CTX_ctrl(cipher_ctx, mode->aead_set_tag_flag, tag_len, NULL)) { ++ php_error_docref(NULL, E_WARNING, "Setting tag length for AEAD cipher failed"); ++ return FAILURE; ++ } + } else if (!enc && tag && tag_len > 0) { + if (!mode->is_aead) { + php_error_docref(NULL, E_WARNING, "The tag cannot be used because the cipher method does not support AEAD"); +diff --git a/ext/openssl/tests/openssl_encrypt_ccm.phpt b/ext/openssl/tests/openssl_encrypt_ccm.phpt +index 64a3b758e2..8c4c41f818 100644 +--- a/ext/openssl/tests/openssl_encrypt_ccm.phpt ++++ b/ext/openssl/tests/openssl_encrypt_ccm.phpt +@@ -26,9 +26,12 @@ foreach ($methods as $method) { + // Empty IV error + var_dump(openssl_encrypt('data', $method, 'password', 0, NULL, $tag, '')); + +-// Test setting different IV length and unlimeted tag +-var_dump(openssl_encrypt('data', $method, 'password', 0, str_repeat('x', 10), $tag, '', 1024)); ++// Test setting different IV length and tag length ++var_dump(openssl_encrypt('data', $method, 'password', 0, str_repeat('x', 10), $tag, '', 14)); + var_dump(strlen($tag)); ++ ++// Test setting invalid tag length ++var_dump(openssl_encrypt('data', $method, 'password', 0, str_repeat('x', 16), $tag, '', 1024)); + ?> + --EXPECTF-- + aes-128-ccm - TEST 0 +@@ -44,4 +47,7 @@ bool(true) + Warning: openssl_encrypt(): Setting of IV length for AEAD mode failed in %s on line %d + bool(false) + string(8) "p/lvgA==" +-int(1024) ++int(14) ++ ++Warning: openssl_encrypt(): Setting of IV length for AEAD mode failed in %s on line %d ++bool(false) diff --git a/php-bug79699.patch b/php-bug79699.patch new file mode 100644 index 0000000..88e7bba --- /dev/null +++ b/php-bug79699.patch @@ -0,0 +1,148 @@ +From 72f993acb5de39ca5f01146ff33ff63dc110b8b4 Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Sun, 20 Sep 2020 18:08:55 -0700 +Subject: [PATCH] Do not decode cookie names anymore + +(cherry picked from commit 6559fe912661ca5ce5f0eeeb591d928451428ed0) +--- + main/php_variables.c | 8 ++++++-- + tests/basic/022.phpt | 10 +++++++--- + tests/basic/023.phpt | 4 +++- + tests/basic/bug79699.phpt | 22 ++++++++++++++++++++++ + 4 files changed, 38 insertions(+), 6 deletions(-) + create mode 100644 tests/basic/bug79699.phpt + +diff --git a/main/php_variables.c b/main/php_variables.c +index c56d23003c..d0223df44a 100644 +--- a/main/php_variables.c ++++ b/main/php_variables.c +@@ -484,7 +484,9 @@ SAPI_API SAPI_TREAT_DATA_FUNC(php_default_treat_data) + size_t new_val_len; + + *val++ = '\0'; +- php_url_decode(var, strlen(var)); ++ if (arg != PARSE_COOKIE) { ++ php_url_decode(var, strlen(var)); ++ } + val_len = php_url_decode(val, strlen(val)); + val = estrndup(val, val_len); + if (sapi_module.input_filter(arg, var, &val, val_len, &new_val_len)) { +@@ -495,7 +497,9 @@ SAPI_API SAPI_TREAT_DATA_FUNC(php_default_treat_data) + size_t val_len; + size_t new_val_len; + +- php_url_decode(var, strlen(var)); ++ if (arg != PARSE_COOKIE) { ++ php_url_decode(var, strlen(var)); ++ } + val_len = 0; + val = estrndup("", val_len); + if (sapi_module.input_filter(arg, var, &val, val_len, &new_val_len)) { +diff --git a/tests/basic/022.phpt b/tests/basic/022.phpt +index 0ab70d4be7..bd1db13701 100644 +--- a/tests/basic/022.phpt ++++ b/tests/basic/022.phpt +@@ -10,7 +10,7 @@ cookie1=val1 ; cookie2=val2%20; cookie3=val 3.; cookie 4= value 4 %3B; cookie1= + var_dump($_COOKIE); + ?> + --EXPECT-- +-array(10) { ++array(12) { + ["cookie1"]=> + string(6) "val1 " + ["cookie2"]=> +@@ -19,11 +19,15 @@ array(10) { + string(6) "val 3." + ["cookie_4"]=> + string(10) " value 4 ;" ++ ["%20cookie1"]=> ++ string(6) "ignore" ++ ["+cookie1"]=> ++ string(6) "ignore" + ["cookie__5"]=> + string(7) " value" +- ["cookie_6"]=> ++ ["cookie%206"]=> + string(3) "þæö" +- ["cookie_7"]=> ++ ["cookie+7"]=> + string(0) "" + ["$cookie_8"]=> + string(0) "" +diff --git a/tests/basic/023.phpt b/tests/basic/023.phpt +index ca5f1dcfbb..0e2e0ac669 100644 +--- a/tests/basic/023.phpt ++++ b/tests/basic/023.phpt +@@ -10,9 +10,11 @@ c o o k i e=value; c o o k i e= v a l u e ;;c%20o+o k+i%20e=v;name="value","valu + var_dump($_COOKIE); + ?> + --EXPECT-- +-array(3) { ++array(4) { + ["c_o_o_k_i_e"]=> + string(5) "value" ++ ["c%20o+o_k+i%20e"]=> ++ string(1) "v" + ["name"]=> + string(24) ""value","value",UEhQIQ==" + ["UEhQIQ"]=> +diff --git a/tests/basic/bug79699.phpt b/tests/basic/bug79699.phpt +new file mode 100644 +index 0000000000..fc3d3fedb0 +--- /dev/null ++++ b/tests/basic/bug79699.phpt +@@ -0,0 +1,22 @@ ++--TEST-- ++Cookies Security Bug ++--INI-- ++max_input_vars=1000 ++filter.default=unsafe_raw ++--COOKIE-- ++__%48ost-evil=evil; __Host-evil=good; %66oo=baz;foo=bar ++--FILE-- ++<?php ++var_dump($_COOKIE); ++?> ++--EXPECT-- ++array(4) { ++ ["__%48ost-evil"]=> ++ string(4) "evil" ++ ["__Host-evil"]=> ++ string(4) "good" ++ ["%66oo"]=> ++ string(3) "baz" ++ ["foo"]=> ++ string(3) "bar" ++} +From ff5acd41c3498c1bf78f2803bbef89f006cbffb8 Mon Sep 17 00:00:00 2001 +From: Remi Collet <remi@remirepo.net> +Date: Tue, 29 Sep 2020 08:53:26 +0200 +Subject: [PATCH] NEWS + +--- + NEWS | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/NEWS b/NEWS +index 2c340eb648..bc49257774 100644 +--- a/NEWS ++++ b/NEWS +@@ -1,6 +1,18 @@ + PHP NEWS + ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| + ++Backported from 7.2.34 ++ ++- Core: ++ . Fixed bug #79699 (PHP parses encoded cookie names so malicious `__Host-` ++ cookies can be sent). (CVE-2020-7070) (Stas) ++ ++- OpenSSL: ++ . Fixed bug #79601 (Wrong ciphertext/tag in AES-CCM encryption for a 12 ++ bytes IV). (CVE-2020-7069) (Jakub Zelenka) ++ . Fixed bug #78079 (openssl_encrypt_ccm.phpt fails with OpenSSL 1.1.1c). ++ (Jakub Zelenka) ++ + Backported from 7.2.33 + + - Core: diff --git a/php-bug79797.patch b/php-bug79797.patch new file mode 100644 index 0000000..9c964ca --- /dev/null +++ b/php-bug79797.patch @@ -0,0 +1,48 @@ +From bdf9d2ee3a565fef3160690d7a0dd06218e6efc0 Mon Sep 17 00:00:00 2001 +From: "Christoph M. Becker" <cmbecker69@gmx.de> +Date: Tue, 14 Jul 2020 17:04:24 +0200 +Subject: [PATCH] Fix #79797: Use of freed hash key in the phar_parse_zipfile + function + +We must not use heap memory after we freed it. + +(cherry picked from commit 7355ab81763a3d6a04ac11660e6a16d58838d187) +--- + NEWS | 6 ++++++ + ext/phar/tests/bug79797.phar | Bin 0 -> 274 bytes + ext/phar/tests/bug79797.phpt | 14 ++++++++++++++ + ext/phar/zip.c | 2 +- + 4 files changed, 21 insertions(+), 1 deletion(-) + create mode 100644 ext/phar/tests/bug79797.phar + create mode 100644 ext/phar/tests/bug79797.phpt + +diff --git a/NEWS b/NEWS +index 19fbb3adf2..69361ae49a 100644 +--- a/NEWS ++++ b/NEWS +@@ -1,6 +1,12 @@ + PHP NEWS + ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| + ++Backported from 7.2.33 ++ ++- Phar: ++ . Fixed bug #79797 (Use of freed hash key in the phar_parse_zipfile ++ function). (CVE-2020-7068) (cmb) ++ + Backported from 7.2.31 + + - Core: +diff --git a/ext/phar/zip.c b/ext/phar/zip.c +index d615e8adda..50c5d69e9b 100644 +--- a/ext/phar/zip.c ++++ b/ext/phar/zip.c +@@ -703,7 +703,7 @@ int phar_parse_zipfile(php_stream *fp, char *fname, int fname_len, char *alias, + efree(actual_alias); + } + +- zend_hash_str_add_ptr(&(PHAR_G(phar_alias_map)), actual_alias, mydata->alias_len, mydata); ++ zend_hash_str_add_ptr(&(PHAR_G(phar_alias_map)), mydata->alias, mydata->alias_len, mydata); + } else { + phar_archive_data *fd_ptr; + diff --git a/php-bug79877.patch b/php-bug79877.patch new file mode 100644 index 0000000..25738d7 --- /dev/null +++ b/php-bug79877.patch @@ -0,0 +1,62 @@ +From 2c27d6bdd38bd8c4a27da5aded3477457e72c639 Mon Sep 17 00:00:00 2001 +From: "Christoph M. Becker" <cmbecker69@gmx.de> +Date: Tue, 21 Jul 2020 11:07:43 +0200 +Subject: [PATCH] Fix #79877: getimagesize function silently truncates after a + null byte + +We have to check for NUL bytes if `getimagesize()` has been called. + +(cherry picked from commit ff577b04c0d250473a0ef46f8e332960fec3ca2c) +--- + NEWS | 4 ++++ + ext/standard/image.c | 5 +++++ + ext/standard/tests/image/bug79877.phpt | 9 +++++++++ + 3 files changed, 18 insertions(+) + create mode 100644 ext/standard/tests/image/bug79877.phpt + +diff --git a/NEWS b/NEWS +index 69361ae49a..2c340eb648 100644 +--- a/NEWS ++++ b/NEWS +@@ -3,6 +3,10 @@ PHP NEWS + + Backported from 7.2.33 + ++- Core: ++ . Fixed bug #79877 (getimagesize function silently truncates after a null ++ byte) (cmb) ++ + - Phar: + . Fixed bug #79797 (Use of freed hash key in the phar_parse_zipfile + function). (CVE-2020-7068) (cmb) +diff --git a/ext/standard/image.c b/ext/standard/image.c +index 1d999ca1b9..a5a86c2b52 100644 +--- a/ext/standard/image.c ++++ b/ext/standard/image.c +@@ -1474,6 +1474,11 @@ static void php_getimagesize_from_any(INTERNAL_FUNCTION_PARAMETERS, int mode) { + return; + } + ++ if (mode == FROM_PATH && CHECK_NULL_PATH(input, input_len)) { ++ php_error_docref(NULL, E_WARNING, "Invalid path"); ++ return; ++ } ++ + if (argc == 2) { + zval_dtor(info); + array_init(info); +diff --git a/ext/standard/tests/image/bug79877.phpt b/ext/standard/tests/image/bug79877.phpt +new file mode 100644 +index 0000000000..92e93e59e5 +--- /dev/null ++++ b/ext/standard/tests/image/bug79877.phpt +@@ -0,0 +1,9 @@ ++--TEST-- ++Bug #79877 (getimagesize function silently truncates after a null byte) ++--FILE-- ++<?php ++var_dump(getimagesize("/tmp/a.png\0xx")); ++?> ++--EXPECTF-- ++Warning: getimagesize(): Invalid path in %s on line %d ++NULL diff --git a/php-bug79971.patch b/php-bug79971.patch new file mode 100644 index 0000000..3dca0ec --- /dev/null +++ b/php-bug79971.patch @@ -0,0 +1,207 @@ +From cdabc241c4f631ffa87e2652fe241184f519618f Mon Sep 17 00:00:00 2001 +From: "Christoph M. Becker" <cmbecker69@gmx.de> +Date: Tue, 1 Sep 2020 10:04:28 +0200 +Subject: [PATCH 1/3] Fix #79971: special character is breaking the path in xml + function + +The libxml based XML functions accepting a filename actually accept +URIs with possibly percent-encoded characters. Percent-encoded NUL +bytes lead to truncation, like non-encoded NUL bytes would. We catch +those, and let the functions fail with a respective warning. + +(cherry picked from commit f15f8fc573eb38c3c73e23e0930063a6f6409ed4) +--- + ext/dom/domimplementation.c | 5 +++++ + ext/dom/tests/bug79971_2.phpt | 20 ++++++++++++++++++++ + ext/libxml/libxml.c | 9 +++++++++ + ext/simplexml/tests/bug79971_1.phpt | 27 +++++++++++++++++++++++++++ + ext/simplexml/tests/bug79971_1.xml | 2 ++ + 5 files changed, 63 insertions(+) + create mode 100644 ext/dom/tests/bug79971_2.phpt + create mode 100644 ext/simplexml/tests/bug79971_1.phpt + create mode 100644 ext/simplexml/tests/bug79971_1.xml + +diff --git a/ext/dom/domimplementation.c b/ext/dom/domimplementation.c +index 28e35eb785..f4d1358b8e 100644 +--- a/ext/dom/domimplementation.c ++++ b/ext/dom/domimplementation.c +@@ -114,6 +114,11 @@ PHP_METHOD(domimplementation, createDocumentType) + pch2 = (xmlChar *) systemid; + } + ++ if (strstr(name, "%00")) { ++ php_error_docref(NULL, E_WARNING, "URI must not contain percent-encoded NUL bytes"); ++ RETURN_FALSE; ++ } ++ + uri = xmlParseURI(name); + if (uri != NULL && uri->opaque != NULL) { + localname = xmlStrdup((xmlChar *) uri->opaque); +diff --git a/ext/dom/tests/bug79971_2.phpt b/ext/dom/tests/bug79971_2.phpt +new file mode 100644 +index 0000000000..c4e6b1e4e0 +--- /dev/null ++++ b/ext/dom/tests/bug79971_2.phpt +@@ -0,0 +1,20 @@ ++--TEST-- ++Bug #79971 (special character is breaking the path in xml function) ++--SKIPIF-- ++<?php ++if (!extension_loaded('dom')) die('skip dom extension not available'); ++?> ++--FILE-- ++<?php ++$imp = new DOMImplementation; ++if (PHP_OS_FAMILY === 'Windows') { ++ $path = '/' . str_replace('\\', '/', __DIR__); ++} else { ++ $path = __DIR__; ++} ++$uri = "file://$path/bug79971_2.xml"; ++var_dump($imp->createDocumentType("$uri%00foo")); ++?> ++--EXPECTF-- ++Warning: DOMImplementation::createDocumentType(): URI must not contain percent-encoded NUL bytes in %s on line %d ++bool(false) +diff --git a/ext/libxml/libxml.c b/ext/libxml/libxml.c +index 85f239d5c7..98344d1d56 100644 +--- a/ext/libxml/libxml.c ++++ b/ext/libxml/libxml.c +@@ -308,6 +308,10 @@ static void *php_libxml_streams_IO_open_wrapper(const char *filename, const char + int isescaped=0; + xmlURI *uri; + ++ if (strstr(filename, "%00")) { ++ php_error_docref(NULL, E_WARNING, "URI must not contain percent-encoded NUL bytes"); ++ return NULL; ++ } + + uri = xmlParseURI(filename); + if (uri && (uri->scheme == NULL || +@@ -438,6 +442,11 @@ php_libxml_output_buffer_create_filename(const char *URI, + if (URI == NULL) + return(NULL); + ++ if (strstr(URI, "%00")) { ++ php_error_docref(NULL, E_WARNING, "URI must not contain percent-encoded NUL bytes"); ++ return NULL; ++ } ++ + puri = xmlParseURI(URI); + if (puri != NULL) { + if (puri->scheme != NULL) +diff --git a/ext/simplexml/tests/bug79971_1.phpt b/ext/simplexml/tests/bug79971_1.phpt +new file mode 100644 +index 0000000000..197776d82d +--- /dev/null ++++ b/ext/simplexml/tests/bug79971_1.phpt +@@ -0,0 +1,27 @@ ++--TEST-- ++Bug #79971 (special character is breaking the path in xml function) ++--SKIPIF-- ++<?php ++if (!extension_loaded('simplexml')) die('skip simplexml extension not available'); ++?> ++--FILE-- ++<?php ++if (PHP_OS_FAMILY === 'Windows') { ++ $path = '/' . str_replace('\\', '/', __DIR__); ++} else { ++ $path = __DIR__; ++} ++$uri = "file://$path/bug79971_1.xml"; ++var_dump(simplexml_load_file("$uri%00foo")); ++ ++$sxe = simplexml_load_file($uri); ++var_dump($sxe->asXML("$uri.out%00foo")); ++?> ++--EXPECTF-- ++Warning: simplexml_load_file(): URI must not contain percent-encoded NUL bytes in %s on line %d ++ ++Warning: simplexml_load_file(): I/O warning : failed to load external entity "%s/bug79971_1.xml%00foo" in %s on line %d ++bool(false) ++ ++Warning: SimpleXMLElement::asXML(): URI must not contain percent-encoded NUL bytes in %s on line %d ++bool(false) +diff --git a/ext/simplexml/tests/bug79971_1.xml b/ext/simplexml/tests/bug79971_1.xml +new file mode 100644 +index 0000000000..912bb76d9d +--- /dev/null ++++ b/ext/simplexml/tests/bug79971_1.xml +@@ -0,0 +1,2 @@ ++<?xml version="1.0"?> ++<root></root> +-- +2.31.1 + +From d2a6660b7942b3b8e4f0e31f3b061dacb4d0b87d Mon Sep 17 00:00:00 2001 +From: Remi Collet <remi@remirepo.net> +Date: Mon, 15 Nov 2021 09:05:33 +0100 +Subject: [PATCH 2/3] NEWS + +(cherry picked from commit c032381da0bfb6457aa9cfa7a430790f6eab8178) +--- + NEWS | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/NEWS b/NEWS +index c0e4078a7b..e5c20296ed 100644 +--- a/NEWS ++++ b/NEWS +@@ -1,7 +1,13 @@ + PHP NEWS + ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| + +-Backported from 7.4.25 ++Backported from 7.3.33 ++ ++- XML: ++ . Fix #79971: special character is breaking the path in xml function. ++ (CVE-2021-21707) (cmb) ++ ++Backported from 7.3.32 + + - FPM: + . Fixed bug #81026 (PHP-FPM oob R/W in root process leading to privilege +-- +2.31.1 + +From b21524ff3db15da5a7779cba73e3774eb5404d40 Mon Sep 17 00:00:00 2001 +From: Remi Collet <remi@remirepo.net> +Date: Mon, 15 Nov 2021 09:57:10 +0100 +Subject: [PATCH 3/3] fix new tests + +--- + ext/dom/tests/bug79971_2.phpt | 2 +- + ext/simplexml/tests/bug79971_1.phpt | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/ext/dom/tests/bug79971_2.phpt b/ext/dom/tests/bug79971_2.phpt +index c4e6b1e4e0..01cd123541 100644 +--- a/ext/dom/tests/bug79971_2.phpt ++++ b/ext/dom/tests/bug79971_2.phpt +@@ -7,7 +7,7 @@ if (!extension_loaded('dom')) die('skip dom extension not available'); + --FILE-- + <?php + $imp = new DOMImplementation; +-if (PHP_OS_FAMILY === 'Windows') { ++if (DIRECTORY_SEPARATOR !== '/') { + $path = '/' . str_replace('\\', '/', __DIR__); + } else { + $path = __DIR__; +diff --git a/ext/simplexml/tests/bug79971_1.phpt b/ext/simplexml/tests/bug79971_1.phpt +index 197776d82d..464112c99e 100644 +--- a/ext/simplexml/tests/bug79971_1.phpt ++++ b/ext/simplexml/tests/bug79971_1.phpt +@@ -6,7 +6,7 @@ if (!extension_loaded('simplexml')) die('skip simplexml extension not available' + ?> + --FILE-- + <?php +-if (PHP_OS_FAMILY === 'Windows') { ++if (DIRECTORY_SEPARATOR !== '/') { + $path = '/' . str_replace('\\', '/', __DIR__); + } else { + $path = __DIR__; +-- +2.31.1 + diff --git a/php-bug80672.patch b/php-bug80672.patch new file mode 100644 index 0000000..ab64121 --- /dev/null +++ b/php-bug80672.patch @@ -0,0 +1,239 @@ +From e8cca879720c308fc1dca4fc4447addfaa910528 Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Sun, 31 Jan 2021 21:15:23 -0800 +Subject: [PATCH 1/2] Fix bug #80672 - Null Dereference in SoapClient + +(cherry picked from commit 3c939e3f69955d087e0bb671868f7267dfb2a502) +(cherry picked from commit f1e2cfa008d1596251968d13eb9a8539dba6879f) +--- + NEWS | 5 +++++ + ext/soap/php_sdl.c | 26 ++++++++++++++------------ + ext/soap/php_xml.c | 4 ++-- + ext/soap/tests/bug80672.phpt | 15 +++++++++++++++ + ext/soap/tests/bug80672.xml | 6 ++++++ + 5 files changed, 42 insertions(+), 14 deletions(-) + create mode 100644 ext/soap/tests/bug80672.phpt + create mode 100644 ext/soap/tests/bug80672.xml + +diff --git a/NEWS b/NEWS +index 1f538b891d..9f4bcd9faf 100644 +--- a/NEWS ++++ b/NEWS +@@ -1,6 +1,11 @@ + PHP NEWS + ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| + ++Backported from 7.3.27 ++ ++- SOAP: ++ . Fixed bug #80672 (Null Dereference in SoapClient). (CVE-2021-21702) (cmb, Stas) ++ + Backported from 7.3.26 + + - Standard: +diff --git a/ext/soap/php_sdl.c b/ext/soap/php_sdl.c +index 2485ef2fd8..aef88471a6 100644 +--- a/ext/soap/php_sdl.c ++++ b/ext/soap/php_sdl.c +@@ -314,6 +314,8 @@ void sdl_restore_uri_credentials(sdlCtx *ctx) + ctx->context = NULL; + } + ++#define SAFE_STR(a) ((a)?a:"") ++ + static void load_wsdl_ex(zval *this_ptr, char *struri, sdlCtx *ctx, int include) + { + sdlPtr tmpsdl = ctx->sdl; +@@ -375,7 +377,7 @@ static void load_wsdl_ex(zval *this_ptr, char *struri, sdlCtx *ctx, int include) + if (node_is_equal_ex(trav2, "schema", XSD_NAMESPACE)) { + load_schema(ctx, trav2); + } else if (is_wsdl_element(trav2) && !node_is_equal(trav2,"documentation")) { +- soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", trav2->name); ++ soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", SAFE_STR(trav2->name)); + } + trav2 = trav2->next; + } +@@ -436,7 +438,7 @@ static void load_wsdl_ex(zval *this_ptr, char *struri, sdlCtx *ctx, int include) + soap_error0(E_ERROR, "Parsing WSDL: <service> has no name attribute"); + } + } else if (!node_is_equal(trav,"documentation")) { +- soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", trav->name); ++ soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", SAFE_STR(trav->name)); + } + trav = trav->next; + } +@@ -546,7 +548,7 @@ static sdlSoapBindingFunctionHeaderPtr wsdl_soap_binding_header(sdlCtx* ctx, xml + } + smart_str_free(&key); + } else if (is_wsdl_element(trav) && !node_is_equal(trav,"documentation")) { +- soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", trav->name); ++ soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", SAFE_STR(trav->name)); + } + trav = trav->next; + } +@@ -648,7 +650,7 @@ static void wsdl_soap_binding_body(sdlCtx* ctx, xmlNodePtr node, char* wsdl_soap + } + smart_str_free(&key); + } else if (is_wsdl_element(trav) && !node_is_equal(trav,"documentation")) { +- soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", trav->name); ++ soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", SAFE_STR(trav->name)); + } + trav = trav->next; + } +@@ -680,14 +682,14 @@ static HashTable* wsdl_message(sdlCtx *ctx, xmlChar* message_name) + sdlParamPtr param; + + if (trav->ns != NULL && strcmp((char*)trav->ns->href, WSDL_NAMESPACE) != 0) { +- soap_error1(E_ERROR, "Parsing WSDL: Unexpected extensibility element <%s>", trav->name); ++ soap_error1(E_ERROR, "Parsing WSDL: Unexpected extensibility element <%s>", SAFE_STR(trav->name)); + } + if (node_is_equal(trav,"documentation")) { + trav = trav->next; + continue; + } + if (!node_is_equal(trav,"part")) { +- soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", trav->name); ++ soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", SAFE_STR(trav->name)); + } + part = trav; + param = emalloc(sizeof(sdlParam)); +@@ -696,7 +698,7 @@ static HashTable* wsdl_message(sdlCtx *ctx, xmlChar* message_name) + + name = get_attribute(part->properties, "name"); + if (name == NULL) { +- soap_error1(E_ERROR, "Parsing WSDL: No name associated with <part> '%s'", message->name); ++ soap_error1(E_ERROR, "Parsing WSDL: No name associated with <part> '%s'", SAFE_STR(message->name)); + } + + param->paramName = estrdup((char*)name->children->content); +@@ -765,7 +767,7 @@ static sdlPtr load_wsdl(zval *this_ptr, char *struri) + continue; + } + if (!node_is_equal(trav,"port")) { +- soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", trav->name); ++ soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", SAFE_STR(trav->name)); + } + + port = trav; +@@ -804,7 +806,7 @@ static sdlPtr load_wsdl(zval *this_ptr, char *struri) + } + } + if (trav2 != address && is_wsdl_element(trav2) && !node_is_equal(trav2,"documentation")) { +- soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", trav2->name); ++ soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", SAFE_STR(trav2->name)); + } + trav2 = trav2->next; + } +@@ -906,7 +908,7 @@ static sdlPtr load_wsdl(zval *this_ptr, char *struri) + continue; + } + if (!node_is_equal(trav2,"operation")) { +- soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", trav2->name); ++ soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", SAFE_STR(trav2->name)); + } + + operation = trav2; +@@ -925,7 +927,7 @@ static sdlPtr load_wsdl(zval *this_ptr, char *struri) + !node_is_equal(trav3,"output") && + !node_is_equal(trav3,"fault") && + !node_is_equal(trav3,"documentation")) { +- soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", trav3->name); ++ soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", SAFE_STR(trav3->name)); + } + trav3 = trav3->next; + } +@@ -1103,7 +1105,7 @@ static sdlPtr load_wsdl(zval *this_ptr, char *struri) + } + } + } else if (is_wsdl_element(trav) && !node_is_equal(trav,"documentation")) { +- soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", trav->name); ++ soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", SAFE_STR(trav->name)); + } + trav = trav->next; + } +diff --git a/ext/soap/php_xml.c b/ext/soap/php_xml.c +index bf76e237a9..1ac684eb81 100644 +--- a/ext/soap/php_xml.c ++++ b/ext/soap/php_xml.c +@@ -204,7 +204,7 @@ xmlNsPtr node_find_ns(xmlNodePtr node) + + int attr_is_equal_ex(xmlAttrPtr node, char *name, char *ns) + { +- if (name == NULL || strcmp((char*)node->name, name) == 0) { ++ if (name == NULL || ((node->name) && strcmp((char*)node->name, name) == 0)) { + if (ns) { + xmlNsPtr nsPtr = attr_find_ns(node); + if (nsPtr) { +@@ -220,7 +220,7 @@ int attr_is_equal_ex(xmlAttrPtr node, char *name, char *ns) + + int node_is_equal_ex(xmlNodePtr node, char *name, char *ns) + { +- if (name == NULL || strcmp((char*)node->name, name) == 0) { ++ if (name == NULL || ((node->name) && strcmp((char*)node->name, name) == 0)) { + if (ns) { + xmlNsPtr nsPtr = node_find_ns(node); + if (nsPtr) { +diff --git a/ext/soap/tests/bug80672.phpt b/ext/soap/tests/bug80672.phpt +new file mode 100644 +index 0000000000..71e2b1d841 +--- /dev/null ++++ b/ext/soap/tests/bug80672.phpt +@@ -0,0 +1,15 @@ ++--TEST-- ++Bug #80672 Null Dereference in SoapClient ++--SKIPIF-- ++<?php require_once('skipif.inc'); ?> ++--FILE-- ++<?php ++try { ++ $client = new SoapClient(__DIR__ . "/bug80672.xml"); ++ $query = $soap->query(array('sXML' => 'something')); ++} catch(SoapFault $e) { ++ print $e->getMessage(); ++} ++?> ++--EXPECTF-- ++SOAP-ERROR: Parsing WSDL: Unexpected WSDL element <> +\ No newline at end of file +diff --git a/ext/soap/tests/bug80672.xml b/ext/soap/tests/bug80672.xml +new file mode 100644 +index 0000000000..0fa185bf1e +--- /dev/null ++++ b/ext/soap/tests/bug80672.xml +@@ -0,0 +1,6 @@ ++<?xml version="1.0" encoding="ISO-8859-1"?> ++<soap:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ++ xmlns:xsd="http://www.w3.org/2001/XMLSchema" ++ xmlns:soap="http://schemas.xmlsoap.org/wsdl/"> ++<![CDATA[test]]> ++</soap:definitions> +-- +2.29.2 + +From 64dd5c5f706372001c51188f3bf584745b629758 Mon Sep 17 00:00:00 2001 +From: Nikita Popov <nikita.ppv@gmail.com> +Date: Mon, 1 Feb 2021 09:46:17 +0100 +Subject: [PATCH 2/2] Fix build + +(cherry picked from commit e5d767d27f94895e09f0321562fd3774d4656164) +(cherry picked from commit 02352d5acc1896756dcb4645f54689ffdcc4ca52) +--- + ext/soap/php_sdl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ext/soap/php_sdl.c b/ext/soap/php_sdl.c +index aef88471a6..2375c3ca1c 100644 +--- a/ext/soap/php_sdl.c ++++ b/ext/soap/php_sdl.c +@@ -314,7 +314,7 @@ void sdl_restore_uri_credentials(sdlCtx *ctx) + ctx->context = NULL; + } + +-#define SAFE_STR(a) ((a)?a:"") ++#define SAFE_STR(a) ((a)?((const char *)a):"") + + static void load_wsdl_ex(zval *this_ptr, char *struri, sdlCtx *ctx, int include) + { +-- +2.29.2 + diff --git a/php-bug80710.patch b/php-bug80710.patch new file mode 100644 index 0000000..b24ac42 --- /dev/null +++ b/php-bug80710.patch @@ -0,0 +1,373 @@ +From b259bf84d8ee47c5d0fd990dbf67d3930572f49d Mon Sep 17 00:00:00 2001 +From: "Christoph M. Becker" <cmbecker69@gmx.de> +Date: Fri, 5 Feb 2021 22:51:41 +0100 +Subject: [PATCH 1/2] Fix #80710: imap_mail_compose() header injection + +Like `mail()` and `mb_send_mail()`, `imap_mail_compose()` must prevent +header injection. For maximum backward compatibility, we still allow +header folding for general headers, and still accept trailing line +breaks for address lists. + +(cherry picked from commit 37962c61d29794645ec45d45d78123382d82c2e5) +(cherry picked from commit 9017896cccefe000938f80b49361b1c183849922) +--- + ext/imap/php_imap.c | 56 ++++++++++++++++++++++++++++++++++ + ext/imap/tests/bug80710_1.phpt | 37 ++++++++++++++++++++++ + ext/imap/tests/bug80710_2.phpt | 37 ++++++++++++++++++++++ + 3 files changed, 130 insertions(+) + create mode 100644 ext/imap/tests/bug80710_1.phpt + create mode 100644 ext/imap/tests/bug80710_2.phpt + +diff --git a/ext/imap/php_imap.c b/ext/imap/php_imap.c +index 6ce4b78179..7de074aeeb 100644 +--- a/ext/imap/php_imap.c ++++ b/ext/imap/php_imap.c +@@ -3531,6 +3531,23 @@ PHP_FUNCTION(imap_fetch_overview) + } + /* }}} */ + ++static zend_bool header_injection(zend_string *str, zend_bool adrlist) ++{ ++ char *p = ZSTR_VAL(str); ++ ++ while ((p = strpbrk(p, "\r\n")) != NULL) { ++ if (!(p[0] == '\r' && p[1] == '\n') ++ /* adrlists do not support folding, but swallow trailing line breaks */ ++ && !((adrlist && p[1] == '\0') ++ /* other headers support folding */ ++ || !adrlist && (p[1] == ' ' || p[1] == '\t'))) { ++ return 1; ++ } ++ p++; ++ } ++ return 0; ++} ++ + /* {{{ proto string imap_mail_compose(array envelope, array body) + Create a MIME message based on given envelope and body sections */ + PHP_FUNCTION(imap_mail_compose) +@@ -3551,6 +3568,13 @@ PHP_FUNCTION(imap_mail_compose) + return; + } + ++#define CHECK_HEADER_INJECTION(zstr, adrlist, header) \ ++ if (header_injection(zstr, adrlist)) { \ ++ php_error_docref(NULL, E_WARNING, "header injection attempt in " header); \ ++ RETVAL_FALSE; \ ++ goto done; \ ++ } ++ + #define PHP_RFC822_PARSE_ADRLIST(target, value) \ + str_copy = estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value)); \ + rfc822_parse_adrlist(target, str_copy, "NO HOST"); \ +@@ -3559,46 +3583,57 @@ PHP_FUNCTION(imap_mail_compose) + env = mail_newenvelope(); + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "remail", sizeof("remail") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "remail"); + env->remail = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "return_path", sizeof("return_path") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "return_path"); + PHP_RFC822_PARSE_ADRLIST(&env->return_path, pvalue); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "date", sizeof("date") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "date"); + env->date = (unsigned char*)cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "from", sizeof("from") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "from"); + PHP_RFC822_PARSE_ADRLIST(&env->from, pvalue); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "reply_to", sizeof("reply_to") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "reply_to"); + PHP_RFC822_PARSE_ADRLIST(&env->reply_to, pvalue); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "in_reply_to", sizeof("in_reply_to") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "in_reply_to"); + env->in_reply_to = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "subject", sizeof("subject") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "subject"); + env->subject = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "to", sizeof("to") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "to"); + PHP_RFC822_PARSE_ADRLIST(&env->to, pvalue); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "cc", sizeof("cc") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "cc"); + PHP_RFC822_PARSE_ADRLIST(&env->cc, pvalue); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "bcc", sizeof("bcc") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "bcc"); + PHP_RFC822_PARSE_ADRLIST(&env->bcc, pvalue); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "message_id", sizeof("message_id") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "message_id"); + env->message_id=cpystr(Z_STRVAL_P(pvalue)); + } + +@@ -3608,6 +3643,7 @@ PHP_FUNCTION(imap_mail_compose) + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pvalue), env_data) { + custom_headers_param = mail_newbody_parameter(); + convert_to_string_ex(env_data); ++ CHECK_HEADER_INJECTION(Z_STR_P(env_data), 0, "custom_headers"); + custom_headers_param->value = (char *) fs_get(Z_STRLEN_P(env_data) + 1); + custom_headers_param->attribute = NULL; + memcpy(custom_headers_param->value, Z_STRVAL_P(env_data), Z_STRLEN_P(env_data) + 1); +@@ -3640,6 +3676,7 @@ PHP_FUNCTION(imap_mail_compose) + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "charset", sizeof("charset") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body charset"); + tmp_param = mail_newbody_parameter(); + tmp_param->value = cpystr(Z_STRVAL_P(pvalue)); + tmp_param->attribute = cpystr("CHARSET"); +@@ -3650,9 +3687,11 @@ PHP_FUNCTION(imap_mail_compose) + if(Z_TYPE_P(pvalue) == IS_ARRAY) { + disp_param = tmp_param = NULL; + ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pvalue), key, disp_data) { ++ CHECK_HEADER_INJECTION(key, 0, "body disposition key"); + disp_param = mail_newbody_parameter(); + disp_param->attribute = cpystr(ZSTR_VAL(key)); + convert_to_string_ex(disp_data); ++ CHECK_HEADER_INJECTION(Z_STR_P(disp_data), 0, "body disposition value"); + disp_param->value = (char *) fs_get(Z_STRLEN_P(disp_data) + 1); + memcpy(disp_param->value, Z_STRVAL_P(disp_data), Z_STRLEN_P(disp_data) + 1); + disp_param->next = tmp_param; +@@ -3663,18 +3702,22 @@ PHP_FUNCTION(imap_mail_compose) + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "subtype", sizeof("subtype") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body subtype"); + bod->subtype = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "id", sizeof("id") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body id"); + bod->id = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "description", sizeof("description") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body description"); + bod->description = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "disposition.type", sizeof("disposition.type") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body disposition.type"); + bod->disposition.type = (char *) fs_get(Z_STRLEN_P(pvalue) + 1); + memcpy(bod->disposition.type, Z_STRVAL_P(pvalue), Z_STRLEN_P(pvalue)+1); + } +@@ -3682,9 +3725,11 @@ PHP_FUNCTION(imap_mail_compose) + if (Z_TYPE_P(pvalue) == IS_ARRAY) { + disp_param = tmp_param = NULL; + ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pvalue), key, disp_data) { ++ CHECK_HEADER_INJECTION(key, 0, "body type.parameters key"); + disp_param = mail_newbody_parameter(); + disp_param->attribute = cpystr(ZSTR_VAL(key)); + convert_to_string_ex(disp_data); ++ CHECK_HEADER_INJECTION(Z_STR_P(disp_data), 0, "body type.parameters value"); + disp_param->value = (char *) fs_get(Z_STRLEN_P(disp_data) + 1); + memcpy(disp_param->value, Z_STRVAL_P(disp_data), Z_STRLEN_P(disp_data) + 1); + disp_param->next = tmp_param; +@@ -3713,6 +3758,7 @@ PHP_FUNCTION(imap_mail_compose) + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "md5", sizeof("md5") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body md5"); + bod->md5 = cpystr(Z_STRVAL_P(pvalue)); + } + } else if (Z_TYPE_P(data) == IS_ARRAY) { +@@ -3743,6 +3789,7 @@ PHP_FUNCTION(imap_mail_compose) + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "charset", sizeof("charset") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body charset"); + tmp_param = mail_newbody_parameter(); + tmp_param->value = (char *) fs_get(Z_STRLEN_P(pvalue) + 1); + memcpy(tmp_param->value, Z_STRVAL_P(pvalue), Z_STRLEN_P(pvalue) + 1); +@@ -3754,9 +3801,11 @@ PHP_FUNCTION(imap_mail_compose) + if (Z_TYPE_P(pvalue) == IS_ARRAY) { + disp_param = tmp_param = NULL; + ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pvalue), key, disp_data) { ++ CHECK_HEADER_INJECTION(key, 0, "body type.parameters key"); + disp_param = mail_newbody_parameter(); + disp_param->attribute = cpystr(ZSTR_VAL(key)); + convert_to_string_ex(disp_data); ++ CHECK_HEADER_INJECTION(Z_STR_P(disp_data), 0, "body type.parameters value"); + disp_param->value = (char *)fs_get(Z_STRLEN_P(disp_data) + 1); + memcpy(disp_param->value, Z_STRVAL_P(disp_data), Z_STRLEN_P(disp_data) + 1); + disp_param->next = tmp_param; +@@ -3767,18 +3816,22 @@ PHP_FUNCTION(imap_mail_compose) + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "subtype", sizeof("subtype") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body subtype"); + bod->subtype = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "id", sizeof("id") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body id"); + bod->id = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "description", sizeof("description") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body description"); + bod->description = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "disposition.type", sizeof("disposition.type") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body disposition.type"); + bod->disposition.type = (char *) fs_get(Z_STRLEN_P(pvalue) + 1); + memcpy(bod->disposition.type, Z_STRVAL_P(pvalue), Z_STRLEN_P(pvalue)+1); + } +@@ -3786,9 +3839,11 @@ PHP_FUNCTION(imap_mail_compose) + if (Z_TYPE_P(pvalue) == IS_ARRAY) { + disp_param = tmp_param = NULL; + ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pvalue), key, disp_data) { ++ CHECK_HEADER_INJECTION(key, 0, "body disposition key"); + disp_param = mail_newbody_parameter(); + disp_param->attribute = cpystr(ZSTR_VAL(key)); + convert_to_string_ex(disp_data); ++ CHECK_HEADER_INJECTION(Z_STR_P(disp_data), 0, "body disposition value"); + disp_param->value = (char *) fs_get(Z_STRLEN_P(disp_data) + 1); + memcpy(disp_param->value, Z_STRVAL_P(disp_data), Z_STRLEN_P(disp_data) + 1); + disp_param->next = tmp_param; +@@ -3817,6 +3872,7 @@ PHP_FUNCTION(imap_mail_compose) + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "md5", sizeof("md5") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body md5"); + bod->md5 = cpystr(Z_STRVAL_P(pvalue)); + } + } +diff --git a/ext/imap/tests/bug80710_1.phpt b/ext/imap/tests/bug80710_1.phpt +new file mode 100644 +index 0000000000..5cdee03401 +--- /dev/null ++++ b/ext/imap/tests/bug80710_1.phpt +@@ -0,0 +1,37 @@ ++--TEST-- ++Bug #80710 (imap_mail_compose() header injection) - MIME Splitting Attack ++--SKIPIF-- ++<?php ++if (!extension_loaded("imap")) die("skip imap extension not available"); ++?> ++--FILE-- ++<?php ++$envelope["from"]= "joe@example.com\n From : X-INJECTED"; ++$envelope["to"] = "foo@example.com\nFrom: X-INJECTED"; ++$envelope["cc"] = "bar@example.com\nFrom: X-INJECTED"; ++$envelope["subject"] = "bar@example.com\n\n From : X-INJECTED"; ++$envelope["x-remail"] = "bar@example.com\nFrom: X-INJECTED"; ++$envelope["something"] = "bar@example.com\nFrom: X-INJECTED"; ++ ++$part1["type"] = TYPEMULTIPART; ++$part1["subtype"] = "mixed"; ++ ++$part2["type"] = TYPEAPPLICATION; ++$part2["encoding"] = ENCBINARY; ++$part2["subtype"] = "octet-stream\nContent-Type: X-INJECTED"; ++$part2["description"] = "some file\nContent-Type: X-INJECTED"; ++$part2["contents.data"] = "ABC\nContent-Type: X-INJECTED"; ++ ++$part3["type"] = TYPETEXT; ++$part3["subtype"] = "plain"; ++$part3["description"] = "description3"; ++$part3["contents.data"] = "contents.data3\n\n\n\t"; ++ ++$body[1] = $part1; ++$body[2] = $part2; ++$body[3] = $part3; ++ ++echo imap_mail_compose($envelope, $body); ++?> ++--EXPECTF-- ++Warning: imap_mail_compose(): header injection attempt in from in %s on line %d +diff --git a/ext/imap/tests/bug80710_2.phpt b/ext/imap/tests/bug80710_2.phpt +new file mode 100644 +index 0000000000..b9f2fa8544 +--- /dev/null ++++ b/ext/imap/tests/bug80710_2.phpt +@@ -0,0 +1,37 @@ ++--TEST-- ++Bug #80710 (imap_mail_compose() header injection) - Remail ++--SKIPIF-- ++<?php ++if (!extension_loaded("imap")) die("skip imap extension not available"); ++?> ++--FILE-- ++<?php ++$envelope["from"]= "joe@example.com\n From : X-INJECTED"; ++$envelope["to"] = "foo@example.com\nFrom: X-INJECTED"; ++$envelope["cc"] = "bar@example.com\nFrom: X-INJECTED"; ++$envelope["subject"] = "bar@example.com\n\n From : X-INJECTED"; ++$envelope["remail"] = "X-INJECTED-REMAIL: X-INJECTED\nFrom: X-INJECTED-REMAIL-FROM"; //<--- Injected as first hdr ++$envelope["something"] = "bar@example.com\nFrom: X-INJECTED"; ++ ++$part1["type"] = TYPEMULTIPART; ++$part1["subtype"] = "mixed"; ++ ++$part2["type"] = TYPEAPPLICATION; ++$part2["encoding"] = ENCBINARY; ++$part2["subtype"] = "octet-stream\nContent-Type: X-INJECTED"; ++$part2["description"] = "some file\nContent-Type: X-INJECTED"; ++$part2["contents.data"] = "ABC\nContent-Type: X-INJECTED"; ++ ++$part3["type"] = TYPETEXT; ++$part3["subtype"] = "plain"; ++$part3["description"] = "description3"; ++$part3["contents.data"] = "contents.data3\n\n\n\t"; ++ ++$body[1] = $part1; ++$body[2] = $part2; ++$body[3] = $part3; ++ ++echo imap_mail_compose($envelope, $body); ++?> ++--EXPECTF-- ++Warning: imap_mail_compose(): header injection attempt in remail in %s on line %d +-- +2.30.2 + +From 82d71819333bf5483e31e7b9f41e9d25526c3c84 Mon Sep 17 00:00:00 2001 +From: "Christoph M. Becker" <cmbecker69@gmx.de> +Date: Tue, 27 Apr 2021 13:38:39 +0200 +Subject: [PATCH 2/2] Add missing NEWS entry for #80710 + +(cherry picked from commit 60a68a45c3e9f63585151221e7fe9ddff78bd71f) +(cherry picked from commit f16c623ec8ae3f3cdc73ab3fa05ae6bb0a77d1f3) +--- + NEWS | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/NEWS b/NEWS +index 9f4bcd9faf..63295d3b76 100644 +--- a/NEWS ++++ b/NEWS +@@ -1,6 +1,11 @@ + PHP NEWS + ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| + ++Backported from 7.3.28 ++ ++- Imap: ++ . Fixed bug #80710 (imap_mail_compose() header injection). (cmb, Stas) ++ + Backported from 7.3.27 + + - SOAP: +-- +2.30.2 + diff --git a/php-bug81026.patch b/php-bug81026.patch new file mode 100644 index 0000000..9da6398 --- /dev/null +++ b/php-bug81026.patch @@ -0,0 +1,429 @@ +From 169a33e8d990d49c69b40a4dbab4b2f56721693f Mon Sep 17 00:00:00 2001 +From: Jakub Zelenka <bukka@php.net> +Date: Sat, 2 Oct 2021 22:53:41 +0100 +Subject: [PATCH 1/2] Fix bug #81026 (PHP-FPM oob R/W in root process leading + to priv escalation) + +The main change is to store scoreboard procs directly to the variable sized +array rather than indirectly through the pointer. + +Signed-off-by: Stanislav Malyshev <stas@php.net> +(cherry picked from commit cb2021e5f69da5e2868130a05bb53db0f9f89e4b) +--- + sapi/fpm/fpm/fpm_children.c | 14 ++--- + sapi/fpm/fpm/fpm_request.c | 4 +- + sapi/fpm/fpm/fpm_scoreboard.c | 106 ++++++++++++++++++++------------- + sapi/fpm/fpm/fpm_scoreboard.h | 11 ++-- + sapi/fpm/fpm/fpm_status.c | 4 +- + sapi/fpm/fpm/fpm_worker_pool.c | 2 +- + 6 files changed, 81 insertions(+), 60 deletions(-) + +diff --git a/sapi/fpm/fpm/fpm_children.c b/sapi/fpm/fpm/fpm_children.c +index bda85ef5a8..48380de542 100644 +--- a/sapi/fpm/fpm/fpm_children.c ++++ b/sapi/fpm/fpm/fpm_children.c +@@ -239,7 +239,7 @@ void fpm_children_bury() /* {{{ */ + + fpm_child_unlink(child); + +- fpm_scoreboard_proc_free(wp->scoreboard, child->scoreboard_i); ++ fpm_scoreboard_proc_free(child); + + fpm_clock_get(&tv1); + +@@ -249,9 +249,9 @@ void fpm_children_bury() /* {{{ */ + if (!fpm_pctl_can_spawn_children()) { + severity = ZLOG_DEBUG; + } +- zlog(severity, "[pool %s] child %d exited %s after %ld.%06d seconds from start", child->wp->config->name, (int) pid, buf, tv2.tv_sec, (int) tv2.tv_usec); ++ zlog(severity, "[pool %s] child %d exited %s after %ld.%06d seconds from start", wp->config->name, (int) pid, buf, tv2.tv_sec, (int) tv2.tv_usec); + } else { +- zlog(ZLOG_DEBUG, "[pool %s] child %d has been killed by the process management after %ld.%06d seconds from start", child->wp->config->name, (int) pid, tv2.tv_sec, (int) tv2.tv_usec); ++ zlog(ZLOG_DEBUG, "[pool %s] child %d has been killed by the process management after %ld.%06d seconds from start", wp->config->name, (int) pid, tv2.tv_sec, (int) tv2.tv_usec); + } + + fpm_child_close(child, 1 /* in event_loop */); +@@ -317,7 +317,7 @@ static struct fpm_child_s *fpm_resources_prepare(struct fpm_worker_pool_s *wp) / + return 0; + } + +- if (0 > fpm_scoreboard_proc_alloc(wp->scoreboard, &c->scoreboard_i)) { ++ if (0 > fpm_scoreboard_proc_alloc(c)) { + fpm_stdio_discard_pipes(c); + fpm_child_free(c); + return 0; +@@ -329,7 +329,7 @@ static struct fpm_child_s *fpm_resources_prepare(struct fpm_worker_pool_s *wp) / + + static void fpm_resources_discard(struct fpm_child_s *child) /* {{{ */ + { +- fpm_scoreboard_proc_free(child->wp->scoreboard, child->scoreboard_i); ++ fpm_scoreboard_proc_free(child); + fpm_stdio_discard_pipes(child); + fpm_child_free(child); + } +@@ -342,10 +342,10 @@ static void fpm_child_resources_use(struct fpm_child_s *child) /* {{{ */ + if (wp == child->wp) { + continue; + } +- fpm_scoreboard_free(wp->scoreboard); ++ fpm_scoreboard_free(wp); + } + +- fpm_scoreboard_child_use(child->wp->scoreboard, child->scoreboard_i, getpid()); ++ fpm_scoreboard_child_use(child, getpid()); + fpm_stdio_child_use_pipes(child); + fpm_child_free(child); + } +diff --git a/sapi/fpm/fpm/fpm_request.c b/sapi/fpm/fpm/fpm_request.c +index a4ace85310..deaccf432a 100644 +--- a/sapi/fpm/fpm/fpm_request.c ++++ b/sapi/fpm/fpm/fpm_request.c +@@ -286,7 +286,7 @@ int fpm_request_is_idle(struct fpm_child_s *child) /* {{{ */ + struct fpm_scoreboard_proc_s *proc; + + /* no need in atomicity here */ +- proc = fpm_scoreboard_proc_get(child->wp->scoreboard, child->scoreboard_i); ++ proc = fpm_scoreboard_proc_get_from_child(child); + if (!proc) { + return 0; + } +@@ -301,7 +301,7 @@ int fpm_request_last_activity(struct fpm_child_s *child, struct timeval *tv) /* + + if (!tv) return -1; + +- proc = fpm_scoreboard_proc_get(child->wp->scoreboard, child->scoreboard_i); ++ proc = fpm_scoreboard_proc_get_from_child(child); + if (!proc) { + return -1; + } +diff --git a/sapi/fpm/fpm/fpm_scoreboard.c b/sapi/fpm/fpm/fpm_scoreboard.c +index 7a65fcbeb7..091efdc574 100644 +--- a/sapi/fpm/fpm/fpm_scoreboard.c ++++ b/sapi/fpm/fpm/fpm_scoreboard.c +@@ -7,6 +7,7 @@ + #include <time.h> + + #include "fpm_config.h" ++#include "fpm_children.h" + #include "fpm_scoreboard.h" + #include "fpm_shm.h" + #include "fpm_sockets.h" +@@ -24,7 +25,6 @@ static float fpm_scoreboard_tick; + int fpm_scoreboard_init_main() /* {{{ */ + { + struct fpm_worker_pool_s *wp; +- unsigned int i; + + #ifdef HAVE_TIMES + #if (defined(HAVE_SYSCONF) && defined(_SC_CLK_TCK)) +@@ -41,7 +41,7 @@ int fpm_scoreboard_init_main() /* {{{ */ + + + for (wp = fpm_worker_all_pools; wp; wp = wp->next) { +- size_t scoreboard_size, scoreboard_nprocs_size; ++ size_t scoreboard_procs_size; + void *shm_mem; + + if (wp->config->pm_max_children < 1) { +@@ -54,22 +54,15 @@ int fpm_scoreboard_init_main() /* {{{ */ + return -1; + } + +- scoreboard_size = sizeof(struct fpm_scoreboard_s) + (wp->config->pm_max_children) * sizeof(struct fpm_scoreboard_proc_s *); +- scoreboard_nprocs_size = sizeof(struct fpm_scoreboard_proc_s) * wp->config->pm_max_children; +- shm_mem = fpm_shm_alloc(scoreboard_size + scoreboard_nprocs_size); ++ scoreboard_procs_size = sizeof(struct fpm_scoreboard_proc_s) * wp->config->pm_max_children; ++ shm_mem = fpm_shm_alloc(sizeof(struct fpm_scoreboard_s) + scoreboard_procs_size); + + if (!shm_mem) { + return -1; + } +- wp->scoreboard = shm_mem; ++ wp->scoreboard = shm_mem; ++ wp->scoreboard->pm = wp->config->pm; + wp->scoreboard->nprocs = wp->config->pm_max_children; +- shm_mem += scoreboard_size; +- +- for (i = 0; i < wp->scoreboard->nprocs; i++, shm_mem += sizeof(struct fpm_scoreboard_proc_s)) { +- wp->scoreboard->procs[i] = shm_mem; +- } +- +- wp->scoreboard->pm = wp->config->pm; + wp->scoreboard->start_epoch = time(NULL); + strlcpy(wp->scoreboard->pool, wp->config->name, sizeof(wp->scoreboard->pool)); + } +@@ -163,28 +156,48 @@ struct fpm_scoreboard_s *fpm_scoreboard_get() /* {{{*/ + } + /* }}} */ + +-struct fpm_scoreboard_proc_s *fpm_scoreboard_proc_get(struct fpm_scoreboard_s *scoreboard, int child_index) /* {{{*/ ++static inline struct fpm_scoreboard_proc_s *fpm_scoreboard_proc_get_ex( ++ struct fpm_scoreboard_s *scoreboard, int child_index, unsigned int nprocs) /* {{{*/ + { + if (!scoreboard) { +- scoreboard = fpm_scoreboard; ++ return NULL; + } + +- if (!scoreboard) { ++ if (child_index < 0 || (unsigned int)child_index >= nprocs) { + return NULL; + } + ++ return &scoreboard->procs[child_index]; ++} ++/* }}} */ ++ ++struct fpm_scoreboard_proc_s *fpm_scoreboard_proc_get( ++ struct fpm_scoreboard_s *scoreboard, int child_index) /* {{{*/ ++{ ++ if (!scoreboard) { ++ scoreboard = fpm_scoreboard; ++ } ++ + if (child_index < 0) { + child_index = fpm_scoreboard_i; + } + +- if (child_index < 0 || (unsigned int)child_index >= scoreboard->nprocs) { +- return NULL; +- } ++ return fpm_scoreboard_proc_get_ex(scoreboard, child_index, scoreboard->nprocs); ++} ++/* }}} */ + +- return scoreboard->procs[child_index]; ++struct fpm_scoreboard_proc_s *fpm_scoreboard_proc_get_from_child(struct fpm_child_s *child) /* {{{*/ ++{ ++ struct fpm_worker_pool_s *wp = child->wp; ++ unsigned int nprocs = wp->config->pm_max_children; ++ struct fpm_scoreboard_s *scoreboard = wp->scoreboard; ++ int child_index = child->scoreboard_i; ++ ++ return fpm_scoreboard_proc_get_ex(scoreboard, child_index, nprocs); + } + /* }}} */ + ++ + struct fpm_scoreboard_s *fpm_scoreboard_acquire(struct fpm_scoreboard_s *scoreboard, int nohang) /* {{{ */ + { + struct fpm_scoreboard_s *s; +@@ -235,28 +248,28 @@ void fpm_scoreboard_proc_release(struct fpm_scoreboard_proc_s *proc) /* {{{ */ + proc->lock = 0; + } + +-void fpm_scoreboard_free(struct fpm_scoreboard_s *scoreboard) /* {{{ */ ++void fpm_scoreboard_free(struct fpm_worker_pool_s *wp) /* {{{ */ + { +- size_t scoreboard_size, scoreboard_nprocs_size; ++ size_t scoreboard_procs_size; ++ struct fpm_scoreboard_s *scoreboard = wp->scoreboard; + + if (!scoreboard) { + zlog(ZLOG_ERROR, "**scoreboard is NULL"); + return; + } + +- scoreboard_size = sizeof(struct fpm_scoreboard_s) + (scoreboard->nprocs) * sizeof(struct fpm_scoreboard_proc_s *); +- scoreboard_nprocs_size = sizeof(struct fpm_scoreboard_proc_s) * scoreboard->nprocs; ++ scoreboard_procs_size = sizeof(struct fpm_scoreboard_proc_s) * wp->config->pm_max_children; + +- fpm_shm_free(scoreboard, scoreboard_size + scoreboard_nprocs_size); ++ fpm_shm_free(scoreboard, sizeof(struct fpm_scoreboard_s) + scoreboard_procs_size); + } + /* }}} */ + +-void fpm_scoreboard_child_use(struct fpm_scoreboard_s *scoreboard, int child_index, pid_t pid) /* {{{ */ ++void fpm_scoreboard_child_use(struct fpm_child_s *child, pid_t pid) /* {{{ */ + { + struct fpm_scoreboard_proc_s *proc; +- fpm_scoreboard = scoreboard; +- fpm_scoreboard_i = child_index; +- proc = fpm_scoreboard_proc_get(scoreboard, child_index); ++ fpm_scoreboard = child->wp->scoreboard; ++ fpm_scoreboard_i = child->scoreboard_i; ++ proc = fpm_scoreboard_proc_get_from_child(child); + if (!proc) { + return; + } +@@ -265,18 +278,22 @@ void fpm_scoreboard_child_use(struct fpm_scoreboard_s *scoreboard, int child_ind + } + /* }}} */ + +-void fpm_scoreboard_proc_free(struct fpm_scoreboard_s *scoreboard, int child_index) /* {{{ */ ++void fpm_scoreboard_proc_free(struct fpm_child_s *child) /* {{{ */ + { ++ struct fpm_worker_pool_s *wp = child->wp; ++ struct fpm_scoreboard_s *scoreboard = wp->scoreboard; ++ int child_index = child->scoreboard_i; ++ + if (!scoreboard) { + return; + } + +- if (child_index < 0 || (unsigned int)child_index >= scoreboard->nprocs) { ++ if (child_index < 0 || child_index >= wp->config->pm_max_children) { + return; + } + +- if (scoreboard->procs[child_index] && scoreboard->procs[child_index]->used > 0) { +- memset(scoreboard->procs[child_index], 0, sizeof(struct fpm_scoreboard_proc_s)); ++ if (scoreboard->procs[child_index].used > 0) { ++ memset(&scoreboard->procs[child_index], 0, sizeof(struct fpm_scoreboard_proc_s)); + } + + /* set this slot as free to avoid search on next alloc */ +@@ -284,41 +301,44 @@ void fpm_scoreboard_proc_free(struct fpm_scoreboard_s *scoreboard, int child_ind + } + /* }}} */ + +-int fpm_scoreboard_proc_alloc(struct fpm_scoreboard_s *scoreboard, int *child_index) /* {{{ */ ++int fpm_scoreboard_proc_alloc(struct fpm_child_s *child) /* {{{ */ + { + int i = -1; ++ struct fpm_worker_pool_s *wp = child->wp; ++ struct fpm_scoreboard_s *scoreboard = wp->scoreboard; ++ int nprocs = wp->config->pm_max_children; + +- if (!scoreboard || !child_index) { ++ if (!scoreboard) { + return -1; + } + + /* first try the slot which is supposed to be free */ +- if (scoreboard->free_proc >= 0 && (unsigned int)scoreboard->free_proc < scoreboard->nprocs) { +- if (scoreboard->procs[scoreboard->free_proc] && !scoreboard->procs[scoreboard->free_proc]->used) { ++ if (scoreboard->free_proc >= 0 && scoreboard->free_proc < nprocs) { ++ if (!scoreboard->procs[scoreboard->free_proc].used) { + i = scoreboard->free_proc; + } + } + + if (i < 0) { /* the supposed free slot is not, let's search for a free slot */ + zlog(ZLOG_DEBUG, "[pool %s] the proc->free_slot was not free. Let's search", scoreboard->pool); +- for (i = 0; i < (int)scoreboard->nprocs; i++) { +- if (scoreboard->procs[i] && !scoreboard->procs[i]->used) { /* found */ ++ for (i = 0; i < nprocs; i++) { ++ if (!scoreboard->procs[i].used) { /* found */ + break; + } + } + } + + /* no free slot */ +- if (i < 0 || i >= (int)scoreboard->nprocs) { ++ if (i < 0 || i >= nprocs) { + zlog(ZLOG_ERROR, "[pool %s] no free scoreboard slot", scoreboard->pool); + return -1; + } + +- scoreboard->procs[i]->used = 1; +- *child_index = i; ++ scoreboard->procs[i].used = 1; ++ child->scoreboard_i = i; + + /* supposed next slot is free */ +- if (i + 1 >= (int)scoreboard->nprocs) { ++ if (i + 1 >= nprocs) { + scoreboard->free_proc = 0; + } else { + scoreboard->free_proc = i + 1; +diff --git a/sapi/fpm/fpm/fpm_scoreboard.h b/sapi/fpm/fpm/fpm_scoreboard.h +index abce616d76..6405abb7cf 100644 +--- a/sapi/fpm/fpm/fpm_scoreboard.h ++++ b/sapi/fpm/fpm/fpm_scoreboard.h +@@ -64,7 +64,7 @@ struct fpm_scoreboard_s { + unsigned int nprocs; + int free_proc; + unsigned long int slow_rq; +- struct fpm_scoreboard_proc_s *procs[]; ++ struct fpm_scoreboard_proc_s procs[]; + }; + + int fpm_scoreboard_init_main(); +@@ -73,18 +73,19 @@ int fpm_scoreboard_init_child(struct fpm_worker_pool_s *wp); + void fpm_scoreboard_update(int idle, int active, int lq, int lq_len, int requests, int max_children_reached, int slow_rq, int action, struct fpm_scoreboard_s *scoreboard); + struct fpm_scoreboard_s *fpm_scoreboard_get(); + struct fpm_scoreboard_proc_s *fpm_scoreboard_proc_get(struct fpm_scoreboard_s *scoreboard, int child_index); ++struct fpm_scoreboard_proc_s *fpm_scoreboard_proc_get_from_child(struct fpm_child_s *child); + + struct fpm_scoreboard_s *fpm_scoreboard_acquire(struct fpm_scoreboard_s *scoreboard, int nohang); + void fpm_scoreboard_release(struct fpm_scoreboard_s *scoreboard); + struct fpm_scoreboard_proc_s *fpm_scoreboard_proc_acquire(struct fpm_scoreboard_s *scoreboard, int child_index, int nohang); + void fpm_scoreboard_proc_release(struct fpm_scoreboard_proc_s *proc); + +-void fpm_scoreboard_free(struct fpm_scoreboard_s *scoreboard); ++void fpm_scoreboard_free(struct fpm_worker_pool_s *wp); + +-void fpm_scoreboard_child_use(struct fpm_scoreboard_s *scoreboard, int child_index, pid_t pid); ++void fpm_scoreboard_child_use(struct fpm_child_s *child, pid_t pid); + +-void fpm_scoreboard_proc_free(struct fpm_scoreboard_s *scoreboard, int child_index); +-int fpm_scoreboard_proc_alloc(struct fpm_scoreboard_s *scoreboard, int *child_index); ++void fpm_scoreboard_proc_free(struct fpm_child_s *child); ++int fpm_scoreboard_proc_alloc(struct fpm_child_s *child); + + #ifdef HAVE_TIMES + float fpm_scoreboard_get_tick(); +diff --git a/sapi/fpm/fpm/fpm_status.c b/sapi/fpm/fpm/fpm_status.c +index 1d78ebf849..45852a5b39 100644 +--- a/sapi/fpm/fpm/fpm_status.c ++++ b/sapi/fpm/fpm/fpm_status.c +@@ -402,10 +402,10 @@ int fpm_status_handle_request(void) /* {{{ */ + + first = 1; + for (i=0; i<scoreboard_p->nprocs; i++) { +- if (!scoreboard_p->procs[i] || !scoreboard_p->procs[i]->used) { ++ if (!scoreboard_p->procs[i].used) { + continue; + } +- proc = *scoreboard_p->procs[i]; ++ proc = scoreboard_p->procs[i]; + + if (first) { + first = 0; +diff --git a/sapi/fpm/fpm/fpm_worker_pool.c b/sapi/fpm/fpm/fpm_worker_pool.c +index 90e155975e..96b7ca50fc 100644 +--- a/sapi/fpm/fpm/fpm_worker_pool.c ++++ b/sapi/fpm/fpm/fpm_worker_pool.c +@@ -43,7 +43,7 @@ static void fpm_worker_pool_cleanup(int which, void *arg) /* {{{ */ + fpm_worker_pool_config_free(wp->config); + fpm_children_free(wp->children); + if ((which & FPM_CLEANUP_CHILD) == 0 && fpm_globals.parent_pid == getpid()) { +- fpm_scoreboard_free(wp->scoreboard); ++ fpm_scoreboard_free(wp); + } + fpm_worker_pool_free(wp); + } +-- +2.31.1 + +From 28c4ee7da2cf3428113e07326dbd46550c50c2bd Mon Sep 17 00:00:00 2001 +From: Remi Collet <remi@remirepo.net> +Date: Wed, 20 Oct 2021 14:11:20 +0200 +Subject: [PATCH 2/2] NEWS + +--- + NEWS | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/NEWS b/NEWS +index 0c1a77167c..f9abcbad3a 100644 +--- a/NEWS ++++ b/NEWS +@@ -1,6 +1,12 @@ + PHP NEWS + ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| + ++Backported from 7.4.25 ++ ++- FPM: ++ . Fixed bug #81026 (PHP-FPM oob R/W in root process leading to privilege ++ escalation) (CVE-2021-21703). (Jakub Zelenka) ++ + Backported from 7.3.30 + + - Phar: +-- +2.31.1 + diff --git a/php-bug81122.patch b/php-bug81122.patch new file mode 100644 index 0000000..9ad5b61 --- /dev/null +++ b/php-bug81122.patch @@ -0,0 +1,88 @@ +From 2ebad60c4ada6a49e5d5ab7abf20fd557c0f7764 Mon Sep 17 00:00:00 2001 +From: "Christoph M. Becker" <cmbecker69@gmx.de> +Date: Mon, 14 Jun 2021 13:22:27 +0200 +Subject: [PATCH 1/7] Fix #81122: SSRF bypass in FILTER_VALIDATE_URL + +We need to ensure that the password detected by parse_url() is actually +a valid password; we can re-use is_userinfo_valid() for that. + +(cherry picked from commit a5538c62293fa782fcc382d0635cfc0c8b9190e3) +--- + ext/filter/logical_filters.c | 4 +++- + ext/filter/tests/bug81122.phpt | 21 +++++++++++++++++++++ + 2 files changed, 24 insertions(+), 1 deletion(-) + create mode 100644 ext/filter/tests/bug81122.phpt + +diff --git a/ext/filter/logical_filters.c b/ext/filter/logical_filters.c +index 1c51e6d2ef..1cd602301f 100644 +--- a/ext/filter/logical_filters.c ++++ b/ext/filter/logical_filters.c +@@ -587,7 +587,9 @@ bad_url: + RETURN_VALIDATION_FAILED + } + +- if (url->user != NULL && !is_userinfo_valid(url->user)) { ++ if (url->user != NULL && !is_userinfo_valid(url->user) ++ || url->pass != NULL && !is_userinfo_valid(url->pass) ++ ) { + php_url_free(url); + RETURN_VALIDATION_FAILED + +diff --git a/ext/filter/tests/bug81122.phpt b/ext/filter/tests/bug81122.phpt +new file mode 100644 +index 0000000000..d89d4114a5 +--- /dev/null ++++ b/ext/filter/tests/bug81122.phpt +@@ -0,0 +1,21 @@ ++--TEST-- ++Bug #81122 (SSRF bypass in FILTER_VALIDATE_URL) ++--SKIPIF-- ++<?php ++if (!extension_loaded('filter')) die("skip filter extension not available"); ++?> ++--FILE-- ++<?php ++$urls = [ ++ "https://example.com:\\@test.com/", ++ "https://user:\\epass@test.com", ++ "https://user:\\@test.com", ++]; ++foreach ($urls as $url) { ++ var_dump(filter_var($url, FILTER_VALIDATE_URL)); ++} ++?> ++--EXPECT-- ++bool(false) ++bool(false) ++bool(false) +-- +2.31.1 + +From 7b18a837649c3b36bd51c46a7c3dc9525a69aba5 Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Sun, 27 Jun 2021 21:57:58 -0700 +Subject: [PATCH 2/7] Fix warning + +(cherry picked from commit 190013787bbc424c240413d914e3a038f974ccef) +--- + ext/filter/logical_filters.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/ext/filter/logical_filters.c b/ext/filter/logical_filters.c +index 1cd602301f..8b0d034e5d 100644 +--- a/ext/filter/logical_filters.c ++++ b/ext/filter/logical_filters.c +@@ -587,8 +587,8 @@ bad_url: + RETURN_VALIDATION_FAILED + } + +- if (url->user != NULL && !is_userinfo_valid(url->user) +- || url->pass != NULL && !is_userinfo_valid(url->pass) ++ if ((url->user != NULL && !is_userinfo_valid(url->user)) ++ || (url->pass != NULL && !is_userinfo_valid(url->pass)) + ) { + php_url_free(url); + RETURN_VALIDATION_FAILED +-- +2.31.1 + diff --git a/php-bug81211.patch b/php-bug81211.patch new file mode 100644 index 0000000..b46c5ad --- /dev/null +++ b/php-bug81211.patch @@ -0,0 +1,164 @@ +From 44cd62fa4427934a511f9d0c6423e9dc471009c5 Mon Sep 17 00:00:00 2001 +From: "Christoph M. Becker" <cmbecker69@gmx.de> +Date: Mon, 23 Aug 2021 13:42:17 +0200 +Subject: [PATCH 1/3] Fix #81211: Symlinks are followed when creating PHAR + archive + +It is insufficient to check whether the `base` is contained in `fname`; +we also need to ensure that `fname` is properly separated. And of +course, `fname` has to start with `base`. + +(cherry picked from commit 2ff853aa113e52637c85e28d1a03df1aa2d747b5) +--- + ext/phar/phar_object.c | 3 +- + ext/phar/tests/bug81211.phpt | 45 +++++++++++++++++++ + .../tests/file/windows_links/common.inc | 9 +++- + 3 files changed, 55 insertions(+), 2 deletions(-) + create mode 100644 ext/phar/tests/bug81211.phpt + +diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c +index b22a6acf90..d639c3b1bd 100644 +--- a/ext/phar/phar_object.c ++++ b/ext/phar/phar_object.c +@@ -1440,6 +1440,7 @@ static int phar_build(zend_object_iterator *iter, void *puser) /* {{{ */ + zend_class_entry *ce = p_obj->c; + phar_archive_object *phar_obj = p_obj->p; + php_stream_statbuf ssb; ++ char ch; + + value = iter->funcs->get_current_data(iter); + +@@ -1569,7 +1570,7 @@ phar_spl_fileinfo: + base = temp; + base_len = (int)strlen(base); + +- if (strstr(fname, base)) { ++ if (fname_len >= base_len && strncmp(fname, base, base_len) == 0 && ((ch = fname[base_len - IS_SLASH(base[base_len - 1])]) == '\0' || IS_SLASH(ch))) { + str_key_len = fname_len - base_len; + + if (str_key_len <= 0) { +diff --git a/ext/phar/tests/bug81211.phpt b/ext/phar/tests/bug81211.phpt +new file mode 100644 +index 0000000000..43d82143f2 +--- /dev/null ++++ b/ext/phar/tests/bug81211.phpt +@@ -0,0 +1,45 @@ ++--TEST-- ++Bug #81211 (Symlinks are followed when creating PHAR archive) ++--SKIPIF-- ++<?php ++if (!extension_loaded('phar')) die('skip phar extension is not available'); ++if (PHP_OS_FAMILY === 'Windows') { ++ if (false === include __DIR__ . '/../../standard/tests/file/windows_links/common.inc') { ++ die('skip windows_links/common.inc is not available'); ++ } ++ skipIfSeCreateSymbolicLinkPrivilegeIsDisabled(__FILE__); ++} ++?> ++--FILE-- ++<?php ++mkdir(__DIR__ . '/bug81211'); ++mkdir(__DIR__ . '/bug81211/foobar'); ++mkdir(__DIR__ . '/bug81211/foo'); ++ ++file_put_contents(__DIR__ . '/bug81211/foobar/file', 'this file should NOT be included in the archive!'); ++symlink(__DIR__ . '/bug81211/foobar/file', __DIR__ . '/bug81211/foo/symlink'); ++ ++$archive = new PharData(__DIR__ . '/bug81211/archive.tar'); ++try { ++ $archive->buildFromDirectory(__DIR__ . '/bug81211/foo'); ++} catch (UnexpectedValueException $ex) { ++ echo $ex->getMessage(), PHP_EOL; ++} ++try { ++ $archive->buildFromIterator(new RecursiveDirectoryIterator(__DIR__ . '/bug81211/foo', FilesystemIterator::SKIP_DOTS), __DIR__ . '/bug81211/foo'); ++} catch (UnexpectedValueException $ex) { ++ echo $ex->getMessage(), PHP_EOL; ++} ++?> ++--CLEAN-- ++<?php ++@unlink(__DIR__ . '/bug81211/archive.tar'); ++@unlink(__DIR__ . '/bug81211/foo/symlink'); ++@unlink(__DIR__ . '/bug81211/foobar/file'); ++@rmdir(__DIR__ . '/bug81211/foo'); ++@rmdir(__DIR__ . '/bug81211/foobar'); ++@rmdir(__DIR__ . '/bug81211'); ++?> ++--EXPECTF-- ++Iterator RecursiveIteratorIterator returned a path "%s%ebug81211\foobar\file" that is not in the base directory "%s%ebug81211\foo" ++Iterator RecursiveDirectoryIterator returned a path "%s%ebug81211\foobar\file" that is not in the base directory "%s%ebug81211\foo" +diff --git a/ext/standard/tests/file/windows_links/common.inc b/ext/standard/tests/file/windows_links/common.inc +index 505368b8b0..caa3758d44 100644 +--- a/ext/standard/tests/file/windows_links/common.inc ++++ b/ext/standard/tests/file/windows_links/common.inc +@@ -20,4 +20,11 @@ function get_mountvol() { + return "$sysroot\\System32\\mountvol.exe"; + } + +-?> ++function skipIfSeCreateSymbolicLinkPrivilegeIsDisabled(string $filename) { ++ $ln = "$filename.lnk"; ++ $ret = exec("mklink $ln " . __FILE__ .' 2>&1', $out); ++ @unlink($ln); ++ if (strpos($ret, 'privilege') !== false) { ++ die('skip SeCreateSymbolicLinkPrivilege not enabled'); ++ } ++} +-- +2.31.1 + +From 072295b550665a57bc4dd7e7a0bd7511c5ba3631 Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Mon, 23 Aug 2021 23:43:32 -0700 +Subject: [PATCH 2/3] Fix test + +(cherry picked from commit b815645aac76b494dc119fa6b88de32fa9bcccf1) +--- + ext/phar/tests/bug81211.phpt | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/ext/phar/tests/bug81211.phpt b/ext/phar/tests/bug81211.phpt +index 43d82143f2..96b1401b40 100644 +--- a/ext/phar/tests/bug81211.phpt ++++ b/ext/phar/tests/bug81211.phpt +@@ -41,5 +41,5 @@ try { + @rmdir(__DIR__ . '/bug81211'); + ?> + --EXPECTF-- +-Iterator RecursiveIteratorIterator returned a path "%s%ebug81211\foobar\file" that is not in the base directory "%s%ebug81211\foo" +-Iterator RecursiveDirectoryIterator returned a path "%s%ebug81211\foobar\file" that is not in the base directory "%s%ebug81211\foo" ++Iterator RecursiveIteratorIterator returned a path "%s%ebug81211%efoobar%efile" that is not in the base directory "%s%ebug81211%efoo" ++Iterator RecursiveDirectoryIterator returned a path "%s%ebug81211%efoobar%efile" that is not in the base directory "%s%ebug81211%efoo" +-- +2.31.1 + +From 655929a3b7a876d00b7e3dea04592e56332727c5 Mon Sep 17 00:00:00 2001 +From: Remi Collet <remi@remirepo.net> +Date: Wed, 25 Aug 2021 15:23:50 +0200 +Subject: [PATCH 3/3] NEWS + +(cherry picked from commit 5539cefcda6aca7af220e7be7760a682abb88200) +--- + NEWS | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/NEWS b/NEWS +index b1b31e5dd0..0c1a77167c 100644 +--- a/NEWS ++++ b/NEWS +@@ -1,6 +1,11 @@ + PHP NEWS + ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| + ++Backported from 7.3.30 ++ ++- Phar: ++ . Fixed bug #81211: Symlinks are followed when creating PHAR archive (cmb) ++ + Backported from 7.3.29 + + - Core: +-- +2.31.1 + diff --git a/php-bug81719.patch b/php-bug81719.patch new file mode 100644 index 0000000..f58c041 --- /dev/null +++ b/php-bug81719.patch @@ -0,0 +1,64 @@ +From 5e1d9182748c5330c4bf2154da858206e76914b6 Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <smalyshev@gmail.com> +Date: Mon, 6 Jun 2022 00:56:51 -0600 +Subject: [PATCH 2/3] Fix bug #81719: mysqlnd/pdo password buffer overflow + +(cherry picked from commit 58006537fc5f133ae8549efe5118cde418b3ace9) +(cherry picked from commit 9433de72e291db518357fe55531cc15432d43ec4) +(cherry picked from commit 1560224d3a26574f0195af3853e4d7e050b0b06f) +--- + ext/mysqlnd/mysqlnd_wireprotocol.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/ext/mysqlnd/mysqlnd_wireprotocol.c b/ext/mysqlnd/mysqlnd_wireprotocol.c +index 1e38b76ff6..610abf99f5 100644 +--- a/ext/mysqlnd/mysqlnd_wireprotocol.c ++++ b/ext/mysqlnd/mysqlnd_wireprotocol.c +@@ -792,7 +792,8 @@ php_mysqlnd_change_auth_response_write(void * _packet) + MYSQLND_VIO * vio = packet->header.vio; + MYSQLND_STATS * stats = packet->header.stats; + MYSQLND_CONNECTION_STATE * connection_state = packet->header.connection_state; +- zend_uchar * buffer = pfc->cmd_buffer.length >= packet->auth_data_len? pfc->cmd_buffer.buffer : mnd_emalloc(packet->auth_data_len); ++ size_t total_packet_size = packet->auth_data_len + MYSQLND_HEADER_SIZE; ++ zend_uchar * const buffer = pfc->cmd_buffer.length >= total_packet_size? pfc->cmd_buffer.buffer : mnd_emalloc(total_packet_size); + zend_uchar * p = buffer + MYSQLND_HEADER_SIZE; /* start after the header */ + + DBG_ENTER("php_mysqlnd_change_auth_response_write"); +-- +2.35.3 + +From 151499ec0f70bf4f1bd65aebf037bd6273f0ef34 Mon Sep 17 00:00:00 2001 +From: Remi Collet <remi@remirepo.net> +Date: Tue, 7 Jun 2022 09:57:15 +0200 +Subject: [PATCH 3/3] NEWS + +(cherry picked from commit f451082baf14ee9ea86cdd19870e906adb368f02) +(cherry picked from commit 87247fb08e905e629836350ac4e639edd1b40ed8) +--- + NEWS | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/NEWS b/NEWS +index e5c20296ed..6e6b4dbcd8 100644 +--- a/NEWS ++++ b/NEWS +@@ -1,6 +1,16 @@ + PHP NEWS + ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| + ++Backported from 7.4.30 ++ ++- mysqlnd: ++ . Fixed bug #81719: mysqlnd/pdo password buffer overflow. ++ (CVE-2022-31626) (c dot fol at ambionics dot io) ++ ++- pgsql ++ . Fixed bug #81720: Uninitialized array in pg_query_params(). ++ (CVE-2022-31625) (cmb) ++ + Backported from 7.3.33 + + - XML: +-- +2.35.3 + diff --git a/php-bug81720.patch b/php-bug81720.patch new file mode 100644 index 0000000..15020d2 --- /dev/null +++ b/php-bug81720.patch @@ -0,0 +1,78 @@ +From 9e7d6a2a1e8f43bdb86a0b6c1199f938f6ba78f5 Mon Sep 17 00:00:00 2001 +From: "Christoph M. Becker" <cmbecker69@gmx.de> +Date: Tue, 17 May 2022 12:59:23 +0200 +Subject: [PATCH 1/3] Fix #81720: Uninitialized array in pg_query_params() + leading to RCE + +We must not free parameters which we haven't initialized yet. + +We also fix the not directly related issue, that we checked for the +wrong value being `NULL`, potentially causing a segfault. + +(cherry picked from commit 55f6895f4b4c677272fd4ee1113acdbd99c4b5ab) +(cherry picked from commit 6f979c832c861fb32e2dbad5e0cc29edcee7c500) +(cherry picked from commit 310b17f5c8938389b1dbd7d8ff5a8144bfb9a351) +--- + ext/pgsql/pgsql.c | 4 ++-- + ext/pgsql/tests/bug81720.phpt | 27 +++++++++++++++++++++++++++ + 2 files changed, 29 insertions(+), 2 deletions(-) + create mode 100644 ext/pgsql/tests/bug81720.phpt + +diff --git a/ext/pgsql/pgsql.c b/ext/pgsql/pgsql.c +index 9410078812..3039c26e07 100644 +--- a/ext/pgsql/pgsql.c ++++ b/ext/pgsql/pgsql.c +@@ -1982,7 +1982,7 @@ PHP_FUNCTION(pg_query_params) + if (Z_TYPE(tmp_val) != IS_STRING) { + php_error_docref(NULL, E_WARNING,"Error converting parameter"); + zval_ptr_dtor(&tmp_val); +- _php_pgsql_free_params(params, num_params); ++ _php_pgsql_free_params(params, i); + RETURN_FALSE; + } + params[i] = estrndup(Z_STRVAL(tmp_val), Z_STRLEN(tmp_val)); +@@ -5182,7 +5182,7 @@ PHP_FUNCTION(pg_send_execute) + if (Z_TYPE(tmp_val) != IS_STRING) { + php_error_docref(NULL, E_WARNING,"Error converting parameter"); + zval_ptr_dtor(&tmp_val); +- _php_pgsql_free_params(params, num_params); ++ _php_pgsql_free_params(params, i); + RETURN_FALSE; + } + params[i] = estrndup(Z_STRVAL(tmp_val), Z_STRLEN(tmp_val)); +diff --git a/ext/pgsql/tests/bug81720.phpt b/ext/pgsql/tests/bug81720.phpt +new file mode 100644 +index 0000000000..d79f1fcdd6 +--- /dev/null ++++ b/ext/pgsql/tests/bug81720.phpt +@@ -0,0 +1,27 @@ ++--TEST-- ++Bug #81720 (Uninitialized array in pg_query_params() leading to RCE) ++--SKIPIF-- ++<?php include("skipif.inc"); ?> ++--FILE-- ++<?php ++include('config.inc'); ++ ++$conn = pg_connect($conn_str); ++ ++try { ++ pg_query_params($conn, 'SELECT $1, $2', [1, new stdClass()]); ++} catch (Throwable $ex) { ++ echo $ex->getMessage(), PHP_EOL; ++} ++ ++try { ++ pg_send_prepare($conn, "my_query", 'SELECT $1, $2'); ++ pg_get_result($conn); ++ pg_send_execute($conn, "my_query", [1, new stdClass()]); ++} catch (Throwable $ex) { ++ echo $ex->getMessage(), PHP_EOL; ++} ++?> ++--EXPECT-- ++Object of class stdClass could not be converted to string ++Object of class stdClass could not be converted to string +-- +2.35.3 + diff --git a/php-bug81726.patch b/php-bug81726.patch new file mode 100644 index 0000000..5d9a972 --- /dev/null +++ b/php-bug81726.patch @@ -0,0 +1,180 @@ +From 8fc7239a03a099ad20c9de4ea32489099b942ea7 Mon Sep 17 00:00:00 2001 +From: "Christoph M. Becker" <cmbecker69@gmx.de> +Date: Mon, 25 Jul 2022 15:58:59 +0200 +Subject: [PATCH 2/2] Fix #81726: phar wrapper: DOS when using quine gzip file + +The phar wrapper needs to uncompress the file; the uncompressed file +might be compressed, so the wrapper implementation loops. This raises +potential DOS issues regarding too deep or even infinite recursion (the +latter are called compressed file quines[1]). We avoid that by +introducing a recursion limit; we choose the somewhat arbitrary limit +`3`. + +This issue has been reported by real_as3617 and gPayl0ad. + +[1] <https://honno.dev/gzip-quine/> + +(cherry picked from commit 404e8bdb68350931176a5bdc86fc417b34fb583d) +(cherry picked from commit 96fda78bcddd1d793cf2d0ee463dbb49621b577f) +--- + NEWS | 2 ++ + ext/phar/phar.c | 16 +++++++++++----- + ext/phar/tests/bug81726.gz | Bin 0 -> 204 bytes + ext/phar/tests/bug81726.phpt | 14 ++++++++++++++ + 4 files changed, 27 insertions(+), 5 deletions(-) + create mode 100644 ext/phar/tests/bug81726.gz + create mode 100644 ext/phar/tests/bug81726.phpt + +diff --git a/NEWS b/NEWS +index e1362dbdd1..4daea9bf2a 100644 +--- a/NEWS ++++ b/NEWS +@@ -4,6 +4,8 @@ PHP NEWS + Backported from 7.4.31 + + - Core: ++ . Fixed bug #81726: phar wrapper: DOS when using quine gzip file. ++ (CVE-2022-31628). (cmb) + . Fixed bug #81727: Don't mangle HTTP variable names that clash with ones + that have a specific semantic meaning. (CVE-2022-31629). (Derick) + +diff --git a/ext/phar/phar.c b/ext/phar/phar.c +index e117ab0dc0..f62d18c094 100644 +--- a/ext/phar/phar.c ++++ b/ext/phar/phar.c +@@ -1574,7 +1574,8 @@ static int phar_open_from_fp(php_stream* fp, char *fname, int fname_len, char *a + const char zip_magic[] = "PK\x03\x04"; + const char gz_magic[] = "\x1f\x8b\x08"; + const char bz_magic[] = "BZh"; +- char *pos, test = '\0'; ++ char *pos; ++ int recursion_count = 3; // arbitrary limit to avoid too deep or even infinite recursion + const int window_size = 1024; + char buffer[1024 + sizeof(token)]; /* a 1024 byte window + the size of the halt_compiler token (moving window) */ + const zend_long readsize = sizeof(buffer) - sizeof(token); +@@ -1602,8 +1603,7 @@ static int phar_open_from_fp(php_stream* fp, char *fname, int fname_len, char *a + MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated entry)") + } + +- if (!test) { +- test = '\1'; ++ if (recursion_count) { + pos = buffer+tokenlen; + if (!memcmp(pos, gz_magic, 3)) { + char err = 0; +@@ -1663,7 +1663,10 @@ static int phar_open_from_fp(php_stream* fp, char *fname, int fname_len, char *a + compression = PHAR_FILE_COMPRESSED_GZ; + + /* now, start over */ +- test = '\0'; ++ if (!--recursion_count) { ++ MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\""); ++ break; ++ } + continue; + } else if (!memcmp(pos, bz_magic, 3)) { + php_stream_filter *filter; +@@ -1701,7 +1704,10 @@ static int phar_open_from_fp(php_stream* fp, char *fname, int fname_len, char *a + compression = PHAR_FILE_COMPRESSED_BZ2; + + /* now, start over */ +- test = '\0'; ++ if (!--recursion_count) { ++ MAPPHAR_ALLOC_FAIL("unable to decompress bzipped phar archive \"%s\""); ++ break; ++ } + continue; + } + +From a73858fe9126c99e6ed5b8201d56ea158468e03e Mon Sep 17 00:00:00 2001 +From: "Christoph M. Becker" <cmbecker69@gmx.de> +Date: Tue, 27 Sep 2022 17:43:40 +0200 +Subject: [PATCH] Fix regression introduced by fixing bug 81726 + +When a tar phar is created, `phar_open_from_fp()` is also called, but +since the file has just been created, none of the format checks can +succeed, so we continue to loop, but must not check again for the +format. Therefore, we bring back the old `test` variable. + +Closes GH-9620. + +(cherry picked from commit 432bf196d59bcb661fcf9cb7029cea9b43f490af) +--- + ext/phar/phar.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/ext/phar/phar.c b/ext/phar/phar.c +index f62d18c094..80102e549a 100644 +--- a/ext/phar/phar.c ++++ b/ext/phar/phar.c +@@ -1574,7 +1574,7 @@ static int phar_open_from_fp(php_stream* fp, char *fname, int fname_len, char *a + const char zip_magic[] = "PK\x03\x04"; + const char gz_magic[] = "\x1f\x8b\x08"; + const char bz_magic[] = "BZh"; +- char *pos; ++ char *pos, test = '\0'; + int recursion_count = 3; // arbitrary limit to avoid too deep or even infinite recursion + const int window_size = 1024; + char buffer[1024 + sizeof(token)]; /* a 1024 byte window + the size of the halt_compiler token (moving window) */ +@@ -1603,7 +1603,8 @@ static int phar_open_from_fp(php_stream* fp, char *fname, int fname_len, char *a + MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated entry)") + } + +- if (recursion_count) { ++ if (!test && recursion_count) { ++ test = '\1'; + pos = buffer+tokenlen; + if (!memcmp(pos, gz_magic, 3)) { + char err = 0; +@@ -1663,6 +1664,7 @@ static int phar_open_from_fp(php_stream* fp, char *fname, int fname_len, char *a + compression = PHAR_FILE_COMPRESSED_GZ; + + /* now, start over */ ++ test = '\0'; + if (!--recursion_count) { + MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\""); + break; +@@ -1704,6 +1706,7 @@ static int phar_open_from_fp(php_stream* fp, char *fname, int fname_len, char *a + compression = PHAR_FILE_COMPRESSED_BZ2; + + /* now, start over */ ++ test = '\0'; + if (!--recursion_count) { + MAPPHAR_ALLOC_FAIL("unable to decompress bzipped phar archive \"%s\""); + break; +-- +2.37.3 + +From 9d32d284b25f5df75780911a47b3c23cbaac1761 Mon Sep 17 00:00:00 2001 +From: Remi Collet <remi@remirepo.net> +Date: Fri, 30 Sep 2022 09:22:14 +0200 +Subject: [PATCH] fix NEWS + +--- + NEWS | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/NEWS b/NEWS +index fe4cb9c484..b7a19aea19 100644 +--- a/NEWS ++++ b/NEWS +@@ -1,14 +1,16 @@ + PHP NEWS + ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| + +-Backported from 7.4.31 ++Backported from 7.4.32 + + - Core: +- . Fixed bug #81726: phar wrapper: DOS when using quine gzip file. +- (CVE-2022-31628). (cmb) + . Fixed bug #81727: Don't mangle HTTP variable names that clash with ones + that have a specific semantic meaning. (CVE-2022-31629). (Derick) + ++- Phar: ++ . Fixed bug #81726: phar wrapper: DOS when using quine gzip file. ++ (CVE-2022-31628). (cmb) ++ + Backported from 7.4.30 + + - mysqlnd: diff --git a/php-bug81727.patch b/php-bug81727.patch new file mode 100644 index 0000000..1a2baaf --- /dev/null +++ b/php-bug81727.patch @@ -0,0 +1,81 @@ +From ca3dd9335387e39c796c83b94b6a6359e22f3fe1 Mon Sep 17 00:00:00 2001 +From: Derick Rethans <github@derickrethans.nl> +Date: Fri, 9 Sep 2022 16:54:03 +0100 +Subject: [PATCH 1/2] Fix #81727: Don't mangle HTTP variable names that clash + with ones that have a specific semantic meaning. + +(cherry picked from commit 0611be4e82887cee0de6c4cbae320d34eec946ca) +(cherry picked from commit 8b300e157e92b0e945ad813d608f076b5323d721) +--- + NEWS | 6 ++++++ + ext/standard/tests/bug81727.phpt | 15 +++++++++++++++ + main/php_variables.c | 14 ++++++++++++++ + 3 files changed, 35 insertions(+) + create mode 100644 ext/standard/tests/bug81727.phpt + +diff --git a/NEWS b/NEWS +index 6e6b4dbcd8..e1362dbdd1 100644 +--- a/NEWS ++++ b/NEWS +@@ -1,6 +1,12 @@ + PHP NEWS + ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| + ++Backported from 7.4.31 ++ ++- Core: ++ . Fixed bug #81727: Don't mangle HTTP variable names that clash with ones ++ that have a specific semantic meaning. (CVE-2022-31629). (Derick) ++ + Backported from 7.4.30 + + - mysqlnd: +diff --git a/ext/standard/tests/bug81727.phpt b/ext/standard/tests/bug81727.phpt +new file mode 100644 +index 0000000000..71a9cb46c8 +--- /dev/null ++++ b/ext/standard/tests/bug81727.phpt +@@ -0,0 +1,15 @@ ++--TEST-- ++Bug #81727: $_COOKIE name starting with ..Host/..Secure should be discarded ++--COOKIE-- ++..Host-test=ignore; __Host-test=correct; . Secure-test=ignore; . Elephpant=Awesome; ++--FILE-- ++<?php ++var_dump($_COOKIE); ++?> ++--EXPECT-- ++array(2) { ++ ["__Host-test"]=> ++ string(7) "correct" ++ ["__Elephpant"]=> ++ string(7) "Awesome" ++} +diff --git a/main/php_variables.c b/main/php_variables.c +index d0223df44a..17a0b053a6 100644 +--- a/main/php_variables.c ++++ b/main/php_variables.c +@@ -103,6 +103,20 @@ PHPAPI void php_register_variable_ex(char *var_name, zval *val, zval *track_vars + } + var_len = p - var; + ++ /* Discard variable if mangling made it start with __Host-, where pre-mangling it did not start with __Host- */ ++ if (strncmp(var, "__Host-", sizeof("__Host-")-1) == 0 && strncmp(var_name, "__Host-", sizeof("__Host-")-1) != 0) { ++ zval_ptr_dtor_nogc(val); ++ free_alloca(var_orig, use_heap); ++ return; ++ } ++ ++ /* Discard variable if mangling made it start with __Secure-, where pre-mangling it did not start with __Secure- */ ++ if (strncmp(var, "__Secure-", sizeof("__Secure-")-1) == 0 && strncmp(var_name, "__Secure-", sizeof("__Secure-")-1) != 0) { ++ zval_ptr_dtor_nogc(val); ++ free_alloca(var_orig, use_heap); ++ return; ++ } ++ + if (var_len==0) { /* empty variable name, or variable name with a space in it */ + zval_dtor(val); + free_alloca(var_orig, use_heap); +-- +2.37.3 + diff --git a/php-bug81740.patch b/php-bug81740.patch new file mode 100644 index 0000000..557ad5b --- /dev/null +++ b/php-bug81740.patch @@ -0,0 +1,86 @@ +From b6caf64f9a0c0d9745962e37a57ba4dd32d6a712 Mon Sep 17 00:00:00 2001 +From: "Christoph M. Becker" <cmbecker69@gmx.de> +Date: Mon, 31 Oct 2022 17:20:23 +0100 +Subject: [PATCH 1/2] Fix #81740: PDO::quote() may return unquoted string + +`sqlite3_snprintf()` expects its first parameter to be `int`; we need +to avoid overflow. + +(cherry picked from commit 921b6813da3237a83e908998483f46ae3d8bacba) +(cherry picked from commit 7cb160efe19d3dfb8b92629805733ea186b55050) +--- + ext/pdo_sqlite/sqlite_driver.c | 3 +++ + ext/pdo_sqlite/tests/bug81740.phpt | 17 +++++++++++++++++ + 2 files changed, 20 insertions(+) + create mode 100644 ext/pdo_sqlite/tests/bug81740.phpt + +diff --git a/ext/pdo_sqlite/sqlite_driver.c b/ext/pdo_sqlite/sqlite_driver.c +index f9a2a4d04f..ac466f488e 100644 +--- a/ext/pdo_sqlite/sqlite_driver.c ++++ b/ext/pdo_sqlite/sqlite_driver.c +@@ -232,6 +232,9 @@ static char *pdo_sqlite_last_insert_id(pdo_dbh_t *dbh, const char *name, size_t + /* NB: doesn't handle binary strings... use prepared stmts for that */ + static int sqlite_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, size_t unquotedlen, char **quoted, size_t *quotedlen, enum pdo_param_type paramtype ) + { ++ if (unquotedlen > (INT_MAX - 3) / 2) { ++ return 0; ++ } + *quoted = safe_emalloc(2, unquotedlen, 3); + sqlite3_snprintf(2*unquotedlen + 3, *quoted, "'%q'", unquoted); + *quotedlen = strlen(*quoted); +diff --git a/ext/pdo_sqlite/tests/bug81740.phpt b/ext/pdo_sqlite/tests/bug81740.phpt +new file mode 100644 +index 0000000000..99fb07c304 +--- /dev/null ++++ b/ext/pdo_sqlite/tests/bug81740.phpt +@@ -0,0 +1,17 @@ ++--TEST-- ++Bug #81740 (PDO::quote() may return unquoted string) ++--SKIPIF-- ++<?php ++if (!extension_loaded('pdo_sqlite')) print 'skip not loaded'; ++if (getenv("SKIP_SLOW_TESTS")) die("skip slow test"); ++?> ++--INI-- ++memory_limit=-1 ++--FILE-- ++<?php ++$pdo = new PDO("sqlite::memory:"); ++$string = str_repeat("a", 0x80000000); ++var_dump($pdo->quote($string)); ++?> ++--EXPECT-- ++bool(false) +-- +2.38.1 + +From dbfbd99e91701c0a5613133c06305fd70545e9ad Mon Sep 17 00:00:00 2001 +From: Remi Collet <remi@remirepo.net> +Date: Mon, 19 Dec 2022 09:24:02 +0100 +Subject: [PATCH 2/2] NEWS + +(cherry picked from commit 7328f3a0344806b846bd05657bdce96e47810bf0) +--- + NEWS | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/NEWS b/NEWS +index 7f30a1cd2e..6b05aa48fe 100644 +--- a/NEWS ++++ b/NEWS +@@ -1,6 +1,12 @@ + PHP NEWS + ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| + ++Backported from 8.0.27 ++ ++- PDO/SQLite: ++ . Fixed bug #81740 (PDO::quote() may return unquoted string). ++ (CVE-2022-31631) (cmb) ++ + Backported from 7.4.32 + + - Core: +-- +2.38.1 + diff --git a/php-bug81744.patch b/php-bug81744.patch new file mode 100644 index 0000000..c940c2a --- /dev/null +++ b/php-bug81744.patch @@ -0,0 +1,190 @@ +From 8cccd1d77222a08d42fbcd252f9ee948db8f676c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= <tim@bastelstu.be> +Date: Mon, 23 Jan 2023 21:15:24 +0100 +Subject: [PATCH 1/8] crypt: Fix validation of malformed BCrypt hashes +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +PHP’s implementation of crypt_blowfish differs from the upstream Openwall +version by adding a “PHP Hackâ€, which allows one to cut short the BCrypt salt +by including a `$` character within the characters that represent the salt. + +Hashes that are affected by the “PHP Hack†may erroneously validate any +password as valid when used with `password_verify` and when comparing the +return value of `crypt()` against the input. + +The PHP Hack exists since the first version of PHP’s own crypt_blowfish +implementation that was added in 1e820eca02dcf322b41fd2fe4ed2a6b8309f8ab5. + +No clear reason is given for the PHP Hack’s existence. This commit removes it, +because BCrypt hashes containing a `$` character in their salt are not valid +BCrypt hashes. + +(cherry picked from commit c840f71524067aa474c00c3eacfb83bd860bfc8a) +(cherry picked from commit 7437aaae38cf4b3357e7580f9e22fd4a403b6c23) +--- + ext/standard/crypt_blowfish.c | 8 -- + .../tests/crypt/bcrypt_salt_dollar.phpt | 82 +++++++++++++++++++ + 2 files changed, 82 insertions(+), 8 deletions(-) + create mode 100644 ext/standard/tests/crypt/bcrypt_salt_dollar.phpt + +diff --git a/ext/standard/crypt_blowfish.c b/ext/standard/crypt_blowfish.c +index 5cf306715f..e923b55ed0 100644 +--- a/ext/standard/crypt_blowfish.c ++++ b/ext/standard/crypt_blowfish.c +@@ -377,7 +377,6 @@ static unsigned char BF_atoi64[0x60] = { + #define BF_safe_atoi64(dst, src) \ + { \ + tmp = (unsigned char)(src); \ +- if (tmp == '$') break; /* PHP hack */ \ + if ((unsigned int)(tmp -= 0x20) >= 0x60) return -1; \ + tmp = BF_atoi64[tmp]; \ + if (tmp > 63) return -1; \ +@@ -405,13 +404,6 @@ static int BF_decode(BF_word *dst, const char *src, int size) + *dptr++ = ((c3 & 0x03) << 6) | c4; + } while (dptr < end); + +- if (end - dptr == size) { +- return -1; +- } +- +- while (dptr < end) /* PHP hack */ +- *dptr++ = 0; +- + return 0; + } + +diff --git a/ext/standard/tests/crypt/bcrypt_salt_dollar.phpt b/ext/standard/tests/crypt/bcrypt_salt_dollar.phpt +new file mode 100644 +index 0000000000..32e335f4b0 +--- /dev/null ++++ b/ext/standard/tests/crypt/bcrypt_salt_dollar.phpt +@@ -0,0 +1,82 @@ ++--TEST-- ++bcrypt correctly rejects salts containing $ ++--FILE-- ++<?php ++for ($i = 0; $i < 23; $i++) { ++ $salt = '$2y$04$' . str_repeat('0', $i) . '$'; ++ $result = crypt("foo", $salt); ++ var_dump($salt); ++ var_dump($result); ++ var_dump($result === $salt); ++} ++?> ++--EXPECT-- ++string(8) "$2y$04$$" ++string(2) "*0" ++bool(false) ++string(9) "$2y$04$0$" ++string(2) "*0" ++bool(false) ++string(10) "$2y$04$00$" ++string(2) "*0" ++bool(false) ++string(11) "$2y$04$000$" ++string(2) "*0" ++bool(false) ++string(12) "$2y$04$0000$" ++string(2) "*0" ++bool(false) ++string(13) "$2y$04$00000$" ++string(2) "*0" ++bool(false) ++string(14) "$2y$04$000000$" ++string(2) "*0" ++bool(false) ++string(15) "$2y$04$0000000$" ++string(2) "*0" ++bool(false) ++string(16) "$2y$04$00000000$" ++string(2) "*0" ++bool(false) ++string(17) "$2y$04$000000000$" ++string(2) "*0" ++bool(false) ++string(18) "$2y$04$0000000000$" ++string(2) "*0" ++bool(false) ++string(19) "$2y$04$00000000000$" ++string(2) "*0" ++bool(false) ++string(20) "$2y$04$000000000000$" ++string(2) "*0" ++bool(false) ++string(21) "$2y$04$0000000000000$" ++string(2) "*0" ++bool(false) ++string(22) "$2y$04$00000000000000$" ++string(2) "*0" ++bool(false) ++string(23) "$2y$04$000000000000000$" ++string(2) "*0" ++bool(false) ++string(24) "$2y$04$0000000000000000$" ++string(2) "*0" ++bool(false) ++string(25) "$2y$04$00000000000000000$" ++string(2) "*0" ++bool(false) ++string(26) "$2y$04$000000000000000000$" ++string(2) "*0" ++bool(false) ++string(27) "$2y$04$0000000000000000000$" ++string(2) "*0" ++bool(false) ++string(28) "$2y$04$00000000000000000000$" ++string(2) "*0" ++bool(false) ++string(29) "$2y$04$000000000000000000000$" ++string(2) "*0" ++bool(false) ++string(30) "$2y$04$0000000000000000000000$" ++string(60) "$2y$04$000000000000000000000u2a2UpVexIt9k3FMJeAVr3c04F5tcI8K" ++bool(false) +-- +2.39.1 + +From c2b9db02d6b889521004a39ba6bae975eeb095fb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= <tim@bastelstu.be> +Date: Mon, 23 Jan 2023 22:13:57 +0100 +Subject: [PATCH 2/8] crypt: Fix possible buffer overread in php_crypt() + +(cherry picked from commit a92acbad873a05470af1a47cb785a18eadd827b5) +(cherry picked from commit ed0281b588a6840cb95f3134a4e68847a3be5bb7) +--- + ext/standard/crypt.c | 1 + + ext/standard/tests/password/password_bcrypt_short.phpt | 8 ++++++++ + 2 files changed, 9 insertions(+) + create mode 100644 ext/standard/tests/password/password_bcrypt_short.phpt + +diff --git a/ext/standard/crypt.c b/ext/standard/crypt.c +index e600367816..d2ec9f76d1 100644 +--- a/ext/standard/crypt.c ++++ b/ext/standard/crypt.c +@@ -156,6 +156,7 @@ PHPAPI zend_string *php_crypt(const char *password, const int pass_len, const ch + } else if ( + salt[0] == '$' && + salt[1] == '2' && ++ salt[2] != 0 && + salt[3] == '$') { + char output[PHP_MAX_SALT_LEN + 1]; + +diff --git a/ext/standard/tests/password/password_bcrypt_short.phpt b/ext/standard/tests/password/password_bcrypt_short.phpt +new file mode 100644 +index 0000000000..085bc8a239 +--- /dev/null ++++ b/ext/standard/tests/password/password_bcrypt_short.phpt +@@ -0,0 +1,8 @@ ++--TEST-- ++Test that password_hash() does not overread buffers when a short hash is passed ++--FILE-- ++<?php ++var_dump(password_verify("foo", '$2')); ++?> ++--EXPECT-- ++bool(false) +-- +2.39.1 + diff --git a/php-bug81746.patch b/php-bug81746.patch new file mode 100644 index 0000000..49b9c5e --- /dev/null +++ b/php-bug81746.patch @@ -0,0 +1,100 @@ +From bd523b8bbb516ee98528a4692601c2e35d3a729d Mon Sep 17 00:00:00 2001 +From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> +Date: Fri, 27 Jan 2023 19:28:27 +0100 +Subject: [PATCH 3/8] Fix array overrun when appending slash to paths + +Fix it by extending the array sizes by one character. As the input is +limited to the maximum path length, there will always be place to append +the slash. As the php_check_specific_open_basedir() simply uses the +strings to compare against each other, no new failures related to too +long paths are introduced. +We'll let the DOM and XML case handle a potentially too long path in the +library code. + +(cherry picked from commit ec10b28d64decbc54aa1e585dce580f0bd7a5953) +(cherry picked from commit 887cd0710ad856a0d22c329b6ea6c71ebd8621ae) +--- + ext/dom/document.c | 2 +- + ext/xmlreader/php_xmlreader.c | 2 +- + main/fopen_wrappers.c | 6 +++--- + 3 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/ext/dom/document.c b/ext/dom/document.c +index 11ef4aa818..c212faa695 100644 +--- a/ext/dom/document.c ++++ b/ext/dom/document.c +@@ -1359,7 +1359,7 @@ static xmlDocPtr dom_document_parser(zval *id, int mode, char *source, size_t so + int validate, recover, resolve_externals, keep_blanks, substitute_ent; + int resolved_path_len; + int old_error_reporting = 0; +- char *directory=NULL, resolved_path[MAXPATHLEN]; ++ char *directory=NULL, resolved_path[MAXPATHLEN + 1]; + + if (id != NULL) { + intern = Z_DOMOBJ_P(id); +diff --git a/ext/xmlreader/php_xmlreader.c b/ext/xmlreader/php_xmlreader.c +index 6c1da2761d..0f2b62ae20 100644 +--- a/ext/xmlreader/php_xmlreader.c ++++ b/ext/xmlreader/php_xmlreader.c +@@ -1040,7 +1040,7 @@ PHP_METHOD(xmlreader, XML) + xmlreader_object *intern = NULL; + char *source, *uri = NULL, *encoding = NULL; + int resolved_path_len, ret = 0; +- char *directory=NULL, resolved_path[MAXPATHLEN]; ++ char *directory=NULL, resolved_path[MAXPATHLEN + 1]; + xmlParserInputBufferPtr inputbfr; + xmlTextReaderPtr reader; + +diff --git a/main/fopen_wrappers.c b/main/fopen_wrappers.c +index 135b1491aa..e50a73547b 100644 +--- a/main/fopen_wrappers.c ++++ b/main/fopen_wrappers.c +@@ -137,10 +137,10 @@ PHPAPI ZEND_INI_MH(OnUpdateBaseDir) + */ + PHPAPI int php_check_specific_open_basedir(const char *basedir, const char *path) + { +- char resolved_name[MAXPATHLEN]; +- char resolved_basedir[MAXPATHLEN]; ++ char resolved_name[MAXPATHLEN + 1]; ++ char resolved_basedir[MAXPATHLEN + 1]; + char local_open_basedir[MAXPATHLEN]; +- char path_tmp[MAXPATHLEN]; ++ char path_tmp[MAXPATHLEN + 1]; + char *path_file; + int resolved_basedir_len; + int resolved_name_len; +-- +2.39.1 + +From 0a2800e554e11f1dbc25602dfa87f574513a092b Mon Sep 17 00:00:00 2001 +From: Remi Collet <remi@remirepo.net> +Date: Mon, 13 Feb 2023 11:46:47 +0100 +Subject: [PATCH 4/8] NEWS + +(cherry picked from commit 614468ce4056c0ef93aae09532dcffdf65b594b5) +--- + NEWS | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/NEWS b/NEWS +index 6b05aa48fe..bc9083d3e8 100644 +--- a/NEWS ++++ b/NEWS +@@ -1,6 +1,14 @@ + PHP NEWS + ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| + ++Backported from 8.0.28 ++ ++- Core: ++ . Fixed bug #81744 (Password_verify() always return true with some hash). ++ (CVE-2023-0567). (Tim Düsterhus) ++ . Fixed bug #81746 (1-byte array overrun in common path resolve code). ++ (CVE-2023-0568). (Niels Dossche) ++ + Backported from 8.0.27 + + - PDO/SQLite: +-- +2.39.1 + diff --git a/php-cve-2023-0662.patch b/php-cve-2023-0662.patch new file mode 100644 index 0000000..89b8b1b --- /dev/null +++ b/php-cve-2023-0662.patch @@ -0,0 +1,148 @@ +From cfc945efd1ad92d7c118ddf4e021f0a2e25969d4 Mon Sep 17 00:00:00 2001 +From: Jakub Zelenka <bukka@php.net> +Date: Thu, 19 Jan 2023 14:11:18 +0000 +Subject: [PATCH 5/8] Fix repeated warning for file uploads limit exceeding + +(cherry picked from commit 3a2fdef1ae38881110006616ee1f0534b082ca45) +--- + main/rfc1867.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/main/rfc1867.c b/main/rfc1867.c +index 1742b9c0a9..4aef7edb6e 100644 +--- a/main/rfc1867.c ++++ b/main/rfc1867.c +@@ -932,7 +932,10 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */ + skip_upload = 1; + } else if (upload_cnt <= 0) { + skip_upload = 1; +- sapi_module.sapi_error(E_WARNING, "Maximum number of allowable file uploads has been exceeded"); ++ if (upload_cnt == 0) { ++ --upload_cnt; ++ sapi_module.sapi_error(E_WARNING, "Maximum number of allowable file uploads has been exceeded"); ++ } + } + + /* Return with an error if the posted data is garbled */ +-- +2.39.1 + +From d727c144435cb656f3636343a17c6bd48102ab95 Mon Sep 17 00:00:00 2001 +From: Jakub Zelenka <bukka@php.net> +Date: Thu, 19 Jan 2023 14:31:25 +0000 +Subject: [PATCH 6/8] Introduce max_multipart_body_parts INI + +This fixes GHSA-54hq-v5wp-fqgv DOS vulnerabality by limitting number of +parsed multipart body parts as currently all parts were always parsed. + +(cherry picked from commit 8ec78d28d20c82c75c4747f44c52601cfdb22516) +--- + main/main.c | 1 + + main/rfc1867.c | 11 +++++++++++ + 2 files changed, 12 insertions(+) + +diff --git a/main/main.c b/main/main.c +index 7deb3010d9..e7edc03530 100644 +--- a/main/main.c ++++ b/main/main.c +@@ -627,6 +627,7 @@ PHP_INI_BEGIN() + PHP_INI_ENTRY("disable_functions", "", PHP_INI_SYSTEM, NULL) + PHP_INI_ENTRY("disable_classes", "", PHP_INI_SYSTEM, NULL) + PHP_INI_ENTRY("max_file_uploads", "20", PHP_INI_SYSTEM|PHP_INI_PERDIR, NULL) ++ PHP_INI_ENTRY("max_multipart_body_parts", "-1", PHP_INI_SYSTEM|PHP_INI_PERDIR, NULL) + + STD_PHP_INI_BOOLEAN("allow_url_fopen", "1", PHP_INI_SYSTEM, OnUpdateBool, allow_url_fopen, php_core_globals, core_globals) + STD_PHP_INI_BOOLEAN("allow_url_include", "0", PHP_INI_SYSTEM, OnUpdateBool, allow_url_include, php_core_globals, core_globals) +diff --git a/main/rfc1867.c b/main/rfc1867.c +index 4aef7edb6e..1eb81827f5 100644 +--- a/main/rfc1867.c ++++ b/main/rfc1867.c +@@ -704,6 +704,7 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */ + void *event_extra_data = NULL; + unsigned int llen = 0; + int upload_cnt = INI_INT("max_file_uploads"); ++ int body_parts_cnt = INI_INT("max_multipart_body_parts"); + const zend_encoding *internal_encoding = zend_multibyte_get_internal_encoding(); + php_rfc1867_getword_t getword; + php_rfc1867_getword_conf_t getword_conf; +@@ -725,6 +726,11 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */ + return; + } + ++ if (body_parts_cnt < 0) { ++ body_parts_cnt = PG(max_input_vars) + upload_cnt; ++ } ++ int body_parts_limit = body_parts_cnt; ++ + /* Get the boundary */ + boundary = strstr(content_type_dup, "boundary"); + if (!boundary) { +@@ -809,6 +815,11 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */ + char *pair = NULL; + int end = 0; + ++ if (--body_parts_cnt < 0) { ++ php_error_docref(NULL, E_WARNING, "Multipart body parts limit exceeded %d. To increase the limit change max_multipart_body_parts in php.ini.", body_parts_limit); ++ goto fileupload_done; ++ } ++ + while (isspace(*cd)) { + ++cd; + } +-- +2.39.1 + +From 953b15210854fcf6f7e97d965a3e26463d91a29f Mon Sep 17 00:00:00 2001 +From: Remi Collet <remi@remirepo.net> +Date: Tue, 14 Feb 2023 09:14:47 +0100 +Subject: [PATCH 7/8] NEWS + +(cherry picked from commit 472db3ee3a00ac00d36019eee0b3b7362334481c) +--- + NEWS | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/NEWS b/NEWS +index bc9083d3e8..7d1786eeb2 100644 +--- a/NEWS ++++ b/NEWS +@@ -9,6 +9,10 @@ Backported from 8.0.28 + . Fixed bug #81746 (1-byte array overrun in common path resolve code). + (CVE-2023-0568). (Niels Dossche) + ++- FPM: ++ . Fixed bug GHSA-54hq-v5wp-fqgv (DOS vulnerability when parsing multipart ++ request body). (CVE-2023-0662) (Jakub Zelenka) ++ + Backported from 8.0.27 + + - PDO/SQLite: +-- +2.39.1 + +From 979ef0c000baf908d8fd5123d18a345fc5b21be1 Mon Sep 17 00:00:00 2001 +From: Remi Collet <remi@remirepo.net> +Date: Tue, 14 Feb 2023 11:47:22 +0100 +Subject: [PATCH 8/8] fix NEWS, not FPM specific + +(cherry picked from commit c04f310440a906fc4ca885f4ecf6e3e4cd36edc7) +--- + NEWS | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/NEWS b/NEWS +index 7d1786eeb2..a2d95193c4 100644 +--- a/NEWS ++++ b/NEWS +@@ -8,8 +8,6 @@ Backported from 8.0.28 + (CVE-2023-0567). (Tim Düsterhus) + . Fixed bug #81746 (1-byte array overrun in common path resolve code). + (CVE-2023-0568). (Niels Dossche) +- +-- FPM: + . Fixed bug GHSA-54hq-v5wp-fqgv (DOS vulnerability when parsing multipart + request body). (CVE-2023-0662) (Jakub Zelenka) + +-- +2.39.1 + diff --git a/php-cve-2023-3247.patch b/php-cve-2023-3247.patch new file mode 100644 index 0000000..4d66794 --- /dev/null +++ b/php-cve-2023-3247.patch @@ -0,0 +1,152 @@ +From e91122cd59b6331574891a5603b3dc173a1ab205 Mon Sep 17 00:00:00 2001 +From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> +Date: Sun, 16 Apr 2023 15:05:03 +0200 +Subject: [PATCH] Fix missing randomness check and insufficient random bytes + for SOAP HTTP Digest +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If php_random_bytes_throw fails, the nonce will be uninitialized, but +still sent to the server. The client nonce is intended to protect +against a malicious server. See section 5.10 and 5.12 of RFC 7616 [1], +and bullet point 2 below. + +Tim pointed out that even though it's the MD5 of the nonce that gets sent, +enumerating 31 bits is trivial. So we have still a stack information leak +of 31 bits. + +Furthermore, Tim found the following issues: +* The small size of cnonce might cause the server to erroneously reject + a request due to a repeated (cnonce, nc) pair. As per the birthday + problem 31 bits of randomness will return a duplication with 50% + chance after less than 55000 requests and nc always starts counting at 1. +* The cnonce is intended to protect the client and password against a + malicious server that returns a constant server nonce where the server + precomputed a rainbow table between passwords and correct client response. + As storage is fairly cheap, a server could precompute the client responses + for (a subset of) client nonces and still have a chance of reversing the + client response with the same probability as the cnonce duplication. + + Precomputing the rainbow table for all 2^31 cnonces increases the rainbow + table size by factor 2 billion, which is infeasible. But precomputing it + for 2^14 cnonces only increases the table size by factor 16k and the server + would still have a 10% chance of successfully reversing a password with a + single client request. + +This patch fixes the issues by increasing the nonce size, and checking +the return value of php_random_bytes_throw(). In the process we also get +rid of the MD5 hashing of the nonce. + +[1] RFC 7616: https://www.rfc-editor.org/rfc/rfc7616 + +Co-authored-by: Tim Düsterhus <timwolla@php.net> +(cherry picked from commit 126d517ce240e9f638d9a5eaa509eaca49ef562a) +(cherry picked from commit 0cfca9aa1395271833848daec0bace51d965531d) +--- + NEWS | 6 ++++++ + ext/soap/php_http.c | 21 +++++++++++++-------- + 2 files changed, 19 insertions(+), 8 deletions(-) + +diff --git a/NEWS b/NEWS +index a2d95193c4b..534c4787b4e 100644 +--- a/NEWS ++++ b/NEWS +@@ -1,6 +1,12 @@ + PHP NEWS + ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| + ++Backported from 8.0.29 ++ ++- Soap: ++ . Fixed bug GHSA-76gg-c692-v2mw (Missing error check and insufficient random ++ bytes in HTTP Digest authentication for SOAP). (nielsdos, timwolla) ++ + Backported from 8.0.28 + + - Core: +diff --git a/ext/soap/php_http.c b/ext/soap/php_http.c +index b894a1eabfe..9e5ecf6d22a 100644 +--- a/ext/soap/php_http.c ++++ b/ext/soap/php_http.c +@@ -646,18 +646,23 @@ int make_http_soap_request(zval *this_ptr, + if ((digest = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "_digest", sizeof("_digest")-1)) != NULL) { + if (Z_TYPE_P(digest) == IS_ARRAY) { + char HA1[33], HA2[33], response[33], cnonce[33], nc[9]; +- zend_long nonce; ++ unsigned char nonce[16]; + PHP_MD5_CTX md5ctx; + unsigned char hash[16]; + +- php_random_bytes_throw(&nonce, sizeof(nonce)); +- nonce &= 0x7fffffff; ++ if (UNEXPECTED(php_random_bytes_throw(&nonce, sizeof(nonce)) != SUCCESS)) { ++ ZEND_ASSERT(EG(exception)); ++ php_stream_close(stream); ++ zend_hash_str_del(Z_OBJPROP_P(this_ptr), "httpurl", sizeof("httpurl")-1); ++ zend_hash_str_del(Z_OBJPROP_P(this_ptr), "httpsocket", sizeof("httpsocket")-1); ++ zend_hash_str_del(Z_OBJPROP_P(this_ptr), "_use_proxy", sizeof("_use_proxy")-1); ++ smart_str_free(&soap_headers_z); ++ smart_str_free(&soap_headers); ++ return FALSE; ++ } + +- PHP_MD5Init(&md5ctx); +- snprintf(cnonce, sizeof(cnonce), ZEND_LONG_FMT, nonce); +- PHP_MD5Update(&md5ctx, (unsigned char*)cnonce, strlen(cnonce)); +- PHP_MD5Final(hash, &md5ctx); +- make_digest(cnonce, hash); ++ php_hash_bin2hex(cnonce, nonce, sizeof(nonce)); ++ cnonce[32] = 0; + + if ((tmp = zend_hash_str_find(Z_ARRVAL_P(digest), "nc", sizeof("nc")-1)) != NULL && + Z_TYPE_P(tmp) == IS_LONG) { +From 24842f1115d64176e545ad893ad95c4650456efa Mon Sep 17 00:00:00 2001 +From: Remi Collet <remi@remirepo.net> +Date: Tue, 6 Jun 2023 18:05:22 +0200 +Subject: [PATCH] Fix GH-11382 add missing hash header for bin2hex + +(cherry picked from commit 40439039c224bb8cdebd1b7b3d03b8cc11e7cce7) +--- + ext/soap/php_http.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/ext/soap/php_http.c b/ext/soap/php_http.c +index 9e5ecf6d22..2f281dd7db 100644 +--- a/ext/soap/php_http.c ++++ b/ext/soap/php_http.c +@@ -23,6 +23,7 @@ + #include "ext/standard/base64.h" + #include "ext/standard/md5.h" + #include "ext/standard/php_random.h" ++#include "ext/hash/php_hash.h" + + static char *get_http_header_value(char *headers, char *type); + static zend_string *get_http_body(php_stream *socketd, int close, char *headers); +From fe8af503fd954396ad061ceecf470e93f490d467 Mon Sep 17 00:00:00 2001 +From: Remi Collet <remi@remirepo.net> +Date: Thu, 15 Jun 2023 08:47:55 +0200 +Subject: [PATCH] add cve + +(cherry picked from commit f3021d66d7bb42d2578530cc94f9bde47e58eb10) +--- + NEWS | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/NEWS b/NEWS +index 534c4787b4..e7cdaa7698 100644 +--- a/NEWS ++++ b/NEWS +@@ -5,7 +5,8 @@ Backported from 8.0.29 + + - Soap: + . Fixed bug GHSA-76gg-c692-v2mw (Missing error check and insufficient random +- bytes in HTTP Digest authentication for SOAP). (nielsdos, timwolla) ++ bytes in HTTP Digest authentication for SOAP). ++ (CVE-2023-3247) (nielsdos, timwolla) + + Backported from 8.0.28 + +-- +2.40.1 + diff --git a/php-cve-2023-3823.patch b/php-cve-2023-3823.patch new file mode 100644 index 0000000..c816653 --- /dev/null +++ b/php-cve-2023-3823.patch @@ -0,0 +1,92 @@ +From f41261182dad0f831d8727967c127da1f08c8ce5 Mon Sep 17 00:00:00 2001 +From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> +Date: Mon, 10 Jul 2023 13:25:34 +0200 +Subject: [PATCH 1/3] Fix buffer mismanagement in phar_dir_read() + +Fixes GHSA-jqcx-ccgc-xwhv. + +(cherry picked from commit 80316123f3e9dcce8ac419bd9dd43546e2ccb5ef) +(cherry picked from commit c398fe98c044c8e7c23135acdc38d4ef7bedc983) +(cherry picked from commit 3f14261065e4c0552afa9cb16411475050a41c2c) +(cherry picked from commit f8f433d0d8eaac21af4f4532496d33f9c2b381d6) +--- + ext/phar/dirstream.c | 15 ++++++++------ + ext/phar/tests/GHSA-jqcx-ccgc-xwhv.phpt | 27 +++++++++++++++++++++++++ + 2 files changed, 36 insertions(+), 6 deletions(-) + create mode 100644 ext/phar/tests/GHSA-jqcx-ccgc-xwhv.phpt + +diff --git a/ext/phar/dirstream.c b/ext/phar/dirstream.c +index 36c7f9e812..6ced23880b 100644 +--- a/ext/phar/dirstream.c ++++ b/ext/phar/dirstream.c +@@ -92,25 +92,28 @@ static int phar_dir_seek(php_stream *stream, zend_off_t offset, int whence, zend + */ + static size_t phar_dir_read(php_stream *stream, char *buf, size_t count) /* {{{ */ + { +- size_t to_read; + HashTable *data = (HashTable *)stream->abstract; + zend_string *str_key; + zend_ulong unused; + ++ if (count != sizeof(php_stream_dirent)) { ++ return -1; ++ } ++ + if (HASH_KEY_NON_EXISTENT == zend_hash_get_current_key(data, &str_key, &unused)) { + return 0; + } + + zend_hash_move_forward(data); +- to_read = MIN(ZSTR_LEN(str_key), count); + +- if (to_read == 0 || count < ZSTR_LEN(str_key)) { ++ php_stream_dirent *dirent = (php_stream_dirent *) buf; ++ ++ if (sizeof(dirent->d_name) <= ZSTR_LEN(str_key)) { + return 0; + } + +- memset(buf, 0, sizeof(php_stream_dirent)); +- memcpy(((php_stream_dirent *) buf)->d_name, ZSTR_VAL(str_key), to_read); +- ((php_stream_dirent *) buf)->d_name[to_read + 1] = '\0'; ++ memset(dirent, 0, sizeof(php_stream_dirent)); ++ PHP_STRLCPY(dirent->d_name, ZSTR_VAL(str_key), sizeof(dirent->d_name), ZSTR_LEN(str_key)); + + return sizeof(php_stream_dirent); + } +diff --git a/ext/phar/tests/GHSA-jqcx-ccgc-xwhv.phpt b/ext/phar/tests/GHSA-jqcx-ccgc-xwhv.phpt +new file mode 100644 +index 0000000000..4e12f05fb6 +--- /dev/null ++++ b/ext/phar/tests/GHSA-jqcx-ccgc-xwhv.phpt +@@ -0,0 +1,27 @@ ++--TEST-- ++GHSA-jqcx-ccgc-xwhv (Buffer overflow and overread in phar_dir_read()) ++--SKIPIF-- ++<?php if (!extension_loaded("phar")) die("skip"); ?> ++--INI-- ++phar.readonly=0 ++--FILE-- ++<?php ++$phar = new Phar(__DIR__. '/GHSA-jqcx-ccgc-xwhv.phar'); ++$phar->startBuffering(); ++$phar->addFromString(str_repeat('A', PHP_MAXPATHLEN - 1), 'This is the content of file 1.'); ++$phar->addFromString(str_repeat('B', PHP_MAXPATHLEN - 1).'C', 'This is the content of file 2.'); ++$phar->stopBuffering(); ++ ++$handle = opendir('phar://' . __DIR__ . '/GHSA-jqcx-ccgc-xwhv.phar'); ++var_dump(strlen(readdir($handle))); ++// Must not be a string of length PHP_MAXPATHLEN+1 ++var_dump(readdir($handle)); ++closedir($handle); ++?> ++--CLEAN-- ++<?php ++unlink(__DIR__. '/GHSA-jqcx-ccgc-xwhv.phar'); ++?> ++--EXPECTF-- ++int(%d) ++bool(false) +-- +2.41.0 + diff --git a/php-cve-2023-3824.patch b/php-cve-2023-3824.patch new file mode 100644 index 0000000..1f5a60b --- /dev/null +++ b/php-cve-2023-3824.patch @@ -0,0 +1,406 @@ +From 66a1fcc69765bb704146fe7d084848302dd3c89e Mon Sep 17 00:00:00 2001 +From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> +Date: Sat, 15 Jul 2023 17:33:52 +0200 +Subject: [PATCH 2/3] Sanitize libxml2 globals before parsing + +Fixes GHSA-3qrf-m4j2-pcrr. + +To parse a document with libxml2, you first need to create a parsing context. +The parsing context contains parsing options (e.g. XML_NOENT to substitute +entities) that the application (in this case PHP) can set. +Unfortunately, libxml2 also supports providing default set options. +For example, if you call xmlSubstituteEntitiesDefault(1) then the XML_NOENT +option will be added to the parsing options every time you create a parsing +context **even if the application never requested XML_NOENT**. + +Third party extensions can override these globals, in particular the +substitute entity global. This causes entity substitution to be +unexpectedly active. + +Fix it by setting the parsing options to a sane known value. +For API calls that depend on global state we introduce +PHP_LIBXML_SANITIZE_GLOBALS() and PHP_LIBXML_RESTORE_GLOBALS(). +For other APIs that work directly with a context we introduce +php_libxml_sanitize_parse_ctxt_options(). + +(cherry picked from commit c283c3ab0ba45d21b2b8745c1f9c7cbfe771c975) +(cherry picked from commit b3758bd21223b97c042cae7bd26a66cde081ea98) +(cherry picked from commit 4fb61f06b1aff89a4d7e548c37ffa5bf573270c3) +(cherry picked from commit d7de6908dfc8774e86a54100ad4e2ee810426001) +--- + ext/dom/document.c | 15 +++++++++++++++ + ext/dom/documentfragment.c | 2 ++ + ext/libxml/php_libxml.h | 36 +++++++++++++++++++++++++++++++++++ + ext/simplexml/simplexml.c | 6 ++++++ + ext/soap/php_xml.c | 2 ++ + ext/xml/compat.c | 2 ++ + ext/xmlreader/php_xmlreader.c | 9 +++++++++ + ext/xsl/xsltprocessor.c | 9 ++++----- + 8 files changed, 76 insertions(+), 5 deletions(-) + +diff --git a/ext/dom/document.c b/ext/dom/document.c +index c212faa695..b0eed5820b 100644 +--- a/ext/dom/document.c ++++ b/ext/dom/document.c +@@ -1438,6 +1438,7 @@ static xmlDocPtr dom_document_parser(zval *id, int mode, char *source, size_t so + options |= XML_PARSE_NOBLANKS; + } + ++ php_libxml_sanitize_parse_ctxt_options(ctxt); + xmlCtxtUseOptions(ctxt, options); + + ctxt->recovery = recover; +@@ -1735,7 +1736,9 @@ PHP_FUNCTION(dom_document_xinclude) + + DOM_GET_OBJ(docp, id, xmlDocPtr, intern); + ++ PHP_LIBXML_SANITIZE_GLOBALS(xinclude); + err = xmlXIncludeProcessFlags(docp, (int)flags); ++ PHP_LIBXML_RESTORE_GLOBALS(xinclude); + + /* XML_XINCLUDE_START and XML_XINCLUDE_END nodes need to be removed as these + are added via xmlXIncludeProcess to mark beginning and ending of xincluded document +@@ -1774,6 +1777,7 @@ PHP_FUNCTION(dom_document_validate) + + DOM_GET_OBJ(docp, id, xmlDocPtr, intern); + ++ PHP_LIBXML_SANITIZE_GLOBALS(validate); + cvp = xmlNewValidCtxt(); + + cvp->userData = NULL; +@@ -1785,6 +1789,7 @@ PHP_FUNCTION(dom_document_validate) + } else { + RETVAL_FALSE; + } ++ PHP_LIBXML_RESTORE_GLOBALS(validate); + + xmlFreeValidCtxt(cvp); + +@@ -1818,14 +1823,18 @@ static void _dom_document_schema_validate(INTERNAL_FUNCTION_PARAMETERS, int type + + DOM_GET_OBJ(docp, id, xmlDocPtr, intern); + ++ PHP_LIBXML_SANITIZE_GLOBALS(new_parser_ctxt); ++ + switch (type) { + case DOM_LOAD_FILE: + if (CHECK_NULL_PATH(source, source_len)) { ++ PHP_LIBXML_RESTORE_GLOBALS(new_parser_ctxt); + php_error_docref(NULL, E_WARNING, "Invalid Schema file source"); + RETURN_FALSE; + } + valid_file = _dom_get_valid_file_path(source, resolved_path, MAXPATHLEN); + if (!valid_file) { ++ PHP_LIBXML_RESTORE_GLOBALS(new_parser_ctxt); + php_error_docref(NULL, E_WARNING, "Invalid Schema file source"); + RETURN_FALSE; + } +@@ -1846,6 +1855,7 @@ static void _dom_document_schema_validate(INTERNAL_FUNCTION_PARAMETERS, int type + parser); + sptr = xmlSchemaParse(parser); + xmlSchemaFreeParserCtxt(parser); ++ PHP_LIBXML_RESTORE_GLOBALS(new_parser_ctxt); + if (!sptr) { + php_error_docref(NULL, E_WARNING, "Invalid Schema"); + RETURN_FALSE; +@@ -1866,11 +1876,13 @@ static void _dom_document_schema_validate(INTERNAL_FUNCTION_PARAMETERS, int type + } + #endif + ++ PHP_LIBXML_SANITIZE_GLOBALS(validate); + xmlSchemaSetValidOptions(vptr, valid_opts); + xmlSchemaSetValidErrors(vptr, php_libxml_error_handler, php_libxml_error_handler, vptr); + is_valid = xmlSchemaValidateDoc(vptr, docp); + xmlSchemaFree(sptr); + xmlSchemaFreeValidCtxt(vptr); ++ PHP_LIBXML_RESTORE_GLOBALS(validate); + + if (is_valid == 0) { + RETURN_TRUE; +@@ -1940,12 +1952,14 @@ static void _dom_document_relaxNG_validate(INTERNAL_FUNCTION_PARAMETERS, int typ + return; + } + ++ PHP_LIBXML_SANITIZE_GLOBALS(parse); + xmlRelaxNGSetParserErrors(parser, + (xmlRelaxNGValidityErrorFunc) php_libxml_error_handler, + (xmlRelaxNGValidityWarningFunc) php_libxml_error_handler, + parser); + sptr = xmlRelaxNGParse(parser); + xmlRelaxNGFreeParserCtxt(parser); ++ PHP_LIBXML_RESTORE_GLOBALS(parse); + if (!sptr) { + php_error_docref(NULL, E_WARNING, "Invalid RelaxNG"); + RETURN_FALSE; +@@ -2045,6 +2059,7 @@ static void dom_load_html(INTERNAL_FUNCTION_PARAMETERS, int mode) /* {{{ */ + ctxt->sax->error = php_libxml_ctx_error; + ctxt->sax->warning = php_libxml_ctx_warning; + } ++ php_libxml_sanitize_parse_ctxt_options(ctxt); + if (options) { + htmlCtxtUseOptions(ctxt, (int)options); + } +diff --git a/ext/dom/documentfragment.c b/ext/dom/documentfragment.c +index 87cb691501..b7ecfdc14b 100644 +--- a/ext/dom/documentfragment.c ++++ b/ext/dom/documentfragment.c +@@ -134,7 +134,9 @@ PHP_METHOD(domdocumentfragment, appendXML) { + } + + if (data) { ++ PHP_LIBXML_SANITIZE_GLOBALS(parse); + err = xmlParseBalancedChunkMemory(nodep->doc, NULL, NULL, 0, (xmlChar *) data, &lst); ++ PHP_LIBXML_RESTORE_GLOBALS(parse); + if (err != 0) { + RETURN_FALSE; + } +diff --git a/ext/libxml/php_libxml.h b/ext/libxml/php_libxml.h +index f7aa726d88..371b4eecc5 100644 +--- a/ext/libxml/php_libxml.h ++++ b/ext/libxml/php_libxml.h +@@ -122,6 +122,42 @@ PHP_LIBXML_API void php_libxml_shutdown(void); + ZEND_TSRMLS_CACHE_EXTERN() + #endif + ++/* Other extension may override the global state options, these global options ++ * are copied initially to ctxt->options. Set the options to a known good value. ++ * See libxml2 globals.c and parserInternals.c. ++ * The unique_name argument allows multiple sanitizes and restores within the ++ * same function, even nested is necessary. */ ++#define PHP_LIBXML_SANITIZE_GLOBALS(unique_name) \ ++ int xml_old_loadsubset_##unique_name = xmlLoadExtDtdDefaultValue; \ ++ xmlLoadExtDtdDefaultValue = 0; \ ++ int xml_old_validate_##unique_name = xmlDoValidityCheckingDefaultValue; \ ++ xmlDoValidityCheckingDefaultValue = 0; \ ++ int xml_old_pedantic_##unique_name = xmlPedanticParserDefault(0); \ ++ int xml_old_substitute_##unique_name = xmlSubstituteEntitiesDefault(0); \ ++ int xml_old_linenrs_##unique_name = xmlLineNumbersDefault(0); \ ++ int xml_old_blanks_##unique_name = xmlKeepBlanksDefault(1); ++ ++#define PHP_LIBXML_RESTORE_GLOBALS(unique_name) \ ++ xmlLoadExtDtdDefaultValue = xml_old_loadsubset_##unique_name; \ ++ xmlDoValidityCheckingDefaultValue = xml_old_validate_##unique_name; \ ++ (void) xmlPedanticParserDefault(xml_old_pedantic_##unique_name); \ ++ (void) xmlSubstituteEntitiesDefault(xml_old_substitute_##unique_name); \ ++ (void) xmlLineNumbersDefault(xml_old_linenrs_##unique_name); \ ++ (void) xmlKeepBlanksDefault(xml_old_blanks_##unique_name); ++ ++/* Alternative for above, working directly on the context and not setting globals. ++ * Generally faster because no locking is involved, and this has the advantage that it sets the options to a known good value. */ ++static zend_always_inline void php_libxml_sanitize_parse_ctxt_options(xmlParserCtxtPtr ctxt) ++{ ++ ctxt->loadsubset = 0; ++ ctxt->validate = 0; ++ ctxt->pedantic = 0; ++ ctxt->replaceEntities = 0; ++ ctxt->linenumbers = 0; ++ ctxt->keepBlanks = 1; ++ ctxt->options = 0; ++} ++ + #else /* HAVE_LIBXML */ + #define libxml_module_ptr NULL + #endif +diff --git a/ext/simplexml/simplexml.c b/ext/simplexml/simplexml.c +index ae067cdcdd..bfac015964 100644 +--- a/ext/simplexml/simplexml.c ++++ b/ext/simplexml/simplexml.c +@@ -2229,7 +2229,9 @@ PHP_FUNCTION(simplexml_load_file) + RETURN_FALSE; + } + ++ PHP_LIBXML_SANITIZE_GLOBALS(read_file); + docp = xmlReadFile(filename, NULL, (int)options); ++ PHP_LIBXML_RESTORE_GLOBALS(read_file); + + if (!docp) { + RETURN_FALSE; +@@ -2283,7 +2285,9 @@ PHP_FUNCTION(simplexml_load_string) + RETURN_FALSE; + } + ++ PHP_LIBXML_SANITIZE_GLOBALS(read_memory); + docp = xmlReadMemory(data, (int)data_len, NULL, NULL, (int)options); ++ PHP_LIBXML_RESTORE_GLOBALS(read_memory); + + if (!docp) { + RETURN_FALSE; +@@ -2333,7 +2337,9 @@ SXE_METHOD(__construct) + return; + } + ++ PHP_LIBXML_SANITIZE_GLOBALS(read_file_or_memory); + docp = is_url ? xmlReadFile(data, NULL, (int)options) : xmlReadMemory(data, (int)data_len, NULL, NULL, (int)options); ++ PHP_LIBXML_RESTORE_GLOBALS(read_file_or_memory); + + if (!docp) { + ((php_libxml_node_object *)sxe)->document = NULL; +diff --git a/ext/soap/php_xml.c b/ext/soap/php_xml.c +index 1ac684eb81..053960c559 100644 +--- a/ext/soap/php_xml.c ++++ b/ext/soap/php_xml.c +@@ -94,6 +94,7 @@ xmlDocPtr soap_xmlParseFile(const char *filename) + if (ctxt) { + zend_bool old; + ++ php_libxml_sanitize_parse_ctxt_options(ctxt); + ctxt->keepBlanks = 0; + ctxt->sax->ignorableWhitespace = soap_ignorableWhitespace; + ctxt->sax->comment = soap_Comment; +@@ -144,6 +145,7 @@ xmlDocPtr soap_xmlParseMemory(const void *buf, size_t buf_size) + if (ctxt) { + zend_bool old; + ++ php_libxml_sanitize_parse_ctxt_options(ctxt); + ctxt->sax->ignorableWhitespace = soap_ignorableWhitespace; + ctxt->sax->comment = soap_Comment; + ctxt->sax->warning = NULL; +diff --git a/ext/xml/compat.c b/ext/xml/compat.c +index ef83485722..c55047215b 100644 +--- a/ext/xml/compat.c ++++ b/ext/xml/compat.c +@@ -19,6 +19,7 @@ + #include "php.h" + #if defined(HAVE_LIBXML) && (defined(HAVE_XML) || defined(HAVE_XMLRPC)) && !defined(HAVE_LIBEXPAT) + #include "expat_compat.h" ++#include "ext/libxml/php_libxml.h" + + typedef struct _php_xml_ns { + xmlNsPtr nsptr; +@@ -473,6 +474,7 @@ XML_ParserCreate_MM(const XML_Char *encoding, const XML_Memory_Handling_Suite *m + parser->parser->charset = XML_CHAR_ENCODING_NONE; + #endif + ++ php_libxml_sanitize_parse_ctxt_options(parser->parser); + #if LIBXML_VERSION >= 20703 + xmlCtxtUseOptions(parser->parser, XML_PARSE_OLDSAX); + #endif +diff --git a/ext/xmlreader/php_xmlreader.c b/ext/xmlreader/php_xmlreader.c +index 0f2b62ae20..f0fd013ff9 100644 +--- a/ext/xmlreader/php_xmlreader.c ++++ b/ext/xmlreader/php_xmlreader.c +@@ -301,6 +301,7 @@ static xmlRelaxNGPtr _xmlreader_get_relaxNG(char *source, size_t source_len, siz + return NULL; + } + ++ PHP_LIBXML_SANITIZE_GLOBALS(parse); + if (error_func || warn_func) { + xmlRelaxNGSetParserErrors(parser, + (xmlRelaxNGValidityErrorFunc) error_func, +@@ -309,6 +310,7 @@ static xmlRelaxNGPtr _xmlreader_get_relaxNG(char *source, size_t source_len, siz + } + sptr = xmlRelaxNGParse(parser); + xmlRelaxNGFreeParserCtxt(parser); ++ PHP_LIBXML_RESTORE_GLOBALS(parse); + + return sptr; + } +@@ -881,7 +883,9 @@ PHP_METHOD(xmlreader, open) + valid_file = _xmlreader_get_valid_file_path(source, resolved_path, MAXPATHLEN ); + + if (valid_file) { ++ PHP_LIBXML_SANITIZE_GLOBALS(reader_for_file); + reader = xmlReaderForFile(valid_file, encoding, options); ++ PHP_LIBXML_RESTORE_GLOBALS(reader_for_file); + } + + if (reader == NULL) { +@@ -959,7 +963,9 @@ PHP_METHOD(xmlreader, setSchema) + + intern = Z_XMLREADER_P(id); + if (intern && intern->ptr) { ++ PHP_LIBXML_SANITIZE_GLOBALS(schema); + retval = xmlTextReaderSchemaValidate(intern->ptr, source); ++ PHP_LIBXML_RESTORE_GLOBALS(schema); + + if (retval == 0) { + RETURN_TRUE; +@@ -1079,6 +1085,7 @@ PHP_METHOD(xmlreader, XML) + } + uri = (char *) xmlCanonicPath((const xmlChar *) resolved_path); + } ++ PHP_LIBXML_SANITIZE_GLOBALS(text_reader); + reader = xmlNewTextReader(inputbfr, uri); + + if (reader != NULL) { +@@ -1099,9 +1106,11 @@ PHP_METHOD(xmlreader, XML) + xmlFree(uri); + } + ++ PHP_LIBXML_RESTORE_GLOBALS(text_reader); + return; + } + } ++ PHP_LIBXML_RESTORE_GLOBALS(text_reader); + } + + if (uri) { +diff --git a/ext/xsl/xsltprocessor.c b/ext/xsl/xsltprocessor.c +index 9948d6f0b3..7bbe640a5c 100644 +--- a/ext/xsl/xsltprocessor.c ++++ b/ext/xsl/xsltprocessor.c +@@ -396,7 +396,7 @@ PHP_FUNCTION(xsl_xsltprocessor_import_stylesheet) + xmlDoc *doc = NULL, *newdoc = NULL; + xsltStylesheetPtr sheetp, oldsheetp; + xsl_object *intern; +- int prevSubstValue, prevExtDtdValue, clone_docu = 0; ++ int clone_docu = 0; + xmlNode *nodep = NULL; + zend_object_handlers *std_hnd; + zval *cloneDocu, member, rv; +@@ -419,13 +419,12 @@ PHP_FUNCTION(xsl_xsltprocessor_import_stylesheet) + stylesheet document otherwise the node proxies will be a mess */ + newdoc = xmlCopyDoc(doc, 1); + xmlNodeSetBase((xmlNodePtr) newdoc, (xmlChar *)doc->URL); +- prevSubstValue = xmlSubstituteEntitiesDefault(1); +- prevExtDtdValue = xmlLoadExtDtdDefaultValue; ++ PHP_LIBXML_SANITIZE_GLOBALS(parse); ++ xmlSubstituteEntitiesDefault(1); + xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS; + + sheetp = xsltParseStylesheetDoc(newdoc); +- xmlSubstituteEntitiesDefault(prevSubstValue); +- xmlLoadExtDtdDefaultValue = prevExtDtdValue; ++ PHP_LIBXML_RESTORE_GLOBALS(parse); + + if (!sheetp) { + xmlFreeDoc(newdoc); +-- +2.41.0 + +From 3ac0ce8a462cb31815330d1410e1a8a615c395eb Mon Sep 17 00:00:00 2001 +From: Remi Collet <remi@remirepo.net> +Date: Tue, 1 Aug 2023 07:22:33 +0200 +Subject: [PATCH 3/3] NEWS + +(cherry picked from commit ef1d507acf7be23d7624dc3c891683b2218feb51) +(cherry picked from commit 3cf7c2b10e577136b267f2d90bfdff6743271c5c) +(cherry picked from commit 79c0bf87711036b83f8ee1723c034ccc839d847b) +--- + NEWS | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/NEWS b/NEWS +index e7cdaa7698..99387fbfd7 100644 +--- a/NEWS ++++ b/NEWS +@@ -1,6 +1,16 @@ + PHP NEWS + ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| + ++Backported from 8.0.30 ++ ++- Libxml: ++ . Fixed bug GHSA-3qrf-m4j2-pcrr (Security issue with external entity loading ++ in XML without enabling it). (CVE-2023-3823) (nielsdos, ilutov) ++ ++- Phar: ++ . Fixed bug GHSA-jqcx-ccgc-xwhv (Buffer mismanagement in phar_dir_read()). ++ (CVE-2023-3824) (nielsdos) ++ + Backported from 8.0.29 + + - Soap: +-- +2.41.0 + diff --git a/php-cve-2024-2756.patch b/php-cve-2024-2756.patch new file mode 100644 index 0000000..61bcafc --- /dev/null +++ b/php-cve-2024-2756.patch @@ -0,0 +1,199 @@ +From a1b0060906bc4eedaf5bb3577a0d6d4b0e6b9dfd Mon Sep 17 00:00:00 2001 +From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> +Date: Sun, 17 Mar 2024 21:04:47 +0100 +Subject: [PATCH 1/4] Fix GHSA-wpj3-hf5j-x4v4: __Host-/__Secure- cookie bypass + due to partial CVE-2022-31629 fix + +The check happened too early as later code paths may perform more +mangling rules. Move the check downwards right before adding the actual +variable. + +(cherry picked from commit 093c08af25fb323efa0c8e6154aa9fdeae3d3b53) +(cherry picked from commit 2e07a3acd7a6b53c55325b94bed97748d7697b53) +(cherry picked from commit a6c1c62a25ac23b08a86af11d68f0e2eaafc102b) +(cherry picked from commit 46b570a1e4aeb4a414898fcc09503ac388d16256) +(cherry picked from commit c213de619a532d35e8f7abe4a245433dbf21c960) +--- + ext/standard/tests/ghsa-wpj3-hf5j-x4v4.phpt | 63 +++++++++++++++++++++ + main/php_variables.c | 41 +++++++++----- + 2 files changed, 90 insertions(+), 14 deletions(-) + create mode 100644 ext/standard/tests/ghsa-wpj3-hf5j-x4v4.phpt + +diff --git a/ext/standard/tests/ghsa-wpj3-hf5j-x4v4.phpt b/ext/standard/tests/ghsa-wpj3-hf5j-x4v4.phpt +new file mode 100644 +index 0000000000..77fcb68089 +--- /dev/null ++++ b/ext/standard/tests/ghsa-wpj3-hf5j-x4v4.phpt +@@ -0,0 +1,63 @@ ++--TEST-- ++ghsa-wpj3-hf5j-x4v4 (__Host-/__Secure- cookie bypass due to partial CVE-2022-31629 fix) ++--COOKIE-- ++..Host-test=ignore_1; ++._Host-test=ignore_2; ++.[Host-test=ignore_3; ++_.Host-test=ignore_4; ++__Host-test=ignore_5; ++_[Host-test=ignore_6; ++[.Host-test=ignore_7; ++[_Host-test=ignore_8; ++[[Host-test=ignore_9; ++..Host-test[]=ignore_10; ++._Host-test[]=ignore_11; ++.[Host-test[]=ignore_12; ++_.Host-test[]=ignore_13; ++__Host-test[]=legitimate_14; ++_[Host-test[]=legitimate_15; ++[.Host-test[]=ignore_16; ++[_Host-test[]=ignore_17; ++[[Host-test[]=ignore_18; ++..Secure-test=ignore_1; ++._Secure-test=ignore_2; ++.[Secure-test=ignore_3; ++_.Secure-test=ignore_4; ++__Secure-test=ignore_5; ++_[Secure-test=ignore_6; ++[.Secure-test=ignore_7; ++[_Secure-test=ignore_8; ++[[Secure-test=ignore_9; ++..Secure-test[]=ignore_10; ++._Secure-test[]=ignore_11; ++.[Secure-test[]=ignore_12; ++_.Secure-test[]=ignore_13; ++__Secure-test[]=legitimate_14; ++_[Secure-test[]=legitimate_15; ++[.Secure-test[]=ignore_16; ++[_Secure-test[]=ignore_17; ++[[Secure-test[]=ignore_18; ++--FILE-- ++<?php ++var_dump($_COOKIE); ++?> ++--EXPECT-- ++array(3) { ++ ["__Host-test"]=> ++ array(1) { ++ [0]=> ++ string(13) "legitimate_14" ++ } ++ ["_"]=> ++ array(2) { ++ ["Host-test["]=> ++ string(13) "legitimate_15" ++ ["Secure-test["]=> ++ string(13) "legitimate_15" ++ } ++ ["__Secure-test"]=> ++ array(1) { ++ [0]=> ++ string(13) "legitimate_14" ++ } ++} +diff --git a/main/php_variables.c b/main/php_variables.c +index 17a0b053a6..e8fcaa088b 100644 +--- a/main/php_variables.c ++++ b/main/php_variables.c +@@ -53,6 +53,21 @@ PHPAPI void php_register_variable_safe(char *var, char *strval, size_t str_len, + php_register_variable_ex(var, &new_entry, track_vars_array); + } + ++/* Discard variable if mangling made it start with __Host-, where pre-mangling it did not start with __Host- ++ * Discard variable if mangling made it start with __Secure-, where pre-mangling it did not start with __Secure- */ ++static zend_bool php_is_forbidden_variable_name(const char *mangled_name, size_t mangled_name_len, const char *pre_mangled_name) ++{ ++ if (mangled_name_len >= sizeof("__Host-")-1 && strncmp(mangled_name, "__Host-", sizeof("__Host-")-1) == 0 && strncmp(pre_mangled_name, "__Host-", sizeof("__Host-")-1) != 0) { ++ return 1; ++ } ++ ++ if (mangled_name_len >= sizeof("__Secure-")-1 && strncmp(mangled_name, "__Secure-", sizeof("__Secure-")-1) == 0 && strncmp(pre_mangled_name, "__Secure-", sizeof("__Secure-")-1) != 0) { ++ return 1; ++ } ++ ++ return 0; ++} ++ + PHPAPI void php_register_variable_ex(char *var_name, zval *val, zval *track_vars_array) + { + char *p = NULL; +@@ -103,20 +118,6 @@ PHPAPI void php_register_variable_ex(char *var_name, zval *val, zval *track_vars + } + var_len = p - var; + +- /* Discard variable if mangling made it start with __Host-, where pre-mangling it did not start with __Host- */ +- if (strncmp(var, "__Host-", sizeof("__Host-")-1) == 0 && strncmp(var_name, "__Host-", sizeof("__Host-")-1) != 0) { +- zval_ptr_dtor_nogc(val); +- free_alloca(var_orig, use_heap); +- return; +- } +- +- /* Discard variable if mangling made it start with __Secure-, where pre-mangling it did not start with __Secure- */ +- if (strncmp(var, "__Secure-", sizeof("__Secure-")-1) == 0 && strncmp(var_name, "__Secure-", sizeof("__Secure-")-1) != 0) { +- zval_ptr_dtor_nogc(val); +- free_alloca(var_orig, use_heap); +- return; +- } +- + if (var_len==0) { /* empty variable name, or variable name with a space in it */ + zval_dtor(val); + free_alloca(var_orig, use_heap); +@@ -214,6 +215,12 @@ PHPAPI void php_register_variable_ex(char *var_name, zval *val, zval *track_vars + return; + } + } else { ++ if (php_is_forbidden_variable_name(index, index_len, var_name)) { ++ zval_ptr_dtor_nogc(val); ++ free_alloca(var_orig, use_heap); ++ return; ++ } ++ + gpc_element_p = zend_symtable_str_find(symtable1, index, index_len); + if (!gpc_element_p) { + zval tmp; +@@ -250,6 +257,12 @@ plain_var: + zval_ptr_dtor(&gpc_element); + } + } else { ++ if (php_is_forbidden_variable_name(index, index_len, var_name)) { ++ zval_ptr_dtor_nogc(val); ++ free_alloca(var_orig, use_heap); ++ return; ++ } ++ + /* + * According to rfc2965, more specific paths are listed above the less specific ones. + * If we encounter a duplicate cookie name, we should skip it, since it is not possible +-- +2.44.0 + +From 035bc48bafe5d567f4ab8de6d1752a724e361690 Mon Sep 17 00:00:00 2001 +From: Remi Collet <remi@remirepo.net> +Date: Wed, 10 Apr 2024 08:59:32 +0200 +Subject: [PATCH 2/4] NEWS + +(cherry picked from commit 366cc249b7d54707572beb7096e8f6c65ee79719) +(cherry picked from commit dcdd49ef3bfbd8ccc778850d6a0f9b98adf625d4) +(cherry picked from commit 8642473b624f809b768180b104c013f74e3a99a0) +(cherry picked from commit ee591001f7a3db7405b4fa027659768c2355df6d) +--- + NEWS | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/NEWS b/NEWS +index 99387fbfd7..ebe7094f36 100644 +--- a/NEWS ++++ b/NEWS +@@ -1,6 +1,12 @@ + PHP NEWS + ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| + ++Backported from 8.1.28 ++ ++- Standard: ++ . Fixed bug GHSA-wpj3-hf5j-x4v4 (__Host-/__Secure- cookie bypass due to ++ partial CVE-2022-31629 fix). (CVE-2024-2756) (nielsdos) ++ + Backported from 8.0.30 + + - Libxml: +-- +2.44.0 + diff --git a/php-cve-2024-3096.patch b/php-cve-2024-3096.patch new file mode 100644 index 0000000..35ae88b --- /dev/null +++ b/php-cve-2024-3096.patch @@ -0,0 +1,87 @@ +From cd9a376c28c6f4ce83aab53ec069234fe1d2a819 Mon Sep 17 00:00:00 2001 +From: Jakub Zelenka <bukka@php.net> +Date: Fri, 29 Mar 2024 15:27:59 +0000 +Subject: [PATCH 3/4] Fix bug GHSA-q6x7-frmf-grcw: password_verify can + erroneously return true + +Disallow null character in bcrypt password + +(cherry picked from commit 0ba5229a3f7572846e91c8f5382e87785f543826) +(cherry picked from commit 81794c73068d9a44bf109bbcc9793e7b56a1c051) +(cherry picked from commit 4a7ceb9d6427f8d368f1a8739267b1f8310ec201) +(cherry picked from commit 747100905eceffb1f67096b437001e42900eb6bb) +(cherry picked from commit d22d9ebb29dce86edd622205dd1196a2796c08c7) +--- + ext/standard/password.c | 5 +++++ + ext/standard/tests/password/password_bcrypt_errors.phpt | 6 ++++++ + 2 files changed, 11 insertions(+) + +diff --git a/ext/standard/password.c b/ext/standard/password.c +index ebf5e98f7f..10dfc77f17 100644 +--- a/ext/standard/password.c ++++ b/ext/standard/password.c +@@ -282,6 +282,11 @@ PHP_FUNCTION(password_hash) + cost = zval_get_long(option_buffer); + } + ++ if (memchr(password, '\0', password_len)) { ++ php_error_docref(NULL, E_WARNING, "Bcrypt password must not contain null character"); ++ RETURN_NULL(); ++ } ++ + if (cost < 4 || cost > 31) { + php_error_docref(NULL, E_WARNING, "Invalid bcrypt cost parameter specified: " ZEND_LONG_FMT, cost); + RETURN_NULL(); +diff --git a/ext/standard/tests/password/password_bcrypt_errors.phpt b/ext/standard/tests/password/password_bcrypt_errors.phpt +index a0826080e6..f95b72670a 100644 +--- a/ext/standard/tests/password/password_bcrypt_errors.phpt ++++ b/ext/standard/tests/password/password_bcrypt_errors.phpt +@@ -16,6 +16,8 @@ var_dump(password_hash("foo", PASSWORD_BCRYPT, array("salt" => 123))); + + var_dump(password_hash("foo", PASSWORD_BCRYPT, array("cost" => "foo"))); + ++var_dump(password_hash("null\0password", PASSWORD_BCRYPT)); ++ + ?> + --EXPECTF-- + Warning: password_hash(): Invalid bcrypt cost parameter specified: 3 in %s on line %d +@@ -41,3 +43,7 @@ NULL + + Warning: password_hash(): Invalid bcrypt cost parameter specified: 0 in %s on line %d + NULL ++ ++Warning: password_hash(): Bcrypt password must not contain null character in %s on line %d ++NULL ++ +-- +2.44.0 + +From 9ec5a1ed8bed7ca5a14e991ff3e767dbfa773dcd Mon Sep 17 00:00:00 2001 +From: Remi Collet <remi@remirepo.net> +Date: Wed, 10 Apr 2024 09:01:09 +0200 +Subject: [PATCH 4/4] NEWS + +(cherry picked from commit 24f77904ee2259d722559f129f96a1f145a2367b) +(cherry picked from commit 027bdbc636632be49ecfad8d4191509faacb34ac) +(cherry picked from commit fbeed182bb0b0c4c453e064198b5cc3814a10de0) +(cherry picked from commit be830600a8e4c33a25e965d0782903e885e91c6d) +--- + NEWS | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/NEWS b/NEWS +index ebe7094f36..da210bad2e 100644 +--- a/NEWS ++++ b/NEWS +@@ -6,6 +6,8 @@ Backported from 8.1.28 + - Standard: + . Fixed bug GHSA-wpj3-hf5j-x4v4 (__Host-/__Secure- cookie bypass due to + partial CVE-2022-31629 fix). (CVE-2024-2756) (nielsdos) ++ . Fixed bug GHSA-h746-cjrr-wfmr (password_verify can erroneously return true, ++ opening ATO risk). (CVE-2024-3096) (Jakub Zelenka) + + Backported from 8.0.30 + +-- +2.44.0 + diff --git a/php-openssl-cert.patch b/php-openssl-cert.patch new file mode 100644 index 0000000..e6e3754 --- /dev/null +++ b/php-openssl-cert.patch @@ -0,0 +1,147 @@ +Without binary patch + + +From d86390c09bada2d660f1395540a3e2fc53992604 Mon Sep 17 00:00:00 2001 +From: Remi Collet <remi@remirepo.net> +Date: Tue, 18 Feb 2020 09:48:40 +0100 +Subject: [PATCH] renew certs for openssl tests + +--- + ext/openssl/tests/bug54992-ca.pem | 54 +++++++++--------- + ext/openssl/tests/bug54992.pem | 28 ++++----- + ext/openssl/tests/bug65538.phar | Bin 11278 -> 11278 bytes + .../tests/openssl_peer_fingerprint_basic.phpt | 4 +- + 4 files changed, 43 insertions(+), 43 deletions(-) + +diff --git a/ext/openssl/tests/bug54992-ca.pem b/ext/openssl/tests/bug54992-ca.pem +index 743a11e8fd..f143138541 100644 +--- a/ext/openssl/tests/bug54992-ca.pem ++++ b/ext/openssl/tests/bug54992-ca.pem +@@ -1,35 +1,35 @@ + -----BEGIN CERTIFICATE----- +-MIIGAzCCA+ugAwIBAgIUZ7ZvvfVqSEf1EswMT9LfMIPc/U8wDQYJKoZIhvcNAQEL ++MIIGAzCCA+ugAwIBAgIUeTcd2nJ3cKHRkuIs6UsAAeV1jVkwDQYJKoZIhvcNAQEL + BQAwgZAxCzAJBgNVBAYTAlBUMQ8wDQYDVQQIDAZMaXNib2ExDzANBgNVBAcMBkxp + c2JvYTEXMBUGA1UECgwOUEhQIEZvdW5kYXRpb24xHjAcBgNVBAMMFVJvb3QgQ0Eg + Zm9yIFBIUCBUZXN0czEmMCQGCSqGSIb3DQEJARYXaW50ZXJuYWxzQGxpc3RzLnBo +-cC5uZXQwHhcNMTgxMjMxMDg0NDU3WhcNMjAwMjA0MDg0NDU3WjCBkDELMAkGA1UE ++cC5uZXQwHhcNMjAwMjE4MDg0MDI4WhcNMjEwMzI0MDg0MDI4WjCBkDELMAkGA1UE + BhMCUFQxDzANBgNVBAgMBkxpc2JvYTEPMA0GA1UEBwwGTGlzYm9hMRcwFQYDVQQK + DA5QSFAgRm91bmRhdGlvbjEeMBwGA1UEAwwVUm9vdCBDQSBmb3IgUEhQIFRlc3Rz + MSYwJAYJKoZIhvcNAQkBFhdpbnRlcm5hbHNAbGlzdHMucGhwLm5ldDCCAiIwDQYJ +-KoZIhvcNAQEBBQADggIPADCCAgoCggIBAPVThsunmhda5hbNi+pXD3WF9ijryB9H +-JDnIbPW/vMffWcQgtiRzc+6aCykBygnhnN91NNRpxOsoLCb7OjUMM0TjhSE9DxKD +-aVLRoDcs5VSaddQjq3AwdkU6ek9InUOeDuZ8gatrpWlEyuQPwwnMAfR9NkcTajuF +-hGO0BlqkHg98GckQD0N5x6CrrDJt6RE6hf9gUZSGSWdPTiETBQUN8LTuxo/ybFSN +-hcpVNCF+r3eozATbSU8YvQU52RmPIZWHHmYb7KtMO3TEX4LnLJUOefUK4qk+ZJ0s +-f4JfnY7RhBlZGh2kIyE5jwqz8/KzKtxrutNaupdTFZO8nX09QSgmDCxVWVclrPaG +-q2ZFYpeauTy71pTm8DjF7PwQI/+PUrBdFIX0V6uxqUEG0pvPdb8zenVbaK4Jh39u +-w0V5tH/rbtd7zZX4vl3bmKo1Wk0SQxd83iXitxLiJnWNOsmrJcM/Hx91kE10+/ly +-zgL/w5A9HSA616kfPdNzny0laH1TXVLJsnyyV3DyfnU4O6VI0JG3WjhgRdMkgobn +-GvGJ2ZsZAxds9lBtT2y+gw5BU+jkSilPk3jM9MA7Kmyci93U9xxMuDNzyUzfcnXR +-UIq99dZWeMMy1LT3buZXrAWu1WRgPdQtDKcQHDIQaIkxlWsT8q2q/wIirb6fwxlw +-vXkFp+aEP35BAgMBAAGjUzBRMB0GA1UdDgQWBBR37F1+W1gcCp8bhZaFFi9JKQhu +-tTAfBgNVHSMEGDAWgBR37F1+W1gcCp8bhZaFFi9JKQhutTAPBgNVHRMBAf8EBTAD +-AQH/MA0GCSqGSIb3DQEBCwUAA4ICAQAYHqpISUI/x8UW33i35rYkFYNvXBMQDc8J +-v4G2eqEBNCOVmHg6P//lq1F2jrtAEr/saESN1uS1Q80sUsthlVsceV1z1isdpugG +-kMbfHxLe0QpthnP3PEChQw30TPB22BThuGVkteNSZKTCPGdzjSTPq2kOR6PCBZRd +-r0r/TW3lT/Ng3KgjT6g7E3ZUpAeFEQMlmNYr/eEOL7K+1jzQrbCLmXbs6rmtffr7 +-n4p+wMPMPaSRqQoQ86ff9GPzxWuAQGlytVoiS5Xt3jotd/RWlOy0YQ2QSzOQvFUW +-4te5lwdOvOFnJTo43U3DqASqMcaazvIsN41zVlOyOyKEr9oZERju6FU1aZmuZtHQ +-wMCmXVj/Swj67Zp9tG+vVQenbEk314+8c2nenuOIFP1F2C/NG3vMLIpENRGxpmAm +-s5gIT6mXvJ4JCwWYc75zucOr2KVkDmEziJh/pARuOrOAPdc6NjKku8HBC9UI96+x +-Db4hG2SqXUzShkFX/px7vlCADvgO3FDk2aiyW02PFsItob2O6OB98VGsU26hgRO/ +-Czz/jbjWTPHNOt6/fcL0m7XLwlJ+K9gRArY15DeJGumcHEq/Vd/Z8iPQKKdzgF4O +-9XFZvu+VHP82AS5TeiYHCddFJyzktQYcNu5/OBuxzO83d7rpqrLFETTEOL4cN8O7 +-LJ7Q89hYAQ== ++KoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK9ulKu0aOrXdRtAG0YgmXqr4Qf13Rf ++pzXTcX38dFDqvHuV9TxKxC9nXhnrvRMEcifQvxeZqBBiuAUUojSK6sLQSR/dtzBB ++7r4+fLuO0baZbbTmvVeknkRHeX67qVLY5k0tjEfl22qrvLUW+d9ZEV9o+BFgHRLK ++iFfLsrk7jMP66mPXfZIGxgzqlrx8wUMfCn37uGHjc5LOdEMl7MlvoYE1LG4RWBys ++KYGoUgv+aNinRrWE7q2OAkjo7C82oEOwz/F5vcJ0TIObUgWQcNiZFQw2OrSp0/0S ++ylXwDEuRnEiLPOWPisHhv4vLQzyT6PzoHvV3MIBU32D6wU1IaPOY7kYMf/P5RF0+ ++zloqR7rIPx6fEqRMaqAiENNf2Cbsg936XpCkTZrYiAw1ldxaFp9Um9BxW9BEWNs3 ++OU4SzUyaoasb++Q7/QVVZl8R3XKuQTM2JYC5Gz9m2g+z3QVq57iyuw1g/oomuaRO ++lfCCrG/62b96reuhVHJjd/sfP8kHuoc15CkHbFn/W8Xo7NCewP9JZbXgSugw1rU7 ++IMM6CIoXnpkjKnWZGRYyQVHHMHJhAUtLcU6j2Y/+Qv/0gSkIXZlKVYRMsBfsFWJ0 ++log1dXxewCAy+WANjC9KzQeTJIIDDyOiGXvsrAY7Q0kYe0jqTZdkVB6NQK8fl/Ex ++H7SAE+dfdtaZAgMBAAGjUzBRMB0GA1UdDgQWBBSrFmYxBsiIxKcT+LT2bC5PGLDj ++vDAfBgNVHSMEGDAWgBSrFmYxBsiIxKcT+LT2bC5PGLDjvDAPBgNVHRMBAf8EBTAD ++AQH/MA0GCSqGSIb3DQEBCwUAA4ICAQAVlLK97lrO1ZiF6RjZlsbaNcBjNECbfE3p ++eE7wcQwE9CB69OzAbTT4f2pOwwj+BfPLr1gMoZ+mz/jDK4NdXKafDRMS4FmvgdZR ++uxTpL3gGr55QPzcukNlLfL7VB3ZXQq7mVG5pq/s1ATnERYB8oOmioVYRZHXF8OK0 ++GCsy/cgvRRpUvNGqLpgD5JiT9LIS39Acul0klUqE3ZNEgeie5k/0l38vO/8vHhMW ++ppG4JSqS1v8PbP+d8V+uv80qYIu0+Bwues9eP27oW2XU0V8H3byU2PIEpNMDOcJt ++qOcbBsPSh7y1Hs0HerLyN3WO8Wx0wBsIMnG3cqbm5a8HIx/pFj+yD56ARqKeHWM8 ++lB/nFaa9LOwFedvhe5xP2uwRyX/5Ih3CzssFQ14MNR/VWcs59c7xNwETL8VHFYBd ++C5VAZLS8Of+1iroK7ZZAoQjzOjuP3rZ6Bd4P5WOp4szl2M0NrgC2Hd77DMrYh+z7 ++FzE3SlUuoizDBYVNHPT/VZEORi1ZuFZqnKdfb9jlwJoPuX75uWtyHyv2uCnA6Vac ++oBHQBdz1Ou8MCiU6Kauo+Iq/iJaYlvF2oUv3mBxEsMWdWb8t5yHgE0T036UobUgT ++Wfy92cEN7WYeZDf6q4GmcX4PUA5byoz17SgVAx9I91dGfhEU0a1ltGxogGmr9Vwl ++YfTbgyFblQ== + -----END CERTIFICATE----- +diff --git a/ext/openssl/tests/bug54992.pem b/ext/openssl/tests/bug54992.pem +index f207c30448..1589821502 100644 +--- a/ext/openssl/tests/bug54992.pem ++++ b/ext/openssl/tests/bug54992.pem +@@ -1,26 +1,26 @@ + -----BEGIN CERTIFICATE----- +-MIID7jCCAdYCFDw0rvm7q8y5HfispK5A2I2+RBqHMA0GCSqGSIb3DQEBCwUAMIGQ ++MIID7jCCAdYCFAa7MOtfbf1+zVobPAQfWKRY7JwmMA0GCSqGSIb3DQEBCwUAMIGQ + MQswCQYDVQQGEwJQVDEPMA0GA1UECAwGTGlzYm9hMQ8wDQYDVQQHDAZMaXNib2Ex + FzAVBgNVBAoMDlBIUCBGb3VuZGF0aW9uMR4wHAYDVQQDDBVSb290IENBIGZvciBQ + SFAgVGVzdHMxJjAkBgkqhkiG9w0BCQEWF2ludGVybmFsc0BsaXN0cy5waHAubmV0 +-MB4XDTE4MTIzMTA4NDY0M1oXDTIwMDIwNDA4NDY0M1owWjEXMBUGA1UEAxMOYnVn ++MB4XDTIwMDIxODA4NDA0NloXDTIxMDMyNDA4NDA0NlowWjEXMBUGA1UEAxMOYnVn + NTQ5OTIubG9jYWwxCzAJBgNVBAYTAlBUMQ8wDQYDVQQHEwZMaXNib2ExDzANBgNV + BAgTBkxpc2JvYTEQMA4GA1UEChMHcGhwLm5ldDCBnzANBgkqhkiG9w0BAQEFAAOB + jQAwgYkCgYEAtUAVQKTgpUPgtFOJ3w3kDJETS45tWeT96kUg1NeYLKW+jNbFhxPo + PJv7XhfemCaqh2tbq1cdYW906Wp1L+eNQvdTYA2IQG4EQBUlmfyIakOIMsN/RizV + kF09vlNQwTpaMpqTv7wB8vvwbxb9jbC2ZhQUBEg6PIn18dSstbM9FZ0CAwEAATAN +-BgkqhkiG9w0BAQsFAAOCAgEAKtSMguV5ZQ2KpdZ9MAFa+GiHL0APb58OrvwNK4BF +-6032UZLOWnsBZlo85WGLNnIT/GNzKKr7n9jHeuZcBVOFQLsebahSlfJZs9FPatlI +-9Md1tRzVoTKohjG86HeFhhL+gZQ69SdIcK40wpH1qNv7KyMGA8gnx6rRKbOxZqsx +-pkA/wS7CTqP9/DeOxh/MZPg7N/GZXW1QOz+SE537E9iyiRsbldNYFtwn5iaVfjpr +-xz09wYYW3HJpR+QKPCfJ79JxDhuMHMoUOpIy8vGFnt5zVTcFLa378Sy3vCT1Qwvt +-tTavFGHby4A7OqT6xu+9GTW37OaiV91UelLLV0+MoR4XiMVMX76mvqzmKCp6L9ae +-7RYHrrCtNxkYUKUSkOEc2VHnT+sENkJIZu7zzN7/QNlc0yE9Rtsmgy4QAxo2m9u0 +-pUZLAulZ1lS7g/sr7/8Pp17RDvJiJh+oAPyVYZ7OoLF1IoHDHcZI0bqcqhDhiHZs +-PXYqyMCxyYzHFOAOgvbrEkmp8z/E8ATVwdUbAYN1dMrYHre1P4HFEtJh2QiGG2KE +-4jheuNhH1R25AizbwYbD33Kdp7ltCgBlfYqjl771SlgY45QYs0mUdc1Pv39SGIwf +-ZUm7mOWjaTBdYANrkvGM5NNT9kESjKkWykyTg4UF5rHV6nlyexR4b3fjabroi4BS +-v6w= ++BgkqhkiG9w0BAQsFAAOCAgEANeuhYhaLnNdT+KJjhX6hfx+xTk5rm1govcSqJOTj ++lia7pZPMIt/h7yqVpbtarJee19LPlNS7IPlGSA7ntWM5hzzq28dGGJhUSsZLiKC6 +++TT3vUjbcat5opWBSD7onps6gYF612fDVpJwcJt2rlve4ljJxUml41x0d4CO3SlJ ++mnWjs/Mz06OIQkGsZdbqRfn8Kh8DDE81yCjGSEcgKeIei/ok6sg4HFNCLtptezAO ++ETmxgoLqUbtWa1VfVCii5ANGjXhARI+NkJMxTAFFGHbIciClVqKZlOkU4GmqGxxW ++k6iDrIFKsSLDtETBoW3kJ/9vPe/Bhnc1JBuLP1n5fuLScrcgFGYltK7w/21POigf ++KfMw8KLOcunsNYxoYoTGsI3pSKzisNcs3kAxJlgf8JZQy+8sV216gTocUkM8szOx ++jRcJ95fbXo3eao3ouuT+46p0K9H1RFkSr3XCbWIqK/E6W72xNwP071ILOViq8WQq ++sxlvnB3nmc4vyaTnjTLojVh76J/fI+VaLeypDb/o2M7jx1Wp/mO5hCyWE8v4W6tx ++M0s7gopy6TmpaK0BfmXpAfRpjU5KRll87OXxEA9Z0FmzzgYKYRxTzKIeX7CgV6UK ++NRJ2NAsDhHRUsuRY0+Gl0pZb4LglvwubjRh0W60ZNX9rjK1YpZlf25yzyZ7PypGt ++E5Y= + -----END CERTIFICATE----- + -----BEGIN RSA PRIVATE KEY----- + MIICXgIBAAKBgQC1QBVApOClQ+C0U4nfDeQMkRNLjm1Z5P3qRSDU15gspb6M1sWH +diff --git a/ext/openssl/tests/openssl_peer_fingerprint_basic.phpt b/ext/openssl/tests/openssl_peer_fingerprint_basic.phpt +index e3699f84fd..c7b7fc860a 100644 +--- a/ext/openssl/tests/openssl_peer_fingerprint_basic.phpt ++++ b/ext/openssl/tests/openssl_peer_fingerprint_basic.phpt +@@ -37,13 +37,13 @@ $clientCode = <<<'CODE' + // openssl x509 -noout -fingerprint -md5 -inform pem -in ext/openssl/tests/bug54992.pem | cut -d '=' -f 2 | tr -d ':' | tr 'A-F' 'a-f' + // Currently it's 4edbbaf40a6a4b6af22b6d6d9818378f + // One below is intentionally broken (compare the last character): +- stream_context_set_option($clientCtx, 'ssl', 'peer_fingerprint', '4edbbaf40a6a4b6af22b6d6d98183780'); ++ stream_context_set_option($clientCtx, 'ssl', 'peer_fingerprint', '6ca1c64686ce3c66c48c8ee9b6e93f20'); + var_dump(stream_socket_client($serverUri, $errno, $errstr, 2, $clientFlags, $clientCtx)); + + // Run the following to get actual sha256 (from sources root): + // openssl x509 -noout -fingerprint -sha256 -inform pem -in ext/openssl/tests/bug54992.pem | cut -d '=' -f 2 | tr -d ':' | tr 'A-F' 'a-f' + stream_context_set_option($clientCtx, 'ssl', 'peer_fingerprint', [ +- 'sha256' => 'b1d480a2f83594fa243d26378cf611f334d369e59558d87e3de1abe8f36cb997', ++ 'sha256' => '5ba604cf6a083d5ed6d5ba92f428202ab0314afbff42f622e24c1b761a0ddc0b', + ]); + var_dump(stream_socket_client($serverUri, $errno, $errstr, 2, $clientFlags, $clientCtx)); + CODE; @@ -26,10 +26,14 @@ %global mysql_sock %(mysql_config --socket 2>/dev/null || echo /var/lib/mysql/mysql.sock) -%ifarch ppc ppc64 -%global oraclever 10.2.0.2 +%ifarch aarch64 +%global oraclever 19.19 +%global oraclelib 19.1 +%global oracledir 19.19 %else -%global oraclever 18.3 +%global oraclever 21.13 +%global oraclelib 21.1 +%global oracledir 21 %endif # Build for LiteSpeed Web Server (LSAPI) @@ -107,12 +111,12 @@ %global db_devel libdb-devel %endif -%global upver 7.1.30 +%global upver 7.1.33 Summary: PHP scripting language for creating dynamic web sites Name: php Version: %{upver}%{?rcver:~%{rcver}} -Release: 1%{?dist} +Release: 28%{?dist} # All files licensed under PHP version 3.01, except # Zend is licensed under Zend # TSRM is licensed under BSD @@ -146,6 +150,7 @@ Source99: php-fpm.init # Build fixes Patch1: php-7.1.7-httpd.patch +Patch2: php-7.1.33-intl.patch Patch5: php-7.0.0-includedir.patch Patch6: php-5.6.3-embed.patch Patch7: php-5.3.0-recode.patch @@ -172,12 +177,56 @@ Patch91: php-5.6.3-oci8conf.patch # Upstream fixes (100+) # Security fixes (200+) +Patch201: php-bug78878.patch +Patch202: php-bug78862.patch +Patch203: php-bug78863.patch +Patch204: php-bug78793.patch +Patch205: php-bug78910.patch +Patch206: php-bug79091.patch +Patch207: php-bug79099.patch +Patch208: php-bug79037.patch +Patch209: php-bug77569.patch +Patch210: php-bug79221.patch +Patch211: php-bug79082.patch +Patch212: php-bug79282.patch +Patch213: php-bug79329.patch +Patch214: php-bug79330.patch +Patch215: php-bug79465.patch +Patch216: php-bug78875.patch +Patch217: php-bug78876.patch +Patch218: php-bug79797.patch +Patch219: php-bug79877.patch +Patch220: php-bug79601.patch +Patch221: php-bug79699.patch +Patch222: php-bug77423.patch +Patch223: php-bug80672.patch +Patch224: php-bug80710.patch +Patch225: php-bug81122.patch +Patch226: php-bug76450.patch +Patch227: php-bug81211.patch +Patch228: php-bug81026.patch +Patch229: php-bug79971.patch +Patch230: php-bug81719.patch +Patch231: php-bug81720.patch +Patch232: php-bug81727.patch +Patch233: php-bug81726.patch +Patch234: php-bug81740.patch +Patch235: php-bug81744.patch +Patch236: php-bug81746.patch +Patch237: php-cve-2023-0662.patch +Patch238: php-cve-2023-3247.patch +Patch239: php-cve-2023-3823.patch +Patch240: php-cve-2023-3824.patch +Patch241: php-cve-2024-2756.patch +Patch242: php-cve-2024-3096.patch # Fixes for tests (300+) # Factory is droped from system tzdata Patch300: php-7.0.10-datetests.patch # Revert changes for pcre < 8.34 Patch301: php-7.0.0-oldpcre.patch +# Renew openssl certs +Patch302: php-openssl-cert.patch # WIP @@ -282,7 +331,7 @@ Group: Development/Languages Summary: The interactive PHP debugger Requires: php-common%{?_isa} = %{version}-%{release} %if 0%{?rhel} -Obsoletes: php56u-dbg, php56w-dbg, php70u-dbg, php70w-phpdbg, php70u-dbg, php71w-phpdbg +Obsoletes: php56u-dbg, php56w-phpdbg, php70u-dbg, php70w-phpdbg, php70u-dbg, php71w-phpdbg %endif %description dbg The php-dbg package contains the interactive PHP debugger. @@ -293,7 +342,6 @@ Group: Development/Languages Summary: PHP FastCGI Process Manager BuildRequires: libacl-devel Requires: php-common%{?_isa} = %{version}-%{release} -Requires(pre): /usr/sbin/useradd %if %{with_systemd} BuildRequires: systemd-devel %{?systemd_requires} @@ -314,6 +362,8 @@ Requires(pre): httpd-filesystem Requires: httpd-filesystem >= 2.4.10 # php engine for Apache httpd webserver Provides: php(httpd) +%else +Requires(pre): /usr/sbin/useradd %endif %if %{with_nginx} # for /etc/nginx ownership @@ -400,7 +450,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} @@ -419,6 +469,7 @@ Provides: php-zts-devel%{?_isa} = %{version}-%{release} %endif %if 0%{?rhel} Obsoletes: php53-devel, php53u-devel, php54-devel, php54w-devel, php55u-devel, php55w-devel, php56u-devel, php56w-devel, php70u-devel, php70w-devel, php71u-devel, php71w-devel +Obsoletes: php55u-pecl-jsonc-devel, php56u-pecl-jsonc-devel %endif %description devel @@ -641,15 +692,20 @@ Summary: A module for PHP applications that use OCI8 databases Group: Development/Languages # All files licensed under PHP version 3.01 License: PHP +%ifarch aarch64 +BuildRequires: oracle-instantclient%{oraclever}-devel +# Should requires libclntsh.so.19.1()(aarch-64), but it's not provided by Oracle RPM. +Requires: libclntsh.so.%{oraclelib} +AutoReq: 0 +%else BuildRequires: oracle-instantclient-devel >= %{oraclever} +%endif Requires: php-pdo%{?_isa} = %{version}-%{release} Provides: php_database Provides: php-pdo_oci, php-pdo_oci%{?_isa} Obsoletes: php-pecl-oci8 < %{oci8ver} Conflicts: php-pecl-oci8 >= %{oci8ver} Provides: php-pecl(oci8) = %{oci8ver}, php-pecl(oci8)%{?_isa} = %{oci8ver} -# Should requires libclntsh.so.12.1, but it's not provided by Oracle RPM. -AutoReq: 0 %if 0%{?rhel} Obsoletes: php53-oci8, php53u-oci8, php54-oci8, php54w-oci8, php55u-oci8, php55w-oci8, php56u-oci8, php56w-oci8, php70u-oci8, php70w-oci8, php71u-oci8, php71w-oci8 %endif @@ -662,13 +718,9 @@ The extension is linked with Oracle client libraries %{oraclever} (Oracle Instant Client). For details, see Oracle's note "Oracle Client / Server Interoperability Support" (ID 207303.1). -You must install libclntsh.so.%{oraclever} to use this package, provided -in the database installation, or in the free Oracle Instant Client -available from Oracle. - -Notice: -- php-oci8 provides oci8 and pdo_oci extensions from php sources. -- php-pecl-oci8 only provides oci8 extension. +You must install libclntsh.so.%{oraclelib} to use this package, +provided by Oracle Instant Client RPM available from Oracle on: +https://www.oracle.com/database/technologies/instant-client/downloads.html Documentation is at http://php.net/oci8 and http://php.net/pdo_oci %endif @@ -757,12 +809,7 @@ License: PHP and BSD %endif Requires: php-common%{?_isa} = %{version}-%{release} %if %{with_libgd} -BuildRequires: gd-devel >= 2.1.1 -%if 0%{?fedora} <= 19 && 0%{?rhel} <= 7 -Requires: gd-last%{?_isa} >= 2.1.1 -%else -Requires: gd%{?_isa} >= 2.1.1 -%endif +BuildRequires: gd-devel >= 2.3.3 %else # Required to build the bundled GD library BuildRequires: libjpeg-devel @@ -922,8 +969,8 @@ Group: System Environment/Libraries # All files licensed under PHP version 3.01 License: PHP Requires: php-common%{?_isa} = %{version}-%{release} -# Upstream requires 4.0, we require 50 to ensure use of libicu-last -BuildRequires: libicu-devel >= 50 +# Upstream requires 4.0, we require 69.1 to ensure use of libicu69 +BuildRequires: libicu-devel = 69.1 %if 0%{?rhel} Obsoletes: php53-intl, php53u-intl, php54-intl, php54w-intl, php55u-intl, php55w-intl, php56u-intl, php56w-intl, php70u-intl, php70w-intl, php71u-intl, php71w-intl %endif @@ -999,48 +1046,94 @@ support for JavaScript Object Notation (JSON) to PHP. %setup -q -n php-%{upver}%{?rcver} -%patch1 -p1 -b .mpmcheck -%patch5 -p1 -b .includedir -%patch6 -p1 -b .embed -%patch7 -p1 -b .recode -%patch8 -p1 -b .libdb +%patch -P1 -p1 -b .mpmcheck +%patch -P2 -p1 -b .true +%patch -P5 -p1 -b .includedir +%patch -P6 -p1 -b .embed +%patch -P7 -p1 -b .recode +%patch -P8 -p1 -b .libdb %if 0%{?rhel} -%patch9 -p1 -b .curltls +%patch -P9 -p1 -b .curltls %endif -%patch40 -p1 -b .dlopen +%patch -P40 -p1 -b .dlopen %if 0%{?fedora} >= 25 || 0%{?rhel} >= 6 -%patch42 -p1 -b .systzdata +%patch -P42 -p1 -b .systzdata %endif -%patch43 -p1 -b .headers +%patch -P43 -p1 -b .headers %if 0%{?fedora} >= 18 || 0%{?rhel} >= 7 -%patch45 -p1 -b .ldap_r +%patch -P45 -p1 -b .ldap_r %endif -%patch47 -p1 -b .phpinfo -%patch48 -p1 -b .loadconf -%patch49 -p1 -b .getallheaders +%patch -P47 -p1 -b .phpinfo +%patch -P48 -p1 -b .loadconf +%patch -P49 -p1 -b .getallheaders -%patch91 -p1 -b .remi-oci8 +%patch -P91 -p1 -b .remi-oci8 # upstream patches # security patches +%patch -P201 -p1 -b .bug78878 +%patch -P202 -p1 -b .bug78862 +%patch -P203 -p1 -b .bug78863 +%patch -P204 -p1 -b .bug78793 +%patch -P205 -p1 -b .bug78910 +%patch -P206 -p1 -b .bug79091 +%patch -P207 -p1 -b .bug79099 +%patch -P208 -p1 -b .bug79037 +%patch -P209 -p1 -b .bug77569 +%patch -P210 -p1 -b .bug79221 +%patch -P211 -p1 -b .bug79082 +%patch -P212 -p1 -b .bug79282 +%patch -P213 -p1 -b .bug79329 +%patch -P214 -p1 -b .bug79330 +%patch -P215 -p1 -b .bug79465 +%patch -P216 -p1 -b .bug78875 +%patch -P217 -p1 -b .bug78876 +%patch -P218 -p1 -b .bug79797 +%patch -P219 -p1 -b .bug79877 +%patch -P220 -p1 -b .bug79601 +%patch -P221 -p1 -b .bug79699 +%patch -P222 -p1 -b .bug77423 +%patch -P223 -p1 -b .bug80672 +%patch -P224 -p1 -b .bug80710 +%patch -P225 -p1 -b .bug81122 +%patch -P226 -p1 -b .bug76450 +%patch -P227 -p1 -b .bug81211 +%patch -P228 -p1 -b .bug81026 +%patch -P229 -p1 -b .bug79971 +%patch -P230 -p1 -b .bug81719 +%patch -P231 -p1 -b .bug81720 +%patch -P232 -p1 -b .bug81727 +%patch -P233 -p1 -b .bug81726 +%patch -P234 -p1 -b .bug81740 +%patch -P235 -p1 -b .bug81744 +%patch -P236 -p1 -b .bug81746 +%patch -P237 -p1 -b .cve0662 +%patch -P238 -p1 -b .cve3247 +%patch -P239 -p1 -b .cve3823 +%patch -P240 -p1 -b .cve3824 +%patch -P241 -p1 -b .cve2756 +%patch -P242 -p1 -b .cve3096 # Fixes for tests %if 0%{?fedora} >= 25 || 0%{?rhel} >= 6 -%patch300 -p1 -b .datetests +%patch -P300 -p1 -b .datetests %endif %if %{with_libpcre} if ! pkg-config libpcre --atleast-version 8.34 ; then # Only apply when system libpcre < 8.34 -%patch301 -p1 -b .pcre834 +%patch -P301 -p1 -b .pcre834 fi %endif +# New openssl certs +%patch -P302 -p1 -b .renewcert +rm ext/openssl/tests/bug65538_003.phpt # WIP patch # Prevent %%doc confusion over LICENSE files -cp Zend/LICENSE Zend/ZEND_LICENSE +cp Zend/LICENSE ZEND_LICENSE cp TSRM/LICENSE TSRM_LICENSE %if ! %{with_libgd} cp ext/gd/libgd/README libgd_README @@ -1076,9 +1169,11 @@ rm Zend/tests/bug54268.phpt rm Zend/tests/bug68412.phpt # slow and erratic result rm sapi/cli/tests/upload_2G.phpt -# avoid issue when 2 builds run simultaneously +# avoid issue when 2 builds run simultaneously (keep 64321 for the SCL) %ifarch x86_64 sed -e 's/64321/64322/' -i ext/openssl/tests/*.phpt +%else +sed -e 's/64321/64323/' -i ext/openssl/tests/*.phpt %endif # Safety check for API version change. @@ -1159,9 +1254,6 @@ cat << EOF >>10-opcache.ini ; This should improve performance, but requires appropriate OS configuration. opcache.huge_code_pages=0 EOF -%ifarch x86_64 -sed -e '/opcache.huge_code_pages/s/0/1/' -i 10-opcache.ini -%endif %endif cp %{SOURCE52} 20-oci8.ini @@ -1312,11 +1404,7 @@ build --libdir=%{_libdir}/php \ --with-mysqli=shared,mysqlnd \ --with-mysql-sock=%{mysql_sock} \ %if %{with_oci8} -%ifarch x86_64 - --with-oci8=shared,instantclient,%{_libdir}/oracle/%{oraclever}/client64/lib,%{oraclever} \ -%else - --with-oci8=shared,instantclient,%{_libdir}/oracle/%{oraclever}/client/lib,%{oraclever} \ -%endif + --with-oci8=shared,instantclient,%{_prefix}/lib/oracle/%{oracledir}/client64/lib,%{oraclever} \ --with-pdo-oci=shared,instantclient,/usr,%{oraclever} \ %endif --with-interbase=shared \ @@ -1459,11 +1547,7 @@ build --includedir=%{_includedir}/php-zts \ --with-mysql-sock=%{mysql_sock} \ --enable-mysqlnd-threading \ %if %{with_oci8} -%ifarch x86_64 - --with-oci8=shared,instantclient,%{_libdir}/oracle/%{oraclever}/client64/lib,%{oraclever} \ -%else - --with-oci8=shared,instantclient,%{_libdir}/oracle/%{oraclever}/client/lib,%{oraclever} \ -%endif + --with-oci8=shared,instantclient,%{_prefix}/lib/oracle/%{oracledir}/client64/lib,%{oraclever} \ --with-pdo-oci=shared,instantclient,/usr,%{oraclever} \ %endif --with-interbase=shared \ @@ -1532,11 +1616,12 @@ popd %check %if %runselftest -cd build-apache +cd build-fpm # Run tests, using the CLI SAPI export NO_INTERACTION=1 REPORT_EXIT_STATUS=1 MALLOC_CHECK_=2 export SKIP_ONLINE_TESTS=1 +export SKIP_SLOW_TESTS=1 unset TZ LANG LC_ALL if ! make test; then set +x @@ -1814,7 +1899,7 @@ sed -e "s/@PHP_APIVER@/%{apiver}%{isasuffix}/" \ %endif < %{SOURCE3} > macros.php %if 0%{?fedora} >= 24 -echo '%pecl_xmldir %{_localstatedir}/lib/php/peclxml' >>macros.php +echo '%%pecl_xmldir %%{_localstatedir}/lib/php/peclxml' >>macros.php %endif install -m 644 -D macros.php \ $RPM_BUILD_ROOT%{macrosdir}/macros.php @@ -1907,6 +1992,19 @@ fi %postun embedded -p /sbin/ldconfig +%posttrans common +cat << EOF +===================================================================== + + WARNING : PHP 7.1 have reached its "End of Life" in + December 2019. Even, if this package includes some of + the important security fixes, backported from 8.1, the + UPGRADE to a maintained version is very strongly RECOMMENDED. + +===================================================================== +EOF + + %{!?_licensedir:%global license %%doc} %files @@ -1925,7 +2023,7 @@ fi %files common -f files.common %doc CODING_STANDARDS CREDITS EXTENSIONS NEWS README* -%license LICENSE TSRM_LICENSE +%license LICENSE TSRM_LICENSE ZEND_LICENSE %license libmagic_LICENSE %license phar_LICENSE %license timelib_LICENSE @@ -2083,6 +2181,175 @@ fi %changelog +* Wed Apr 10 2024 Remi Collet <remi@remirepo.net> - 7.1.33-28 +- use oracle client library version 21.13 on x86_64, 19.19 on aarch64 +- Fix __Host-/__Secure- cookie bypass due to partial CVE-2022-31629 fix + CVE-2024-2756 +- Fix password_verify can erroneously return true opening ATO risk + CVE-2024-3096 + +* Tue Aug 1 2023 Remi Collet <remi@remirepo.net> - 7.1.33-27 +- Fix Security issue with external entity loading in XML without enabling it + GHSA-3qrf-m4j2-pcrr CVE-2023-3823 +- Fix Buffer mismanagement in phar_dir_read() + GHSA-jqcx-ccgc-xwhv CVE-2023-3824 + +* Wed Jun 21 2023 Remi Collet <remi@remirepo.net> - 7.1.33-26 +- fix possible buffer overflow in date + +* Wed Jun 7 2023 Remi Collet <remi@remirepo.net> - 7.1.33-25 +- Fix Missing error check and insufficient random bytes in HTTP Digest + authentication for SOAP + GHSA-76gg-c692-v2mw CVE-2023-3247 +- use oracle client library version 21.10 +- define __phpize and __phpconfig + +* Tue Feb 14 2023 Remi Collet <remi@remirepo.net> - 7.1.33-24 +- fix #81744: Password_verify() always return true with some hash + CVE-2023-0567 +- fix #81746: 1-byte array overrun in common path resolve code + CVE-2023-0568 +- fix DOS vulnerability when parsing multipart request body + CVE-2023-0662 + +* Mon Dec 19 2022 Remi Collet <remi@remirepo.net> - 7.1.33-23 +- pdo: fix #81740: PDO::quote() may return unquoted string + CVE-2022-31631 +- use oracle client library version 21.8 + +* Tue Sep 27 2022 Remi Collet <remi@remirepo.net> - 7.1.33-22 +- phar: fix #81726 DOS when using quine gzip file. CVE-2022-31628 +- core: fix #81727 Don't mangle HTTP variable names that clash with ones + that have a specific semantic meaning. CVE-2022-31629 +- use oracle client library version 21.7 + +* Tue Jun 7 2022 Remi Collet <remi@remirepo.net> - 7.1.33-20 +- use oracle client library version 21.6 +- mysqlnd: fix #81719: mysqlnd/pdo password buffer overflow. CVE-2022-31626 +- pgsql: fix #81720: Uninitialized array in pg_query_params(). CVE-2022-31625 + +* Mon Nov 15 2021 Remi Collet <remi@remirepo.net> - 7.1.33-19 +- Fix #79971 special character is breaking the path in xml function + CVE-2021-21707 + +* Wed Oct 20 2021 Remi Collet <remi@remirepo.net> - 7.1.33-18 +- fix PHP-FPM oob R/W in root process leading to priv escalation + CVE-2021-21703 +- use libicu version 69 +- use oracle client library version 21.3 + +* Wed Aug 25 2021 Remi Collet <remi@remirepo.net> - 7.1.33-16 +- Fix #81211 Symlinks are followed when creating PHAR archive + +* Mon Jun 28 2021 Remi Collet <remi@remirepo.net> - 7.1.33-15 +- Fix #81122 SSRF bypass in FILTER_VALIDATE_URL + CVE-2021-21705 +- Fix #76448 Stack buffer overflow in firebird_info_cb +- Fix #76449 SIGSEGV in firebird_handle_doer +- Fix #76450 SIGSEGV in firebird_stmt_execute +- Fix #76452 Crash while parsing blob data in firebird_fetch_blob + CVE-2021-21704 + +* Wed Apr 28 2021 Remi Collet <remi@remirepo.net> - 7.1.33-13 +- Fix #80710 imap_mail_compose() header injection +- use oracle client library version 21.1 + +* Wed Feb 3 2021 Remi Collet <remi@remirepo.net> - 7.1.33-12 +- Fix #80672 Null Dereference in SoapClient + CVE-2021-21702 +- better fix for #77423 + +* Mon Jan 4 2021 Remi Collet <remi@remirepo.net> - 7.1.33-11 +- Fix #77423 FILTER_VALIDATE_URL accepts URLs with invalid userinfo + CVE-2020-7071 + +* Tue Sep 29 2020 Remi Collet <remi@remirepo.net> - 7.1.33-10 +- Core: + Fix #79699 PHP parses encoded cookie names so malicious `__Host-` cookies can be sent + CVE-2020-7070 +- OpenSSL: + Fix #79601 Wrong ciphertext/tag in AES-CCM encryption for a 12 bytes IV + CVE-2020-7069 + Fix bug #78079 openssl_encrypt_ccm.phpt fails with OpenSSL 1.1.1c + +* Tue Aug 4 2020 Remi Collet <remi@remirepo.net> - 7.1.33-9 +- Core: + Fix #79877 getimagesize function silently truncates after a null byte +- Phar: + Fix #79797 use of freed hash key in the phar_parse_zipfile function + CVE-2020-7068 + +* Tue May 12 2020 Remi Collet <remi@remirepo.net> - 7.1.33-8 +- Core: + Fix #78875 Long filenames cause OOM and temp files are not cleaned + CVE-2019-11048 + Fix #78876 Long variables in multipart/form-data cause OOM and temp + files are not cleaned + +* Tue Apr 14 2020 Remi Collet <remi@remirepo.net> - 7.1.33-7 +- standard: + Fix #79330 shell_exec silently truncates after a null byte + Fix #79465 OOB Read in urldecode + CVE-2020-7067 + +* Tue Mar 17 2020 Remi Collet <remi@remirepo.net> - 7.1.33-6 +- standard: + Fix #79329 get_headers() silently truncates after a null byte + CVE-2020-7066 +- exif: + Fix #79282 Use-of-uninitialized-value in exif + CVE-2020-7064 +- use oracle client library version 19.6 (18.5 on EL-6) + +* Tue Feb 18 2020 Remi Collet <remi@remirepo.net> - 7.1.33-5 +- dom: + Fix #77569 Write Access Violation in DomImplementation +- phar: + Fix #79082 Files added to tar with Phar::buildFromIterator have all-access permissions + CVE-2020-7063 +- session: + Fix #79221 Null Pointer Dereference in PHP Session Upload Progress + CVE-2020-7062 + +* Thu Jan 23 2020 Remi Collet <remi@remirepo.net> - 7.1.33-4 +- mbstring: + Fix #79037 global buffer-overflow in mbfl_filt_conv_big5_wchar + CVE-2020-7060 +- session: + Fix #79091 heap use-after-free in session_create_id +- standard: + Fix #79099 OOB read in php_strip_tags_ex + CVE-2020-7059 + +* Tue Dec 17 2019 Remi Collet <remi@remirepo.net> - 7.1.33-2 +- bcmath: + Fix #78878 Buffer underflow in bc_shift_addsub + CVE-2019-11046 +- core: + Fix #78862 link() silently truncates after a null byte on Windows + CVE-2019-11044 + Fix #78863 DirectoryIterator class silently truncates after a null byte + CVE-2019-11045 +- exif + Fix #78793 Use-after-free in exif parsing under memory sanitizer + CVE-2019-11050 + Fix #78910 Heap-buffer-overflow READ in exif + CVE-2019-11047 +- use oracle client library version 19.5 (18.5 on EL-6) + +* Wed Oct 23 2019 Remi Collet <remi@remirepo.net> - 7.1.33-1 +- Update to 7.1.33 - http://www.php.net/releases/7_1_33.php + +* Wed Aug 28 2019 Remi Collet <remi@remirepo.net> - 7.1.32-1 +- Update to 7.1.32 - http://www.php.net/releases/7_1_32.php + +* Wed Jul 31 2019 Remi Collet <remi@remirepo.net> - 7.1.31-1 +- Update to 7.1.31 - http://www.php.net/releases/7_1_31.php + +* Tue Jul 2 2019 Remi Collet <remi@remirepo.net> - 7.1.30-3 +- use oracle client library version 19.3 +- disable opcache.huge_code_pages in default configuration + * Tue May 28 2019 Remi Collet <remi@remirepo.net> - 7.1.30-1 - Update to 7.1.30 - http://www.php.net/releases/7_1_30.php |