From b218c578c405d584b0e4c2f040f39d28485bc0a1 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 | 35 +++++++++++++++++++++++++++++++++ 3 files changed, 39 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..587dd22e4a5a --- /dev/null +++ b/ext/pdo_odbc/tests/gh22665.phpt @@ -0,0 +1,35 @@ +--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"; + +@unlink($file); +?> +--EXPECT-- +sqlstate: HY000 +done