Skip to content

Prevent reentrant PDOStatement operations#22739

Open
iliaal wants to merge 1 commit into
php:masterfrom
iliaal:fix/pdo-stmt-reentrant-operations
Open

Prevent reentrant PDOStatement operations#22739
iliaal wants to merge 1 commit into
php:masterfrom
iliaal:fix/pdo-stmt-reentrant-operations

Conversation

@iliaal

@iliaal iliaal commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

PDO core runs userland PHP while holding or mutating a statement's live binding and fetch state (object parameter stringification, bound-value destructors, error/fetch/output handlers). That code can reenter the same statement's execute() or bind*() and free the hash or parameter the outer call is still using, a use-after-free in pure PDO core affecting every driver (confirmed on pdo_sqlite and pdo_odbc under debug+ASan, USE_ZEND_ALLOC=0). Minimal reproducer, UAF in really_register_bound_param:

class Reenter {
    public PDOStatement $s;
    public function __toString(): string {
        $this->s->execute([]);
        return "x";
    }
}

$pdo = new PDO('sqlite::memory:');
$stmt = $pdo->prepare('SELECT ?');
$r = new Reenter();
$r->s = $stmt;
$stmt->bindParam(1, $r);

A per-statement guard rejects reentry into any binding or fetch operation already in progress, throwing an Error; it holds across Fiber suspension and invalidates weak references before callback-capable teardown. The flag reuses a spare pdo_stmt_t reserved bit, so size and offsets are unchanged; since that edits the driver-facing header, master only.

Reject same-statement reentry while PDO traverses or mutates live binding
and fetch state. Keep the guard across Fiber suspension and invalidate weak
references before callback-capable statement teardown.
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