similarity index 100%
rename from meta/recipes-core/libxml/libxml2/CVE-2026-0992.patch
rename to meta/recipes-core/libxml/libxml2/CVE-2026-0992-01.patch
new file mode 100644
@@ -0,0 +1,323 @@
+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
new file mode 100644
@@ -0,0 +1,33 @@
+From deed3b7873dff30b7f87f7f33154c9932a772522 Mon Sep 17 00:00:00 2001
+From: Daniel Garcia Moreno <dani@danigm.net>
+Date: Sun, 18 Jan 2026 19:47:11 +0100
+Subject: [PATCH] catalog: Do not check value for duplication nextCatalog
+
+The value field stores the path as it appears in the catalog definition,
+the URL is built using xmlBuildURI that changes the relative paths to
+absolute.
+
+This change fixes the issue of using relative path to the same catalog
+in the same file.
+
+Fix https://gitlab.gnome.org/GNOME/libxml2/-/issues/1040
+
+CVE: CVE-2026-0992
+Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libxml2/-/commit/deed3b7873dff30b7f87f7f33154c9932a772522]
+Signed-off-by: Peter Marko <peter.marko@siemens.com>
+---
+ catalog.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/catalog.c b/catalog.c
+index eb889162..ba9ee7ae 100644
+--- a/catalog.c
++++ b/catalog.c
+@@ -1286,7 +1286,6 @@ xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer,
+ 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)
@@ -27,7 +27,9 @@ SRC_URI += "http://www.w3.org/XML/Test/xmlts20130923.tar;subdir=${BP};name=testt
file://CVE-2025-7425.patch \
file://CVE-2026-0989.patch \
file://CVE-2026-0990.patch \
- file://CVE-2026-0992.patch \
+ file://CVE-2026-0992-01.patch \
+ file://CVE-2026-0992-02.patch \
+ file://CVE-2026-0992-03.patch \
"
SRC_URI[archive.sha256sum] = "c3d8c0c34aa39098f66576fe51969db12a5100b956233dc56506f7a8679be995"