From 544e29f1e739eb8ab335c130788d46161141d338 Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Thu, 7 May 2026 10:15:48 +0200 Subject: Fix XSS within status endpoint CVE-2026-6735 Fix Null pointer dereference in php_mb_check_encoding() via mb_ereg_search_init() CVE-2026-7259 Fix SQL injection via NUL bytes in quoted strings CVE-2025-14179 Fix Stale SOAP_GLOBAL(ref_map) pointer with Apache Map CVE-2026-6722 Fix Use-after-free after header parsing failure with SOAP_PERSISTENCE_SESSION CVE-2026-7261 Fix Broken Apache map value NULL check CVE-2026-7262 Fix Signed integer overflow of char array offset CVE-2026-7568 Fix Consistently pass unsigned char to ctype.h functions CVE-2026-7258 --- failed.txt | 29 +- php-cve-2026-14179.patch | 274 ++++++++ php-cve-2026-6722.patch | 107 +++ php-cve-2026-6735.patch | 144 ++++ php-cve-2026-7258.patch | 1719 ++++++++++++++++++++++++++++++++++++++++++++++ php-cve-2026-7259.patch | 66 ++ php-cve-2026-7261.patch | 111 +++ php-cve-2026-7262.patch | 77 +++ php-cve-2026-7568.patch | 101 +++ php81.spec | 51 +- 10 files changed, 2664 insertions(+), 15 deletions(-) create mode 100644 php-cve-2026-14179.patch create mode 100644 php-cve-2026-6722.patch create mode 100644 php-cve-2026-6735.patch create mode 100644 php-cve-2026-7258.patch create mode 100644 php-cve-2026-7259.patch create mode 100644 php-cve-2026-7261.patch create mode 100644 php-cve-2026-7262.patch create mode 100644 php-cve-2026-7568.patch diff --git a/failed.txt b/failed.txt index 51bc18f..b6e729d 100644 --- a/failed.txt +++ b/failed.txt @@ -1,25 +1,28 @@ -===== 8.1.34 (2025-12-18) +===== 8.1.34-2 (2026-05-07) $ grep -ar 'Tests failed' /var/lib/mock/*/build.log -/var/lib/mock/el8a81/build.log:Tests failed : 0 -/var/lib/mock/el8x81/build.log:Tests failed : 0 -/var/lib/mock/el9a81/build.log:Tests failed : 2 -/var/lib/mock/el9x81/build.log:Tests failed : 2 -/var/lib/mock/el10a81/build.log:Tests failed : 2 -/var/lib/mock/el10x81/build.log:Tests failed : 2 -/var/lib/mock/fc41a81/build.log:Tests failed : 1 -/var/lib/mock/fc41x81/build.log:Tests failed : 1 -/var/lib/mock/fc42a81/build.log:Tests failed : 1 -/var/lib/mock/fc42x81/build.log:Tests failed : 1 -/var/lib/mock/fc43a81/build.log:Tests failed : 2 -/var/lib/mock/fc43x81/build.log:Tests failed : 2 +/var/lib/mock/el8a81/build.log:Tests failed : 2 +/var/lib/mock/el8x81/build.log:Tests failed : 2 +/var/lib/mock/el9a81/build.log:Tests failed : 4 +/var/lib/mock/el9x81/build.log:Tests failed : 4 +/var/lib/mock/el10a81/build.log:Tests failed : 4 +/var/lib/mock/el10x81/build.log:Tests failed : 4 +/var/lib/mock/fc42a81/build.log:Tests failed : 3 +/var/lib/mock/fc42x81/build.log:Tests failed : 3 +/var/lib/mock/fc43a81/build.log:Tests failed : 4 +/var/lib/mock/fc43x81/build.log:Tests failed : 4 +/var/lib/mock/fc44a81/build.log:Tests failed : 4 +/var/lib/mock/fc44x81/build.log:Tests failed : 4 fc*, el10: 3 openssl_x509_parse() tests [ext/openssl/tests/openssl_x509_parse_basic.phpt] fc43, el9, el10: 3 Bug #74341 (openssl_x509_parse fails to parse ASN.1 UTCTime without seconds) [ext/openssl/tests/bug74341.phpt] +all + 3 sni_server [ext/openssl/tests/sni_server.phpt] + 3 sni_server with separate pk and cert [ext/openssl/tests/sni_server_key_cert.phpt] 1 proc_open give erratic test results :( diff --git a/php-cve-2026-14179.patch b/php-cve-2026-14179.patch new file mode 100644 index 0000000..71e15cd --- /dev/null +++ b/php-cve-2026-14179.patch @@ -0,0 +1,274 @@ +From 4b0dd469bbba7bf5f25f1a4f694aeb15c3515be4 Mon Sep 17 00:00:00 2001 +From: Saki Takamachi +Date: Sun, 3 May 2026 19:56:30 +0200 +Subject: [PATCH 07/10] GHSA-w476-322c-wpvm: [pdo_firebird] Fix SQL injection + via NUL bytes in quoted strings + +Fixes GHSA-w476-322c-wpvm +Fixes CVE-2025-14179 + +(cherry picked from commit 3f40b65323dd1b85e9bab6878237d3867e449d5c) +--- + ext/pdo_firebird/firebird_driver.c | 69 ++++++++++++------- + .../tests/ghsa-w476-322c-wpvm.phpt | 44 ++++++++++++ + 2 files changed, 88 insertions(+), 25 deletions(-) + create mode 100644 ext/pdo_firebird/tests/ghsa-w476-322c-wpvm.phpt + +diff --git a/ext/pdo_firebird/firebird_driver.c b/ext/pdo_firebird/firebird_driver.c +index a446622c90e..25882919f86 100644 +--- a/ext/pdo_firebird/firebird_driver.c ++++ b/ext/pdo_firebird/firebird_driver.c +@@ -291,7 +291,7 @@ static FbTokenType getToken(const char** begin, const char* end) + return ret; + } + +-int preprocess(const zend_string* sql, char* sql_out, HashTable* named_params) ++int preprocess(const zend_string* sql, char* sql_out, size_t* sql_out_len, HashTable* named_params) + { + bool passAsIs = 1, execBlock = 0; + zend_long pindex = -1; +@@ -322,7 +322,7 @@ int preprocess(const zend_string* sql, char* sql_out, HashTable* named_params) + if (l > 252) { + return 0; + } +- strncpy(ident, i, l); ++ memcpy(ident, i, l); + ident[l] = '\0'; + if (!strcasecmp(ident, "EXECUTE")) + { +@@ -347,7 +347,7 @@ int preprocess(const zend_string* sql, char* sql_out, HashTable* named_params) + if (l > 252) { + return 0; + } +- strncpy(ident2, i2, l); ++ memcpy(ident2, i2, l); + ident2[l] = '\0'; + execBlock = !strcasecmp(ident2, "BLOCK"); + passAsIs = 0; +@@ -363,11 +363,15 @@ int preprocess(const zend_string* sql, char* sql_out, HashTable* named_params) + + if (passAsIs) + { +- strcpy(sql_out, ZSTR_VAL(sql)); ++ memcpy(sql_out, ZSTR_VAL(sql), ZSTR_LEN(sql)); ++ sql_out[ZSTR_LEN(sql)] = '\0'; ++ *sql_out_len = ZSTR_LEN(sql); + return 1; + } + +- strncat(sql_out, start, p - start); ++ char *sql_out_p = sql_out; ++ memcpy(sql_out_p, start, p - start); ++ sql_out_p += p - start; + + while (p < end) + { +@@ -375,10 +379,12 @@ int preprocess(const zend_string* sql, char* sql_out, HashTable* named_params) + tok = getToken(&p, end); + switch (tok) + { +- case ttParamMark: +- tok = getToken(&p, end); ++ case ttParamMark: { ++ const char* p_peek = p; ++ tok = getToken(&p_peek, end); + if (tok == ttIdent /*|| tok == ttString*/) + { ++ p = p_peek; + ++pindex; + l = p - start; + /* check the length of the identifier */ +@@ -387,7 +393,7 @@ int preprocess(const zend_string* sql, char* sql_out, HashTable* named_params) + if (l > 253) { + return 0; + } +- strncpy(pname, start, l); ++ memcpy(pname, start, l); + pname[l] = '\0'; + + if (named_params) { +@@ -396,7 +402,7 @@ int preprocess(const zend_string* sql, char* sql_out, HashTable* named_params) + zend_hash_str_update(named_params, pname, l, &tmp); + } + +- strcat(sql_out, "?"); ++ *sql_out_p++ = '?'; + } + else + { +@@ -406,10 +412,11 @@ int preprocess(const zend_string* sql, char* sql_out, HashTable* named_params) + return 0; + } + ++pindex; +- strncat(sql_out, start, p - start); ++ memcpy(sql_out_p, start, p - start); ++ sql_out_p += p - start; + } + break; +- ++ } + case ttIdent: + if (execBlock) + { +@@ -421,11 +428,14 @@ int preprocess(const zend_string* sql, char* sql_out, HashTable* named_params) + if (l > 252) { + return 0; + } +- strncpy(ident, start, l); ++ memcpy(ident, start, l); + ident[l] = '\0'; + if (!strcasecmp(ident, "AS")) + { +- strncat(sql_out, start, end - start); ++ memcpy(sql_out_p, start, end - start); ++ sql_out_p += end - start; ++ *sql_out_p = '\0'; ++ *sql_out_len = sql_out_p - sql_out; + return 1; + } + } +@@ -436,7 +446,8 @@ int preprocess(const zend_string* sql, char* sql_out, HashTable* named_params) + case ttComment: + case ttString: + case ttOther: +- strncat(sql_out, start, p - start); ++ memcpy(sql_out_p, start, p - start); ++ sql_out_p += p - start; + break; + + case ttBrokenComment: +@@ -454,6 +465,8 @@ int preprocess(const zend_string* sql, char* sql_out, HashTable* named_params) + break; + } + } ++ *sql_out_p = '\0'; ++ *sql_out_len = sql_out_p - sql_out; + return 1; + } + +@@ -663,7 +676,7 @@ free_statement: + static zend_string* firebird_handle_quoter(pdo_dbh_t *dbh, const zend_string *unquoted, enum pdo_param_type paramtype) + { + size_t qcount = 0; +- char const *co, *l, *r; ++ char const *co, *l; + char *c; + size_t quotedlen; + zend_string *quoted_str; +@@ -672,9 +685,15 @@ static zend_string* firebird_handle_quoter(pdo_dbh_t *dbh, const zend_string *un + return zend_string_init("''", 2, 0); + } + ++ const char * const end = ZSTR_VAL(unquoted) + ZSTR_LEN(unquoted); ++ + /* Firebird only requires single quotes to be doubled if string lengths are used */ + /* count the number of ' characters */ +- for (co = ZSTR_VAL(unquoted); (co = strchr(co,'\'')); qcount++, co++); ++ for (co = ZSTR_VAL(unquoted); co < end; co++) { ++ if (*co == '\'') { ++ qcount++; ++ } ++ } + + if (UNEXPECTED(ZSTR_LEN(unquoted) + 2 > ZSTR_MAX_LEN - qcount)) { + return NULL; +@@ -686,15 +705,14 @@ static zend_string* firebird_handle_quoter(pdo_dbh_t *dbh, const zend_string *un + *c++ = '\''; + + /* foreach (chunk that ends in a quote) */ +- for (l = ZSTR_VAL(unquoted); (r = strchr(l,'\'')); l = r+1) { +- strncpy(c, l, r-l+1); +- c += (r-l+1); +- /* add the second quote */ +- *c++ = '\''; ++ for (l = ZSTR_VAL(unquoted); l < end; l++) { ++ *c++ = *l; ++ if (*l == '\'') { ++ /* add the second quote */ ++ *c++ = '\''; ++ } + } + +- /* copy the remainder */ +- strncpy(c, l, quotedlen-(c-ZSTR_VAL(quoted_str))-1); + ZSTR_VAL(quoted_str)[quotedlen-1] = '\''; + ZSTR_VAL(quoted_str)[quotedlen] = '\0'; + +@@ -787,6 +805,7 @@ static int firebird_alloc_prepare_stmt(pdo_dbh_t *dbh, const zend_string *sql, + { + pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data; + char *new_sql; ++ size_t new_sql_len; + + /* Firebird allows SQL statements up to 64k, so bail if it doesn't fit */ + if (ZSTR_LEN(sql) > 65536) { +@@ -814,14 +833,14 @@ static int firebird_alloc_prepare_stmt(pdo_dbh_t *dbh, const zend_string *sql, + we need to replace :foo by ?, and store the name we just replaced */ + new_sql = emalloc(ZSTR_LEN(sql)+1); + new_sql[0] = '\0'; +- if (!preprocess(sql, new_sql, named_params)) { ++ if (!preprocess(sql, new_sql, &new_sql_len, named_params)) { + strcpy(dbh->error_code, "07000"); + efree(new_sql); + return 0; + } + + /* prepare the statement */ +- if (isc_dsql_prepare(H->isc_status, &H->tr, s, 0, new_sql, H->sql_dialect, out_sqlda)) { ++ if (isc_dsql_prepare(H->isc_status, &H->tr, s, new_sql_len, new_sql, H->sql_dialect, out_sqlda)) { + RECORD_ERROR(dbh); + efree(new_sql); + return 0; +diff --git a/ext/pdo_firebird/tests/ghsa-w476-322c-wpvm.phpt b/ext/pdo_firebird/tests/ghsa-w476-322c-wpvm.phpt +new file mode 100644 +index 00000000000..41c1125e9b9 +--- /dev/null ++++ b/ext/pdo_firebird/tests/ghsa-w476-322c-wpvm.phpt +@@ -0,0 +1,44 @@ ++--TEST-- ++GHSA-w476-322c-wpvm: SQL injection in pdo_firebird via NUL bytes in quoted strings ++--EXTENSIONS-- ++pdo_firebird ++--SKIPIF-- ++ ++--XLEAK-- ++A bug in firebird causes a memory leak when calling `isc_attach_database()`. ++See https://github.com/FirebirdSQL/firebird/issues/7849 ++--FILE-- ++exec('CREATE TABLE ghsa_w476_322c_wpvm (name VARCHAR(255))'); ++ ++$param = $dbh->quote("\0"); ++$param2 = $dbh->quote('or 1=1--'); ++var_export($param); ++echo("\n"); ++ ++echo "prepare: "; ++$stmt = $dbh->prepare("SELECT * FROM ghsa_w476_322c_wpvm WHERE name = {$param} AND name = {$param2}"); ++$stmt->execute(); ++echo json_encode($stmt->fetchAll(PDO::FETCH_ASSOC)) . "\n"; ++ ++echo "query: "; ++$stmt = $dbh->query("SELECT * FROM ghsa_w476_322c_wpvm WHERE name = {$param} AND name = {$param2}"); ++echo json_encode($stmt->fetchAll(PDO::FETCH_ASSOC)) . "\n"; ++ ++echo "exec: "; ++$affectedRows = $dbh->exec("UPDATE ghsa_w476_322c_wpvm SET name = 'updated' WHERE name = {$param} AND name = {$param2}"); ++echo $affectedRows . "\n"; ++?> ++--CLEAN-- ++exec("DROP TABLE ghsa_w476_322c_wpvm"); ++?> ++--EXPECT-- ++'\'' . "\0" . '\'' ++prepare: [] ++query: [] ++exec: 0 +-- +2.54.0 + diff --git a/php-cve-2026-6722.patch b/php-cve-2026-6722.patch new file mode 100644 index 0000000..3365479 --- /dev/null +++ b/php-cve-2026-6722.patch @@ -0,0 +1,107 @@ +From 15064460d6682766f91c1a841d27cdfbc38907e8 Mon Sep 17 00:00:00 2001 +From: Ilija Tovilo +Date: Sun, 3 May 2026 19:56:53 +0200 +Subject: [PATCH 01/10] GHSA-85c2-q967-79q5: [soap] Fix stale + SOAP_GLOBAL(ref_map) pointer with Apache Map + +Fixes GHSA-85c2-q967-79q5 +Fixes CVE-2026-6722 + +(cherry picked from commit aee3b3ac9b816b0def1c462695b483b49a83148e) +--- + ext/soap/php_encoding.c | 3 +- + ext/soap/tests/GHSA-85c2-q967-79q5.phpt | 61 +++++++++++++++++++++++++ + 2 files changed, 63 insertions(+), 1 deletion(-) + create mode 100644 ext/soap/tests/GHSA-85c2-q967-79q5.phpt + +diff --git a/ext/soap/php_encoding.c b/ext/soap/php_encoding.c +index 4d389a8c585..bf394f7ea92 100644 +--- a/ext/soap/php_encoding.c ++++ b/ext/soap/php_encoding.c +@@ -365,6 +365,7 @@ static bool soap_check_xml_ref(zval *data, xmlNodePtr node) + static void soap_add_xml_ref(zval *data, xmlNodePtr node) + { + if (SOAP_GLOBAL(ref_map)) { ++ Z_TRY_ADDREF_P(data); + zend_hash_index_update(SOAP_GLOBAL(ref_map), (zend_ulong)node, data); + } + } +@@ -3437,7 +3438,7 @@ void encode_reset_ns() + } else { + SOAP_GLOBAL(ref_map) = emalloc(sizeof(HashTable)); + } +- zend_hash_init(SOAP_GLOBAL(ref_map), 0, NULL, NULL, 0); ++ zend_hash_init(SOAP_GLOBAL(ref_map), 0, NULL, ZVAL_PTR_DTOR, 0); + } + + void encode_finish() +diff --git a/ext/soap/tests/GHSA-85c2-q967-79q5.phpt b/ext/soap/tests/GHSA-85c2-q967-79q5.phpt +new file mode 100644 +index 00000000000..8bcac26ad18 +--- /dev/null ++++ b/ext/soap/tests/GHSA-85c2-q967-79q5.phpt +@@ -0,0 +1,61 @@ ++--TEST-- ++GHSA-85c2-q967-79q5: Stale SOAP_GLOBAL(ref_map) pointer with Apache Map ++--CREDITS-- ++brettgervasoni ++--EXTENSIONS-- ++soap ++--FILE-- ++ ++ ++ ++ ++ ++ ++ ++ foo ++ bar ++ ++ ++ foo ++ baz ++ ++ ++ ++ ++ ++ ++XML; ++ ++$s = new SoapServer(null, ['uri' => 'urn:a']); ++$s->setClass(Handler::class); ++$s->handle($envelope); ++var_dump($result); ++ ++?> ++--EXPECTF-- ++ ++ ++array(2) { ++ [0]=> ++ array(1) { ++ ["foo"]=> ++ string(3) "baz" ++ } ++ [1]=> ++ object(stdClass)#%d (1) { ++ ["object"]=> ++ string(3) "bar" ++ } ++} +-- +2.54.0 + diff --git a/php-cve-2026-6735.patch b/php-cve-2026-6735.patch new file mode 100644 index 0000000..9f287dd --- /dev/null +++ b/php-cve-2026-6735.patch @@ -0,0 +1,144 @@ +From cc2960e782eb5cc262d7bd572a7d18979a811954 Mon Sep 17 00:00:00 2001 +From: Jakub Zelenka +Date: Sun, 3 May 2026 20:01:41 +0200 +Subject: [PATCH 04/10] GHSA-7qg2-v9fj-4mwv: [fpm] XSS within status endpoint + +Fixes GHSA-7qg2-v9fj-4mwv +Fixes CVE-2026-6735 + +(cherry picked from commit 99a5ad7441de9914246c7863adb6997396008b9d) +--- + sapi/fpm/fpm/fpm_status.c | 34 +++++++++++-- + .../tests/ghsa-7qg2-v9fj-4mwv-status-xss.phpt | 48 +++++++++++++++++++ + 2 files changed, 78 insertions(+), 4 deletions(-) + create mode 100644 sapi/fpm/tests/ghsa-7qg2-v9fj-4mwv-status-xss.phpt + +diff --git a/sapi/fpm/fpm/fpm_status.c b/sapi/fpm/fpm/fpm_status.c +index f698753cf4c..81292aa3bf8 100644 +--- a/sapi/fpm/fpm/fpm_status.c ++++ b/sapi/fpm/fpm/fpm_status.c +@@ -525,8 +525,8 @@ int fpm_status_handle_request(void) /* {{{ */ + if (full_syntax) { + unsigned int i; + int first; +- zend_string *tmp_query_string; +- char *query_string; ++ zend_string *tmp_query_string, *tmp_request_uri_string; ++ char *query_string, *request_uri_string; + struct timeval duration, now; + float cpu; + +@@ -551,13 +551,36 @@ int fpm_status_handle_request(void) /* {{{ */ + } + } + ++ request_uri_string = NULL; ++ tmp_request_uri_string = NULL; ++ if (proc->request_uri[0] != '\0') { ++ if (encode_html) { ++ tmp_request_uri_string = php_escape_html_entities_ex( ++ (const unsigned char *) proc->request_uri, ++ strlen(proc->request_uri), 1, ENT_DISALLOWED | ENT_HTML_DOC_XML1 | ENT_COMPAT, ++ NULL, /* double_encode */ 1, /* quiet */ 0); ++ request_uri_string = ZSTR_VAL(tmp_request_uri_string); ++ } else if (encode_json) { ++ tmp_request_uri_string = php_json_encode_string(proc->request_uri, ++ strlen(proc->request_uri), PHP_JSON_INVALID_UTF8_IGNORE); ++ request_uri_string = ZSTR_VAL(tmp_request_uri_string); ++ /* remove quotes around the string */ ++ if (ZSTR_LEN(tmp_request_uri_string) >= 2) { ++ request_uri_string[ZSTR_LEN(tmp_request_uri_string) - 1] = '\0'; ++ ++request_uri_string; ++ } ++ } else { ++ request_uri_string = proc->request_uri; ++ } ++ } ++ + query_string = NULL; + tmp_query_string = NULL; + if (proc->query_string[0] != '\0') { + if (encode_html) { + tmp_query_string = php_escape_html_entities_ex( + (const unsigned char *) proc->query_string, +- strlen(proc->query_string), 1, ENT_HTML_IGNORE_ERRORS & ENT_COMPAT, ++ strlen(proc->query_string), 1, ENT_DISALLOWED | ENT_HTML_DOC_XML1 | ENT_COMPAT, + NULL, /* double_encode */ 1, /* quiet */ 0); + } else if (encode_json) { + tmp_query_string = php_json_encode_string(proc->query_string, +@@ -596,7 +619,7 @@ int fpm_status_handle_request(void) /* {{{ */ + proc->requests, + duration.tv_sec * 1000000UL + duration.tv_usec, + proc->request_method[0] != '\0' ? proc->request_method : "-", +- proc->request_uri[0] != '\0' ? proc->request_uri : "-", ++ request_uri_string ? request_uri_string : "-", + query_string ? "?" : "", + query_string ? query_string : "", + proc->content_length, +@@ -607,6 +630,9 @@ int fpm_status_handle_request(void) /* {{{ */ + PUTS(buffer); + efree(buffer); + ++ if (tmp_request_uri_string) { ++ zend_string_free(tmp_request_uri_string); ++ } + if (tmp_query_string) { + zend_string_free(tmp_query_string); + } +diff --git a/sapi/fpm/tests/ghsa-7qg2-v9fj-4mwv-status-xss.phpt b/sapi/fpm/tests/ghsa-7qg2-v9fj-4mwv-status-xss.phpt +new file mode 100644 +index 00000000000..475bc130a42 +--- /dev/null ++++ b/sapi/fpm/tests/ghsa-7qg2-v9fj-4mwv-status-xss.phpt +@@ -0,0 +1,48 @@ ++--TEST-- ++FPM: GHSA-7qg2-v9fj-4mwv - status xss ++--SKIPIF-- ++ ++--FILE-- ++start(); ++$tester->expectLogStartNotices(); ++$responses = $tester ++ ->multiRequest([ ++ ['uri' => '/', 'query' => ''], ++ ['uri' => '/status', 'query' => 'full&html', 'delay' => 100000], ++ ]); ++var_dump(strpos($responses[1]->getBody(), '