We have some news to share for the request index beta feature. We’ve added more options to sort your requests, counters to the individual filters and documentation for the search functionality. Checkout the blog post for more details.

File libxml2-CVE-2026-0989.patch of Package libxml2.42407

From 19549c61590c1873468c53e0026a2fbffae428ef Mon Sep 17 00:00:00 2001
From: Daniel Garcia Moreno <daniel.garcia@suse.com>
Date: Fri, 10 Oct 2025 09:38:31 +0200
Subject: [PATCH] Add RelaxNG include limit

This patch adds a default xmlRelaxNGIncludeLimit of 1.000, and that
limit can be modified at runtime with the env variable
RNG_INCLUDE_LIMIT.

Fix https://gitlab.gnome.org/GNOME/libxml2/-/issues/998
---
 include/libxml/relaxng.h                 |  4 ++
 relaxng.c                                | 63 ++++++++++++++++++++--
 runtest.c                                | 67 ++++++++++++++++++++++++
 test/relaxng/include/include-limit.rng   |  4 ++
 test/relaxng/include/include-limit_1.rng |  4 ++
 test/relaxng/include/include-limit_2.rng |  4 ++
 test/relaxng/include/include-limit_3.rng |  8 +++
 7 files changed, 150 insertions(+), 4 deletions(-)
 create mode 100644 test/relaxng/include/include-limit.rng
 create mode 100644 test/relaxng/include/include-limit_1.rng
 create mode 100644 test/relaxng/include/include-limit_2.rng
 create mode 100644 test/relaxng/include/include-limit_3.rng

Index: libxml2-2.9.4/include/libxml/relaxng.h
===================================================================
--- libxml2-2.9.4.orig/include/libxml/relaxng.h
+++ libxml2-2.9.4/include/libxml/relaxng.h
@@ -136,6 +136,10 @@ XMLPUBFUN int XMLCALL
 		    xmlRelaxParserSetFlag	(xmlRelaxNGParserCtxtPtr ctxt,
 						 int flag);
 
+XMLPUBFUN int XMLCALL
+		    xmlRelaxParserSetIncLImit	(xmlRelaxNGParserCtxt *ctxt,
+						 int limit);
+
 XMLPUBFUN void XMLCALL
 		    xmlRelaxNGFreeParserCtxt	(xmlRelaxNGParserCtxtPtr ctxt);
 XMLPUBFUN void XMLCALL
Index: libxml2-2.9.4/relaxng.c
===================================================================
--- libxml2-2.9.4.orig/relaxng.c
+++ libxml2-2.9.4/relaxng.c
@@ -18,6 +18,8 @@
 
 #ifdef LIBXML_SCHEMAS_ENABLED
 
+#include <errno.h>
+#include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
 #include <libxml/xmlmemory.h>
@@ -39,6 +41,12 @@
 static const xmlChar *xmlRelaxNGNs = (const xmlChar *)
     "http://relaxng.org/ns/structure/1.0";
 
