From 0ee0bae7c8bb85c8121f8c13da9338a8a91cbda8 Mon Sep 17 00:00:00 2001 From: Ilia Alshanetsky Date: Fri, 10 Jul 2026 08:32:15 -0400 Subject: [PATCH] Fix GH-22665: pdo_odbc OOB write on oversized diagnostic length pdo_odbc_error() writes the NUL terminator at einfo->last_err_msg[errmsgsize], where errmsgsize is the diagnostic length SQLGetDiagRec reports. On a truncated message (SQL_SUCCESS_WITH_INFO) the driver reports the full untruncated length, which can reach or exceed the 512-byte buffer, so the terminator lands out of bounds in the adjacent last_error field. Clamp the index to sizeof(last_err_msg) - 1; the size_t cast also folds a negative driver-reported length into the same guard. Fixes GH-22665 --- NEWS | 2 ++ ext/pdo_odbc/odbc_driver.c | 2 ++ ext/pdo_odbc/tests/gh22665.phpt | 30 ++++++++++++++++++++++++++++++ 3 files changed, 34 insertions(+) create mode 100644 ext/pdo_odbc/tests/gh22665.phpt diff --git a/NEWS b/NEWS index 7aada8213bb5..a813980b77b1 100644 --- a/NEWS +++ b/NEWS @@ -43,6 +43,8 @@ PHP NEWS - PDO_ODBC: . Fixed bug GH-20726 (Crash with ODBC connection pooling when the DSN carries no credentials). (iliaal) + . Fixed bug GH-22665 (Out-of-bounds write when the ODBC driver reports a + diagnostic message length beyond the error buffer). (iliaal) - Phar: . Fixed inconsistent handling of the magic ".phar" directory. Paths such as diff --git a/ext/pdo_odbc/odbc_driver.c b/ext/pdo_odbc/odbc_driver.c index 2cdac30223c0..3bb028ed6314 100644 --- a/ext/pdo_odbc/odbc_driver.c +++ b/ext/pdo_odbc/odbc_driver.c @@ -90,6 +90,8 @@ void pdo_odbc_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, PDO_ODBC_HSTMT statement, if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { errmsgsize = 0; + } else if ((size_t) errmsgsize >= sizeof(einfo->last_err_msg)) { + errmsgsize = sizeof(einfo->last_err_msg) - 1; } einfo->last_err_msg[errmsgsize] = '\0'; diff --git a/ext/pdo_odbc/tests/gh22665.phpt b/ext/pdo_odbc/tests/gh22665.phpt new file mode 100644 index 000000000000..aa3eaf914c93 --- /dev/null +++ b/ext/pdo_odbc/tests/gh22665.phpt @@ -0,0 +1,30 @@ +--TEST-- +GH-22665 (OOB write in pdo_odbc_error when the driver reports a long message) +--EXTENSIONS-- +pdo_odbc +--SKIPIF-- + +--FILE-- + PDO::ERRMODE_SILENT, +]); + +// A failing query with a long identifier makes the driver report a diagnostic +// message length >= the fixed last_err_msg buffer. The terminator write must +// stay inside the buffer. +$pdo->query('SELECT * FROM "' . str_repeat('A', 4096) . '"'); +$info = $pdo->errorInfo(); + +echo "sqlstate: ", $info[0], "\n"; +echo "done\n"; +?> +--EXPECT-- +sqlstate: HY000 +done