[php-src] PR #24546: var_destroy(): hold serialize_lock around deferred destructor pass

From: Date: Thu, 22 Oct 2026 15:13:15 +0000
Subject: [php-src] PR #24546: var_destroy(): hold serialize_lock around deferred destructor pass
Groups: php.git-pulls 
Request: Send a blank email to git-pulls+get-39710@lists.php.net to get a copy of this message
Pull Request: https://github.com/php/php-src/pull/24546 Author: omaraltamimi1 Reported in GH-24481 (ASAN traces, gdb capture and PoCs attached there). Master already contains the php_var_unserialize_init() context-isolation part of the fix; the destructor path was still open. ## Problem var_destroy() frees the var_entries chain first, then runs the deferred __wakeup()/destructor pass **without** holding BG(serialize_lock). A destructor reached from that pass that calls unserialize() takes the else branch of php_var_unserialize_init() (lock not held, BG(unserialize).level still 1) and receives the very context whose chunks were just efree()d. The nested var_push() then reads used_slots from freed memory and writes zval pointers into the freed chunk (ASAN: heap-use-after-free read at var_unserializer.c:906, write at :143); with a groomed chunk the write index comes from attacker-controlled bytes. Observable without any crash: a crafted 1017-element payload silently returns ARRAY(1016) on an unpatched build - element loss caused by the corrupted slot count. ## Fix Hold BG(serialize_lock) around i_zval_ptr_dtor() in var_destroy(), so a re-entering unserialize() cannot reuse the chain being destroyed. ## Validation php-8.5.12 ASAN build with this change (plus the init isolation master already has): the three PoCs posted in GH-24481 run clean (exit 0, no ASAN report) and return correct array counts; the unpatched build reports heap-use-after-free (read + write).

« previous php.git-pulls (#39710) next »