Skip to content

Fix pdo_odbc output-buffer leak and stale-binding out-of-bounds read#22735

Open
iliaal wants to merge 1 commit into
php:PHP-8.4from
iliaal:fix/pdo-odbc-param-lifecycle
Open

Fix pdo_odbc output-buffer leak and stale-binding out-of-bounds read#22735
iliaal wants to merge 1 commit into
php:PHP-8.4from
iliaal:fix/pdo-odbc-param-lifecycle

Conversation

@iliaal

@iliaal iliaal commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

pdo_odbc bound each parameter with SQLBindParameter at PDO_PARAM_EVT_ALLOC, recording deferred pointers (P->outbuf for output, &P->len, and the bound-parameter struct itself for input) into the ODBC statement, and never freed P->outbuf. Both outlive the bound-parameter struct, which PDO destroys mid-statement when execute() is given an array or a position is rebound, so the output buffer leaked and the stale binding made the next SQLExecute read freed memory. This tracks the output buffers on the statement and frees them in the destructor after SQLFreeHandle, and defers SQLBindParameter to execute time, rebinding the current parameters when the parameter set has changed.

Reproducers, both under a debug or ASAN build:

// out-of-bounds read (freed length indicator drives a wild over-read)
$stmt = $pdo->prepare('SELECT ? AS v');
$v = 'x';
$stmt->bindParam(1, $v, PDO::PARAM_STR | PDO::PARAM_INPUT_OUTPUT, 256);
$stmt->execute([]);

// leak of the output buffer
$stmt = $pdo->prepare('SELECT ? AS v');
$stmt->bindParam(1, $v, PDO::PARAM_STR | PDO::PARAM_INPUT_OUTPUT, 256);
$stmt->execute();

SQLBindParameter recorded deferred pointers (P->outbuf, &P->len, and the
bound-parameter struct) into the ODBC statement at PDO_PARAM_EVT_ALLOC, and
P->outbuf was never freed. Both outlive the bound-parameter struct, which
PDO destroys mid-statement on execute() with an array or a rebind: the
buffer leaked and the stale binding made the next SQLExecute read freed
memory. Track output buffers on the statement and free them in the
destructor, and defer binding to execute time, resetting and rebinding the
current parameters when the set changed.

Closes phpGH-22735
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant