[GIT-PULLS] [php-src] PR #23337: Fix GH-23331: UAF when an attribute child keeps a live wrapper
[email protected] (iliaal)
| Newsgroups | php.git-pulls |
|---|---|
| Message-ID | <[email protected]> |
Pull Request: https://github.com/php/php-src/pull/23337 Author: iliaal node_list_unlink() abandoned an attribute's remaining children at two exits: xmlUnlinkNode() clears node->next, so the loop stopped at the first child that had a wrapper, and the XML_ENTITY_REF_NODE case broke out of the loop instead of only skipping the borrowed entity children. xmlSetProp(), xmlSetNsProp() and xmlFreeProp() then freed everything past either exit while a live wrapper still pointed at it. The #37456 recursion guard is kept: entity-reference children are still never walked. Every caller passes an attribute's or an element's child list rather than a DTD list, so continuing the sibling walk stays inside a finite content list. setAttribute(), setAttributeNS(), removeAttribute(), removeAttributeNode() and removeAttributeNS() all reach it, on both the legacy and the modern classes. The remove methods reach it only when the attribute itself carries no wrapper, where dom_remove_attribute() falls through to xmlFreeProp(); that case segfaults rather than reading freed memory. dom_remove_all_children() is unaffected because php_libxml_node_free_list() already caches the sibling before unlinking. The wrapper positions decide which exit fires rather than the caller, so gh23331.phpt pins the first and gh23331_2.phpt the second.