Skip to content

Commit f527fab

Browse files
committed
ext/dom: Fix UAF in custom XPath function
Co-authored-by: David CARLIER devnexen@gmail.com
1 parent ed2c6ba commit f527fab

2 files changed

Lines changed: 45 additions & 1 deletion

File tree

ext/dom/tests/bug22077.phpt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
--TEST--
2+
test for issue #22077
3+
--DESCRIPTION--
4+
Registers a custom XPath function providing nodes from a new document.
5+
Results in a heap UAF in request shutdown if these nodes are accessed further
6+
down the road without protecting their origin document from GC.
7+
Build with '-fsanitize=address' or test with 'valgrind' or '-m'.
8+
--FILE--
9+
<?php
10+
$document = new DOMDocument;
11+
$xpath = new DOMXPath($document);
12+
$xpath->registerNamespace("my", "my.ns");
13+
$xpath->registerPHPFunctionNS('my.ns', 'include', function(): DOMElement {
14+
$includedDocument = new DOMDocument;
15+
$includedDocument->loadXML('<root><uaf/><node/><uaf/></root>');
16+
return $includedDocument->documentElement;
17+
});
18+
$nodeset = $xpath->query('my:include()/uaf');
19+
$node = $nodeset->item(0);
20+
var_dump($nodeset->length);
21+
var_dump($node->ownerDocument->saveXML($node));
22+
?>
23+
--EXPECT--
24+
int(2)
25+
string(6) "<uaf/>"

ext/dom/xpath.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,24 @@
3535

3636
#ifdef LIBXML_XPATH_ENABLED
3737

38+
static dom_object *dom_xpath_intern_for_doc(dom_xpath_object *xpath_obj, xmlDocPtr doc)
39+
{
40+
if (xpath_obj->dom.document && xpath_obj->dom.document->ptr == doc) {
41+
return &xpath_obj->dom;
42+
}
43+
HashTable *node_list = xpath_obj->xpath_callbacks.node_list;
44+
if (node_list) {
45+
zval *entry;
46+
ZEND_HASH_PACKED_FOREACH_VAL(node_list, entry) {
47+
dom_object *obj = Z_DOMOBJ_P(entry);
48+
if (obj->document && obj->document->ptr == doc) {
49+
return obj;
50+
}
51+
} ZEND_HASH_FOREACH_END();
52+
}
53+
return &xpath_obj->dom;
54+
}
55+
3856
void dom_xpath_objects_free_storage(zend_object *object)
3957
{
4058
dom_xpath_object *intern = php_xpath_obj_from_obj(object);
@@ -357,7 +375,8 @@ static void php_xpath_eval(INTERNAL_FUNCTION_PARAMETERS, int type, bool modern)
357375

358376
node = php_dom_create_fake_namespace_decl(nsparent, original, &child, parent_intern);
359377
} else {
360-
php_dom_create_object(node, &child, &intern->dom);
378+
dom_object *parent = dom_xpath_intern_for_doc(intern, node->doc);
379+
php_dom_create_object(node, &child, parent);
361380
}
362381
add_next_index_zval(&retval, &child);
363382
}

0 commit comments

Comments
 (0)