+/*
+ * Default include limit, this can be override with RNG_INCLUDE_LIMIT
+ * env variable
+ */
+static const int _xmlRelaxNGIncludeLimit = 1000;
+
 #define IS_RELAXNG(node, typ)						\
    ((node != NULL) && (node->ns != NULL) &&				\
     (node->type == XML_ELEMENT_NODE) &&					\
@@ -244,6 +252,7 @@ struct _xmlRelaxNGParserCtxt {
     int incNr;                  /* Depth of the include parsing stack */
     int incMax;                 /* Max depth of the parsing stack */
     xmlRelaxNGIncludePtr *incTab;       /* array of incs */
+    int incLimit;               /* Include limit, to avoid stack-overflow on parse */
 
     int idref;                  /* requires idref checking */
 
@@ -1429,6 +1438,23 @@ xmlRelaxParserSetFlag(xmlRelaxNGParserCt
     return(0);
 }
 
+/**
+ * Semi private function used to set the include recursion limit to a
+ * parser context. Set to 0 to use the default value.
+ *
+ * @param ctxt  a RelaxNG parser context
+ * @param limit the new include depth limit
+ * @returns 0 if success and -1 in case of error
+ */
+int
+xmlRelaxParserSetIncLImit(xmlRelaxNGParserCtxt *ctxt, int limit)
+{
+    if (ctxt == NULL) return(-1);
+    if (limit < 0) return(-1);
+    ctxt->incLimit = limit;
+    return(0);
+}
+
 /************************************************************************
  *									*
  *			Document functions				*
@@ -1444,7 +1470,7 @@ static xmlDocPtr xmlRelaxNGCleanupDoc(xm
  *
  * Pushes a new include on top of the include stack
  *
- * Returns 0 in case of error, the index in the stack otherwise
+ * @returns -1 in case of error, the index in the stack otherwise
  */
 static int
 xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt,
@@ -1458,9 +1484,15 @@ xmlRelaxNGIncludePush(xmlRelaxNGParserCt
                                                sizeof(ctxt->incTab[0]));
         if (ctxt->incTab == NULL) {
             xmlRngPErrMemory(ctxt, "allocating include\n");
-            return (0);
+            return (-1);
         }
     }
+    if (ctxt->incNr >= ctxt->incLimit) {
+        xmlRngPErr(ctxt, (xmlNodePtr)value->doc, XML_RNGP_PARSE_ERROR,
+                   "xmlRelaxNG: inclusion recursion limit reached\n", NULL, NULL);
+        return(-1);
+    }
+
     if (ctxt->incNr >= ctxt->incMax) {
         ctxt->incMax *= 2;
         ctxt->incTab =
@@ -1469,7 +1501,7 @@ xmlRelaxNGIncludePush(xmlRelaxNGParserCt
                                                 sizeof(ctxt->incTab[0]));
         if (ctxt->incTab == NULL) {
             xmlRngPErrMemory(ctxt, "allocating include\n");
-            return (0);
+            return (-1);
         }
     }
     ctxt->incTab[ctxt->incNr] = value;
@@ -1660,7 +1692,9 @@ xmlRelaxNGLoadInclude(xmlRelaxNGParserCt
     /*
      * push it on the stack
      */
-    xmlRelaxNGIncludePush(ctxt, ret);
+    if (xmlRelaxNGIncludePush(ctxt, ret) < 0) {
+        return (NULL);
+    }
 
     /*
      * Some preprocessing of the document content, this include recursing
@@ -7477,11 +7511,32 @@ xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr
     xmlDocPtr doc;
     xmlNodePtr root;
 
+    const char *include_limit_env = getenv("RNG_INCLUDE_LIMIT");
+
     xmlRelaxNGInitTypes();
 
     if (ctxt == NULL)
         return (NULL);
 
+    if (ctxt->incLimit == 0) {
+        ctxt->incLimit = _xmlRelaxNGIncludeLimit;
+        if (include_limit_env != NULL) {
+            char *strEnd;
+            unsigned long val = 0;
+            errno = 0;
+            val = strtoul(include_limit_env, &strEnd, 10);
+            if (errno != 0 || *strEnd != 0 || val > INT_MAX) {
+                xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
+                           "xmlRelaxNGParse: invalid RNG_INCLUDE_LIMIT %s\n",
+                           (const xmlChar*)include_limit_env,
+                           NULL);
+                return(NULL);
+            }
+            if (val)
+                ctxt->incLimit = val;
+        }
+    }
+
     /*
      * First step is to parse the input document into an DOM/Infoset
      */
Index: libxml2-2.9.4/runtest.c
===================================================================
--- libxml2-2.9.4.orig/runtest.c
+++ libxml2-2.9.4/runtest.c
@@ -3278,6 +3278,70 @@ rngTest(const char *filename,
     return(ret);
 }
 
+/**
+ * Parse an RNG schemas with a custom RNG_INCLUDE_LIMIT
+ *
+ * @param filename  the schemas file
+ * @param result  the file with expected result
+ * @param err  the file with error messages
+ * @returns 0 in case of success, an error code otherwise
+ */
+static int
+rngIncludeTest(const char *filename,
+               const char *resul ATTRIBUTE_UNUSED,
+               const char *errr ATTRIBUTE_UNUSED,
+               int options ATTRIBUTE_UNUSED) {
+    xmlRelaxNGParserCtxtPtr ctxt;
+    xmlRelaxNGPtr schemas;
+    int ret = 0;
+
+    /* first compile the schemas if possible */
+    ctxt = xmlRelaxNGNewParserCtxt(filename);
+    xmlRelaxNGSetParserStructuredErrors(ctxt, testStructuredErrorHandler,
+                                        NULL);
+
+    /* Should work */
+    schemas = xmlRelaxNGParse(ctxt);
+    if (schemas == NULL) {
+        testErrorHandler(NULL, "Relax-NG schema %s failed to compile\n",
+                         filename);
+        ret = -1;
+        goto done;
+    }
+    xmlRelaxNGFree(schemas);
+    xmlRelaxNGFreeParserCtxt(ctxt);
+
+    ctxt = xmlRelaxNGNewParserCtxt(filename);
+    /* Should fail */
+    xmlRelaxParserSetIncLImit(ctxt, 2);
+    xmlRelaxNGSetParserStructuredErrors(ctxt, testStructuredErrorHandler,
+                                        NULL);
+    schemas = xmlRelaxNGParse(ctxt);
+    if (schemas != NULL) {
+        ret = -1;
+        xmlRelaxNGFree(schemas);
+    }
+    xmlRelaxNGFreeParserCtxt(ctxt);
+
+    ctxt = xmlRelaxNGNewParserCtxt(filename);
+    /* Should work */
+    xmlRelaxParserSetIncLImit(ctxt, 3);
+    xmlRelaxNGSetParserStructuredErrors(ctxt, testStructuredErrorHandler,
+                                        NULL);
+    schemas = xmlRelaxNGParse(ctxt);
+    if (schemas == NULL) {
+        testErrorHandler(NULL, "Relax-NG schema %s failed to compile\n",
+                         filename);
+        ret = -1;
+        goto done;
+    }
+    xmlRelaxNGFree(schemas);
+
+done:
+    xmlRelaxNGFreeParserCtxt(ctxt);
+    return(ret);
+}
+
 #ifdef LIBXML_READER_ENABLED
 /**
  * rngStreamTest:
@@ -4325,6 +4389,9 @@ testDesc testDescriptions[] = {
     { "Relax-NG regression tests" ,
       rngTest, "./test/relaxng/*.rng", NULL, NULL, NULL,
       XML_PARSE_DTDATTR | XML_PARSE_NOENT },
+    { "Relax-NG include limit tests" ,
+      rngIncludeTest, "./test/relaxng/include/include-limit.rng", NULL, NULL, NULL,
+      0 },
 #ifdef LIBXML_READER_ENABLED
     { "Relax-NG streaming regression tests" ,
       rngStreamTest, "./test/relaxng/*.rng", NULL, NULL, NULL,
Index: libxml2-2.9.4/test/relaxng/include/include-limit.rng
===================================================================
--- /dev/null
+++ libxml2-2.9.4/test/relaxng/include/include-limit.rng
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<grammar xmlns="http://relaxng.org/ns/structure/1.0">
+    <include href="include-limit_1.rng"/>
+</grammar>
Index: libxml2-2.9.4/test/relaxng/include/include-limit_1.rng
===================================================================
--- /dev/null
+++ libxml2-2.9.4/test/relaxng/include/include-limit_1.rng
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<grammar xmlns="http://relaxng.org/ns/structure/1.0">
+    <include href="include-limit_2.rng"/>
+</grammar>
Index: libxml2-2.9.4/test/relaxng/include/include-limit_2.rng
===================================================================
--- /dev/null
+++ libxml2-2.9.4/test/relaxng/include/include-limit_2.rng
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<grammar xmlns="http://relaxng.org/ns/structure/1.0">
+    <include href="include-limit_3.rng"/>
+</grammar>
Index: libxml2-2.9.4/test/relaxng/include/include-limit_3.rng
===================================================================
--- /dev/null
+++ libxml2-2.9.4/test/relaxng/include/include-limit_3.rng
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<grammar xmlns="http://relaxng.org/ns/structure/1.0">
+    <start>
+        <element name="root">
+            <empty/>
+        </element>
+    </start>
+</grammar>
openSUSE Build Service is sponsored by