Skip to content

Commit 22bf64b

Browse files
committed
ext/dom: use-after-free via DOMNameSpaceNode after DOMDocument::xinclude().
Fix #22624
1 parent 01c4124 commit 22bf64b

2 files changed

Lines changed: 58 additions & 2 deletions

File tree

ext/dom/node.c

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -245,11 +245,21 @@ zend_result dom_node_node_type_read(dom_object *obj, zval *retval)
245245

246246
/* }}} */
247247

248+
static xmlNodePtr dom_node_get_parent(dom_object *obj, xmlNodePtr nodep)
249+
{
250+
if (nodep->type == XML_NAMESPACE_DECL) {
251+
dom_object_namespace_node *ns = php_dom_namespace_node_obj_from_obj(&obj->std);
252+
return ns->parent_intern ? dom_object_get_node(ns->parent_intern) : NULL;
253+
}
254+
return nodep->parent;
255+
}
256+
257+
248258
static zend_result dom_node_parent_get(dom_object *obj, zval *retval, bool only_element)
249259
{
250260
DOM_PROP_NODE(xmlNodePtr, nodep, obj);
251261

252-
xmlNodePtr nodeparent = nodep->parent;
262+
xmlNodePtr nodeparent = dom_node_get_parent(obj, nodep);
253263
if (!nodeparent || (only_element && nodeparent->type != XML_ELEMENT_NODE)) {
254264
ZVAL_NULL(retval);
255265
return SUCCESS;
@@ -457,7 +467,12 @@ URL: https://dom.spec.whatwg.org/#dom-node-isconnected
457467
zend_result dom_node_is_connected_read(dom_object *obj, zval *retval)
458468
{
459469
DOM_PROP_NODE(xmlNodePtr, nodep, obj);
460-
ZVAL_BOOL(retval, php_dom_is_node_connected(nodep));
470+
if (nodep->type == XML_NAMESPACE_DECL) {
471+
xmlNodePtr parent = dom_node_get_parent(obj, nodep);
472+
ZVAL_BOOL(retval, parent && php_dom_is_node_connected(parent));
473+
} else {
474+
ZVAL_BOOL(retval, php_dom_is_node_connected(nodep));
475+
}
461476
return SUCCESS;
462477
}
463478
/* }}} */

ext/dom/tests/gh22624.phpt

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
--TEST--
2+
GH-22624 (Use-after-free via DOMNameSpaceNode after DOMDocument::xinclude())
3+
--CREDITS--
4+
ExPatch-LLC
5+
--EXTENSIONS--
6+
dom
7+
--SKIPIF--
8+
<?php
9+
if (!function_exists('libxml_set_external_entity_loader')) die('skip xinclude not available');
10+
?>
11+
--FILE--
12+
<?php
13+
$included = __DIR__ . '/gh22624_included.xml';
14+
file_put_contents($included, '<?xml version="1.0"?><included/>');
15+
$href = 'file:///' . ltrim(str_replace('\\', '/', $included), '/');
16+
17+
$doc = new DOMDocument();
18+
$doc->loadXML('<?xml version="1.0"?>
19+
<root xmlns:xi="http://www.w3.org/2001/XInclude">
20+
<xi:include href="' . $href . '" xmlns:local="urn:test"/>
21+
</root>');
22+
23+
$xpath = new DOMXPath($doc);
24+
$xpath->registerNamespace('xi', 'http://www.w3.org/2001/XInclude');
25+
$xi = $xpath->query('//xi:include')->item(0);
26+
$ns = $xpath->query('namespace::local', $xi)->item(0); // DOMNameSpaceNode
27+
28+
$doc->xinclude(); // frees the xi:include element
29+
30+
var_dump($ns->parentNode);
31+
var_dump($ns->parentElement);
32+
var_dump($ns->isConnected);
33+
?>
34+
--CLEAN--
35+
<?php
36+
@unlink(__DIR__ . '/gh22624_included.xml');
37+
?>
38+
--EXPECT--
39+
NULL
40+
NULL
41+
bool(false)

0 commit comments

Comments
 (0)