diff --git a/NEWS b/NEWS index 34534553324..897b3f72267 100644 --- a/NEWS +++ b/NEWS @@ -14,6 +14,8 @@ PHP NEWS - DOM: . Fixed bug GH-13988 (Storing DOMElement consume 4 times more memory in PHP 8.1 than in PHP 8.0). (nielsdos) + . Fixed bug GH-15654 (Signed integer overflow in ext/dom/nodelist.c). + (nielsdos) - GD: . Added gdImageClone to bundled libgd. (David Carlier) diff --git a/ext/dom/dom_iterators.c b/ext/dom/dom_iterators.c index 378e841137f..ad7dae5b3f1 100644 --- a/ext/dom/dom_iterators.c +++ b/ext/dom/dom_iterators.c @@ -152,7 +152,7 @@ static xmlNodePtr dom_fetch_first_iteration_item(dom_nnodemap_object *objmap) return dom_nodelist_iter_start_first_child(basep); } } else { - int curindex = 0; + zend_long curindex = 0; xmlNodePtr nodep = php_dom_first_child_of_container_node(basep); return dom_get_elements_by_tag_name_ns_raw( basep, nodep, objmap->ns, objmap->local, objmap->local_lower, &curindex, 0); @@ -209,7 +209,7 @@ static void php_dom_iterator_move_forward(zend_object_iterator *iter) /* {{{ */ /* We have a strong reference to the base node via baseobj_zv, this cannot become NULL */ ZEND_ASSERT(basenode != NULL); - int previndex; + zend_long previndex; if (php_dom_is_cache_tag_stale_from_node(&iterator->cache_tag, basenode)) { php_dom_mark_cache_tag_up_to_date_from_node(&iterator->cache_tag, basenode); previndex = 0; diff --git a/ext/dom/html_collection.c b/ext/dom/html_collection.c index 4bc5713d37c..e4c04460166 100644 --- a/ext/dom/html_collection.c +++ b/ext/dom/html_collection.c @@ -46,8 +46,8 @@ static dom_named_item dom_html_collection_named_item(zend_string *key, zend_obje /* 2. Return the first element in the collection for which at least one of the following is true: */ xmlNodePtr basep = dom_object_get_node(objmap->baseobj); if (basep != NULL) { - int cur = 0; - int next = cur; /* not +1, otherwise we skip the first candidate */ + zend_long cur = 0; + zend_long next = cur; /* not +1, otherwise we skip the first candidate */ xmlNodePtr candidate = basep->children; while (candidate != NULL) { candidate = dom_get_elements_by_tag_name_ns_raw(basep, candidate, objmap->ns, objmap->local, objmap->local_lower, &cur, next); diff --git a/ext/dom/nodelist.c b/ext/dom/nodelist.c index 8fa8c59bb58..d2e05a7b736 100644 --- a/ext/dom/nodelist.c +++ b/ext/dom/nodelist.c @@ -92,7 +92,7 @@ zend_long 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) { @@ -106,7 +106,7 @@ zend_long php_dom_get_nodelist_length(dom_object *obj) xmlNodePtr basep = nodep; nodep = php_dom_first_child_of_container_node(basep); dom_get_elements_by_tag_name_ns_raw( - basep, nodep, objmap->ns, objmap->local, objmap->local_lower, &count, INT_MAX - 1 /* because of <= */); + basep, nodep, objmap->ns, objmap->local, objmap->local_lower, &count, ZEND_LONG_MAX - 1 /* because of <= */); } objmap->cached_length = count; @@ -159,7 +159,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); @@ -177,7 +177,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); diff --git a/ext/dom/php_dom.c b/ext/dom/php_dom.c index 42a6876b414..79cd3085c82 100644 --- a/ext/dom/php_dom.c +++ b/ext/dom/php_dom.c @@ -1855,7 +1855,7 @@ static bool dom_match_qualified_name_for_tag_name_equality(const xmlChar *local, return dom_match_qualified_name_according_to_spec(local_to_use, nodep); } -xmlNode *dom_get_elements_by_tag_name_ns_raw(xmlNodePtr basep, xmlNodePtr nodep, xmlChar *ns, xmlChar *local, xmlChar *local_lower, int *cur, int index) /* {{{ */ +xmlNode *dom_get_elements_by_tag_name_ns_raw(xmlNodePtr basep, xmlNodePtr nodep, xmlChar *ns, xmlChar *local, xmlChar *local_lower, zend_long *cur, zend_long index) /* {{{ */ { /* Can happen with detached document */ if (UNEXPECTED(nodep == NULL)) { diff --git a/ext/dom/php_dom.h b/ext/dom/php_dom.h index 07137320baf..bf671577980 100644 --- a/ext/dom/php_dom.h +++ b/ext/dom/php_dom.h @@ -87,7 +87,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; @@ -143,7 +143,7 @@ void dom_reconcile_ns_list(xmlDocPtr doc, xmlNodePtr nodep, xmlNodePtr last); xmlNsPtr dom_get_nsdecl(xmlNode *node, xmlChar *localName); void php_dom_normalize_legacy(xmlNodePtr nodep); void php_dom_normalize_modern(xmlNodePtr nodep); -xmlNode *dom_get_elements_by_tag_name_ns_raw(xmlNodePtr basep, xmlNodePtr nodep, xmlChar *ns, xmlChar *local, xmlChar *local_lower, int *cur, int index); +xmlNode *dom_get_elements_by_tag_name_ns_raw(xmlNodePtr basep, xmlNodePtr nodep, xmlChar *ns, xmlChar *local, xmlChar *local_lower, zend_long *cur, zend_long index); void php_dom_create_implementation(zval *retval, bool modern); int dom_hierarchy(xmlNodePtr parent, xmlNodePtr child); bool dom_has_feature(zend_string *feature, zend_string *version); diff --git a/ext/dom/tests/gh15654.phpt b/ext/dom/tests/gh15654.phpt new file mode 100644 index 00000000000..ed4b0f34aff --- /dev/null +++ b/ext/dom/tests/gh15654.phpt @@ -0,0 +1,32 @@ +--TEST-- +GH-15654 (Signed integer overflow in ext/dom/nodelist.c) +--EXTENSIONS-- +dom +--SKIPIF-- + +--FILE-- +loadXML(''); +$children = $dom->documentElement->childNodes; +foreach ($longVals as $value) { + var_dump($children[$value]?->nodeName); +} +?> +--EXPECT-- +string(1) "a" +NULL +NULL +NULL +NULL +NULL +NULL