Skip to content

Fix GH-15654: Signed integer overflow in ext/dom/nodelist.c #15669

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions ext/dom/dom_iterators.c
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ static void php_dom_iterator_move_forward(zend_object_iterator *iter) /* {{{ */
dom_object *intern;
dom_object *nnmap;
dom_nnodemap_object *objmap;
int previndex;
zend_long previndex;
HashTable *nodeht;
zval *entry;
bool do_curobj_undef = 1;
Expand Down Expand Up @@ -269,7 +269,7 @@ zend_object_iterator *php_dom_get_iterator(zend_class_entry *ce, zval *object, i
dom_object *intern;
dom_nnodemap_object *objmap;
xmlNodePtr curnode=NULL;
int curindex = 0;
zend_long curindex = 0;
HashTable *nodeht;
zval *entry;
php_dom_iterator *iterator;
Expand Down
8 changes: 4 additions & 4 deletions ext/dom/nodelist.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ int php_dom_get_nodelist_length(dom_object *obj)
reset_objmap_cache(objmap);
}

int count = 0;
zend_long count = 0;
if (objmap->nodetype == XML_ATTRIBUTE_NODE || objmap->nodetype == XML_ELEMENT_NODE) {
xmlNodePtr curnode = dom_nodelist_iter_start_first_child(nodep);
if (curnode) {
Expand All @@ -109,7 +109,7 @@ int php_dom_get_nodelist_length(dom_object *obj)
nodep = nodep->children;
}
dom_get_elements_by_tag_name_ns_raw(
basep, nodep, (char *) objmap->ns, (char *) objmap->local, &count, INT_MAX - 1 /* because of <= */);
basep, nodep, (char *) objmap->ns, (char *) objmap->local, &count, ZEND_LONG_MAX - 1 /* because of <= */);
}

objmap->cached_length = count;
Expand Down Expand Up @@ -174,7 +174,7 @@ void php_dom_nodelist_get_item_into_zval(dom_nnodemap_object *objmap, zend_long
* TODO: in the future we could extend the logic of the node list such that backwards searches
* are also possible. */
bool restart = true;
int relative_index = index;
zend_long relative_index = index;
if (index >= objmap->cached_obj_index && objmap->cached_obj && !php_dom_is_cache_tag_stale_from_node(&objmap->cache_tag, nodep)) {
xmlNodePtr cached_obj_xml_node = dom_object_get_node(objmap->cached_obj);

Expand All @@ -192,7 +192,7 @@ void php_dom_nodelist_get_item_into_zval(dom_nnodemap_object *objmap, zend_long
nodep = cached_obj_xml_node;
}
}
int count = 0;
zend_long count = 0;
if (objmap->nodetype == XML_ATTRIBUTE_NODE || objmap->nodetype == XML_ELEMENT_NODE) {
if (restart) {
nodep = dom_nodelist_iter_start_first_child(nodep);
Expand Down
2 changes: 1 addition & 1 deletion ext/dom/php_dom.c
Original file line number Diff line number Diff line change
Expand Up @@ -1334,7 +1334,7 @@ bool dom_has_feature(zend_string *feature, zend_string *version)
}
/* }}} end dom_has_feature */

xmlNode *dom_get_elements_by_tag_name_ns_raw(xmlNodePtr basep, xmlNodePtr nodep, char *ns, char *local, int *cur, int index) /* {{{ */
xmlNode *dom_get_elements_by_tag_name_ns_raw(xmlNodePtr basep, xmlNodePtr nodep, char *ns, char *local, zend_long *cur, zend_long index) /* {{{ */
{
/* Can happen with detached document */
if (UNEXPECTED(nodep == NULL)) {
Expand Down
4 changes: 2 additions & 2 deletions ext/dom/php_dom.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ typedef struct _dom_nnodemap_object {
xmlChar *ns;
php_libxml_cache_tag cache_tag;
dom_object *cached_obj;
int cached_obj_index;
zend_long cached_obj_index;
bool free_local : 1;
bool free_ns : 1;
} dom_nnodemap_object;
Expand Down Expand Up @@ -133,7 +133,7 @@ void dom_reconcile_ns(xmlDocPtr doc, xmlNodePtr nodep);
void dom_reconcile_ns_list(xmlDocPtr doc, xmlNodePtr nodep, xmlNodePtr last);
xmlNsPtr dom_get_nsdecl(xmlNode *node, xmlChar *localName);
void dom_normalize (xmlNodePtr nodep);
xmlNode *dom_get_elements_by_tag_name_ns_raw(xmlNodePtr basep, xmlNodePtr nodep, char *ns, char *local, int *cur, int index);
xmlNode *dom_get_elements_by_tag_name_ns_raw(xmlNodePtr basep, xmlNodePtr nodep, char *ns, char *local, zend_long *cur, zend_long index);
void php_dom_create_implementation(zval *retval);
int dom_hierarchy(xmlNodePtr parent, xmlNodePtr child);
bool dom_has_feature(zend_string *feature, zend_string *version);
Expand Down
32 changes: 32 additions & 0 deletions ext/dom/tests/gh15654.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
--TEST--
GH-15654 (Signed integer overflow in ext/dom/nodelist.c)
--EXTENSIONS--
dom
--SKIPIF--
<?php
if (PHP_INT_SIZE != 8) die('skip 64-bit only');
?>
--FILE--
<?php
define("MAX_64Bit", 9223372036854775807);
define("MAX_32Bit", 2147483647);
define("MIN_64Bit", -9223372036854775807 - 1);
define("MIN_32Bit", -2147483647 - 1);
$longVals = array(
0, MAX_64Bit, MIN_64Bit, MAX_32Bit, MIN_32Bit, MAX_64Bit - MAX_32Bit, MIN_64Bit - MIN_32Bit,
);
$dom = new DOMDocument;
$dom->loadXML('<root><a/><b/><c/></root>');
$children = $dom->documentElement->childNodes;
foreach ($longVals as $value) {
var_dump($children[$value]?->nodeName);
}
?>
--EXPECT--
string(1) "a"
NULL
NULL
NULL
NULL
NULL
NULL
Loading