Skip to content

Commit 4eced77

Browse files
committed
Merge branch 'PHP-8.4' into PHP-8.5
* PHP-8.4: Fix GH-22667: pdo_odbc heap over-read on oversized column value
2 parents 1b2c0ab + 103c84f commit 4eced77

4 files changed

Lines changed: 45 additions & 1 deletion

File tree

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ PHP NEWS
6666
- PDO_ODBC:
6767
. Fixed bug GH-20726 (Crash with ODBC connection pooling when the DSN
6868
carries no credentials). (iliaal)
69+
. Fixed bug GH-22667 (Heap buffer over-read when a column value exceeds the
70+
driver-reported display size). (iliaal)
6971

7072
- Phar:
7173
. Fixed inconsistent handling of the magic ".phar" directory. Paths such as

ext/pdo_odbc/odbc_stmt.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -763,7 +763,14 @@ static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, zval *result, enum pdo
763763
return 1;
764764
} else if (C->fetched_len >= 0) {
765765
/* it was stored perfectly */
766-
ZVAL_STRINGL_FAST(result, C->data, C->fetched_len);
766+
SQLLEN data_len = C->fetched_len;
767+
if (!C->is_long) {
768+
SQLLEN max_len = C->is_unicode ? (SQLLEN)C->datalen + 1 : (SQLLEN)C->datalen;
769+
if (data_len > max_len) {
770+
data_len = max_len;
771+
}
772+
}
773+
ZVAL_STRINGL_FAST(result, C->data, data_len);
767774
if (C->is_unicode) {
768775
goto unicode_conv;
769776
}

ext/pdo_odbc/tests/config.inc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<?php
2+
3+
const PDO_ODBC_SQLITE_DSN = "odbc:Driver=SQLite3;Database=:memory:";

ext/pdo_odbc/tests/gh22667.phpt

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
--TEST--
2+
GH-22667 (Heap buffer over-read when a column value exceeds the bound buffer)
3+
--EXTENSIONS--
4+
pdo_odbc
5+
--SKIPIF--
6+
<?php
7+
require __DIR__ . '/config.inc';
8+
try {
9+
$pdo = new PDO(PDO_ODBC_SQLITE_DSN);
10+
} catch (PDOException $e) {
11+
die("skip requires the SQLite3 ODBC driver");
12+
}
13+
?>
14+
--FILE--
15+
<?php
16+
require __DIR__ . '/config.inc';
17+
$pdo = new PDO(PDO_ODBC_SQLITE_DSN);
18+
19+
// The SQLite3 driver reports a 255 byte display size for a computed column, so
20+
// the short-bound buffer holds at most 255 bytes while the value is far longer.
21+
// A conforming driver truncates into the buffer but reports the full length; the
22+
// returned string must stay within the buffer, not over-read past it.
23+
$stmt = $pdo->query("SELECT printf('%.*c', 4096, 'A') AS data");
24+
$row = $stmt->fetch(PDO::FETCH_ASSOC);
25+
$s = $row['data'];
26+
27+
echo "clamped to buffer: "; var_dump(strlen($s) < 4096);
28+
echo "only value bytes: "; var_dump(strlen($s) === substr_count($s, 'A'));
29+
?>
30+
--EXPECT--
31+
clamped to buffer: bool(true)
32+
only value bytes: bool(true)

0 commit comments

Comments
 (0)