public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
From: Remi Collet <remi@fedoraproject.org>
To: git-commits@fedoraproject.org
Subject: [rpms/php-extras] epel9: Fix SQL injection via NUL bytes in quoted strings
Date: Wed, 03 Jun 2026 09:44:58 GMT	[thread overview]
Message-ID: <178047989855.1.13406939322719484290.rpms-php-extras-fe822628da71@fedoraproject.org> (raw)

          A new commit has been pushed.

          Repo   : rpms/php-extras
          Branch : epel9
          Commit : fe822628da71c5bb9f76b7d34b18b755d48178b9
          Author : Remi Collet <remi@fedoraproject.org>
          Date   : 2026-06-03T11:44:51+02:00
          Stats  : +279/-1 in 2 file(s)
          URL    : https://src.fedoraproject.org/rpms/php-extras/c/fe822628da71c5bb9f76b7d34b18b755d48178b9?branch=epel9

          Log:
          Fix SQL injection via NUL bytes in quoted strings

CVE-2025-14179

---
diff --git a/php-cve-2025-14179.patch b/php-cve-2025-14179.patch
new file mode 100644
index 0000000..d51aeb4
--- /dev/null
+++ b/php-cve-2025-14179.patch
@@ -0,0 +1,272 @@
+From abf5a10618537332f63194f2cf72b019c592029c Mon Sep 17 00:00:00 2001
+From: Saki Takamachi <saki@sakiot.com>
+Date: Sun, 3 May 2026 19:56:30 +0200
+Subject: [PATCH] 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)
+(cherry picked from commit 4b0dd469bbba7bf5f25f1a4f694aeb15c3515be4)
+---
+ ext/pdo_firebird/firebird_driver.c            | 68 ++++++++++++-------
+ .../tests/ghsa-w476-322c-wpvm.phpt            | 44 ++++++++++++
+ 2 files changed, 88 insertions(+), 24 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 fb69797850..06a33651d7 100644
+--- a/ext/pdo_firebird/firebird_driver.c
++++ b/ext/pdo_firebird/firebird_driver.c
+@@ -290,7 +290,7 @@ static FbTokenType getToken(const char** begin, const char* end)
+ 	return ret;
+ }
+ 
+-int preprocess(const char* sql, int sql_len, char* sql_out, HashTable* named_params)
++int preprocess(const char* sql, int sql_len, char* sql_out, size_t* sql_out_len, HashTable* named_params)
+ {
+ 	zend_bool passAsIs = 1, execBlock = 0;
+ 	zend_long pindex = -1;
+@@ -321,7 +321,7 @@ int preprocess(const char* sql, int sql_len, char* sql_out, HashTable* named_par
+ 	if (l > 252) {
+ 		return 0;
+ 	}
+-	strncpy(ident, i, l);
++	memcpy(ident, i, l);
+ 	ident[l] = '\0';
+ 	if (!strcasecmp(ident, "EXECUTE"))
+ 	{
+@@ -346,7 +346,7 @@ int preprocess(const char* sql, int sql_len, char* sql_out, HashTable* named_par
+ 		if (l > 252) {
+ 			return 0;
+ 		}
+-		strncpy(ident2, i2, l);
++		memcpy(ident2, i2, l);
+ 		ident2[l] = '\0';
+ 		execBlock = !strcasecmp(ident2, "BLOCK");
+ 		passAsIs = 0;
+@@ -362,11 +362,15 @@ int preprocess(const char* sql, int sql_len, char* sql_out, HashTable* named_par
+ 
+ 	if (passAsIs)
+ 	{
+-		strcpy(sql_out, sql);
++		memcpy(sql_out, sql, sql_len);
++		sql_out[sql_len] = '\0';
++		*sql_out_len = sql_len;
+ 		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)
+ 	{
+@@ -374,10 +378,12 @@ int preprocess(const char* sql, int sql_len, char* sql_out, HashTable* named_par
+ 		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 */
+@@ -386,7 +392,7 @@ int preprocess(const char* sql, int sql_len, char* sql_out, HashTable* named_par
+ 				if (l > 253) {
+ 					return 0;
+ 				}
+-				strncpy(pname, start, l);
++				memcpy(pname, start, l);
+ 				pname[l] = '\0';
+ 				
+ 				if (named_params) {
+@@ -395,7 +401,7 @@ int preprocess(const char* sql, int sql_len, char* sql_out, HashTable* named_par
+ 					zend_hash_str_update(named_params, pname, l, &tmp);
+ 				}
+ 
+-				strcat(sql_out, "?");
++				*sql_out_p++ = '?';
+ 			}
+ 			else
+ 			{
+@@ -405,10 +411,11 @@ int preprocess(const char* sql, int sql_len, char* sql_out, HashTable* named_par
+ 					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)
+ 			{
+@@ -420,11 +427,14 @@ int preprocess(const char* sql, int sql_len, char* sql_out, HashTable* named_par
+ 				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;
+ 				}
+ 			}
+@@ -433,7 +443,8 @@ int preprocess(const char* sql, int sql_len, char* sql_out, HashTable* named_par
+ 		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:
+@@ -451,6 +462,8 @@ int preprocess(const char* sql, int sql_len, char* sql_out, HashTable* named_par
+ 			break;
+ 		}
+ 	}
++	*sql_out_p = '\0';
++	*sql_out_len = sql_out_p - sql_out;
+ 	return 1;
+ }
+ 
+@@ -664,7 +677,7 @@ static int firebird_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, size_t u
+ 	char **quoted, size_t *quotedlen, enum pdo_param_type paramtype)
+ {
+ 	size_t qcount = 0;
+-	char const *co, *l, *r;
++	char const *co, *l;
+ 	char *c;
+ 
+ 	if (!unquotedlen) {
+@@ -674,9 +687,15 @@ static int firebird_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, size_t u
+ 		return 1;
+ 	}
+ 
++	const char * const end = unquoted + unquotedlen;
++
+ 	/* Firebird only requires single quotes to be doubled if string lengths are used */
+ 	/* count the number of ' characters */
+-	for (co = unquoted; (co = strchr(co,'\'')); qcount++, co++);
++	for (co = unquoted; co < end; co++) {
++		if (*co == '\'') {
++			qcount++;
++		}
++	}
+ 
+ 	if (UNEXPECTED(unquotedlen + 2 > ZSTR_MAX_LEN - qcount)) {
+ 		return 0;
+@@ -687,15 +706,15 @@ static int firebird_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, size_t u
+ 	*c++ = '\'';
+ 
+ 	/* foreach (chunk that ends in a quote) */
+-	for (l = unquoted; (r = strchr(l,'\'')); l = r+1) {
+-		strncpy(c, l, r-l+1);
+-		c += (r-l+1);
+-		/* add the second quote */
+-		*c++ = '\'';
++	for (l = unquoted; l < end; l++) {
++		*c++ = *l;
++		if (*l == '\'') {
++			/* add the second quote */
++			*c++ = '\'';
++		}
+ 	}
+ 
+ 	/* copy the remainder */
+-	strncpy(c, l, *quotedlen-(c-*quoted)-1);
+ 	(*quoted)[*quotedlen-1] = '\'';
+ 	(*quoted)[*quotedlen]   = '\0';
+ 
+@@ -788,6 +807,7 @@ static int firebird_alloc_prepare_stmt(pdo_dbh_t *dbh, const char *sql, size_t s
+ {
+ 	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 (sql_len > 65536) {
+@@ -815,14 +835,14 @@ static int firebird_alloc_prepare_stmt(pdo_dbh_t *dbh, const char *sql, size_t s
+ 	   we need to replace :foo by ?, and store the name we just replaced */
+ 	new_sql = emalloc(sql_len+1);
+ 	new_sql[0] = '\0';
+-	if (!preprocess(sql, sql_len, new_sql, named_params)) {
++	if (!preprocess(sql, sql_len, 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 0000000000..41c1125e9b
+--- /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

diff --git a/php-extras.spec b/php-extras.spec
index 06a1988..720aa28 100644
--- a/php-extras.spec
+++ b/php-extras.spec
@@ -13,13 +13,14 @@
 Name:       php-extras
 Summary:    Additional PHP extensions from the standard PHP distribution
 Version:    8.0.30
-Release:    2%{?dist}
+Release:    3%{?dist}
 License:    PHP
 URL:        https://www.php.net/
 Source0:    https://www.php.net/distributions/php-%{version}.tar.xz
 
 # Security patches
 Patch100:   php-cve-2024-11236.patch
+Patch101:   php-cve-2025-14179.patch
 
 BuildRequires: (php-devel >= 8.0 with php-devel < 8.1)
 BuildRequires:  php-pdo
@@ -140,6 +141,7 @@ low-level PHP extension for the libsodium cryptographic library.
 %setup -q -n php-%{version}
 
 %patch -P100 -p1 -b .cve11236
+%patch -P101 -p1 -b .cve14179
 
 
 %build
@@ -310,6 +312,10 @@ done
 %endif
 
 %changelog
+* Wed Jun  3 2026 Remi Collet <rcollet@redhat.com> - 8.0.30-3
+- Fix SQL injection via NUL bytes in quoted strings
+  CVE-2025-14179
+
 * Fri Nov 29 2024 Remi Collet <rcollet@redhat.com> - 8.0.30-2
 - Fix Integer overflow in the dblib/firebird quoter causing OOB writes
   CVE-2024-11236

                 reply	other threads:[~2026-06-03  9:44 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=178047989855.1.13406939322719484290.rpms-php-extras-fe822628da71@fedoraproject.org \
    --to=remi@fedoraproject.org \
    --cc=git-commits@fedoraproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox