Commit ffe75c98a22 for php

commit ffe75c98a22037b7c2836dc1c437a07e2beea20a
Author: Ilia Alshanetsky <ilia@ilia.ws>
Date:   Fri Sep 25 00:02:47 2026 -0400

    ext/pdo_firebird: Fix DPB stack overflow on long connection parameters

    slprintf() stores its terminating NUL within the size it is given, and the
    DPB is written from offset 1 of a 256-byte buffer with a size of 256, so a
    user name, password, charset, or role that filled the buffer wrote one byte
    past its end. A value longer than 255 bytes also had its one-byte length
    truncated. Reject such values with a PDOException before writing them.

    Closes GH-25292

diff --git a/NEWS b/NEWS
index a84629e1877..100a5cddcbe 100644
--- a/NEWS
+++ b/NEWS
@@ -43,6 +43,10 @@ PHP                                                                        NEWS
   . Fixed bug GH-25037 (Function JIT ENTRY live var assertion).
     (Ilia Alshanetsky)

+- PDO_Firebird:
+  . Fixed stack buffer overflow with long connection user names, passwords,
+    charsets, or roles. (Ilia Alshanetsky)
+
 - SOAP:
   . Fixed bug GH-25267 (NULL dereference in to_xml_any() with integer key).
     (lazerg)
diff --git a/ext/pdo_firebird/firebird_driver.c b/ext/pdo_firebird/firebird_driver.c
index e45a9108f72..7faace6ee5e 100644
--- a/ext/pdo_firebird/firebird_driver.c
+++ b/ext/pdo_firebird/firebird_driver.c
@@ -1376,7 +1376,6 @@ static int pdo_firebird_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /*
 		{ "password", NULL, 0 }
 	};
 	int i, ret = 0;
-	short buf_len = 256, dpb_len;

 	pdo_firebird_db_handle *H = dbh->driver_data = pecalloc(1,sizeof(*H),dbh->is_persistent);

@@ -1407,8 +1406,12 @@ static int pdo_firebird_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /*
 	do {
 		static char const dpb_flags[] = {
 			isc_dpb_user_name, isc_dpb_password, isc_dpb_lc_ctype, isc_dpb_sql_role_name };
+		static char const *const dpb_names[] = { "user", "password", "charset", "role" };
 		char const *dpb_values[] = { dbh->username, dbh->password, vars[1].optval, vars[2].optval };
 		char dpb_buffer[256] = { isc_dpb_version1 }, *dpb;
+		size_t buf_len = sizeof(dpb_buffer) - 1;
+		size_t dpb_value_len;
+		int dpb_len;

 		if (EG(exception)) {
 			break;
@@ -1418,14 +1421,26 @@ static int pdo_firebird_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /*

 		/* loop through all the provided arguments and set dpb fields accordingly */
 		for (i = 0; i < sizeof(dpb_flags); ++i) {
-			if (dpb_values[i] && buf_len > 0) {
-				dpb_len = slprintf(dpb, buf_len, "%c%c%s", dpb_flags[i], (unsigned char)strlen(dpb_values[i]),
+			if (dpb_values[i]) {
+				dpb_value_len = strlen(dpb_values[i]);
+				if (dpb_value_len + 2 >= buf_len) {
+					zend_throw_exception_ex(php_pdo_get_exception(), 0,
+						"Firebird database parameter \"%s\" is too long", dpb_names[i]);
+					break;
+				}
+				ZEND_ASSERT(dpb_value_len <= UCHAR_MAX);
+
+				dpb_len = slprintf(dpb, buf_len, "%c%c%s", dpb_flags[i], (unsigned char)dpb_value_len,
 					dpb_values[i]);
 				dpb += dpb_len;
 				buf_len -= dpb_len;
 			}
 		}

+		if (EG(exception)) {
+			break;
+		}
+
 		H->sql_dialect = PDO_FB_DIALECT;
 		if (vars[3].optval) {
 			H->sql_dialect = atoi(vars[3].optval);
diff --git a/ext/pdo_firebird/tests/dpb_overflow.phpt b/ext/pdo_firebird/tests/dpb_overflow.phpt
new file mode 100644
index 00000000000..27d1b3e5d15
--- /dev/null
+++ b/ext/pdo_firebird/tests/dpb_overflow.phpt
@@ -0,0 +1,27 @@
+--TEST--
+PDO_Firebird rejects values that overflow the database parameter buffer
+--EXTENSIONS--
+pdo_firebird
+--SKIPIF--
+<?php require('skipif.inc'); ?>
+--FILE--
+<?php
+require("testdb.inc");
+
+$tests = [
+    'one-byte length overflow' => [str_repeat('u', 256), PDO_FIREBIRD_TEST_PASS],
+    'DPB capacity overflow' => [str_repeat('u', 200), str_repeat('p', 52)],
+];
+
+foreach ($tests as $description => [$username, $password]) {
+    try {
+        new PDO(PDO_FIREBIRD_TEST_DSN, $username, $password);
+        echo "$description: accepted\n";
+    } catch (PDOException $e) {
+        echo "$description: ", $e::class, ": ", $e->getMessage(), "\n";
+    }
+}
+?>
+--EXPECT--
+one-byte length overflow: PDOException: Firebird database parameter "user" is too long
+DPB capacity overflow: PDOException: Firebird database parameter "password" is too long