[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.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.