File libxml2-CVE-2025-9714-0.patch of Package libxml2.41582

From 852c93a2dc2224f020aab55a9702f992db404836 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Tue, 12 Mar 2019 16:12:05 +0100
Subject: [PATCH] Optional XPath operation limit

Optionally limit the maximum numbers of XPath operations when evaluating
an expression. Useful to avoid timeouts when fuzzing. The following
operations count towards the limit:

- XPath operations
- Location step iterations
- Union operations

Enabled by setting opLimit to a non-zero value. Note that it's the user's
responsibility to reset opCount. This allows to enforce the operation
limit across multiple reuses of an XPath context.
---
 include/libxml/xpath.h |  7 +++-
 xpath.c                | 81 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 87 insertions(+), 1 deletion(-)

Index: libxml2-2.9.7/include/libxml/xpath.h
===================================================================
--- libxml2-2.9.7.orig/include/libxml/xpath.h
+++ libxml2-2.9.7/include/libxml/xpath.h
@@ -70,7 +70,8 @@ typedef enum {
     XPATH_INVALID_CHAR_ERROR,
     XPATH_INVALID_CTXT,
     XPATH_STACK_ERROR,
-    XPATH_FORBID_VARIABLE_ERROR
+    XPATH_FORBID_VARIABLE_ERROR,
+    XPATH_OP_LIMIT_EXCEEDED
 } xmlXPathError;
 
 /*
@@ -352,6 +353,10 @@ struct _xmlXPathContext {
 
     /* Cache for reusal of XPath objects */
     void *cache;
+
+    /* Resource limits */
+    unsigned long opLimit;
+    unsigned long opCount;
 };
 
 /*
Index: libxml2-2.9.7/xpath.c
===================================================================
--- libxml2-2.9.7.orig/xpath.c
+++ libxml2-2.9.7/xpath.c
@@ -645,6 +645,7 @@ static const char *xmlXPathErrorMessages
     "Invalid or incomplete context\n",
     "Stack usage error\n",
     "Forbidden variable\n",
+    "Operation limit exceeded\n",
     "?? Unknown error ??\n"	/* Must be last in the list! */
 };
 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /	\
@@ -782,6 +783,32 @@ xmlXPatherror(xmlXPathParserContextPtr c
     xmlXPathErr(ctxt, no);
 }
 
