Skip to content

Fix use-after-free during lazy object initialization#22401

Open
iliaal wants to merge 1 commit into
php:PHP-8.4from
iliaal:fix/gh-22399-lazy-revert-double-free
Open

Fix use-after-free during lazy object initialization#22401
iliaal wants to merge 1 commit into
php:PHP-8.4from
iliaal:fix/gh-22399-lazy-revert-double-free

Conversation

@iliaal

@iliaal iliaal commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Lazy object initialization destroyed property values while the slot or the dynamic-properties HashTable still aliased them, so a value whose __destruct reaches back through a reference cycle (unset($this->obj->prop)) double-freed it, a UAF in zend_objects_store_del. The fix clears the slot and detaches the properties table before dropping the refcount, across all four destruction sites in zend_lazy_object_revert_init and zend_lazy_object_init_proxy (declared and dynamic properties, ghost revert and proxy cleanup); verified under ASAN.

Fixes GH-22399

@morrisonlevi morrisonlevi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't really comment about the fix but here's one small thing I did notice.

Comment thread Zend/zend_lazy_objects.c Outdated
zval garbage;
ZVAL_COPY_VALUE(&garbage, p);
ZVAL_UNDEF(p);
i_zval_ptr_dtor(&garbage);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

zend_lazy_object_revert_init is entirely off the hot path, right? I think zval_ptr_dtor would be more appropriate to avoid excess code size?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, switched both new dtors to zval_ptr_dtor.

zend_lazy_object_revert_init() and zend_lazy_object_init_proxy() dropped a
property value's refcount while the slot or dynamic-properties table still
aliased it, so a value whose destructor reaches back through a reference
cycle (unset($this->obj->prop)) freed it twice. Clear the slot and detach
the properties table before dropping the refcount.

Fixes phpGH-22399
@iliaal iliaal force-pushed the fix/gh-22399-lazy-revert-double-free branch from d924213 to 7a36177 Compare June 23, 2026 22:26
@iliaal iliaal requested a review from morrisonlevi June 24, 2026 11:55
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.

Lazy object revert init with object destructor can lead to double free

2 participants