Skip to content

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

Closed
iliaal wants to merge 1 commit into
masterfrom
fix/gh-22060-autoload-uaf
Closed

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

Conversation

@iliaal
Copy link
Copy Markdown
Owner

@iliaal iliaal commented May 18, 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
@iliaal
Copy link
Copy Markdown
Owner Author

iliaal commented May 19, 2026

Superseded by upstream PR php#22085.

@iliaal iliaal closed this May 19, 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