summaryrefslogtreecommitdiffstats
path: root/php-cve-2026-14179.patch
diff options
context:
space:
mode:
authorRemi Collet <remi@remirepo.net>2026-05-07 10:15:48 +0200
committerRemi Collet <remi@php.net>2026-05-07 10:15:48 +0200
commit544e29f1e739eb8ab335c130788d46161141d338 (patch)
treeffdbfd2c6808eb9483c1c8e669714a30b691e7a6 /php-cve-2026-14179.patch
parent77305ec39e7214bd36a29a98dffa6f1a74ec343f (diff)
Fix XSS within status endpointHEADmaster
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
Diffstat (limited to 'php-cve-2026-14179.patch')
-rw-r--r--php-cve-2026-14179.patch274
1 files changed, 274 insertions, 0 deletions
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 <saki@sakiot.com>
+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--
++<?php require('skipif.inc'); ?>
++--XLEAK--
++A bug in firebird causes a memory leak when calling `isc_attach_database()`.
++See https://github.com/FirebirdSQL/firebird/issues/7849
++--FILE--
++<?php
++
++require("testdb.inc");
++
++$dbh->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--
++<?php
++require 'testdb.inc';
++$dbh->exec("DROP TABLE ghsa_w476_322c_wpvm");
++?>
++--EXPECT--
++'\'' . "\0" . '\''
++prepare: []
++query: []
++exec: 0
+--
+2.54.0
+