catalog: Fix NULL deref for nextCatalog without 'catalog' attribute
diff --git a/CMakeLists.txt b/CMakeLists.txt index 04d373b..ec9e73d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt
@@ -525,7 +525,7 @@ add_test(NAME runxmlconf COMMAND runxmlconf WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) endif() add_test(NAME testapi COMMAND testapi) - add_test(NAME testcatalog COMMAND testcatalog) + add_test(NAME testcatalog COMMAND testcatalog WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) add_test(NAME testchar COMMAND testchar) add_test(NAME testdict COMMAND testdict) add_test(NAME testparser COMMAND testparser WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
diff --git a/catalog.c b/catalog.c index 448c88a..2a080f8 100644 --- a/catalog.c +++ b/catalog.c
@@ -1329,7 +1329,7 @@ BAD_CAST "nextCatalog", NULL, BAD_CAST "catalog", prefer, cgroup); /* Avoid duplication of nextCatalog */ - while (prev != NULL) { + while ((entry != NULL) && (prev != NULL)) { if ((prev->type == XML_CATA_NEXT_CATALOG) && (xmlStrEqual (prev->URL, entry->URL)) && (prev->prefer == entry->prefer) &&
diff --git a/test/catalogs/next-catalog-missing-attr.xml b/test/catalogs/next-catalog-missing-attr.xml new file mode 100644 index 0000000..b31a490 --- /dev/null +++ b/test/catalogs/next-catalog-missing-attr.xml
@@ -0,0 +1,4 @@ +<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog"> + <nextCatalog catalog="registry.xml"/> + <nextCatalog/> +</catalog>
diff --git a/testcatalog.c b/testcatalog.c index 56c9bef..d3384a4 100644 --- a/testcatalog.c +++ b/testcatalog.c
@@ -80,6 +80,62 @@ } /* + * Test a nextCatalog entry which lacks the mandatory 'catalog' attribute + * See https://gitlab.gnome.org/GNOME/libxml2/-/issues/1143 + */ +static int +testNextCatalogMissingAttr(void) { + int ret = 0; + int i = 0; + const char *cat = "test/catalogs/next-catalog-missing-attr.xml"; + const char *sysId = "http://www.oasis-open.org/docbook/xml/4.1.2/dbpoolx.mod"; + const char *expect = "/usr/share/xml/docbook/xml/4.1.2/dbpoolx.mod"; + xmlChar *resolved = NULL; + xmlDocPtr doc = NULL; + xmlNodePtr node = NULL; + + xmlInitParser(); + + xmlLoadCatalog(cat); + /* + * The malformed nextCatalog must be ignored, the valid one must still + * be followed. This also forces the complete recursive load. + */ + resolved = xmlCatalogResolveSystem(BAD_CAST sysId); + if ((resolved == NULL) || (strcmp((char *) resolved, expect) != 0)) { + fprintf(stderr, "CATALOG-FAILURE: %s resolved to %s, expected %s\n", + sysId, resolved == NULL ? "NULL" : (char *) resolved, expect); + ret = 1; + } + if (resolved != NULL) + xmlFree(resolved); + + /** + * Ensure that only the valid nextCatalog was recorded + */ + doc = xmlCatalogDumpDoc(); + xmlCatalogCleanup(); + + if (doc == NULL) { + fprintf(stderr, "CATALOG-FAILURE: Failed to dump the catalog\n"); + return 1; + } + + /* Just the root "catalog" node with a single nextCatalog */ + node = xmlDocGetRootElement(doc); + node = node->children; + for (i=0; node != NULL; node=node->next, i++) {} + if (i != 1) { + fprintf(stderr, "CATALOG-FAILURE: Found %d nextCatalog entries and should be 1\n", i); + ret = 1; + } + + xmlFreeDoc(doc); + + return ret; +} + +/* * Test repeated call to xmlCatalogResolveURI * See https://gitlab.gnome.org/GNOME/libxml2/-/work_items/1125 */ @@ -135,6 +191,7 @@ err |= testRecursiveDelegateUri(); err |= testRepeatedNextCatalog(); + err |= testNextCatalogMissingAttr(); err |= testRepeatedResolveURI(); return err;