mirror of
https://git.yoctoproject.org/poky
synced 2026-02-25 19:09:41 +01:00
References: * https://gitlab.gnome.org/GNOME/libxml2/-/issues/1019 * https://gitlab.gnome.org/GNOME/libxml2/-/merge_requests/377 (From OE-Core rev: 2c8e455148e12e097ff757bcf0a57d7d5bd77c30) Signed-off-by: Peter Marko <peter.marko@siemens.com> Signed-off-by: Yoann Congal <yoann.congal@smile.fr> Signed-off-by: Paul Barker <paul@pbarker.dev> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
324 lines
8.9 KiB
Diff
324 lines
8.9 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] 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
|
|
|
|
CVE: CVE-2026-0992
|
|
Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libxml2/-/commit/f8399e62a31095bf1ced01827c33f9b29494046f]
|
|
Signed-off-by: Peter Marko <peter.marko@siemens.com>
|
|
---
|
|
CMakeLists.txt | 2 +
|
|
Makefile.am | 6 ++
|
|
catalog.c | 63 +++++++++++-----
|
|
include/libxml/catalog.h | 2 +
|
|
test/catalogs/catalog-recursive.xml | 3 +
|
|
test/catalogs/repeated-next-catalog.xml | 10 +++
|
|
testcatalog.c | 96 +++++++++++++++++++++++++
|
|
7 files changed, 163 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
|
|
|
|
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
|
index 163661f8..7d5702df 100644
|
|
--- a/CMakeLists.txt
|
|
+++ b/CMakeLists.txt
|
|
@@ -517,6 +517,7 @@ if(LIBXML2_WITH_TESTS)
|
|
runxmlconf
|
|
runsuite
|
|
testapi
|
|
+ testcatalog
|
|
testchar
|
|
testdict
|
|
testModule
|
|
@@ -543,6 +544,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)
|
|
diff --git a/Makefile.am b/Makefile.am
|
|
index c51dfd8e..c794eac8 100644
|
|
--- a/Makefile.am
|
|
+++ b/Makefile.am
|
|
@@ -21,6 +21,7 @@ check_PROGRAMS = \
|
|
testModule \
|
|
testThreads \
|
|
testapi \
|
|
+ testcatalog \
|
|
testchar \
|
|
testdict \
|
|
testlimits \
|
|
@@ -143,6 +144,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)
|
|
@@ -206,6 +211,7 @@ check-local:
|
|
$(CHECKER) ./runtest$(EXEEXT)
|
|
$(CHECKER) ./testrecurse$(EXEEXT)
|
|
$(CHECKER) ./testapi$(EXEEXT)
|
|
+ $(CHECKER) ./testcatalog$(EXEEXT)
|
|
$(CHECKER) ./testchar$(EXEEXT)
|
|
$(CHECKER) ./testdict$(EXEEXT)
|
|
$(CHECKER) ./testparser$(EXEEXT)
|
|
diff --git a/catalog.c b/catalog.c
|
|
index 401dbc14..eb889162 100644
|
|
--- a/catalog.c
|
|
+++ b/catalog.c
|
|
@@ -649,43 +649,54 @@ static void xmlDumpXMLCatalogNode(xmlCatalogEntryPtr catal, xmlNodePtr catalog,
|
|
}
|
|
}
|
|
|
|
-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
|
|
*/
|
|
@@ -3417,6 +3428,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 */
|
|
|
|
/**
|
|
diff --git a/include/libxml/catalog.h b/include/libxml/catalog.h
|
|
index 88a7483c..e1bc5feb 100644
|
|
--- a/include/libxml/catalog.h
|
|
+++ b/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,
|
|
diff --git a/test/catalogs/catalog-recursive.xml b/test/catalogs/catalog-recursive.xml
|
|
new file mode 100644
|
|
index 00000000..3b3d03f9
|
|
--- /dev/null
|
|
+++ b/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>
|
|
diff --git a/test/catalogs/repeated-next-catalog.xml b/test/catalogs/repeated-next-catalog.xml
|
|
new file mode 100644
|
|
index 00000000..76d34c3c
|
|
--- /dev/null
|
|
+++ b/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>
|
|
+
|
|
diff --git a/testcatalog.c b/testcatalog.c
|
|
new file mode 100644
|
|
index 00000000..86d33bd0
|
|
--- /dev/null
|
|
+++ b/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
|