Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions debian/changelog
Original file line number Diff line number Diff line change
@@ -1,3 +1,35 @@
libxml2 (2.12.7+dfsg+really2.9.14-2.1+deb13u3) trixie; urgency=high

* Non-maintainer upload.
* Fix CVE-2026-0989: Specially crafted or overly complex schemas can cause
excessive recursion during parsing, which may lead to stack exhaustion and
application crashes. The parser now enforces a limit on inclusion depth
when resolving nested `<include>` directives; the limit defaults to 1000
and can be modified at runtime with the env variable `RNG_INCLUDE_LIMIT`.
(Closes: #1125691)
* Fix CVE-2026-0990: `xmlCatalogXMLResolveURI()` will recurse infinitely if
a catalog has a URI delegate referencing itself, eventually resulting in a
call stack overflow. (Closes: #1125695)
* Fix CVE-2026-0992: Denial of Service vulnerability due to uncontrolled
resource consumption when processing XML catalogs containing repeated
`<nextCatalog>` elements pointing to the same downstream catalog.
(Closes: #1125696)
* Fix CVE-2025-8732: When a catalog file contains a CATALOG directive
pointing to itself, `xmlExpandCatalog()` and `xmlParseSGMLCatalog()`
recursively call each other without bounds until stack overflow.
* Fix CVE-2026-1757: Memory leak issue in the command parsing logic of the
xmllint interactive shell.
* Fix unit tests for CVE-2025-49794 and -49796.
* Backport some more upstream changes from v2.15.2:
+ Fix memory leak of prefix in `xmlTextWriterStartElementNS()`.
+ Mitigate use-after-free issue in `xmlRelaxNGValidateValue()`.
+ Fix memory leak in `xmlTextWriterStartAttributeNS()`.
+ Schematron: Fix additional memory leaks on error paths.
+ Catalog: Fix stack overflow from self-referencing SGML CATALOG entries.
* Add d/salsa-ci.yml for Salsa CI.

-- Guilhem Moulin <guilhem@debian.org> Sun, 07 Jun 2026 19:02:23 +0200

libxml2 (2.12.7+dfsg+really2.9.14-2.1+deb13u2) trixie; urgency=high

* Non-maintainer upload.
Expand Down
2 changes: 2 additions & 0 deletions debian/libxml2.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ libxml2.so.2 libxml2 #MINVER#
xmlBufWriteQuotedString@Base 2.9.0
xmlBufferDetach@LIBXML2_2.8.0 2.8.0
xmlBuildRelativeURI@LIBXML2_2.6.11 2.8.0
xmlCatalogDumpDoc@Base 2.12.7+dfsg+really2.9.14-2.1+deb13u3~
xmlCharEncFirstLineInput@Base 2.9.0
xmlCharEncFirstLineInt@Base 2.7.4
xmlCharEncInput@Base 2.9.0
Expand All @@ -158,6 +159,7 @@ libxml2.so.2 libxml2 #MINVER#
xmlParserInputBufferCreateFilenameDefault@LIBXML2_2.6.11 2.8.0
xmlParserInputBufferCreateFilenameValue@LIBXML2_2.6.11 2.8.0
xmlPopOutputCallbacks@LIBXML2_2.9.11 2.9.11
xmlRelaxParserSetIncLImit@Base 2.12.7+dfsg+really2.9.14-2.1+deb13u3~
xmlSchemaCollapseString@LIBXML2_2.6.11 2.8.0
xmlSchemaFreeWildcard@LIBXML2_2.6.11 2.8.0
xmlSchemaGetBuiltInListSimpleTypeItemType@LIBXML2_2.6.11 2.8.0
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
Date: Thu, 4 Sep 2025 21:13:24 +0200
Subject: Fix memory leak of prefix in xmlTextWriterStartElementNS()

Origin: https://gitlab.gnome.org/GNOME/libxml2/-/commit/7d138310f1d4f006d490e29c72168c8ede3a020a
---
xmlwriter.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/xmlwriter.c b/xmlwriter.c
index 58445c8..49b3012 100644
--- a/xmlwriter.c
+++ b/xmlwriter.c
@@ -1095,6 +1095,7 @@ xmlTextWriterStartElementNS(xmlTextWriterPtr writer,
if (p->uri == 0) {
xmlWriterErrMsg(writer, XML_ERR_NO_MEMORY,
"xmlTextWriterStartElementNS : out of memory!\n");
+ xmlFree(p->prefix);
xmlFree(p);
return -1;
}
306 changes: 306 additions & 0 deletions debian/patches/0035-testcatalog-Add-new-tests-for-catalog.c.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,306 @@
From: Daniel Garcia Moreno <daniel.garcia@suse.com>
Date: Fri, 19 Dec 2025 12:27:54 +0100
Subject: 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

Origin: https://gitlab.gnome.org/GNOME/libxml2/-/commit/f14c733327f163b49a632f03d05a58c119ed7e57
Bug: https://gitlab.gnome.org/GNOME/libxml2/-/issues/1018
Bug: https://gitlab.gnome.org/GNOME/libxml2/-/issues/1019
Bug: https://gitlab.gnome.org/GNOME/libxml2/-/issues/1040
Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2026-0990
Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2026-0992
---
Makefile.am | 8 ++-
catalog.c | 63 +++++++++++++++-------
include/libxml/catalog.h | 2 +
test/catalogs/catalog-recursive.xml | 3 ++
test/catalogs/repeated-next-catalog.xml | 10 ++++
testcatalog.c | 96 +++++++++++++++++++++++++++++++++
6 files changed, 161 insertions(+), 21 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/Makefile.am b/Makefile.am
index 7917b59..17b2496 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -12,7 +12,7 @@ AM_CFLAGS = $(EXTRA_CFLAGS) $(THREAD_CFLAGS) $(Z_CFLAGS) $(LZMA_CFLAGS)

check_PROGRAMS=testSchemas testRelax testSAX testHTML testXPath testURI \
testThreads testC14N testAutomata testRegexp \
- testReader testapi testModule runtest runsuite testchar \
+ testReader testapi testcatalog testModule runtest runsuite testchar \
testdict runxmlconf testrecurse testlimits

bin_PROGRAMS = xmllint xmlcatalog
@@ -81,6 +81,10 @@ testlimits_LDFLAGS =
testlimits_DEPENDENCIES = $(DEPS)
testlimits_LDADD= $(BASE_THREAD_LIBS) $(RDL_LIBS) $(LDADDS)

+testcatalog_SOURCES=testcatalog.c
+testcatalog_DEPENDENCIES = $(DEPS)
+testcatalog_LDADD= $(LDADDS)
+
testchar_SOURCES=testchar.c
testchar_LDFLAGS =
testchar_DEPENDENCIES = $(DEPS)
@@ -198,7 +202,7 @@ runxmlconf_LDADD= $(LDADDS)
#testOOM_DEPENDENCIES = $(DEPS)
#testOOM_LDADD= $(LDADDS)

-runtests: runtest$(EXEEXT) testrecurse$(EXEEXT) testapi$(EXEEXT) \
+runtests: runtest$(EXEEXT) testrecurse$(EXEEXT) testapi$(EXEEXT) testcatalog$(EXEEXT) \
testchar$(EXEEXT) testdict$(EXEEXT) runxmlconf$(EXEEXT)
[ -d test ] || $(LN_S) $(srcdir)/test .
[ -d result ] || $(LN_S) $(srcdir)/result .
diff --git a/catalog.c b/catalog.c
index c211812..df97a67 100644
--- a/catalog.c
+++ b/catalog.c
@@ -658,43 +658,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
*/
@@ -3441,6 +3452,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 26b178d..a507a87 100644
--- a/include/libxml/catalog.h
+++ b/include/libxml/catalog.h
@@ -119,6 +119,8 @@ XMLPUBFUN void XMLCALL
#ifdef LIBXML_OUTPUT_ENABLED
XMLPUBFUN void XMLCALL
xmlCatalogDump (FILE *out);
+XMLPUBFUN xmlDocPtr
+ xmlCatalogDumpDoc (void);
#endif /* LIBXML_OUTPUT_ENABLED */
XMLPUBFUN xmlChar * XMLCALL
xmlCatalogResolve (const xmlChar *pubID,
diff --git a/test/catalogs/catalog-recursive.xml b/test/catalogs/catalog-recursive.xml
new file mode 100644
index 0000000..3b3d03f
--- /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 0000000..76d34c3
--- /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 0000000..86d33bd
--- /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
Loading
Loading