diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | failed.txt | 16 | ||||
-rw-r--r-- | macros.php | 4 | ||||
-rw-r--r-- | php-7.1.33-intl.patch | 13 | ||||
-rw-r--r-- | php-7.2.0-oci8conf.patch | 24 | ||||
-rw-r--r-- | php-7.2.16-systzdata-v17.patch | 2 | ||||
-rw-r--r-- | php-bug76450.patch | 208 | ||||
-rw-r--r-- | php-bug77423.patch | 465 | ||||
-rw-r--r-- | php-bug79971.patch | 167 | ||||
-rw-r--r-- | php-bug80672.patch | 237 | ||||
-rw-r--r-- | php-bug80710.patch | 371 | ||||
-rw-r--r-- | php-bug81026.patch | 429 | ||||
-rw-r--r-- | php-bug81122.patch | 88 | ||||
-rw-r--r-- | php-bug81211.patch | 163 | ||||
-rw-r--r-- | php-bug81719.patch | 62 | ||||
-rw-r--r-- | php-bug81720.patch | 77 | ||||
-rw-r--r-- | php-bug81726.patch | 180 | ||||
-rw-r--r-- | php-bug81727.patch | 81 | ||||
-rw-r--r-- | php-bug81738.patch | 129 | ||||
-rw-r--r-- | php-bug81740.patch | 87 | ||||
-rw-r--r-- | php-bug81744.patch | 190 | ||||
-rw-r--r-- | php-bug81746.patch | 100 | ||||
-rw-r--r-- | php-cve-2023-0662.patch | 148 | ||||
-rw-r--r-- | php-cve-2023-3247.patch | 152 | ||||
-rw-r--r-- | php-cve-2023-3823.patch | 91 | ||||
-rw-r--r-- | php-cve-2023-3824.patch | 714 | ||||
-rw-r--r-- | php-cve-2024-2756.patch | 197 | ||||
-rw-r--r-- | php-cve-2024-3096.patch | 85 | ||||
-rw-r--r-- | php-keyring.gpg | 853 | ||||
-rw-r--r-- | php72.spec | 292 |
30 files changed, 5201 insertions, 425 deletions
@@ -1,3 +1,4 @@ +clog TODO package-*.xml *.tgz @@ -1,15 +1,16 @@ -===== 7.2.34 (2020-10-01) +===== 7.2.34-21 (2024-04-11) -$ grep -r 'Tests failed' /var/lib/mock/{fc,el}*/build.log +$ 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/el8x72/build.logTests failed : 17 +/var/lib/mock/el7x72/build.log:Tests failed : 1 +/var/lib/mock/el8a72/build.log:Tests failed : 19 +/var/lib/mock/el8x72/build.log:Tests failed : 19 +el7x: + 3 ext/openssl/tests/openssl_x509_checkpurpose_basic.phpt el8x: - 5 openssl failure under investigation + 3 buildroot issue with strict openssl policy (fixed in 7.4) and tzdata 1 proc_open give erratic test results :( @@ -17,4 +18,3 @@ el8x: 3 known issue 4 bugs related to tzdata 5 need investigation - @@ -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-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-7.2.0-oci8conf.patch b/php-7.2.0-oci8conf.patch index 0ad16a1..d026575 100644 --- a/php-7.2.0-oci8conf.patch +++ b/php-7.2.0-oci8conf.patch @@ -10,26 +10,4 @@ diff -up ./ext/ldap/php_ldap.h.remi-oci8 ./ext/ldap/php_ldap.h extern zend_module_entry ldap_module_entry; #define ldap_module_ptr &ldap_module_entry -diff -up ./ext/oci8/config.m4.remi-oci8 ./ext/oci8/config.m4 ---- ./ext/oci8/config.m4.remi-oci8 2017-06-20 15:45:39.000000000 +0200 -+++ ./ext/oci8/config.m4 2017-06-20 16:55:01.640203868 +0200 -@@ -372,6 +372,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 ./ext/pdo_oci/config.m4.remi-oci8 ./ext/pdo_oci/config.m4 ---- ./ext/pdo_oci/config.m4.remi-oci8 2017-06-20 16:55:01.640203868 +0200 -+++ ./ext/pdo_oci/config.m4 2017-06-20 17:16:03.053538358 +0200 -@@ -93,7 +93,7 @@ if test "$PHP_PDO_OCI" != "no"; then - - AC_MSG_CHECKING([for oci.h]) - dnl Header directory for Instant Client SDK RPM install -- OCISDKRPMINC=`echo "$PDO_OCI_LIB_DIR" | $PHP_PDO_OCI_SED -e 's!^\(.*\)/lib/oracle/\(.*\)/\('${PDO_OCI_CLIENT_DIR}'\)/lib[/]*$!\1/include/oracle/\2/\3!'` -+ OCISDKRPMINC=`echo "$PDO_OCI_LIB_DIR" | $PHP_PDO_OCI_SED -e 's!^\(.*\)/\(lib64\|lib\)/oracle/\(.*\)/\('${PDO_OCI_CLIENT_DIR}'\)/lib[/]*$!\1/include/oracle/\3/\4!'` - - dnl Header directory for manual installation - OCISDKMANINC=`echo "$PDO_OCI_LIB_DIR" | $PHP_PDO_OCI_SED -e 's!^\(.*\)/lib[/]*$!\1/include!'` + diff --git a/php-7.2.16-systzdata-v17.patch b/php-7.2.16-systzdata-v17.patch index 640bff2..e8ae8b2 100644 --- a/php-7.2.16-systzdata-v17.patch +++ b/php-7.2.16-systzdata-v17.patch @@ -410,7 +410,7 @@ diff -up php-7.2.16RC1/ext/date/lib/parse_tz.c.systzdata php-7.2.16RC1/ext/date/ + 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-bug76450.patch b/php-bug76450.patch new file mode 100644 index 0000000..e1cffa6 --- /dev/null +++ b/php-bug76450.patch @@ -0,0 +1,208 @@ +From 18aadb2d10b70f40f67b3fa233f67f366d7d2572 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 e968635df5b42b9358c08f3c57bf15f24e4de62e 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 6c114f1907051632e02cdc45de8b4b249d84e7df 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 3060615e8d..c9f90fdef1 100644 +--- a/ext/pdo_firebird/firebird_driver.c ++++ b/ext/pdo_firebird/firebird_driver.c +@@ -206,8 +206,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 c9bdb0c993a079102ce854ef7859087170e7b9a1 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 c9f90fdef1..1e2e7746fa 100644 +--- a/ext/pdo_firebird/firebird_driver.c ++++ b/ext/pdo_firebird/firebird_driver.c +@@ -509,14 +509,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); + } + } + /* }}} */ +@@ -527,7 +529,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 7598733c51af30611aa64e456c9a777069d2efb9 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) +--- + NEWS | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/NEWS b/NEWS +index e331598176..f083e44dcc 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..5d61bc1 --- /dev/null +++ b/php-bug77423.patch @@ -0,0 +1,465 @@ +From 2d3d72412a6734e19a38ed10f385227a6238e4a6 Mon Sep 17 00:00:00 2001 +From: "Christoph M. Becker" <cmbecker69@gmx.de> +Date: Wed, 13 May 2020 09:36:52 +0200 +Subject: [PATCH] Fix #77423: parse_url() will deliver a wrong host to user + +To avoid that `parse_url()` returns an erroneous host, which would be +valid for `FILTER_VALIDATE_URL`, we make sure that only userinfo which +is valid according to RFC 3986 is treated as such. + +For consistency with the existing url parsing code, we use ctype +functions, although that is not necessarily correct. +--- + ext/standard/tests/strings/url_t.phpt | 6 ++-- + ext/standard/tests/url/bug77423.phpt | 30 +++++++++++++++++++ + .../tests/url/parse_url_basic_001.phpt | 6 ++-- + .../tests/url/parse_url_basic_003.phpt | 2 +- + .../tests/url/parse_url_basic_005.phpt | 2 +- + .../tests/url/parse_url_unterminated.phpt | 6 ++-- + ext/standard/url.c | 21 +++++++++++++ + 7 files changed, 59 insertions(+), 14 deletions(-) + create mode 100644 ext/standard/tests/url/bug77423.phpt + +diff --git a/ext/standard/tests/strings/url_t.phpt b/ext/standard/tests/strings/url_t.phpt +index 79ff3bc4a8e3..f564f59f0632 100644 +--- a/ext/standard/tests/strings/url_t.phpt ++++ b/ext/standard/tests/strings/url_t.phpt +@@ -575,15 +575,13 @@ $sample_urls = array ( + string(16) "some_page_ref123" + } + +---> http://secret@hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123: array(7) { ++--> http://secret@hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123: array(6) { + ["scheme"]=> + string(4) "http" + ["host"]=> +- string(11) "www.php.net" ++ string(26) "secret@hideout@www.php.net" + ["port"]=> + int(80) +- ["user"]=> +- string(14) "secret@hideout" + ["path"]=> + string(10) "/index.php" + ["query"]=> +diff --git a/ext/standard/tests/url/bug77423.phpt b/ext/standard/tests/url/bug77423.phpt +new file mode 100644 +index 000000000000..be03fe95e24e +--- /dev/null ++++ b/ext/standard/tests/url/bug77423.phpt +@@ -0,0 +1,30 @@ ++--TEST-- ++Bug #77423 (parse_url() will deliver a wrong host to user) ++--FILE-- ++<?php ++$urls = array( ++ "http://php.net\@aliyun.com/aaa.do", ++ "https://example.com\uFF03@bing.com", ++); ++foreach ($urls as $url) { ++ var_dump(filter_var($url, FILTER_VALIDATE_URL)); ++ var_dump(parse_url($url)); ++} ++?> ++--EXPECT-- ++bool(false) ++array(3) { ++ ["scheme"]=> ++ string(4) "http" ++ ["host"]=> ++ string(19) "php.net\@aliyun.com" ++ ["path"]=> ++ string(7) "/aaa.do" ++} ++bool(false) ++array(2) { ++ ["scheme"]=> ++ string(5) "https" ++ ["host"]=> ++ string(26) "example.com\uFF03@bing.com" ++} +diff --git a/ext/standard/tests/url/parse_url_basic_001.phpt b/ext/standard/tests/url/parse_url_basic_001.phpt +index 4606849c5781..51010991326c 100644 +--- a/ext/standard/tests/url/parse_url_basic_001.phpt ++++ b/ext/standard/tests/url/parse_url_basic_001.phpt +@@ -506,15 +506,13 @@ echo "Done"; + string(16) "some_page_ref123" + } + +---> http://secret@hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123: array(7) { ++--> http://secret@hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123: array(6) { + ["scheme"]=> + string(4) "http" + ["host"]=> +- string(11) "www.php.net" ++ string(26) "secret@hideout@www.php.net" + ["port"]=> + int(80) +- ["user"]=> +- string(14) "secret@hideout" + ["path"]=> + string(10) "/index.php" + ["query"]=> +diff --git a/ext/standard/tests/url/parse_url_basic_003.phpt b/ext/standard/tests/url/parse_url_basic_003.phpt +index 3d5a4a344afd..7968fd3f09fd 100644 +--- a/ext/standard/tests/url/parse_url_basic_003.phpt ++++ b/ext/standard/tests/url/parse_url_basic_003.phpt +@@ -68,7 +68,7 @@ echo "Done"; + --> http://secret:@www.php.net/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123 : string(11) "www.php.net" + --> http://:hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123 : string(11) "www.php.net" + --> http://secret:hideout@www.php.net/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123 : string(11) "www.php.net" +---> http://secret@hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123 : string(11) "www.php.net" ++--> http://secret@hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123 : string(26) "secret@hideout@www.php.net" + --> http://secret:hid:out@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123 : string(11) "www.php.net" + --> nntp://news.php.net : string(12) "news.php.net" + --> ftp://ftp.gnu.org/gnu/glic/glibc.tar.gz : string(11) "ftp.gnu.org" +diff --git a/ext/standard/tests/url/parse_url_basic_005.phpt b/ext/standard/tests/url/parse_url_basic_005.phpt +index aefb33964bc4..ba778bf9035d 100644 +--- a/ext/standard/tests/url/parse_url_basic_005.phpt ++++ b/ext/standard/tests/url/parse_url_basic_005.phpt +@@ -68,7 +68,7 @@ echo "Done"; + --> http://secret:@www.php.net/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123 : string(6) "secret" + --> http://:hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123 : string(0) "" + --> http://secret:hideout@www.php.net/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123 : string(6) "secret" +---> http://secret@hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123 : string(14) "secret@hideout" ++--> http://secret@hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123 : NULL + --> http://secret:hid:out@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123 : string(6) "secret" + --> nntp://news.php.net : NULL + --> ftp://ftp.gnu.org/gnu/glic/glibc.tar.gz : NULL +diff --git a/ext/standard/tests/url/parse_url_unterminated.phpt b/ext/standard/tests/url/parse_url_unterminated.phpt +index 912b6a5641e8..875d93a10948 100644 +--- a/ext/standard/tests/url/parse_url_unterminated.phpt ++++ b/ext/standard/tests/url/parse_url_unterminated.phpt +@@ -508,15 +508,13 @@ echo "Done"; + string(16) "some_page_ref123" + } + +---> http://secret@hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123: array(7) { ++--> http://secret@hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123: array(6) { + ["scheme"]=> + string(4) "http" + ["host"]=> +- string(11) "www.php.net" ++ string(26) "secret@hideout@www.php.net" + ["port"]=> + int(80) +- ["user"]=> +- string(14) "secret@hideout" + ["path"]=> + string(10) "/index.php" + ["query"]=> +diff --git a/ext/standard/url.c b/ext/standard/url.c +index 1dd073e2bb42..8d155bb9846c 100644 +--- a/ext/standard/url.c ++++ b/ext/standard/url.c +@@ -92,6 +92,22 @@ PHPAPI php_url *php_url_parse(char const *str) + return php_url_parse_ex(str, strlen(str)); + } + ++static int is_userinfo_valid(const char *str, size_t len) ++{ ++ char *valid = "-._~!$&'()*+,;=:"; ++ char *p = str; ++ while (p - str < len) { ++ if (isalpha(*p) || isdigit(*p) || strchr(valid, *p)) { ++ p++; ++ } else if (*p == '%' && p - str <= len - 3 && isdigit(*(p+1)) && isxdigit(*(p+2))) { ++ p += 3; ++ } else { ++ return 0; ++ } ++ } ++ return 1; ++} ++ + /* {{{ php_url_parse + */ + PHPAPI php_url *php_url_parse_ex(char const *str, size_t length) +@@ -235,13 +251,18 @@ PHPAPI php_url *php_url_parse_ex(char const *str, size_t length) + ret->pass = estrndup(pp, (p-pp)); + php_replace_controlchars_ex(ret->pass, (p-pp)); + } else { ++ if (!is_userinfo_valid(s, p-s)) { ++ goto check_port; ++ } + ret->user = estrndup(s, (p-s)); + php_replace_controlchars_ex(ret->user, (p-s)); ++ + } + + s = p + 1; + } + ++check_port: + /* check for port */ + if (s < ue && *s == '[' && *(e-1) == ']') { + /* Short circuit portscan, +From 22756113c67b9fc7dce542c80722f24351e85a45 Mon Sep 17 00:00:00 2001 +From: Remi Collet <remi@remirepo.net> +Date: Thu, 7 Jan 2021 11:42:58 +0100 +Subject: [PATCH] NEWS + +--- + NEWS | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/NEWS b/NEWS +index 1f037cb301..7f2d588c4d 100644 +--- a/NEWS ++++ b/NEWS +@@ -1,5 +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) ++ + 01 Oct 2020, PHP 7.2.34 + + - Core: +From 356f7008f36da60ec9794d48c55d117f1dd31903 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) +--- + 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 +- + .../tests/url/parse_url_unterminated.phpt | 6 +++-- + ext/standard/url.c | 21 ---------------- + 8 files changed, 39 insertions(+), 44 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 b2d0264b76..ad0956a505 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/tests/url/parse_url_unterminated.phpt b/ext/standard/tests/url/parse_url_unterminated.phpt +index 875d93a109..912b6a5641 100644 +--- a/ext/standard/tests/url/parse_url_unterminated.phpt ++++ b/ext/standard/tests/url/parse_url_unterminated.phpt +@@ -508,13 +508,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/url.c b/ext/standard/url.c +index 8d155bb984..1dd073e2bb 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-bug79971.patch b/php-bug79971.patch new file mode 100644 index 0000000..9f31d28 --- /dev/null +++ b/php-bug79971.patch @@ -0,0 +1,167 @@ +From 2936b97fe42fb5713595a1559b91d568ccddb04a 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/2] 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 c871cb89bd..da553d64ee 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 c032381da0bfb6457aa9cfa7a430790f6eab8178 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/2] NEWS + +--- + NEWS | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/NEWS b/NEWS +index e5ecd3865a..2177c64aef 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 + diff --git a/php-bug80672.patch b/php-bug80672.patch new file mode 100644 index 0000000..5f63aab --- /dev/null +++ b/php-bug80672.patch @@ -0,0 +1,237 @@ +From f1e2cfa008d1596251968d13eb9a8539dba6879f 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) +--- + 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 7f2d588c4d..884285f05f 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 d16056e4a3..b8d40f0cfe 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 02352d5acc1896756dcb4645f54689ffdcc4ca52 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) +--- + 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 b8d40f0cfe..522db1c979 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..2dd68f0 --- /dev/null +++ b/php-bug80710.patch @@ -0,0 +1,371 @@ +From 9017896cccefe000938f80b49361b1c183849922 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) +--- + 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 37eb5e1296..9cac2264fb 100644 +--- a/ext/imap/php_imap.c ++++ b/ext/imap/php_imap.c +@@ -3528,6 +3528,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) +@@ -3548,6 +3565,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"); \ +@@ -3556,46 +3580,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)); + } + +@@ -3605,6 +3640,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); +@@ -3637,6 +3673,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"); +@@ -3647,9 +3684,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; +@@ -3660,18 +3699,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); + } +@@ -3679,9 +3722,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; +@@ -3710,6 +3755,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) { +@@ -3740,6 +3786,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); +@@ -3751,9 +3798,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; +@@ -3764,18 +3813,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); + } +@@ -3783,9 +3836,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; +@@ -3814,6 +3869,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 f16c623ec8ae3f3cdc73ab3fa05ae6bb0a77d1f3 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) +--- + NEWS | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/NEWS b/NEWS +index 884285f05f..e331598176 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..3bb8cc7 --- /dev/null +++ b/php-bug81026.patch @@ -0,0 +1,429 @@ +From 7e7f808fbc9a6a5d2eabdd9e7cb058a61f439aee 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 eed0c6757a..05513f0084 100644 +--- a/sapi/fpm/fpm/fpm_children.c ++++ b/sapi/fpm/fpm/fpm_children.c +@@ -243,7 +243,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); + +@@ -253,9 +253,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 */); +@@ -321,7 +321,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; +@@ -333,7 +333,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); + } +@@ -346,10 +346,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 b84a7a8c2db91714bfb2894894e61758189983df Mon Sep 17 00:00:00 2001 +From: Remi Collet <remi@remirepo.net> +Date: Wed, 20 Oct 2021 14:06:59 +0200 +Subject: [PATCH 2/2] NEWS + +--- + NEWS | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/NEWS b/NEWS +index 1e8a7c7903..b8b1849134 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..a534139 --- /dev/null +++ b/php-bug81122.patch @@ -0,0 +1,88 @@ +From 34e7f97cf67a8e2e0dd6675e4d82c0f8be7ad77f 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 ad0956a505..7ddf44cff0 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 84d1d39e26520ae131a6ac14891c836adc969ad5 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 7ddf44cff0..6894fa2551 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..1e09d65 --- /dev/null +++ b/php-bug81211.patch @@ -0,0 +1,163 @@ +From 92a270e564ffda7fe825d1472fe567323f137fba 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 2987b64012..01bdc0596b 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 cb376010c6a48c5454c47140dfbdee6f0e48bb12 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 5539cefcda6aca7af220e7be7760a682abb88200 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 + +--- + NEWS | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/NEWS b/NEWS +index f083e44dcc..1e8a7c7903 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..5aa8ab5 --- /dev/null +++ b/php-bug81719.patch @@ -0,0 +1,62 @@ +From 1560224d3a26574f0195af3853e4d7e050b0b06f 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) +--- + 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 759b131b63..eb7af323a4 100644 +--- a/ext/mysqlnd/mysqlnd_wireprotocol.c ++++ b/ext/mysqlnd/mysqlnd_wireprotocol.c +@@ -794,7 +794,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 87247fb08e905e629836350ac4e639edd1b40ed8 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) +--- + NEWS | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/NEWS b/NEWS +index 2177c64aef..8f09ddfee0 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..3e47b6c --- /dev/null +++ b/php-bug81720.patch @@ -0,0 +1,77 @@ +From 310b17f5c8938389b1dbd7d8ff5a8144bfb9a351 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) +--- + 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 c97c600b66..8bc7568056 100644 +--- a/ext/pgsql/pgsql.c ++++ b/ext/pgsql/pgsql.c +@@ -1988,7 +1988,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)); +@@ -5188,7 +5188,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..847ebff --- /dev/null +++ b/php-bug81726.patch @@ -0,0 +1,180 @@ +From 2bdc26af43cdd4376bf8e0fdf532bb12dd35d3dd 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 90ac6b751b..be8bfd2f98 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 ba76a9b0e0..52c973d7c4 100644 +--- a/ext/phar/phar.c ++++ b/ext/phar/phar.c +@@ -1575,7 +1575,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); +@@ -1603,8 +1604,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; +@@ -1664,7 +1664,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; +@@ -1702,7 +1705,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 8fad7bf40e1b5bf74f308eb882b1d72987ef539c 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 52c973d7c4..534af318f4 100644 +--- a/ext/phar/phar.c ++++ b/ext/phar/phar.c +@@ -1575,7 +1575,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) */ +@@ -1604,7 +1604,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; +@@ -1664,6 +1665,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; +@@ -1705,6 +1707,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..74a25eb --- /dev/null +++ b/php-bug81727.patch @@ -0,0 +1,81 @@ +From e92c3b23aa13860777dd09106ce309dac49edd13 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 8f09ddfee0..90ac6b751b 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 097c17d32a..bd59134fc9 100644 +--- a/main/php_variables.c ++++ b/main/php_variables.c +@@ -109,6 +109,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-bug81738.patch b/php-bug81738.patch new file mode 100644 index 0000000..6fceeab --- /dev/null +++ b/php-bug81738.patch @@ -0,0 +1,129 @@ +From 4b1f3b84336a26db9649c5175e29984fa1b54950 Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <smalyshev@gmail.com> +Date: Thu, 20 Oct 2022 23:57:35 -0600 +Subject: [PATCH] Fix bug #81738 (buffer overflow in hash_update() on long + parameter) + +(cherry picked from commit de4517ad607df8d4cb3735228b39e4a48f95556c) +--- + NEWS | 6 ++++++ + ext/hash/sha3/generic32lc/KeccakSponge.inc | 14 ++++++++------ + ext/hash/sha3/generic64lc/KeccakSponge.inc | 14 ++++++++------ + 3 files changed, 22 insertions(+), 12 deletions(-) + +diff --git a/NEWS b/NEWS +index e31f007ad0..b6e3c4fe6c 100644 +--- a/NEWS ++++ b/NEWS +@@ -1,6 +1,12 @@ + PHP NEWS + ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| + ++Backported from 7.4.33 ++ ++- Hash: ++ . Fixed bug #81738: buffer overflow in hash_update() on long parameter. ++ (CVE-2022-37454) (nicky at mouha dot be) ++ + Backported from 7.4.32 + + - Core: +diff --git a/ext/hash/sha3/generic32lc/KeccakSponge.inc b/ext/hash/sha3/generic32lc/KeccakSponge.inc +index 42a15aac6d..f8c42ff788 100644 +--- a/ext/hash/sha3/generic32lc/KeccakSponge.inc ++++ b/ext/hash/sha3/generic32lc/KeccakSponge.inc +@@ -160,7 +160,7 @@ int SpongeAbsorb(SpongeInstance *instance, const unsigned char *data, size_t dat + i = 0; + curData = data; + while(i < dataByteLen) { +- if ((instance->byteIOIndex == 0) && (dataByteLen >= (i + rateInBytes))) { ++ if ((instance->byteIOIndex == 0) && (dataByteLen-i >= rateInBytes)) { + #ifdef SnP_FastLoop_Absorb + /* processing full blocks first */ + if ((rateInBytes % (SnP_width/200)) == 0) { +@@ -186,9 +186,10 @@ int SpongeAbsorb(SpongeInstance *instance, const unsigned char *data, size_t dat + } + else { + /* normal lane: using the message queue */ +- partialBlock = (unsigned int)(dataByteLen - i); +- if (partialBlock+instance->byteIOIndex > rateInBytes) ++ if (dataByteLen-i > rateInBytes-instance->byteIOIndex) + partialBlock = rateInBytes-instance->byteIOIndex; ++ else ++ partialBlock = (unsigned int)(dataByteLen - i); + #ifdef KeccakReference + displayBytes(1, "Block to be absorbed (part)", curData, partialBlock); + #endif +@@ -263,7 +264,7 @@ int SpongeSqueeze(SpongeInstance *instance, unsigned char *data, size_t dataByte + i = 0; + curData = data; + while(i < dataByteLen) { +- if ((instance->byteIOIndex == rateInBytes) && (dataByteLen >= (i + rateInBytes))) { ++ if ((instance->byteIOIndex == rateInBytes) && (dataByteLen-i >= rateInBytes)) { + for(j=dataByteLen-i; j>=rateInBytes; j-=rateInBytes) { + SnP_Permute(instance->state); + SnP_ExtractBytes(instance->state, curData, 0, rateInBytes); +@@ -280,9 +281,10 @@ int SpongeSqueeze(SpongeInstance *instance, unsigned char *data, size_t dataByte + SnP_Permute(instance->state); + instance->byteIOIndex = 0; + } +- partialBlock = (unsigned int)(dataByteLen - i); +- if (partialBlock+instance->byteIOIndex > rateInBytes) ++ if (dataByteLen-i > rateInBytes-instance->byteIOIndex) + partialBlock = rateInBytes-instance->byteIOIndex; ++ else ++ partialBlock = (unsigned int)(dataByteLen - i); + i += partialBlock; + + SnP_ExtractBytes(instance->state, curData, instance->byteIOIndex, partialBlock); +diff --git a/ext/hash/sha3/generic64lc/KeccakSponge.inc b/ext/hash/sha3/generic64lc/KeccakSponge.inc +index 42a15aac6d..f8c42ff788 100644 +--- a/ext/hash/sha3/generic64lc/KeccakSponge.inc ++++ b/ext/hash/sha3/generic64lc/KeccakSponge.inc +@@ -160,7 +160,7 @@ int SpongeAbsorb(SpongeInstance *instance, const unsigned char *data, size_t dat + i = 0; + curData = data; + while(i < dataByteLen) { +- if ((instance->byteIOIndex == 0) && (dataByteLen >= (i + rateInBytes))) { ++ if ((instance->byteIOIndex == 0) && (dataByteLen-i >= rateInBytes)) { + #ifdef SnP_FastLoop_Absorb + /* processing full blocks first */ + if ((rateInBytes % (SnP_width/200)) == 0) { +@@ -186,9 +186,10 @@ int SpongeAbsorb(SpongeInstance *instance, const unsigned char *data, size_t dat + } + else { + /* normal lane: using the message queue */ +- partialBlock = (unsigned int)(dataByteLen - i); +- if (partialBlock+instance->byteIOIndex > rateInBytes) ++ if (dataByteLen-i > rateInBytes-instance->byteIOIndex) + partialBlock = rateInBytes-instance->byteIOIndex; ++ else ++ partialBlock = (unsigned int)(dataByteLen - i); + #ifdef KeccakReference + displayBytes(1, "Block to be absorbed (part)", curData, partialBlock); + #endif +@@ -263,7 +264,7 @@ int SpongeSqueeze(SpongeInstance *instance, unsigned char *data, size_t dataByte + i = 0; + curData = data; + while(i < dataByteLen) { +- if ((instance->byteIOIndex == rateInBytes) && (dataByteLen >= (i + rateInBytes))) { ++ if ((instance->byteIOIndex == rateInBytes) && (dataByteLen-i >= rateInBytes)) { + for(j=dataByteLen-i; j>=rateInBytes; j-=rateInBytes) { + SnP_Permute(instance->state); + SnP_ExtractBytes(instance->state, curData, 0, rateInBytes); +@@ -280,9 +281,10 @@ int SpongeSqueeze(SpongeInstance *instance, unsigned char *data, size_t dataByte + SnP_Permute(instance->state); + instance->byteIOIndex = 0; + } +- partialBlock = (unsigned int)(dataByteLen - i); +- if (partialBlock+instance->byteIOIndex > rateInBytes) ++ if (dataByteLen-i > rateInBytes-instance->byteIOIndex) + partialBlock = rateInBytes-instance->byteIOIndex; ++ else ++ partialBlock = (unsigned int)(dataByteLen - i); + i += partialBlock; + + SnP_ExtractBytes(instance->state, curData, instance->byteIOIndex, partialBlock); +-- +2.37.3 + diff --git a/php-bug81740.patch b/php-bug81740.patch new file mode 100644 index 0000000..de24046 --- /dev/null +++ b/php-bug81740.patch @@ -0,0 +1,87 @@ +From 67ef55c661506875d04e58bc9d1293a919eb798e 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 2bf452a88a..4bd844e2b5 100644 +--- a/ext/pdo_sqlite/sqlite_driver.c ++++ b/ext/pdo_sqlite/sqlite_driver.c +@@ -236,6 +236,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 09d73edbbcdb419611e341bec46bf083c708d864 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) +(cherry picked from commit 144d79977c7e2a410a705f550dbc8ee754dd1cb3) +--- + NEWS | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/NEWS b/NEWS +index b6e3c4fe6c..1c00ef6357 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.33 + + - Hash: +-- +2.38.1 + diff --git a/php-bug81744.patch b/php-bug81744.patch new file mode 100644 index 0000000..2864136 --- /dev/null +++ b/php-bug81744.patch @@ -0,0 +1,190 @@ +From 77e6dd89b92c3c7b3191e53508b1cd1744a89208 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 c57400002961b6df74960c52777ad0fb3dbeabea 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 e873ca7946..c391cfd3f6 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..c654709 --- /dev/null +++ b/php-bug81746.patch @@ -0,0 +1,100 @@ +From 3640e9897928d5b5607270c20593a0c04a455e1e 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 520edfadbb..33047bb160 100644 +--- a/main/fopen_wrappers.c ++++ b/main/fopen_wrappers.c +@@ -135,10 +135,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; + size_t resolved_basedir_len; + size_t resolved_name_len; +-- +2.39.1 + +From 2b9c9a8cb00914c08e34ee242d4aa3ba4aa74ef4 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 1c00ef6357..ad57c5ccd5 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..07361d1 --- /dev/null +++ b/php-cve-2023-0662.patch @@ -0,0 +1,148 @@ +From 1548e88ea16f68d15a71040c7fb6bff3874c5e32 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 27718e72a4..3f7a0c76f9 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 7d196fe1295491e624edf263525148c8c3bfd902 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 a3fc980b17..0cfdb91368 100644 +--- a/main/main.c ++++ b/main/main.c +@@ -621,6 +621,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 3f7a0c76f9..14813a300c 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 7900df2bfa37eaf0217fd2d62f3418b0be096cba 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 ad57c5ccd5..e59c43300a 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 27d1f29635717f619267b5e2ebf87ec43faa18f0 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 e59c43300a..47e9f89a64 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..54e8592 --- /dev/null +++ b/php-cve-2023-3247.patch @@ -0,0 +1,152 @@ +From a8cd8000fe5814302758a26f4ad4fd9d392c91e0 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 47e9f89a646..ae5101b368e 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 57754021b77..15b086e21c4 100644 +--- a/ext/soap/php_http.c ++++ b/ext/soap/php_http.c +@@ -665,18 +665,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 1563873cd3f1fbd2464d3521b699f14efce1db13 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 15b086e21c..6903a3b9c9 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 24d822d4e70431cc6dc795f7ff5193960f385c2f 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 ae5101b368..5f49a7ee04 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..70829bf --- /dev/null +++ b/php-cve-2023-3823.patch @@ -0,0 +1,91 @@ +From f8f433d0d8eaac21af4f4532496d33f9c2b381d6 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/5] 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) +--- + 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 1ee886ec2f..66931b652c 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..e807dd6 --- /dev/null +++ b/php-cve-2023-3824.patch @@ -0,0 +1,714 @@ +From d7de6908dfc8774e86a54100ad4e2ee810426001 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/5] 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) +--- + ext/dom/document.c | 15 ++++++++ + ext/dom/documentfragment.c | 2 ++ + ...xml_global_state_entity_loader_bypass.phpt | 36 +++++++++++++++++++ + ext/libxml/php_libxml.h | 36 +++++++++++++++++++ + ext/simplexml/simplexml.c | 6 ++++ + ...xml_global_state_entity_loader_bypass.phpt | 36 +++++++++++++++++++ + ext/soap/php_xml.c | 2 ++ + ext/xml/compat.c | 2 ++ + ext/xmlreader/php_xmlreader.c | 9 +++++ + ...xml_global_state_entity_loader_bypass.phpt | 35 ++++++++++++++++++ + ext/xsl/xsltprocessor.c | 9 +++-- + 11 files changed, 183 insertions(+), 5 deletions(-) + create mode 100644 ext/dom/tests/libxml_global_state_entity_loader_bypass.phpt + create mode 100644 ext/simplexml/tests/libxml_global_state_entity_loader_bypass.phpt + create mode 100644 ext/xmlreader/tests/libxml_global_state_entity_loader_bypass.phpt + +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/dom/tests/libxml_global_state_entity_loader_bypass.phpt b/ext/dom/tests/libxml_global_state_entity_loader_bypass.phpt +new file mode 100644 +index 0000000000..b28afd4694 +--- /dev/null ++++ b/ext/dom/tests/libxml_global_state_entity_loader_bypass.phpt +@@ -0,0 +1,36 @@ ++--TEST-- ++GHSA-3qrf-m4j2-pcrr (libxml global state entity loader bypass) ++--SKIPIF-- ++<?php ++if (!extension_loaded('libxml')) die('skip libxml extension not available'); ++if (!extension_loaded('dom')) die('skip dom extension not available'); ++if (!extension_loaded('zend-test')) die('skip zend-test extension not available'); ++?> ++--FILE-- ++<?php ++ ++$xml = "<?xml version='1.0'?><!DOCTYPE root [<!ENTITY % bork SYSTEM \"php://nope\"> %bork;]><nothing/>"; ++ ++libxml_use_internal_errors(true); ++ ++function parseXML($xml) { ++ $doc = new DOMDocument(); ++ @$doc->loadXML($xml); ++ $doc->createDocumentFragment()->appendXML("&bork;"); ++ foreach (libxml_get_errors() as $error) { ++ var_dump(trim($error->message)); ++ } ++} ++ ++parseXML($xml); ++zend_test_override_libxml_global_state(); ++parseXML($xml); ++ ++echo "Done\n"; ++ ++?> ++--EXPECT-- ++string(25) "Entity 'bork' not defined" ++string(25) "Entity 'bork' not defined" ++string(25) "Entity 'bork' not defined" ++Done +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 341daed0ee..c2b0230e19 100644 +--- a/ext/simplexml/simplexml.c ++++ b/ext/simplexml/simplexml.c +@@ -2217,7 +2217,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; +@@ -2271,7 +2273,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; +@@ -2321,7 +2325,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/simplexml/tests/libxml_global_state_entity_loader_bypass.phpt b/ext/simplexml/tests/libxml_global_state_entity_loader_bypass.phpt +new file mode 100644 +index 0000000000..2152e01232 +--- /dev/null ++++ b/ext/simplexml/tests/libxml_global_state_entity_loader_bypass.phpt +@@ -0,0 +1,36 @@ ++--TEST-- ++GHSA-3qrf-m4j2-pcrr (libxml global state entity loader bypass) ++--SKIPIF-- ++<?php ++if (!extension_loaded('libxml')) die('skip libxml extension not available'); ++if (!extension_loaded('simplexml')) die('skip simplexml extension not available'); ++if (!extension_loaded('zend-test')) die('skip zend-test extension not available'); ++?> ++--FILE-- ++<?php ++ ++$xml = "<?xml version='1.0'?><!DOCTYPE root [<!ENTITY % bork SYSTEM \"php://nope\"> %bork;]><nothing/>"; ++ ++libxml_use_internal_errors(true); ++zend_test_override_libxml_global_state(); ++ ++echo "--- String test ---\n"; ++simplexml_load_string($xml); ++echo "--- Constructor test ---\n"; ++new SimpleXMLElement($xml); ++echo "--- File test ---\n"; ++file_put_contents("libxml_global_state_entity_loader_bypass.tmp", $xml); ++simplexml_load_file("libxml_global_state_entity_loader_bypass.tmp"); ++ ++echo "Done\n"; ++ ++?> ++--CLEAN-- ++<?php ++@unlink("libxml_global_state_entity_loader_bypass.tmp"); ++?> ++--EXPECT-- ++--- String test --- ++--- Constructor test --- ++--- File test --- ++Done +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/xmlreader/tests/libxml_global_state_entity_loader_bypass.phpt b/ext/xmlreader/tests/libxml_global_state_entity_loader_bypass.phpt +new file mode 100644 +index 0000000000..e9ffb04c2b +--- /dev/null ++++ b/ext/xmlreader/tests/libxml_global_state_entity_loader_bypass.phpt +@@ -0,0 +1,35 @@ ++--TEST-- ++GHSA-3qrf-m4j2-pcrr (libxml global state entity loader bypass) ++--SKIPIF-- ++<?php ++if (!extension_loaded('libxml')) die('skip libxml extension not available'); ++if (!extension_loaded('xmlreader')) die('skip xmlreader extension not available'); ++if (!extension_loaded('zend-test')) die('skip zend-test extension not available'); ++?> ++--FILE-- ++<?php ++ ++$xml = "<?xml version='1.0'?><!DOCTYPE root [<!ENTITY % bork SYSTEM \"php://nope\"> %bork;]><nothing/>"; ++ ++libxml_use_internal_errors(true); ++zend_test_override_libxml_global_state(); ++ ++echo "--- String test ---\n"; ++$reader = XMLReader::xml($xml); ++$reader->read(); ++echo "--- File test ---\n"; ++file_put_contents("libxml_global_state_entity_loader_bypass.tmp", $xml); ++$reader = XMLReader::open("libxml_global_state_entity_loader_bypass.tmp"); ++$reader->read(); ++ ++echo "Done\n"; ++ ++?> ++--CLEAN-- ++<?php ++@unlink("libxml_global_state_entity_loader_bypass.tmp"); ++?> ++--EXPECT-- ++--- String test --- ++--- File test --- ++Done +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 3535016313ece1e12ffd5d9fc2f39478941be3d8 Mon Sep 17 00:00:00 2001 +From: Remi Collet <remi@remirepo.net> +Date: Tue, 1 Aug 2023 07:37:25 +0200 +Subject: [PATCH 3/5] backport zend_test changes + (zend_test_override_libxml_global_state) + +(cherry picked from commit 24e669e790e6aebd219c9a9fa19017455c8646b4) +(cherry picked from commit 79a97d0e2b93c40c3728d587046266989c5acc42) +--- + ...xml_global_state_entity_loader_bypass.phpt | 1 + + ...xml_global_state_entity_loader_bypass.phpt | 1 + + ...xml_global_state_entity_loader_bypass.phpt | 5 +++-- + ext/zend_test/test.c | 22 +++++++++++++++++++ + 4 files changed, 27 insertions(+), 2 deletions(-) + +diff --git a/ext/dom/tests/libxml_global_state_entity_loader_bypass.phpt b/ext/dom/tests/libxml_global_state_entity_loader_bypass.phpt +index b28afd4694..7fc2a249ac 100644 +--- a/ext/dom/tests/libxml_global_state_entity_loader_bypass.phpt ++++ b/ext/dom/tests/libxml_global_state_entity_loader_bypass.phpt +@@ -5,6 +5,7 @@ GHSA-3qrf-m4j2-pcrr (libxml global state entity loader bypass) + if (!extension_loaded('libxml')) die('skip libxml extension not available'); + if (!extension_loaded('dom')) die('skip dom extension not available'); + if (!extension_loaded('zend-test')) die('skip zend-test extension not available'); ++if (!function_exists('zend_test_override_libxml_global_state')) die('skip not for Windows'); + ?> + --FILE-- + <?php +diff --git a/ext/simplexml/tests/libxml_global_state_entity_loader_bypass.phpt b/ext/simplexml/tests/libxml_global_state_entity_loader_bypass.phpt +index 2152e01232..54f9d4941e 100644 +--- a/ext/simplexml/tests/libxml_global_state_entity_loader_bypass.phpt ++++ b/ext/simplexml/tests/libxml_global_state_entity_loader_bypass.phpt +@@ -5,6 +5,7 @@ GHSA-3qrf-m4j2-pcrr (libxml global state entity loader bypass) + if (!extension_loaded('libxml')) die('skip libxml extension not available'); + if (!extension_loaded('simplexml')) die('skip simplexml extension not available'); + if (!extension_loaded('zend-test')) die('skip zend-test extension not available'); ++if (!function_exists('zend_test_override_libxml_global_state')) die('skip not for Windows'); + ?> + --FILE-- + <?php +diff --git a/ext/xmlreader/tests/libxml_global_state_entity_loader_bypass.phpt b/ext/xmlreader/tests/libxml_global_state_entity_loader_bypass.phpt +index e9ffb04c2b..b0120b325e 100644 +--- a/ext/xmlreader/tests/libxml_global_state_entity_loader_bypass.phpt ++++ b/ext/xmlreader/tests/libxml_global_state_entity_loader_bypass.phpt +@@ -5,6 +5,7 @@ GHSA-3qrf-m4j2-pcrr (libxml global state entity loader bypass) + if (!extension_loaded('libxml')) die('skip libxml extension not available'); + if (!extension_loaded('xmlreader')) die('skip xmlreader extension not available'); + if (!extension_loaded('zend-test')) die('skip zend-test extension not available'); ++if (!function_exists('zend_test_override_libxml_global_state')) die('skip not for Windows'); + ?> + --FILE-- + <?php +@@ -15,11 +16,11 @@ libxml_use_internal_errors(true); + zend_test_override_libxml_global_state(); + + echo "--- String test ---\n"; +-$reader = XMLReader::xml($xml); ++$reader = @XMLReader::xml($xml); + $reader->read(); + echo "--- File test ---\n"; + file_put_contents("libxml_global_state_entity_loader_bypass.tmp", $xml); +-$reader = XMLReader::open("libxml_global_state_entity_loader_bypass.tmp"); ++$reader = @XMLReader::open("libxml_global_state_entity_loader_bypass.tmp"); + $reader->read(); + + echo "Done\n"; +diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c +index 4a7fe540fb..611bc9b68c 100644 +--- a/ext/zend_test/test.c ++++ b/ext/zend_test/test.c +@@ -25,6 +25,11 @@ + #include "ext/standard/info.h" + #include "php_test.h" + ++#if defined(HAVE_LIBXML) && !defined(PHP_WIN32) ++# include <libxml/globals.h> ++# include <libxml/parser.h> ++#endif ++ + static zend_class_entry *zend_test_interface; + static zend_class_entry *zend_test_class; + static zend_class_entry *zend_test_trait; +@@ -44,6 +49,20 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_zend_leak_variable, 0, 0, 1) + ZEND_ARG_INFO(0, variable) + ZEND_END_ARG_INFO() + ++#if defined(HAVE_LIBXML) && !defined(PHP_WIN32) ++static ZEND_FUNCTION(zend_test_override_libxml_global_state) ++{ ++ ZEND_PARSE_PARAMETERS_NONE(); ++ ++ xmlLoadExtDtdDefaultValue = 1; ++ xmlDoValidityCheckingDefaultValue = 1; ++ (void) xmlPedanticParserDefault(1); ++ (void) xmlSubstituteEntitiesDefault(1); ++ (void) xmlLineNumbersDefault(1); ++ (void) xmlKeepBlanksDefault(0); ++} ++#endif ++ + ZEND_FUNCTION(zend_test_func) + { + /* dummy */ +@@ -251,6 +270,9 @@ const zend_function_entry zend_test_functions[] = { + ZEND_FE(zend_terminate_string, arginfo_zend_terminate_string) + ZEND_FE(zend_leak_bytes, NULL) + ZEND_FE(zend_leak_variable, arginfo_zend_leak_variable) ++#if defined(HAVE_LIBXML) && !defined(PHP_WIN32) ++ ZEND_FE(zend_test_override_libxml_global_state, NULL) ++#endif + ZEND_FE_END + }; + +-- +2.41.0 + +From 26d70866843598f4a2ed94b01999b38e1d7c0e97 Mon Sep 17 00:00:00 2001 +From: Remi Collet <remi@remirepo.net> +Date: Tue, 1 Aug 2023 15:45:24 +0200 +Subject: [PATCH 4/5] adapt to 7.2 + +--- + ext/dom/tests/libxml_global_state_entity_loader_bypass.phpt | 1 - + .../tests/libxml_global_state_entity_loader_bypass.phpt | 1 - + .../tests/libxml_global_state_entity_loader_bypass.phpt | 1 - + ext/zend_test/test.c | 2 -- + 4 files changed, 5 deletions(-) + +diff --git a/ext/dom/tests/libxml_global_state_entity_loader_bypass.phpt b/ext/dom/tests/libxml_global_state_entity_loader_bypass.phpt +index 7fc2a249ac..25499006d9 100644 +--- a/ext/dom/tests/libxml_global_state_entity_loader_bypass.phpt ++++ b/ext/dom/tests/libxml_global_state_entity_loader_bypass.phpt +@@ -4,7 +4,6 @@ GHSA-3qrf-m4j2-pcrr (libxml global state entity loader bypass) + <?php + if (!extension_loaded('libxml')) die('skip libxml extension not available'); + if (!extension_loaded('dom')) die('skip dom extension not available'); +-if (!extension_loaded('zend-test')) die('skip zend-test extension not available'); + if (!function_exists('zend_test_override_libxml_global_state')) die('skip not for Windows'); + ?> + --FILE-- +diff --git a/ext/simplexml/tests/libxml_global_state_entity_loader_bypass.phpt b/ext/simplexml/tests/libxml_global_state_entity_loader_bypass.phpt +index 54f9d4941e..e09ecb5d72 100644 +--- a/ext/simplexml/tests/libxml_global_state_entity_loader_bypass.phpt ++++ b/ext/simplexml/tests/libxml_global_state_entity_loader_bypass.phpt +@@ -4,7 +4,6 @@ GHSA-3qrf-m4j2-pcrr (libxml global state entity loader bypass) + <?php + if (!extension_loaded('libxml')) die('skip libxml extension not available'); + if (!extension_loaded('simplexml')) die('skip simplexml extension not available'); +-if (!extension_loaded('zend-test')) die('skip zend-test extension not available'); + if (!function_exists('zend_test_override_libxml_global_state')) die('skip not for Windows'); + ?> + --FILE-- +diff --git a/ext/xmlreader/tests/libxml_global_state_entity_loader_bypass.phpt b/ext/xmlreader/tests/libxml_global_state_entity_loader_bypass.phpt +index b0120b325e..9824e10603 100644 +--- a/ext/xmlreader/tests/libxml_global_state_entity_loader_bypass.phpt ++++ b/ext/xmlreader/tests/libxml_global_state_entity_loader_bypass.phpt +@@ -4,7 +4,6 @@ GHSA-3qrf-m4j2-pcrr (libxml global state entity loader bypass) + <?php + if (!extension_loaded('libxml')) die('skip libxml extension not available'); + if (!extension_loaded('xmlreader')) die('skip xmlreader extension not available'); +-if (!extension_loaded('zend-test')) die('skip zend-test extension not available'); + if (!function_exists('zend_test_override_libxml_global_state')) die('skip not for Windows'); + ?> + --FILE-- +diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c +index 611bc9b68c..51818083d9 100644 +--- a/ext/zend_test/test.c ++++ b/ext/zend_test/test.c +@@ -52,8 +52,6 @@ ZEND_END_ARG_INFO() + #if defined(HAVE_LIBXML) && !defined(PHP_WIN32) + static ZEND_FUNCTION(zend_test_override_libxml_global_state) + { +- ZEND_PARSE_PARAMETERS_NONE(); +- + xmlLoadExtDtdDefaultValue = 1; + xmlDoValidityCheckingDefaultValue = 1; + (void) xmlPedanticParserDefault(1); +-- +2.41.0 + +From 79c0bf87711036b83f8ee1723c034ccc839d847b Mon Sep 17 00:00:00 2001 +From: Remi Collet <remi@remirepo.net> +Date: Tue, 1 Aug 2023 07:22:33 +0200 +Subject: [PATCH 5/5] NEWS + +(cherry picked from commit ef1d507acf7be23d7624dc3c891683b2218feb51) +(cherry picked from commit 3cf7c2b10e577136b267f2d90bfdff6743271c5c) +--- + NEWS | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/NEWS b/NEWS +index 5f49a7ee04..286f3df0f4 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..6e13a30 --- /dev/null +++ b/php-cve-2024-2756.patch @@ -0,0 +1,197 @@ +From c213de619a532d35e8f7abe4a245433dbf21c960 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) +--- + 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 bd59134fc9..3e0e8d767e 100644 +--- a/main/php_variables.c ++++ b/main/php_variables.c +@@ -59,6 +59,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; +@@ -109,20 +124,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); +@@ -220,6 +221,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; +@@ -258,6 +265,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 ee591001f7a3db7405b4fa027659768c2355df6d 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) +--- + NEWS | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/NEWS b/NEWS +index 286f3df0f4..e55195bc56 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..ca137c6 --- /dev/null +++ b/php-cve-2024-3096.patch @@ -0,0 +1,85 @@ +From d22d9ebb29dce86edd622205dd1196a2796c08c7 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) +--- + 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 c92925b903..4944369ba8 100644 +--- a/ext/standard/password.c ++++ b/ext/standard/password.c +@@ -438,6 +438,11 @@ PHP_FUNCTION(password_hash) + cost = zval_get_long(option_buffer); + } + ++ if (memchr(ZSTR_VAL(password), '\0', ZSTR_LEN(password))) { ++ 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 be830600a8e4c33a25e965d0782903e885e91c6d 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) +--- + NEWS | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/NEWS b/NEWS +index e55195bc56..7d99fb7d60 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-keyring.gpg b/php-keyring.gpg index b5318b2..f06ffb0 100644 --- a/php-keyring.gpg +++ b/php-keyring.gpg @@ -1,320 +1,539 @@ -----BEGIN PGP PUBLIC KEY BLOCK----- -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 -jZkkGZj3BY/7ApoLq4mwqzbh+CpLXwNn20tFNvSXfb8RdeXvVEb7Scx+W9qYpiau -n2iXJgCVH8fgpZpR856ulT1q6uCG++CXubEvip/eJkZl93/84h04KQJwsgOrAh0O -m3OePRn8Pr+++0LNS0EL8uX/YHeTOGOnnmTqYTeySBVFdov6L4mepddfjekicKQq -hL7mZh/xuq29JijT0uNNX8v4vDWQDu5dlAcdd+uB3gcXMD/PginD11zp+6wtrWCm -/+yBqpvDwXQX5PGUnwvbRfl7Ay3MmwmoXiecZMg0dwTSc7e0lhB4HGRHZdBMJB4r -HUVGdzqujK/ctOvrAAMFB/0Utb76Qe6sCMlHxVAmeE/fbo7Pi05btZ/x01r67dHf -aMSP0riCKJ7M0OW+jAXtu9+z/BVnYisW67WWfxl2cS5tZDgiHgJARXWUOO72+sSc -HP8KQmTl1z16gyKbwY3SmyBkwcpOL35nhUWNLy93syPoY6sZUTikr2bZYukHDQ33 -XBPs4e6MbWKfsa9qaVmnlOF3k5UqChjutfHaEa4Q7VP4wBIpphHBi9MI16oJIzzB -PbGl2uoedjwiZ6QeQZnSuOVYZxU2d3lRA8PrtfFN1VSlpEm/VcAvtieHUYWHN0wO -u+cp3Slr5XJVNjTjJhl28SlinMME54mKAGf2Ldr/dRwXiGEEGBEIAAkFAk9mqaAC -GwwACgkQL3lWvF2gS126EQD/VVd3FgjLKglClRQPzdfU847tqDK4zJjbmRv5vLLw -oE0A+wbrQs7jVGU3NrS0AIl5vUmewpp2BKzSkepy23nWmejwmQINBFjxRtoBEADk -S6+Q7afwYDPFnqJXuyF2ZIvXysDBrpr/xbre4jVeiC/HIELaQedOJqO1V+BgnTRk -fhor+Yq3mZ1un+6zJIiFcm5Kp7sPZjh15JF96PsA4e2Eh5eCeJzjXHj1nAKXfn5+ -CgpYEyL30r1/ACkmo9TKIiUxIDZRkZvxjY4UKeo+EoJo0ViutV8mvSTgxaz9gzPh -Z5OJR8zECT8j3T8d+tBD8wWxxmGZ0veOu/MBew1C/BDr8RqTCXDywUbyNuSsdb3a -5aLuIuLekSJVSCcFwPIje1WrX4FyC42+elOp0SXpjWzdb08NXX4DEY8zVyVXI1Sc -SpTbslffcFkY60NJhjpP7t856L9vTLRfHIM9BIdSYH/ar5mEQ0vyJbiNfkx5tIMn -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 -RbbnRGir0GxlvcmpWMLo+2IqeVyRrbY= -=jKsj +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 +T8nOkbAfOLH7JNkFYr1PMPAJLxkHmI16M+yMGqPefn1rXlc2d+ikUL1HJD/KRox5 +Q15x8SdByNSP5DgWUo8EcFH9HXe98unqz4Wy5PoH/jXSNx/ShiQcxuf61clisFHk +PXebneI0yUZEBrwD+aYO+rxGvXaIG6XuFuWftAX24iUp0JkFkh4mXXY/7d96bW7q +eOApOmU4HZZhWDCxdYUeOzyGUwyhERLimBnIv76vLJ2bxCT/WAsP07Yh3DHazCnG +P/i6fJUDtBhyzwfYJVYZwtHW+pdV6YNQjCPP0aMwTHIo99BIAE4IAv8ts24qgBaE +vRTfZ1z23uKYUragARMnmfp17nbez1GE41YHK6qPGx2QorAaG1guzpyslM8Vcc1H +rj5CH5mbs5C2jMNjHEHb8MLDb0NA82iz99HNV7Jv+xCGCXDlqc5VSeUK3ZhNPwW0 +MlN0YW5pc2xhdiBNYWx5c2hldiAoUEhQIGtleSkgPHNtYWx5c2hldkBnbWFpbC5j +b20+iHoEExEIACIFAk9mqrQCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJ +EC95VrxdoEtdlzMA/R7kSKJUsCCu+7vBGOOtctrurG19+p+f7qPyw0LsaIt7AP9D +L6Z78zob/SLn777GRI9xO4t4fog+euPGDMH0xQoo/rQrU3RhbmlzbGF2IE1hbHlz +aGV2IChQSFAga2V5KSA8c3Rhc0BwaHAubmV0Poh6BBMRCAAiBQJPZqmgAhsDBgsJ +CAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRAveVa8XaBLXYXbAP9akG+UWW4ej5SF +XhwhRQt3zL8uesCdSgtJJ4aYcmXXBgD/W0BYVhm8cpRZ+8Zp2ydm6WvtGH80VsG4 +JniEqGSLUNW0NVN0YW5pc2xhdiBNYWx5c2hldiAoUEhQIGtleSkgPHNtYWx5c2hl +dkBzdWdhcmNybS5jb20+iHoEExEIACIFAk9mqp0CGwMGCwkIBwMCBhUIAgkKCwQW +AgMBAh4BAheAAAoJEC95VrxdoEtda6EA/0v39zO2IAoWjPEgLe/YgD7y4nqZVAYG +ILjiYx3NekANAPwJtJoypjat1uT9LgP7wfpYghHDC3XGYjiLDSOOHh4+T7kCDQRP +ZqmgEAgA32TzKY2ZJBmY9wWP+wKaC6uJsKs24fgqS18DZ9tLRTb0l32/EXXl71RG ++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 +=BHrR -----END PGP PUBLIC KEY BLOCK----- @@ -25,21 +25,14 @@ %global mysql_sock %(mysql_config --socket 2>/dev/null || echo /var/lib/mysql/mysql.sock) -%if 0%{?rhel} == 6 -%ifarch x86_64 -%global oraclever 18.5 -%else -%global oraclever 18.3 -%endif -%global oraclelib 18.1 - -%else -%ifarch x86_64 -%global oraclever 19.8 -%else -%global oraclever 19.6 -%endif +%ifarch aarch64 +%global oraclever 19.19 %global oraclelib 19.1 +%global oracledir 19.19 +%else +%global oraclever 21.13 +%global oraclelib 21.1 +%global oracledir 21 %endif # Build for LiteSpeed Web Server (LSAPI) @@ -66,7 +59,11 @@ %global with_sqlite3 1 # Build ZTS extension or only NTS +%ifarch x86_64 %global with_zts 1 +%else +%global with_zts 0 +%endif # Debuild build %global with_debug %{?_with_debug:1}%{!?_with_debug:0} @@ -124,7 +121,7 @@ Summary: PHP scripting language for creating dynamic web sites Name: php Version: %{upver}%{?rcver:~%{rcver}} -Release: 1%{?dist} +Release: 21%{?dist} # All files licensed under PHP version 3.01, except # Zend is licensed under Zend # TSRM is licensed under BSD @@ -161,6 +158,7 @@ Source99: php-fpm.init # Build fixes Patch1: php-7.1.7-httpd.patch +Patch2: php-7.1.33-intl.patch Patch5: php-7.2.0-includedir.patch Patch6: php-5.6.3-embed.patch Patch7: php-5.3.0-recode.patch @@ -190,6 +188,28 @@ Patch91: php-7.2.0-oci8conf.patch # Upstream fixes (100+) # Security fixes (200+) +Patch200: php-bug77423.patch +Patch201: php-bug80672.patch +Patch202: php-bug80710.patch +Patch203: php-bug81122.patch +Patch204: php-bug76450.patch +Patch205: php-bug81211.patch +Patch206: php-bug81026.patch +Patch207: php-bug79971.patch +Patch208: php-bug81719.patch +Patch209: php-bug81720.patch +Patch210: php-bug81727.patch +Patch211: php-bug81726.patch +Patch212: php-bug81738.patch +Patch213: php-bug81740.patch +Patch214: php-bug81744.patch +Patch215: php-bug81746.patch +Patch216: php-cve-2023-0662.patch +Patch217: php-cve-2023-3247.patch +Patch218: php-cve-2023-3823.patch +Patch219: php-cve-2023-3824.patch +Patch220: php-cve-2024-2756.patch +Patch221: php-cve-2024-3096.patch # Fixes for tests (300+) # Factory is droped from system tzdata @@ -225,6 +245,7 @@ BuildRequires: bzip2 BuildRequires: perl BuildRequires: autoconf BuildRequires: automake +BuildRequires: make BuildRequires: %{?dtsprefix}gcc BuildRequires: %{?dtsprefix}gcc-c++ BuildRequires: libtool @@ -320,7 +341,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} @@ -341,6 +361,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 @@ -437,6 +459,7 @@ Requires: php-cli%{?_isa} = %{version}-%{release} # always needed to build extension Requires: autoconf Requires: automake +Requires: make Requires: gcc Requires: gcc-c++ Requires: libtool @@ -697,15 +720,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.18.3, 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 Obsoletes: php70u-oci8, php70w-oci8, php71u-oci8, php71w-oci8, php72u-oci8, php72w-oci8 @@ -719,13 +747,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.%{oraclelib} 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 @@ -828,12 +852,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 @@ -992,8 +1011,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 / libicu62 -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 Obsoletes: php70u-intl, php70w-intl, php71u-intl, php71w-intl, php72u-intl, php72w-intl @@ -1096,49 +1115,72 @@ low-level PHP extension for the libsodium cryptographic library. %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} >= 28 || 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 -%patch46 -p1 -b .fixheader -%patch47 -p1 -b .phpinfo -%patch48 -p1 -b .getallheaders -%patch49 -p1 -b .pdooci +%patch -P46 -p1 -b .fixheader +%patch -P47 -p1 -b .phpinfo +%patch -P48 -p1 -b .getallheaders +%patch -P49 -p1 -b .pdooci -%patch91 -p1 -b .remi-oci8 +%patch -P91 -p1 -b .remi-oci8 # upstream patches # security patches +%patch -P200 -p1 -b .bug77423 +%patch -P201 -p1 -b .bug80672 +%patch -P202 -p1 -b .bug80710 +%patch -P203 -p1 -b .bug81122 +%patch -P204 -p1 -b .bug76450 +%patch -P205 -p1 -b .bug81211 +%patch -P206 -p1 -b .bug81026 +%patch -P207 -p1 -b .bug79971 +%patch -P208 -p1 -b .bug81719 +%patch -P209 -p1 -b .bug81720 +%patch -P210 -p1 -b .bug81727 +%patch -P211 -p1 -b .bug81726 +%patch -P212 -p1 -b .bug81738 +%patch -P213 -p1 -b .bug81740 +%patch -P214 -p1 -b .bug81744 +%patch -P215 -p1 -b .bug81746 +%patch -P216 -p1 -b .cve0662 +%patch -P217 -p1 -b .cve3247 +%patch -P218 -p1 -b .cve3823 +%patch -P219 -p1 -b .cve3824 +%patch -P220 -p1 -b .cve2756 +%patch -P221 -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 # 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 @@ -1424,13 +1466,8 @@ 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} \ - --with-pdo-oci=shared,instantclient,%{_libdir}/oracle/%{oraclever}/client64/lib,%{oraclever} \ -%else - --with-oci8=shared,instantclient,%{_libdir}/oracle/%{oraclever}/client/lib,%{oraclever} \ - --with-pdo-oci=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,%{_prefix}/lib/oracle/%{oracledir}/client64/lib,%{oraclever} \ %endif %if %{with_firebird} --with-interbase=shared \ @@ -1580,13 +1617,8 @@ 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} \ - --with-pdo-oci=shared,instantclient,%{_libdir}/oracle/%{oraclever}/client64/lib,%{oraclever} \ -%else - --with-oci8=shared,instantclient,%{_libdir}/oracle/%{oraclever}/client/lib,%{oraclever} \ - --with-pdo-oci=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,%{_prefix}/lib/oracle/%{oracledir}/client64/lib,%{oraclever} \ %endif %if %{with_firebird} --with-interbase=shared \ @@ -1656,7 +1688,7 @@ 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 @@ -1795,8 +1827,8 @@ install -m 755 -d $RPM_BUILD_ROOT/run/php-fpm install -m 755 -d $RPM_BUILD_ROOT%{_sysconfdir}/systemd/system/php-fpm.service.d install -Dm 644 %{SOURCE6} $RPM_BUILD_ROOT%{_unitdir}/php-fpm.service %if 0%{?fedora} >= 27 || 0%{?rhel} >= 8 -install -Dm 644 %{SOURCE12} $RPM_BUILD_ROOT%{_unitdir}/httpd.service.d/php-fpm.conf -install -Dm 644 %{SOURCE12} $RPM_BUILD_ROOT%{_unitdir}/nginx.service.d/php-fpm.conf +install -Dm 644 %{SOURCE12} $RPM_BUILD_ROOT%{_sysconfdir}/systemd/system/httpd.service.d/php-fpm.conf +install -Dm 644 %{SOURCE12} $RPM_BUILD_ROOT%{_sysconfdir}/systemd/system/nginx.service.d/php-fpm.conf %endif %else sed -ne '1,2p' -i $RPM_BUILD_ROOT%{_sysconfdir}/sysconfig/php-fpm @@ -1949,7 +1981,7 @@ sed -e "s/@PHP_APIVER@/%{apiver}%{isasuffix}/" \ %endif < %{SOURCE3} > macros.php %if 0%{?fedora} >= 24 || 0%{?rhel} >= 8 -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 @@ -2045,6 +2077,19 @@ fi %endif +%posttrans common +cat << EOF +===================================================================== + + WARNING : PHP 7.2 have reached its "End of Life" in + November 2020. 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 @@ -2063,7 +2108,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 @@ -2088,20 +2133,22 @@ fi %files cli %{_bindir}/php -%{_bindir}/zts-php %{_bindir}/php-cgi %{_bindir}/phar.phar %{_bindir}/phar # provides phpize here (not in -devel) for pecl command %{_bindir}/phpize %{_mandir}/man1/php.1* -%{_mandir}/man1/zts-php.1* %{_mandir}/man1/php-cgi.1* %{_mandir}/man1/phar.1* %{_mandir}/man1/phar.phar.1* %{_mandir}/man1/phpize.1* -%{_mandir}/man1/zts-phpize.1* %doc sapi/cgi/README* sapi/cli/README +%if %{with_zts} +%{_bindir}/zts-php +%{_mandir}/man1/zts-php.1* +%{_mandir}/man1/zts-phpize.1* +%endif %files dbg %{_bindir}/phpdbg @@ -2136,8 +2183,8 @@ fi %if %{with_systemd} %{_unitdir}/php-fpm.service %if 0%{?fedora} >= 27 || 0%{?rhel} >= 8 -%{_unitdir}/httpd.service.d/%{?scl_prefix}php-fpm.conf -%{_unitdir}/nginx.service.d/%{?scl_prefix}php-fpm.conf +%config(noreplace) %{_sysconfdir}/systemd/system/httpd.service.d/%{?scl_prefix}php-fpm.conf +%config(noreplace) %{_sysconfdir}/systemd/system/nginx.service.d/%{?scl_prefix}php-fpm.conf %endif %dir %{_sysconfdir}/systemd/system/php-fpm.service.d %dir %ghost /run/php-fpm @@ -2167,9 +2214,9 @@ fi %{_includedir}/php-zts %{_bindir}/zts-phpize %{_libdir}/php-zts/build +%{_mandir}/man1/zts-php-config.1* %endif %{_mandir}/man1/php-config.1* -%{_mandir}/man1/zts-php-config.1* %{macrosdir}/macros.php %files embedded @@ -2211,7 +2258,9 @@ fi %files mysqlnd -f files.mysqlnd %files opcache -f files.opcache %config(noreplace) %{_sysconfdir}/php.d/opcache-default.blacklist +%if %{with_zts} %config(noreplace) %{_sysconfdir}/php-zts.d/opcache-default.blacklist +%endif %if %{with_oci8} %files oci8 -f files.oci8 %endif @@ -2223,6 +2272,97 @@ fi %changelog +* Wed Apr 10 2024 Remi Collet <remi@remirepo.net> - 7.2.34-21 +- 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 + +* Thu Sep 21 2023 Remi Collet <remi@remirepo.net> - 7.2.34-20 +- use oracle client library version 21.11 on x86_64, 19.19 on aarch64 +- use official Oracle Instant Client RPM + +* Tue Aug 1 2023 Remi Collet <remi@remirepo.net> - 7.2.34-19 +- 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 +- move httpd/nginx wants directive to config files in /etc + +* Tue Jun 20 2023 Remi Collet <remi@remirepo.net> - 7.2.34-18 +- fix possible buffer overflow in date + +* Wed Jun 7 2023 Remi Collet <remi@remirepo.net> - 7.2.34-17 +- 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.2.34-16 +- 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.2.34-15 +- pdo: fix #81740: PDO::quote() may return unquoted string + CVE-2022-31631 +- use oracle client library version 21.8 + +* Mon Oct 24 2022 Remi Collet <remi@remirepo.net> - 7.2.34-14 +- hash: fix #81738: buffer overflow in hash_update() on long parameter. + CVE-2022-37454 + +* Tue Sep 27 2022 Remi Collet <remi@remirepo.net> - 7.2.34-13 +- 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.2.34-11 +- 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.2.34-10 +- Fix #79971 special character is breaking the path in xml function + CVE-2021-21707 + +* Wed Oct 20 2021 Remi Collet <remi@remirepo.net> - 7.2.34-9 +- 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.2.34-7 +- Fix #81211 Symlinks are followed when creating PHAR archive + +* Mon Jun 28 2021 Remi Collet <remi@remirepo.net> - 7.2.34-6 +- 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.2.34-4 +- Fix #80710 imap_mail_compose() header injection +- use oracle client library version 21.1 + +* Wed Feb 3 2021 Remi Collet <remi@remirepo.net> - 7.2.34-3 +- Fix #80672 Null Dereference in SoapClient + CVE-2021-21702 +- better fix for #77423 + +* Mon Jan 4 2021 Remi Collet <remi@remirepo.net> - 7.2.34-2 +- Fix #77423 FILTER_VALIDATE_URL accepts URLs with invalid userinfo + CVE-2020-7071 + * Wed Sep 30 2020 Remi Collet <remi@remirepo.net> - 7.2.34-1 - Update to 7.2.34 - http://www.php.net/releases/7_2_34.php |