Skip to content

Fix use-after-free serializing an array grown by an element's hook#158

Closed
iliaal wants to merge 1 commit into
PHP-8.4from
fix-serialize-array-ref-uaf
Closed

Fix use-after-free serializing an array grown by an element's hook#158
iliaal wants to merge 1 commit into
PHP-8.4from
fix-serialize-array-ref-uaf

Conversation

@iliaal

@iliaal iliaal commented Jul 13, 2026

Copy link
Copy Markdown
Owner

The IS_ARRAY case of serialize() walks the array's HashTable without holding a reference while it recurses into user hooks, so a __serialize() (or __sleep(), or Serializable::serialize()) that grows the same array through a by-reference alias reallocs the backing store mid-walk and the walk then reads freed memory. The object case and var_dump/var_export already hold a ref across the walk; this adds the same for arrays. Triggering it needs an attacker-defined mutating hook, so it is an ordinary memory-safety bug, not a security issue. The test is an ASan/valgrind canary: a normal build usually reads the freed memory and passes.

Reproducer (invalid read in php_var_serialize_nested_data under ASan/valgrind):

<?php
class G {
    public $ref;
    public function __serialize(): array {
        for ($i = 0; $i < 128; $i++) $this->ref[] = 'x' . $i;
        return ['d' => 1];
    }
}
$g = new G();
$inner = [$g, 'tail'];
$g->ref = &$inner;
$top = [&$inner];
serialize($top);

The IS_ARRAY case of php_var_serialize_intern() walked the array's
HashTable without holding a reference across
php_var_serialize_nested_data(), which recurses into user hooks
(__serialize, __sleep, Serializable::serialize). A hook that grows the
same array through a by-reference alias reallocs the backing store
mid-walk, so the iterator reads freed memory. Hold a ref across the walk,
as the object path and var_dump/var_export already do, so the append
separates a copy instead of reallocating in place.
@iliaal

iliaal commented Jul 13, 2026

Copy link
Copy Markdown
Owner Author

Superseded by php#22714.

@iliaal iliaal closed this Jul 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant