Skip to content

Commit e00aab5

Browse files
committed
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.
1 parent a2011db commit e00aab5

3 files changed

Lines changed: 48 additions & 3 deletions

File tree

‎NEWS‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ PHP NEWS
2323
or never terminates). (Ilia Alshanetsky)
2424
. Fixed memory leak in JIT ASSIGN_DIM when the assignment fails. (Jorg Sowa)
2525

26+
- PDO_Firebird:
27+
. Fixed stack buffer overflow with long connection user names, passwords,
28+
charsets, or roles. (Ilia Alshanetsky)
29+
2630
- Streams:
2731
. Fixed bug GH-22063 (Stream filter chain UAF on self-removal during
2832
callback). (Ilia Alshanetsky)

‎ext/pdo_firebird/firebird_driver.c‎

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1376,7 +1376,6 @@ static int pdo_firebird_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /*
13761376
{ "password", NULL, 0 }
13771377
};
13781378
int i, ret = 0;
1379-
short buf_len = 256, dpb_len;
13801379

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

@@ -1409,6 +1408,9 @@ static int pdo_firebird_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /*
14091408
isc_dpb_user_name, isc_dpb_password, isc_dpb_lc_ctype, isc_dpb_sql_role_name };
14101409
char const *dpb_values[] = { dbh->username, dbh->password, vars[1].optval, vars[2].optval };
14111410
char dpb_buffer[256] = { isc_dpb_version1 }, *dpb;
1411+
size_t buf_len = sizeof(dpb_buffer) - 1;
1412+
size_t dpb_value_len;
1413+
int dpb_len;
14121414

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

14191421
/* loop through all the provided arguments and set dpb fields accordingly */
14201422
for (i = 0; i < sizeof(dpb_flags); ++i) {
1421-
if (dpb_values[i] && buf_len > 0) {
1422-
dpb_len = slprintf(dpb, buf_len, "%c%c%s", dpb_flags[i], (unsigned char)strlen(dpb_values[i]),
1423+
if (dpb_values[i]) {
1424+
dpb_value_len = strlen(dpb_values[i]);
1425+
if (dpb_value_len + 2 >= buf_len) {
1426+
zend_throw_exception_ex(php_pdo_get_exception(), 0,
1427+
"Firebird database parameter value is too long");
1428+
break;
1429+
}
1430+
ZEND_ASSERT(dpb_value_len <= UCHAR_MAX);
1431+
1432+
dpb_len = slprintf(dpb, buf_len, "%c%c%s", dpb_flags[i], (unsigned char)dpb_value_len,
14231433
dpb_values[i]);
14241434
dpb += dpb_len;
14251435
buf_len -= dpb_len;
14261436
}
14271437
}
14281438

1439+
if (EG(exception)) {
1440+
break;
1441+
}
1442+
14291443
H->sql_dialect = PDO_FB_DIALECT;
14301444
if (vars[3].optval) {
14311445
H->sql_dialect = atoi(vars[3].optval);
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
--TEST--
2+
PDO_Firebird rejects values that overflow the database parameter buffer
3+
--EXTENSIONS--
4+
pdo_firebird
5+
--SKIPIF--
6+
<?php require('skipif.inc'); ?>
7+
--FILE--
8+
<?php
9+
require("testdb.inc");
10+
11+
$tests = [
12+
'one-byte length overflow' => [str_repeat('u', 256), PDO_FIREBIRD_TEST_PASS],
13+
'DPB capacity overflow' => [str_repeat('u', 200), str_repeat('p', 52)],
14+
];
15+
16+
foreach ($tests as $description => [$username, $password]) {
17+
try {
18+
new PDO(PDO_FIREBIRD_TEST_DSN, $username, $password);
19+
echo "$description: accepted\n";
20+
} catch (PDOException $e) {
21+
echo "$description: ", $e::class, ": ", $e->getMessage(), "\n";
22+
}
23+
}
24+
?>
25+
--EXPECT--
26+
one-byte length overflow: PDOException: Firebird database parameter value is too long
27+
DPB capacity overflow: PDOException: Firebird database parameter value is too long

0 commit comments

Comments
 (0)