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

There's implicit truncation casts from zend_long to int which cause
issues because checks are done against the zend_longs. Since the
iterator infrastructure uses zend_longs, just convert everything to
zend_long.

Closes GH-15669.
This commit is contained in:
Niels Dossche 2024-08-31 01:01:59 +02:00
parent 8ad7d8f1cd
commit 9cb23a3dec
No known key found for this signature in database
GPG key ID: B8A8AD166DF0E2E5
6 changed files with 43 additions and 9 deletions

2
NEWS
View file

@ -20,6 +20,8 @@ PHP NEWS
- DOM:
. Fixed bug GH-15551 (Segmentation fault (access null pointer) in
ext/dom/xml_common.h). (nielsdos)
. Fixed bug GH-15654 (Signed integer overflow in ext/dom/nodelist.c).
(nielsdos)
- MySQLnd:
. Fixed bug GH-15432 (Heap corruption when querying a vector). (cmb,

View file

@ -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;
@ -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;

View file

@ -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) {
@ -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;
@ -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);
@ -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);

View file

@ -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)) {

View file

@ -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;
@ -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);

View file

@ -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