Skip to content

Fix GH-22060: UAF in class-autoloader dispatch on self-unregister#22085

Open
iliaal wants to merge 1 commit into
php:masterfrom
iliaal:fix/gh-22060-autoload-uaf
Open

Fix GH-22060: UAF in class-autoloader dispatch on self-unregister#22085
iliaal wants to merge 1 commit into
php:masterfrom
iliaal:fix/gh-22060-autoload-uaf

Conversation

@iliaal
Copy link
Copy Markdown
Contributor

@iliaal iliaal commented May 19, 2026

A method-bound autoloader registered as [$obj, 'load'] can call spl_autoload_unregister([$this, 'load']) from inside its own callback. The hash entry's destructor releases the last ref on the object, frees it, and the rest of the PHP body (e.g. echo $this->data) reads freed memory. The dispatch loop in zend_perform_class_autoload calls zend_call_known_fcc(func_info, ...), but zend_call_function reads fci_cache->object into EX(This) without bumping the refcount; the call convention is that the caller holds the ref, and here the only ref was the hash entry's.

Fix pins object and closure across the call with GC_ADDREF/OBJ_RELEASE. The pointers are saved locally before the call so the releases work even when func_info itself is freed mid-call by self-unregister.

zend_perform_class_autoload walked the autoloader hashtable and called
zend_call_known_fcc on each FCC without pinning its refcounted owners.
When the autoloader's PHP body called spl_autoload_unregister([$this,
'load']), the hash bucket destructor released the last ref on $this
and freed it mid-call; the subsequent $this->data read landed in
freed memory.

Pin object and closure manually around the call. Don't use
zend_fcc_dup/zend_fcc_dtor: zend_fcc_dtor frees trampoline storage
based on ZEND_ACC_CALL_VIA_TRAMPOLINE, which would double-free the
hash entry's trampoline copy for __call-based autoloaders.

Fixes phpGH-22060
Copy link
Copy Markdown
Member

@Girgias Girgias left a comment

Choose a reason for hiding this comment

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

So this is the exact problem that #22126 has.

I would appreciate that rather just asking an LLM to do fixes at calls sites randomly to instead use the human capability of critical thinking to actually reason and understand the underlying issue, and determining that the root cause of the problem is within the API.

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.

2 participants