diff --git a/NEWS b/NEWS index 7aada8213bb5..481bef902d30 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-22667 (Heap buffer over-read when a column value exceeds the + driver-reported display size). (iliaal) - Phar: . Fixed inconsistent handling of the magic ".phar" directory. Paths such as diff --git a/ext/pdo_odbc/odbc_stmt.c b/ext/pdo_odbc/odbc_stmt.c index c114f721a7a7..5b9104895854 100644 --- a/ext/pdo_odbc/odbc_stmt.c +++ b/ext/pdo_odbc/odbc_stmt.c @@ -744,7 +744,14 @@ static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, zval *result, enum pdo return 1; } else if (C->fetched_len >= 0) { /* it was stored perfectly */ - ZVAL_STRINGL_FAST(result, C->data, C->fetched_len); + SQLLEN data_len = C->fetched_len; + if (!C->is_long) { + SQLLEN max_len = C->is_unicode ? (SQLLEN)C->datalen + 1 : (SQLLEN)C->datalen; + if (data_len > max_len) { + data_len = max_len; + } + } + ZVAL_STRINGL_FAST(result, C->data, data_len); if (C->is_unicode) { goto unicode_conv; } diff --git a/ext/pdo_odbc/tests/gh22667.phpt b/ext/pdo_odbc/tests/gh22667.phpt new file mode 100644 index 000000000000..4d7c8b7b03f3 --- /dev/null +++ b/ext/pdo_odbc/tests/gh22667.phpt @@ -0,0 +1,30 @@ +--TEST-- +GH-22667 (Heap buffer over-read when a column value exceeds the bound buffer) +--EXTENSIONS-- +pdo_odbc +--SKIPIF-- + +--FILE-- +query("SELECT printf('%.*c', 4096, 'A') AS data"); +$row = $stmt->fetch(PDO::FETCH_ASSOC); +$s = $row['data']; + +echo "clamped to buffer: "; var_dump(strlen($s) < 4096); +echo "only value bytes: "; var_dump(strlen($s) === substr_count($s, 'A')); +?> +--EXPECT-- +clamped to buffer: bool(true) +only value bytes: bool(true)