due to infinite recursion in `xmlCatalogXMLResolveURI` (bsc#1256807, bsc#1256811) * Add patch libxml2-CVE-2026-0990.patch - CVE-2026-0992: excessive resource consumption when processing XML catalogs due to exponential behavior when handling `<nextCatalog>` elements (bsc#1256808, bsc#1256809, bsc#1256812) * Add patch libxml2-CVE-2026-0992.patch - CVE-2025-8732: infinite recursion in catalog parsing functions when processing malformed SGML catalog files (bsc#1247858, bsc#1247850) * Add patch libxml2-CVE-2025-8732.patch - CVE-2026-1757: memory leak in the `xmllint` interactive shell (bsc#1257593, bsc#1257594, bsc#1257595) * Add patch libxml2-CVE-2026-1757.patch - CVE-2025-10911: use-after-free with key data stored cross-RVT (bsc#1250553) * Add patch libxml2-CVE-2025-10911.patch - CVE-2026-0989: call stack exhaustion leading to application crash due to RelaxNG parser not limiting the recursion depth when resolving `<include>` directives (bsc#1256804, bsc#1256805, bsc#1256810) * Add patch libxml2-CVE-2026-0989.patch * https://gitlab.gnome.org/GNOME/libxml2/-/merge_requests/374 OBS-URL: https://build.opensuse.org/package/show/devel:libraries:c_c++/libxml2?expand=0&rev=260
351 lines
10 KiB
Diff
351 lines
10 KiB
Diff
From f8399e62a31095bf1ced01827c33f9b29494046f Mon Sep 17 00:00:00 2001
|
|
From: Daniel Garcia Moreno <daniel.garcia@suse.com>
|
|
Date: Fri, 19 Dec 2025 12:27:54 +0100
|
|
Subject: [PATCH 1/2] testcatalog: Add new tests for catalog.c
|
|
|
|
Adds a new test program to run specific tests related to catalog
|
|
parsing.
|
|
|
|
This initial version includes a couple of tests, the first one to check
|
|
the infinite recursion detection related to:
|
|
https://gitlab.gnome.org/GNOME/libxml2/-/issues/1018.
|
|
|
|
The second one tests the nextCatalog element repeated parsing, related
|
|
to:
|
|
https://gitlab.gnome.org/GNOME/libxml2/-/issues/1019
|
|
https://gitlab.gnome.org/GNOME/libxml2/-/issues/1040
|
|
---
|
|
CMakeLists.txt | 2 +
|
|
Makefile.am | 6 ++
|
|
catalog.c | 63 +++++++++++-----
|
|
include/libxml/catalog.h | 2 +
|
|
meson.build | 1 +
|
|
test/catalogs/catalog-recursive.xml | 3 +
|
|
test/catalogs/repeated-next-catalog.xml | 10 +++
|
|
testcatalog.c | 96 +++++++++++++++++++++++++
|
|
8 files changed, 164 insertions(+), 19 deletions(-)
|
|
create mode 100644 test/catalogs/catalog-recursive.xml
|
|
create mode 100644 test/catalogs/repeated-next-catalog.xml
|
|
create mode 100644 testcatalog.c
|
|
|
|
Index: libxml2-2.14.5/CMakeLists.txt
|
|
===================================================================
|
|
--- libxml2-2.14.5.orig/CMakeLists.txt
|
|
+++ libxml2-2.14.5/CMakeLists.txt
|
|
@@ -488,6 +488,7 @@ if(LIBXML2_WITH_TESTS)
|
|
runxmlconf
|
|
runsuite
|
|
testapi
|
|
+ testcatalog
|
|
testchar
|
|
testdict
|
|
testModule
|
|
@@ -512,6 +513,7 @@ if(LIBXML2_WITH_TESTS)
|
|
if(NOT WIN32)
|
|
add_test(NAME testapi COMMAND testapi)
|
|
endif()
|
|
+ add_test(NAME testcatalog COMMAND testcatalog)
|
|
add_test(NAME testchar COMMAND testchar)
|
|
add_test(NAME testdict COMMAND testdict)
|
|
add_test(NAME testparser COMMAND testparser WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
|
Index: libxml2-2.14.5/Makefile.am
|
|
===================================================================
|
|
--- libxml2-2.14.5.orig/Makefile.am
|
|
+++ libxml2-2.14.5/Makefile.am
|
|
@@ -20,6 +20,7 @@ check_PROGRAMS = \
|
|
runxmlconf \
|
|
testModule \
|
|
testapi \
|
|
+ testcatalog \
|
|
testchar \
|
|
testdict \
|
|
testlimits \
|
|
@@ -120,6 +121,10 @@ testlimits_SOURCES=testlimits.c
|
|
testlimits_DEPENDENCIES = $(DEPS)
|
|
testlimits_LDADD= $(LDADDS)
|
|
|
|
+testcatalog_SOURCES=testcatalog.c
|
|
+testcatalog_DEPENDENCIES = $(DEPS)
|
|
+testcatalog_LDADD= $(LDADDS)
|
|
+
|
|
testchar_SOURCES=testchar.c
|
|
testchar_DEPENDENCIES = $(DEPS)
|
|
testchar_LDADD= $(LDADDS)
|
|
@@ -169,6 +174,7 @@ check-local:
|
|
$(CHECKER) ./runtest$(EXEEXT)
|
|
$(CHECKER) ./testrecurse$(EXEEXT)
|
|
$(CHECKER) ./testapi$(EXEEXT)
|
|
+ $(CHECKER) ./testcatalog$(EXEEXT)
|
|
$(CHECKER) ./testchar$(EXEEXT)
|
|
$(CHECKER) ./testdict$(EXEEXT)
|
|
$(CHECKER) ./testparser$(EXEEXT)
|
|
Index: libxml2-2.14.5/catalog.c
|
|
===================================================================
|
|
--- libxml2-2.14.5.orig/catalog.c
|
|
+++ libxml2-2.14.5/catalog.c
|
|
@@ -637,43 +637,54 @@ static void xmlDumpXMLCatalogNode(xmlCat
|
|
}
|
|
}
|
|
|
|
-static int
|
|
-xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) {
|
|
- int ret;
|
|
- xmlDocPtr doc;
|
|
+static xmlDocPtr
|
|
+xmlDumpXMLCatalogToDoc(xmlCatalogEntryPtr catal) {
|
|
xmlNsPtr ns;
|
|
xmlDtdPtr dtd;
|
|
xmlNodePtr catalog;
|
|
- xmlOutputBufferPtr buf;
|
|
+ xmlDocPtr doc = xmlNewDoc(NULL);
|
|
+ if (doc == NULL) {
|
|
+ return(NULL);
|
|
+ }
|
|
|
|
- /*
|
|
- * Rebuild a catalog
|
|
- */
|
|
- doc = xmlNewDoc(NULL);
|
|
- if (doc == NULL)
|
|
- return(-1);
|
|
dtd = xmlNewDtd(doc, BAD_CAST "catalog",
|
|
- BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN",
|
|
-BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd");
|
|
+ BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN",
|
|
+ BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd");
|
|
|
|
xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd);
|
|
|
|
ns = xmlNewNs(NULL, XML_CATALOGS_NAMESPACE, NULL);
|
|
if (ns == NULL) {
|
|
- xmlFreeDoc(doc);
|
|
- return(-1);
|
|
+ xmlFreeDoc(doc);
|
|
+ return(NULL);
|
|
}
|
|
catalog = xmlNewDocNode(doc, ns, BAD_CAST "catalog", NULL);
|
|
if (catalog == NULL) {
|
|
- xmlFreeNs(ns);
|
|
- xmlFreeDoc(doc);
|
|
- return(-1);
|
|
+ xmlFreeDoc(doc);
|
|
+ xmlFreeNs(ns);
|
|
+ return(NULL);
|
|
}
|
|
catalog->nsDef = ns;
|
|
xmlAddChild((xmlNodePtr) doc, catalog);
|
|
-
|
|
xmlDumpXMLCatalogNode(catal, catalog, doc, ns, NULL);
|
|
|
|
+ return(doc);
|
|
+}
|
|
+
|
|
+static int
|
|
+xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) {
|
|
+ int ret;
|
|
+ xmlDocPtr doc;
|
|
+ xmlOutputBufferPtr buf;
|
|
+
|
|
+ /*
|
|
+ * Rebuild a catalog
|
|
+ */
|
|
+ doc = xmlDumpXMLCatalogToDoc(catal);
|
|
+ if (doc == NULL) {
|
|
+ return(-1);
|
|
+ }
|
|
+
|
|
/*
|
|
* reserialize it
|
|
*/
|
|
@@ -1236,7 +1247,6 @@ xmlParseXMLCatalogNode(xmlNodePtr cur, x
|
|
while (prev != NULL) {
|
|
if ((prev->type == XML_CATA_NEXT_CATALOG) &&
|
|
(xmlStrEqual (prev->URL, entry->URL)) &&
|
|
- (xmlStrEqual (prev->value, entry->value)) &&
|
|
(prev->prefer == entry->prefer) &&
|
|
(prev->group == entry->group)) {
|
|
if (xmlDebugCatalogs)
|
|
@@ -3369,6 +3379,20 @@ xmlCatalogDump(FILE *out) {
|
|
|
|
xmlACatalogDump(xmlDefaultCatalog, out);
|
|
}
|
|
+
|
|
+/**
|
|
+ * Dump all the global catalog content as a xmlDoc
|
|
+ * This function is just for testing/debugging purposes
|
|
+ *
|
|
+ * @returns The catalog as xmlDoc or NULL if failed, it must be freed by the caller.
|
|
+ */
|
|
+xmlDocPtr
|
|
+xmlCatalogDumpDoc(void) {
|
|
+ if (!xmlCatalogInitialized)
|
|
+ xmlInitializeCatalog();
|
|
+
|
|
+ return xmlDumpXMLCatalogToDoc(xmlDefaultCatalog->xml);
|
|
+}
|
|
#endif /* LIBXML_OUTPUT_ENABLED */
|
|
|
|
/**
|
|
Index: libxml2-2.14.5/include/libxml/catalog.h
|
|
===================================================================
|
|
--- libxml2-2.14.5.orig/include/libxml/catalog.h
|
|
+++ libxml2-2.14.5/include/libxml/catalog.h
|
|
@@ -119,6 +119,8 @@ XMLPUBFUN void
|
|
#ifdef LIBXML_OUTPUT_ENABLED
|
|
XMLPUBFUN void
|
|
xmlCatalogDump (FILE *out);
|
|
+XMLPUBFUN xmlDocPtr
|
|
+ xmlCatalogDumpDoc (void);
|
|
#endif /* LIBXML_OUTPUT_ENABLED */
|
|
XMLPUBFUN xmlChar *
|
|
xmlCatalogResolve (const xmlChar *pubID,
|
|
Index: libxml2-2.14.5/meson.build
|
|
===================================================================
|
|
--- libxml2-2.14.5.orig/meson.build
|
|
+++ libxml2-2.14.5/meson.build
|
|
@@ -539,6 +539,7 @@ checks = {
|
|
# Disabled for now, see #694
|
|
# 'testModule': [],
|
|
'testapi': [],
|
|
+ 'testcatalog': [],
|
|
'testchar': [],
|
|
'testdict': [],
|
|
'testlimits': [],
|
|
Index: libxml2-2.14.5/test/catalogs/catalog-recursive.xml
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ libxml2-2.14.5/test/catalogs/catalog-recursive.xml
|
|
@@ -0,0 +1,3 @@
|
|
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
|
|
+ <delegateURI uriStartString="/foo" catalog="catalog-recursive.xml"/>
|
|
+</catalog>
|
|
Index: libxml2-2.14.5/test/catalogs/repeated-next-catalog.xml
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ libxml2-2.14.5/test/catalogs/repeated-next-catalog.xml
|
|
@@ -0,0 +1,10 @@
|
|
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
|
|
+ <nextCatalog catalog="registry.xml"/>
|
|
+ <nextCatalog catalog="registry.xml"/>
|
|
+ <nextCatalog catalog="./registry.xml"/>
|
|
+ <nextCatalog catalog="././registry.xml"/>
|
|
+ <nextCatalog catalog="./././registry.xml"/>
|
|
+ <nextCatalog catalog="./../catalogs/registry.xml"/>
|
|
+ <nextCatalog catalog="./../catalogs/./registry.xml"/>
|
|
+</catalog>
|
|
+
|
|
Index: libxml2-2.14.5/testcatalog.c
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ libxml2-2.14.5/testcatalog.c
|
|
@@ -0,0 +1,96 @@
|
|
+/*
|
|
+ * testcatalog.c: C program to run libxml2 catalog.c unit tests
|
|
+ *
|
|
+ * To compile on Unixes:
|
|
+ * cc -o testcatalog `xml2-config --cflags` testcatalog.c `xml2-config --libs` -lpthread
|
|
+ *
|
|
+ * See Copyright for the status of this software.
|
|
+ *
|
|
+ * Author: Daniel Garcia <dani@danigm.net>
|
|
+ */
|
|
+
|
|
+
|
|
+#include "libxml.h"
|
|
+#include <stdio.h>
|
|
+
|
|
+#ifdef LIBXML_CATALOG_ENABLED
|
|
+#include <libxml/catalog.h>
|
|
+
|
|
+/* Test catalog resolve uri with recursive catalog */
|
|
+static int
|
|
+testRecursiveDelegateUri(void) {
|
|
+ int ret = 0;
|
|
+ const char *cat = "test/catalogs/catalog-recursive.xml";
|
|
+ const char *entity = "/foo.ent";
|
|
+ xmlChar *resolved = NULL;
|
|
+
|
|
+ xmlInitParser();
|
|
+ xmlLoadCatalog(cat);
|
|
+
|
|
+ /* This should trigger recursive error */
|
|
+ resolved = xmlCatalogResolveURI(BAD_CAST entity);
|
|
+ if (resolved != NULL) {
|
|
+ fprintf(stderr, "CATALOG-FAILURE: Catalog %s entity should fail to resolve\n", entity);
|
|
+ ret = 1;
|
|
+ }
|
|
+ xmlCatalogCleanup();
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/* Test parsing repeated NextCatalog */
|
|
+static int
|
|
+testRepeatedNextCatalog(void) {
|
|
+ int ret = 0;
|
|
+ int i = 0;
|
|
+ const char *cat = "test/catalogs/repeated-next-catalog.xml";
|
|
+ const char *entity = "/foo.ent";
|
|
+ xmlDocPtr doc = NULL;
|
|
+ xmlNodePtr node = NULL;
|
|
+
|
|
+ xmlInitParser();
|
|
+
|
|
+ xmlLoadCatalog(cat);
|
|
+ /* To force the complete recursive load */
|
|
+ xmlCatalogResolveURI(BAD_CAST entity);
|
|
+ /**
|
|
+ * Ensure that the doc doesn't contain the same nextCatalog
|
|
+ */
|
|
+ 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 series of 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;
|
|
+}
|
|
+
|
|
+int
|
|
+main(void) {
|
|
+ int err = 0;
|
|
+
|
|
+ err |= testRecursiveDelegateUri();
|
|
+ err |= testRepeatedNextCatalog();
|
|
+
|
|
+ return err;
|
|
+}
|
|
+#else
|
|
+/* No catalog, so everything okay */
|
|
+int
|
|
+main(void) {
|
|
+ return 0;
|
|
+}
|
|
+#endif
|
|
Index: libxml2-2.14.5/configure.ac
|
|
===================================================================
|
|
--- libxml2-2.14.5.orig/configure.ac
|
|
+++ libxml2-2.14.5/configure.ac
|
|
@@ -41,7 +41,7 @@ AC_SUBST(LIBXML_VERSION_INFO)
|
|
AC_SUBST(LIBXML_VERSION_NUMBER)
|
|
AC_SUBST(LIBXML_VERSION_EXTRA)
|
|
|
|
-AM_INIT_AUTOMAKE([1.16.3 foreign subdir-objects no-dist-gzip dist-xz])
|
|
+AM_INIT_AUTOMAKE([1.15.1 foreign subdir-objects no-dist-gzip dist-xz])
|
|
AM_MAINTAINER_MODE([enable])
|
|
AM_SILENT_RULES([yes])
|
|
|