+/**
+ * xmlXPathCheckOpLimit:
+ * @ctxt:  the XPath Parser context
+ * @opCount:  the number of operations to be added
+ *
+ * Adds opCount to the running total of operations and returns -1 if the
+ * operation limit is exceeded. Returns 0 otherwise.
+ */
+static int
+xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
+    xmlXPathContextPtr xpctxt = ctxt->context;
+
+    if ((opCount > xpctxt->opLimit) ||
+        (xpctxt->opCount > xpctxt->opLimit - opCount)) {
+        xpctxt->opCount = xpctxt->opLimit;
+        xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
+        return(-1);
+    }
+
+    xpctxt->opCount += opCount;
+    return(0);
+}
+
+#define OP_LIMIT_EXCEEDED(ctxt, n) \
+    ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
+
 /************************************************************************
  *									*
  *			Utilities					*
@@ -12371,6 +12398,9 @@ xmlXPathNodeCollectAndTest(xmlXPathParse
 	cur = NULL;
 	hasNsNodes = 0;
         do {
+            if (OP_LIMIT_EXCEEDED(ctxt, 1))
+                goto error;
+
             cur = next(ctxt, cur);
             if (cur == NULL)
                 break;
@@ -12774,6 +12804,8 @@ xmlXPathCompOpEvalFirst(xmlXPathParserCo
     xmlXPathObjectPtr arg1, arg2;
 
     CHECK_ERROR0;
+    if (OP_LIMIT_EXCEEDED(ctxt, 1))
+        return(0);
     comp = ctxt->comp;
     switch (op->op) {
         case XPATH_OP_END:
@@ -12814,6 +12846,17 @@ xmlXPathCompOpEvalFirst(xmlXPathParserCo
 	        xmlXPathReleaseObject(ctxt->context, arg2);
                 XP_ERROR0(XPATH_INVALID_TYPE);
             }
+            if ((ctxt->context->opLimit != 0) &&
+                (((arg1->nodesetval != NULL) &&
+                  (xmlXPathCheckOpLimit(ctxt,
+                                        arg1->nodesetval->nodeNr) < 0)) ||
+                 ((arg2->nodesetval != NULL) &&
+                  (xmlXPathCheckOpLimit(ctxt,
+                                        arg2->nodesetval->nodeNr) < 0)))) {
+	        xmlXPathReleaseObject(ctxt->context, arg1);
+	        xmlXPathReleaseObject(ctxt->context, arg2);
+                return(0);
+            }
 
             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
                                                     arg2->nodesetval);
@@ -12906,6 +12949,8 @@ xmlXPathCompOpEvalLast(xmlXPathParserCon
     int cs;
 
     CHECK_ERROR0;
+    if (OP_LIMIT_EXCEEDED(ctxt, 1))
+        return(0);
     comp = ctxt->comp;
     switch (op->op) {
         case XPATH_OP_END:
@@ -12953,6 +12998,17 @@ xmlXPathCompOpEvalLast(xmlXPathParserCon
 	        xmlXPathReleaseObject(ctxt->context, arg2);
                 XP_ERROR0(XPATH_INVALID_TYPE);
             }
+            if ((ctxt->context->opLimit != 0) &&
+                (((arg1->nodesetval != NULL) &&
+                  (xmlXPathCheckOpLimit(ctxt,
+                                        arg1->nodesetval->nodeNr) < 0)) ||
+                 ((arg2->nodesetval != NULL) &&
+                  (xmlXPathCheckOpLimit(ctxt,
+                                        arg2->nodesetval->nodeNr) < 0)))) {
+	        xmlXPathReleaseObject(ctxt->context, arg1);
+	        xmlXPathReleaseObject(ctxt->context, arg2);
+                return(0);
+            }
 
             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
                                                     arg2->nodesetval);
@@ -13330,6 +13386,8 @@ xmlXPathCompOpEval(xmlXPathParserContext
     int cs;
 
     CHECK_ERROR0;
+    if (OP_LIMIT_EXCEEDED(ctxt, 1))
+        return(0);
     comp = ctxt->comp;
     switch (op->op) {
         case XPATH_OP_END:
@@ -13487,6 +13545,17 @@ xmlXPathCompOpEval(xmlXPathParserContext
 	        xmlXPathReleaseObject(ctxt->context, arg2);
                 XP_ERROR0(XPATH_INVALID_TYPE);
             }
+            if ((ctxt->context->opLimit != 0) &&
+                (((arg1->nodesetval != NULL) &&
+                  (xmlXPathCheckOpLimit(ctxt,
+                                        arg1->nodesetval->nodeNr) < 0)) ||
+                 ((arg2->nodesetval != NULL) &&
+                  (xmlXPathCheckOpLimit(ctxt,
+                                        arg2->nodesetval->nodeNr) < 0)))) {
+	        xmlXPathReleaseObject(ctxt->context, arg1);
+	        xmlXPathReleaseObject(ctxt->context, arg2);
+                return(0);
+            }
 
 	    if ((arg1->nodesetval == NULL) ||
 		((arg2->nodesetval != NULL) &&
@@ -14218,6 +14287,8 @@ xmlXPathCompOpEvalToBoolean(xmlXPathPars
     xmlXPathObjectPtr resObj = NULL;
 
 start:
+    if (OP_LIMIT_EXCEEDED(ctxt, 1))
+        return(0);
     /* comp = ctxt->comp; */
     switch (op->op) {
         case XPATH_OP_END:
@@ -14417,6 +14488,16 @@ xmlXPathRunStreamEval(xmlXPathContextPtr
     goto scan_children;
 next_node:
     do {
+        if (ctxt->opLimit != 0) {
+            if (ctxt->opCount >= ctxt->opLimit) {
+                xmlGenericError(xmlGenericErrorContext,
+                        "XPath operation limit exceeded\n");
+                xmlFreeStreamCtxt(patstream);
+                return(-1);
+            }
+            ctxt->opCount++;
+        }
+
         nb_nodes++;
 
 	switch (cur->type) {
openSUSE Build Service is sponsored by