From 6ef8b9f05cc21d3fc28156fe5d1251834c29c7d7 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Thu, 28 Jul 2022 20:21:24 +0200
Subject: [PATCH] Make XPath depth check work with recursive invocations

EXSLT functions like dyn:map or dyn:evaluate invoke xmlXPathRunEval
recursively. Don't set depth to zero but keep and restore the original
value to avoid stack overflows when abusing these functions.

Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libxml2/-/commit/677a42645ef22b5a50741bad5facf9d8a8bc6d21]
CVE: CVE-2025-9714

Signed-off-by: Theo GAIGE <tgaige.opensource@witekio.com>
---
 xpath.c | 23 +++++++++++++++++------
 1 file changed, 17 insertions(+), 6 deletions(-)

diff --git a/xpath.c b/xpath.c
index c2d845888..028471d53 100644
--- a/xpath.c
+++ b/xpath.c
@@ -13883,12 +13883,11 @@ static int
 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
 {
     xmlXPathCompExprPtr comp;
+    int oldDepth;
 
     if ((ctxt == NULL) || (ctxt->comp == NULL))
 	return(-1);
 
-    ctxt->context->depth = 0;
-
     if (ctxt->valueTab == NULL) {
 	/* Allocate the value stack */
 	ctxt->valueTab = (xmlXPathObjectPtr *)
@@ -13942,11 +13941,13 @@ xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
 	    "xmlXPathRunEval: last is less than zero\n");
 	return(-1);
     }
+    oldDepth = ctxt->context->depth;
     if (toBool)
 	return(xmlXPathCompOpEvalToBoolean(ctxt,
 	    &comp->steps[comp->last], 0));
     else
 	xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
+    ctxt->context->depth = oldDepth;
 
     return(0);
 }
@@ -14217,6 +14218,7 @@ xmlXPathCompExprPtr
 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
     xmlXPathParserContextPtr pctxt;
     xmlXPathCompExprPtr comp;
+    int oldDepth = 0;
 
 #ifdef XPATH_STREAMING
     comp = xmlXPathTryStreamCompile(ctxt, str);
@@ -14230,8 +14232,10 @@ xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
     if (pctxt == NULL)
         return NULL;
     if (ctxt != NULL)
-        ctxt->depth = 0;
+        oldDepth = ctxt->depth;
     xmlXPathCompileExpr(pctxt, 1);
+    if (ctxt != NULL)
+        ctxt->depth = oldDepth;
 
     if( pctxt->error != XPATH_EXPRESSION_OK )
     {
@@ -14252,8 +14256,10 @@ xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
 	comp = pctxt->comp;
 	if ((comp->nbStep > 1) && (comp->last >= 0)) {
             if (ctxt != NULL)
-                ctxt->depth = 0;
+                oldDepth = ctxt->depth;
 	    xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
+            if (ctxt != NULL)
+                ctxt->depth = oldDepth;
 	}
 	pctxt->comp = NULL;
     }
@@ -14409,6 +14415,7 @@ xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
 #ifdef XPATH_STREAMING
     xmlXPathCompExprPtr comp;
 #endif
+    int oldDepth = 0;
 
     if (ctxt == NULL) return;
 
@@ -14422,8 +14429,10 @@ xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
 #endif
     {
         if (ctxt->context != NULL)
-            ctxt->context->depth = 0;
+            oldDepth = ctxt->context->depth;
 	xmlXPathCompileExpr(ctxt, 1);
+        if (ctxt->context != NULL)
+            ctxt->context->depth = oldDepth;
         CHECK_ERROR;
 
         /* Check for trailing characters. */
@@ -14432,9 +14441,11 @@ xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
 
 	if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
             if (ctxt->context != NULL)
-                ctxt->context->depth = 0;
+                oldDepth = ctxt->context->depth;
 	    xmlXPathOptimizeExpression(ctxt,
 		&ctxt->comp->steps[ctxt->comp->last]);
+            if (ctxt->context != NULL)
+                ctxt->context->depth = oldDepth;
         }
     }
 
-- 
2.43.0

