Fix GH-22060 and GH-22122: pin $this in zend_call_known_fcc#22151
Fix GH-22060 and GH-22122: pin $this in zend_call_known_fcc#22151iliaal wants to merge 1 commit into
Conversation
DanielEScherzer
left a comment
There was a problem hiding this comment.
okay for ext/reflection, don't know about the other parts
Girgias
left a comment
There was a problem hiding this comment.
I was trying to understand why we would need to add ref the fcc.object, and my understanding is that it represents the $this value, so I guess this is valid.
However, we are once again fixing bugs and affecting performance for idiosyncratic code. I would rather prefer a solution that bans unsetting such callables within the calls. Similar to a fix we recently did for an unserialising routine in SPL.
|
Pinning is two refcount ops against a full call-frame setup, so the per-call cost is negligible. Banning is the bigger change: the autoload loop is deliberately built to allow add/remove mid-iteration, and disabling the authorizer mid-call is a one-shot the sqlite3 test relies on. Turning either into a thrown error is a behavior change that can't go in a stable branch. If the stricter semantics are worth having, that's a master-only follow-up. |
Such things will come up more and more with the raise of AI. A while ago when fixing a similar issue, @TimWolla asked me if This should target master anyway (we agreed to not fixing such bugs on stable branches that are unlikely to cause issues in the real world). So maybe let's just go with the above instead. |
02a264f to
7720c11
Compare
7720c11 to
497f3fa
Compare
497f3fa to
502eb4b
Compare
|
First part's done: On removing the add/delref throughout the codebase: most of them can't go. The pin is released when the call returns, so it only guarantees |
zend_call_known_fcc() ran the callback with fcc->object as $this without holding a reference, so a callback that released the last reference to its own receiver (an autoloader unregistering itself, a SQLite3 authorizer calling setAuthorizer(null)) freed $this while its frame was still executing. Hold a reference across the call. Fixes phpGH-22060 Fixes phpGH-22122
502eb4b to
a85e9ba
Compare
Both reports are the same use-after-free:
zend_call_known_fcc()ran the callback withfcc->objectas$thiswithout holding a reference, so a callback that released the last reference to its own receiver (autoloader self-unregistering, SQLite3 authorizer callingsetAuthorizer(null)) freed it mid-call. Pinning the receiver across the call covers the autoloader and the sqlite3/pdo_sqlite authorizers, which all dispatch through it.