libxml2/libxml2-2.9.7-CVE-2025-9714.patch
David King a56d25ce33 Fix CVE-2025-9714 (RHEL-119279)
Resolves: RHEL-119279
2026-04-22 11:45:48 +01:00

1300 lines
45 KiB
Diff

From 497fb24df7bdced5a8548f50b7b282ec73886a51 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Tue, 12 Mar 2019 16:12:05 +0100
Subject: [PATCH 01/12] 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(-)
diff --git a/include/libxml/xpath.h b/include/libxml/xpath.h
index d96776c5..d782ab0b 100644
--- a/include/libxml/xpath.h
+++ b/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;
};
/*
diff --git a/xpath.c b/xpath.c
index 3fcdc9e1..416b837c 100644
--- a/xpath.c
+++ b/xpath.c
@@ -627,6 +627,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) / \
@@ -764,6 +765,32 @@ xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
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 *
@@ -12353,6 +12380,9 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
cur = NULL;
hasNsNodes = 0;
do {
+ if (OP_LIMIT_EXCEEDED(ctxt, 1))
+ goto error;
+
cur = next(ctxt, cur);
if (cur == NULL)
break;
@@ -12756,6 +12786,8 @@ xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
xmlXPathObjectPtr arg1, arg2;
CHECK_ERROR0;
+ if (OP_LIMIT_EXCEEDED(ctxt, 1))
+ return(0);
comp = ctxt->comp;
switch (op->op) {
case XPATH_OP_END:
@@ -12796,6 +12828,17 @@ xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
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);
@@ -12888,6 +12931,8 @@ xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
int cs;
CHECK_ERROR0;
+ if (OP_LIMIT_EXCEEDED(ctxt, 1))
+ return(0);
comp = ctxt->comp;
switch (op->op) {
case XPATH_OP_END:
@@ -12935,6 +12980,17 @@ xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
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);
@@ -13312,6 +13368,8 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
int cs;
CHECK_ERROR0;
+ if (OP_LIMIT_EXCEEDED(ctxt, 1))
+ return(0);
comp = ctxt->comp;
switch (op->op) {
case XPATH_OP_END:
@@ -13469,6 +13527,17 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
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) &&
@@ -14200,6 +14269,8 @@ xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
xmlXPathObjectPtr resObj = NULL;
start:
+ if (OP_LIMIT_EXCEEDED(ctxt, 1))
+ return(0);
/* comp = ctxt->comp; */
switch (op->op) {
case XPATH_OP_END:
@@ -14399,6 +14470,16 @@ xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
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) {
--
2.47.3
From f8abfff734d21b3b594892e0df38942a8eb07b84 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Mon, 18 Mar 2019 11:34:26 +0100
Subject: [PATCH 02/12] Optional recursion limit when evaluating XPath
expressions
Useful to avoid call stack overflows when fuzzing.
---
include/libxml/xpath.h | 5 ++-
xpath.c | 84 +++++++++++++++++++++++++++++++++++++++++-
2 files changed, 86 insertions(+), 3 deletions(-)
diff --git a/include/libxml/xpath.h b/include/libxml/xpath.h
index d782ab0b..3d9b1cee 100644
--- a/include/libxml/xpath.h
+++ b/include/libxml/xpath.h
@@ -71,7 +71,8 @@ typedef enum {
XPATH_INVALID_CTXT,
XPATH_STACK_ERROR,
XPATH_FORBID_VARIABLE_ERROR,
- XPATH_OP_LIMIT_EXCEEDED
+ XPATH_OP_LIMIT_EXCEEDED,
+ XPATH_RECURSION_LIMIT_EXCEEDED
} xmlXPathError;
/*
@@ -357,6 +358,8 @@ struct _xmlXPathContext {
/* Resource limits */
unsigned long opLimit;
unsigned long opCount;
+ int depth;
+ int maxDepth;
};
/*
diff --git a/xpath.c b/xpath.c
index 416b837c..aaa85446 100644
--- a/xpath.c
+++ b/xpath.c
@@ -628,6 +628,7 @@ static const char *xmlXPathErrorMessages[] = {
"Stack usage error\n",
"Forbidden variable\n",
"Operation limit exceeded\n",
+ "Recursion limit exceeded\n",
"?? Unknown error ??\n" /* Must be last in the list! */
};
#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
@@ -6187,6 +6188,8 @@ xmlXPathNewContext(xmlDocPtr doc) {
ret->contextSize = -1;
ret->proximityPosition = -1;
+ ret->maxDepth = INT_MAX;
+
#ifdef XP_DEFAULT_CACHE_ON
if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
xmlXPathFreeContext(ret);
@@ -12788,9 +12791,13 @@ xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
CHECK_ERROR0;
if (OP_LIMIT_EXCEEDED(ctxt, 1))
return(0);
+ if (ctxt->context->depth >= ctxt->context->maxDepth)
+ XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
+ ctxt->context->depth += 1;
comp = ctxt->comp;
switch (op->op) {
case XPATH_OP_END:
+ ctxt->context->depth -= 1;
return (0);
case XPATH_OP_UNION:
total =
@@ -12847,9 +12854,11 @@ xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
/* optimizer */
if (total > cur)
xmlXPathCompSwap(op);
+ ctxt->context->depth -= 1;
return (total + cur);
case XPATH_OP_ROOT:
xmlXPathRoot(ctxt);
+ ctxt->context->depth -= 1;
return (0);
case XPATH_OP_NODE:
if (op->ch1 != -1)
@@ -12860,6 +12869,7 @@ xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
CHECK_ERROR0;
valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
ctxt->context->node));
+ ctxt->context->depth -= 1;
return (total);
case XPATH_OP_RESET:
if (op->ch1 != -1)
@@ -12869,21 +12879,26 @@ xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
CHECK_ERROR0;
ctxt->context->node = NULL;
+ ctxt->context->depth -= 1;
return (total);
case XPATH_OP_COLLECT:{
- if (op->ch1 == -1)
+ if (op->ch1 == -1) {
+ ctxt->context->depth -= 1;
return (total);
+ }
total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
CHECK_ERROR0;
total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
+ ctxt->context->depth -= 1;
return (total);
}
case XPATH_OP_VALUE:
valuePush(ctxt,
xmlXPathCacheObjectCopy(ctxt->context,
(xmlXPathObjectPtr) op->value4));
+ ctxt->context->depth -= 1;
return (0);
case XPATH_OP_SORT:
if (op->ch1 != -1)
@@ -12896,15 +12911,21 @@ xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
&& (ctxt->value->nodesetval != NULL)
&& (ctxt->value->nodesetval->nodeNr > 1))
xmlXPathNodeSetSort(ctxt->value->nodesetval);
+ ctxt->context->depth -= 1;
return (total);
#ifdef XP_OPTIMIZED_FILTER_FIRST
case XPATH_OP_FILTER:
total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
+ ctxt->context->depth -= 1;
return (total);
#endif
default:
+ ctxt->context->depth -= 1;
return (xmlXPathCompOpEval(ctxt, op));
}
+
+ ctxt->context->depth -= 1;
+ return(total);
}
/**
@@ -12933,9 +12954,13 @@ xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
CHECK_ERROR0;
if (OP_LIMIT_EXCEEDED(ctxt, 1))
return(0);
+ if (ctxt->context->depth >= ctxt->context->maxDepth)
+ XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
+ ctxt->context->depth += 1;
comp = ctxt->comp;
switch (op->op) {
case XPATH_OP_END:
+ ctxt->context->depth -= 1;
return (0);
case XPATH_OP_UNION:
bakd = ctxt->context->doc;
@@ -12999,9 +13024,11 @@ xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
/* optimizer */
if (total > cur)
xmlXPathCompSwap(op);
+ ctxt->context->depth -= 1;
return (total + cur);
case XPATH_OP_ROOT:
xmlXPathRoot(ctxt);
+ ctxt->context->depth -= 1;
return (0);
case XPATH_OP_NODE:
if (op->ch1 != -1)
@@ -13012,6 +13039,7 @@ xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
CHECK_ERROR0;
valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
ctxt->context->node));
+ ctxt->context->depth -= 1;
return (total);
case XPATH_OP_RESET:
if (op->ch1 != -1)
@@ -13021,21 +13049,26 @@ xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
CHECK_ERROR0;
ctxt->context->node = NULL;
+ ctxt->context->depth -= 1;
return (total);
case XPATH_OP_COLLECT:{
- if (op->ch1 == -1)
+ if (op->ch1 == -1) {
+ ctxt->context->depth -= 1;
return (0);
+ }
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
CHECK_ERROR0;
total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
+ ctxt->context->depth -= 1;
return (total);
}
case XPATH_OP_VALUE:
valuePush(ctxt,
xmlXPathCacheObjectCopy(ctxt->context,
(xmlXPathObjectPtr) op->value4));
+ ctxt->context->depth -= 1;
return (0);
case XPATH_OP_SORT:
if (op->ch1 != -1)
@@ -13048,10 +13081,15 @@ xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
&& (ctxt->value->nodesetval != NULL)
&& (ctxt->value->nodesetval->nodeNr > 1))
xmlXPathNodeSetSort(ctxt->value->nodesetval);
+ ctxt->context->depth -= 1;
return (total);
default:
+ ctxt->context->depth -= 1;
return (xmlXPathCompOpEval(ctxt, op));
}
+
+ ctxt->context->depth -= 1;
+ return (total);
}
#ifdef XP_OPTIMIZED_FILTER_FIRST
@@ -13370,9 +13408,13 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
CHECK_ERROR0;
if (OP_LIMIT_EXCEEDED(ctxt, 1))
return(0);
+ if (ctxt->context->depth >= ctxt->context->maxDepth)
+ XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
+ ctxt->context->depth += 1;
comp = ctxt->comp;
switch (op->op) {
case XPATH_OP_END:
+ ctxt->context->depth -= 1;
return (0);
case XPATH_OP_AND:
bakd = ctxt->context->doc;
@@ -13383,6 +13425,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
CHECK_ERROR0;
xmlXPathBooleanFunction(ctxt, 1);
if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
+ ctxt->context->depth -= 1;
return (total);
arg2 = valuePop(ctxt);
ctxt->context->doc = bakd;
@@ -13398,6 +13441,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
if (ctxt->value != NULL)
ctxt->value->boolval &= arg2->boolval;
xmlXPathReleaseObject(ctxt->context, arg2);
+ ctxt->context->depth -= 1;
return (total);
case XPATH_OP_OR:
bakd = ctxt->context->doc;
@@ -13408,6 +13452,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
CHECK_ERROR0;
xmlXPathBooleanFunction(ctxt, 1);
if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
+ ctxt->context->depth -= 1;
return (total);
arg2 = valuePop(ctxt);
ctxt->context->doc = bakd;
@@ -13423,6 +13468,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
if (ctxt->value != NULL)
ctxt->value->boolval |= arg2->boolval;
xmlXPathReleaseObject(ctxt->context, arg2);
+ ctxt->context->depth -= 1;
return (total);
case XPATH_OP_EQUAL:
bakd = ctxt->context->doc;
@@ -13442,6 +13488,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
else
equal = xmlXPathNotEqualValues(ctxt);
valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
+ ctxt->context->depth -= 1;
return (total);
case XPATH_OP_CMP:
bakd = ctxt->context->doc;
@@ -13458,6 +13505,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
CHECK_ERROR0;
ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
+ ctxt->context->depth -= 1;
return (total);
case XPATH_OP_PLUS:
bakd = ctxt->context->doc;
@@ -13484,6 +13532,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
CAST_TO_NUMBER;
CHECK_TYPE0(XPATH_NUMBER);
}
+ ctxt->context->depth -= 1;
return (total);
case XPATH_OP_MULT:
bakd = ctxt->context->doc;
@@ -13504,6 +13553,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
xmlXPathDivValues(ctxt);
else if (op->value == 2)
xmlXPathModValues(ctxt);
+ ctxt->context->depth -= 1;
return (total);
case XPATH_OP_UNION:
bakd = ctxt->context->doc;
@@ -13549,9 +13599,11 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
valuePush(ctxt, arg1);
xmlXPathReleaseObject(ctxt->context, arg2);
+ ctxt->context->depth -= 1;
return (total);
case XPATH_OP_ROOT:
xmlXPathRoot(ctxt);
+ ctxt->context->depth -= 1;
return (total);
case XPATH_OP_NODE:
if (op->ch1 != -1)
@@ -13562,6 +13614,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
CHECK_ERROR0;
valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
ctxt->context->node));
+ ctxt->context->depth -= 1;
return (total);
case XPATH_OP_RESET:
if (op->ch1 != -1)
@@ -13571,21 +13624,25 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
CHECK_ERROR0;
ctxt->context->node = NULL;
+ ctxt->context->depth -= 1;
return (total);
case XPATH_OP_COLLECT:{
if (op->ch1 == -1)
+ ctxt->context->depth -= 1;
return (total);
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
CHECK_ERROR0;
total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
+ ctxt->context->depth -= 1;
return (total);
}
case XPATH_OP_VALUE:
valuePush(ctxt,
xmlXPathCacheObjectCopy(ctxt->context,
(xmlXPathObjectPtr) op->value4));
+ ctxt->context->depth -= 1;
return (total);
case XPATH_OP_VARIABLE:{
xmlXPathObjectPtr val;
@@ -13607,6 +13664,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
"xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
(char *) op->value4, (char *)op->value5);
ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
+ ctxt->context->depth -= 1;
return (total);
}
val = xmlXPathVariableLookupNS(ctxt->context,
@@ -13615,6 +13673,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
valuePush(ctxt, val);
}
+ ctxt->context->depth -= 1;
return (total);
}
case XPATH_OP_FUNCTION:{
@@ -13629,6 +13688,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
if (ctxt->error != XPATH_EXPRESSION_OK) {
xmlXPathPopFrame(ctxt, frame);
+ ctxt->context->depth -= 1;
return (total);
}
}
@@ -13637,6 +13697,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
"xmlXPathCompOpEval: parameter error\n");
ctxt->error = XPATH_INVALID_OPERAND;
xmlXPathPopFrame(ctxt, frame);
+ ctxt->context->depth -= 1;
return (total);
}
for (i = 0; i < op->value; i++) {
@@ -13645,6 +13706,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
"xmlXPathCompOpEval: parameter error\n");
ctxt->error = XPATH_INVALID_OPERAND;
xmlXPathPopFrame(ctxt, frame);
+ ctxt->context->depth -= 1;
return (total);
}
}
@@ -13665,6 +13727,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
(char *)op->value4, (char *)op->value5);
xmlXPathPopFrame(ctxt, frame);
ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
+ ctxt->context->depth -= 1;
return (total);
}
func = xmlXPathFunctionLookupNS(ctxt->context,
@@ -13687,6 +13750,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
ctxt->context->function = oldFunc;
ctxt->context->functionURI = oldFuncURI;
xmlXPathPopFrame(ctxt, frame);
+ ctxt->context->depth -= 1;
return (total);
}
case XPATH_OP_ARG:
@@ -13710,6 +13774,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
ctxt->context->doc = bakd;
CHECK_ERROR0;
}
+ ctxt->context->depth -= 1;
return (total);
case XPATH_OP_PREDICATE:
case XPATH_OP_FILTER:{
@@ -13763,6 +13828,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
(ctxt->value->nodesetval->nodeNr > 1))
xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
1, 1);
+ ctxt->context->depth -= 1;
return (total);
}
}
@@ -13798,6 +13864,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
(ctxt->value->nodesetval->nodeTab != NULL) &&
(ctxt->value->nodesetval->nodeNr > 1))
xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
+ ctxt->context->depth -= 1;
return (total);
}
}
@@ -13817,8 +13884,10 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
CHECK_ERROR0;
if (op->ch2 == -1)
+ ctxt->context->depth -= 1;
return (total);
if (ctxt->value == NULL)
+ ctxt->context->depth -= 1;
return (total);
oldnode = ctxt->context->node;
@@ -13854,6 +13923,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
}
valuePush(ctxt, obj);
CHECK_ERROR0;
+ ctxt->context->depth -= 1;
return (total);
}
newlocset = xmlXPtrLocationSetCreate(NULL);
@@ -13913,6 +13983,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
ctxt->context->proximityPosition = -1;
valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
ctxt->context->node = oldnode;
+ ctxt->context->depth -= 1;
return (total);
}
#endif /* LIBXML_XPTR_ENABLED */
@@ -14064,6 +14135,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
xmlXPathCacheWrapNodeSet(ctxt->context, newset));
}
ctxt->context->node = oldnode;
+ ctxt->context->depth -= 1;
return (total);
}
case XPATH_OP_SORT:
@@ -14077,6 +14149,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
{
xmlXPathNodeSetSort(ctxt->value->nodesetval);
}
+ ctxt->context->depth -= 1;
return (total);
#ifdef LIBXML_XPTR_ENABLED
case XPATH_OP_RANGETO:{
@@ -14097,6 +14170,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
XP_ERROR0(XPATH_INVALID_OPERAND);
}
if (op->ch2 == -1)
+ ctxt->context->depth -= 1;
return (total);
if (ctxt->value->type == XPATH_LOCATIONSET) {
@@ -14120,6 +14194,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
}
valuePush(ctxt, obj);
CHECK_ERROR0;
+ ctxt->context->depth -= 1;
return (total);
}
newlocset = xmlXPtrLocationSetCreate(NULL);
@@ -14243,6 +14318,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
ctxt->context->contextSize = -1;
ctxt->context->proximityPosition = -1;
valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
+ ctxt->context->depth -= 1;
return (total);
}
#endif /* LIBXML_XPTR_ENABLED */
@@ -14250,6 +14326,8 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
xmlGenericError(xmlGenericErrorContext,
"XPath: unknown precompiled operation %d\n", op->op);
ctxt->error = XPATH_INVALID_OPERAND;
+
+ ctxt->context->depth -= 1;
return (total);
}
@@ -14603,6 +14681,8 @@ xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
if ((ctxt == NULL) || (ctxt->comp == NULL))
return(-1);
+ ctxt->context->depth = 0;
+
if (ctxt->valueTab == NULL) {
/* Allocate the value stack */
ctxt->valueTab = (xmlXPathObjectPtr *)
--
2.47.3
From 732305df78d8e8491e057a014df822dff0770a20 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Sat, 20 Apr 2019 17:01:19 +0200
Subject: [PATCH 03/12] Limit recursion depth in xmlXPathOptimizeExpression
---
xpath.c | 33 +++++++++++++++++++++++++--------
1 file changed, 25 insertions(+), 8 deletions(-)
diff --git a/xpath.c b/xpath.c
index aaa85446..47f394aa 100644
--- a/xpath.c
+++ b/xpath.c
@@ -14923,8 +14923,12 @@ xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
#endif /* XPATH_STREAMING */
static void
-xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
+xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
+ xmlXPathStepOpPtr op)
{
+ xmlXPathCompExprPtr comp = pctxt->comp;
+ xmlXPathContextPtr ctxt;
+
/*
* Try to rewrite "descendant-or-self::node()/foo" to an optimized
* internal representation.
@@ -14980,10 +14984,18 @@ xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
return;
/* Recurse */
+ ctxt = pctxt->context;
+ if (ctxt != NULL) {
+ if (ctxt->depth >= ctxt->maxDepth)
+ return;
+ ctxt->depth += 1;
+ }
if (op->ch1 != -1)
- xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
+ xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
if (op->ch2 != -1)
- xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
+ xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
+ if (ctxt != NULL)
+ ctxt->depth -= 1;
}
/**
@@ -15031,6 +15043,11 @@ xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
comp = NULL;
} else {
comp = pctxt->comp;
+ if ((comp->nbStep > 1) && (comp->last >= 0)) {
+ if (ctxt != NULL)
+ ctxt->depth = 0;
+ xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
+ }
pctxt->comp = NULL;
}
xmlXPathFreeParserContext(pctxt);
@@ -15041,9 +15058,6 @@ xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
comp->string = xmlStrdup(str);
comp->nb = 0;
#endif
- if ((comp->nbStep > 1) && (comp->last >= 0)) {
- xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
- }
}
return(comp);
}
@@ -15207,9 +15221,12 @@ xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
if (*ctxt->cur != 0)
XP_ERROR(XPATH_EXPR_ERROR);
- if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0))
- xmlXPathOptimizeExpression(ctxt->comp,
+ if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
+ if (ctxt->context != NULL)
+ ctxt->context->depth = 0;
+ xmlXPathOptimizeExpression(ctxt,
&ctxt->comp->steps[ctxt->comp->last]);
+ }
}
xmlXPathRunEval(ctxt, 0);
--
2.47.3
From 65b588d99e50903504bab022e2cb94b25690113b Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Mon, 17 Aug 2020 03:37:18 +0200
Subject: [PATCH 04/12] Stop using maxParserDepth in xpath.c
Only use a single maxDepth value.
---
xpath.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/xpath.c b/xpath.c
index 47f394aa..8c0b793e 100644
--- a/xpath.c
+++ b/xpath.c
@@ -11069,6 +11069,18 @@ xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
*/
static void
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
+ xmlXPathContextPtr xpctxt = ctxt->context;
+
+ if (xpctxt != NULL) {
+ if (xpctxt->depth >= xpctxt->maxDepth)
+ XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
+ /*
+ * Parsing a single '(' pushes about 10 functions on the call stack
+ * before recursing!
+ */
+ xpctxt->depth += 10;
+ }
+
xmlXPathCompAndExpr(ctxt);
CHECK_ERROR;
SKIP_BLANKS;
--
2.47.3
From 4afa73ca76211158e6121b1849c40952e757176c Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Wed, 2 Jun 2021 17:31:49 +0200
Subject: [PATCH 05/12] Fix XPath recursion limit
Fix accounting of recursion depth when parsing XPath expressions.
This silly bug introduced in commit 804c5297 could lead to spurious
errors when parsing larger expressions or XSLT documents.
Should fix #264.
---
xpath.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/xpath.c b/xpath.c
index 8c0b793e..70dda1be 100644
--- a/xpath.c
+++ b/xpath.c
@@ -11102,6 +11102,9 @@ xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
*/
PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
}
+
+ if (xpctxt != NULL)
+ xpctxt->depth -= 10;
}
/**
--
2.47.3
From 20159ae640cef072e4838e38a9bf1791ea78db43 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Thu, 28 Jul 2022 20:21:24 +0200
Subject: [PATCH 06/12] 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.
---
xpath.c | 23 +++++++++++++++++++----
1 file changed, 19 insertions(+), 4 deletions(-)
diff --git a/xpath.c b/xpath.c
index 70dda1be..b16ae0f8 100644
--- a/xpath.c
+++ b/xpath.c
@@ -14692,12 +14692,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 *)
@@ -14751,11 +14750,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);
}
@@ -15027,6 +15028,7 @@ xmlXPathCompExprPtr
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
xmlXPathParserContextPtr pctxt;
xmlXPathCompExprPtr comp;
+ int oldDepth = 0;
#ifdef XPATH_STREAMING
comp = xmlXPathTryStreamCompile(ctxt, str);
@@ -15039,7 +15041,11 @@ xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
pctxt = xmlXPathNewParserContext(str, ctxt);
if (pctxt == NULL)
return NULL;
+ if (ctxt != NULL)
+ oldDepth = ctxt->depth;
xmlXPathCompileExpr(pctxt, 1);
+ if (ctxt != NULL)
+ ctxt->depth = oldDepth;
if( pctxt->error != XPATH_EXPRESSION_OK )
{
@@ -15060,8 +15066,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;
}
@@ -15217,6 +15225,7 @@ xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
#ifdef XPATH_STREAMING
xmlXPathCompExprPtr comp;
#endif
+ int oldDepth = 0;
if (ctxt == NULL) return;
@@ -15229,7 +15238,11 @@ xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
} else
#endif
{
+ if (ctxt->context != NULL)
+ oldDepth = ctxt->context->depth;
xmlXPathCompileExpr(ctxt, 1);
+ if (ctxt->context != NULL)
+ ctxt->context->depth = oldDepth;
CHECK_ERROR;
/* Check for trailing characters. */
@@ -15238,9 +15251,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.47.3
From 293505285f50bb9c3e69ffa7fa49c1f25512eb09 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Fri, 13 Sep 2024 20:59:47 +0200
Subject: [PATCH 07/12] xpath: Make recursion check work with xmlXPathCompile
The check for maximum recursion depth required a parser context with an
xmlXPathContext which xmlXPathCompile didn't provide.
All other code should already set up or require an xmlXPathContext.
---
xpath.c | 27 ++++++++++++++++++++++-----
1 file changed, 22 insertions(+), 5 deletions(-)
diff --git a/xpath.c b/xpath.c
index b16ae0f8..bca0ba77 100644
--- a/xpath.c
+++ b/xpath.c
@@ -15027,6 +15027,7 @@ xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
xmlXPathCompExprPtr
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
xmlXPathParserContextPtr pctxt;
+ xmlXPathContextPtr tmpctxt = NULL;
xmlXPathCompExprPtr comp;
int oldDepth = 0;
@@ -15038,18 +15039,32 @@ xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
xmlXPathInit();
+ /*
+ * We need an xmlXPathContext for the depth check.
+ */
+ if (ctxt == NULL) {
+ tmpctxt = xmlXPathNewContext(NULL);
+ if (tmpctxt == NULL)
+ return(NULL);
+ ctxt = tmpctxt;
+ }
+
pctxt = xmlXPathNewParserContext(str, ctxt);
- if (pctxt == NULL)
+ if (pctxt == NULL) {
+ if (tmpctxt != NULL)
+ xmlXPathFreeContext(tmpctxt);
return NULL;
- if (ctxt != NULL)
- oldDepth = ctxt->depth;
+ }
+
+ oldDepth = ctxt->depth;
xmlXPathCompileExpr(pctxt, 1);
- if (ctxt != NULL)
- ctxt->depth = oldDepth;
+ ctxt->depth = oldDepth;
if( pctxt->error != XPATH_EXPRESSION_OK )
{
xmlXPathFreeParserContext(pctxt);
+ if (tmpctxt != NULL)
+ xmlXPathFreeContext(tmpctxt);
return(NULL);
}
@@ -15074,6 +15089,8 @@ xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
pctxt->comp = NULL;
}
xmlXPathFreeParserContext(pctxt);
+ if (tmpctxt != NULL)
+ xmlXPathFreeContext(tmpctxt);
if (comp != NULL) {
comp->expr = xmlStrdup(str);
--
2.47.3
From 0afa658c7820cf32d5d880a4b3f4eb9ea95898b4 Mon Sep 17 00:00:00 2001
From: RHEL Packaging Agent <jotnar@redhat.com>
Date: Tue, 18 Nov 2025 14:20:08 +0000
Subject: [PATCH 08/12] xpath: Fix depth restoration in xmlXPathRunEval
Ensure that the depth is always restored in xmlXPathRunEval, even when
toBool is true or when an error occurs. This prevents depth from
accumulating incorrectly across XPath evaluations.
---
xpath.c | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/xpath.c b/xpath.c
index bca0ba77..90d624a2 100644
--- a/xpath.c
+++ b/xpath.c
@@ -14751,12 +14751,15 @@ xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
return(-1);
}
oldDepth = ctxt->context->depth;
- if (toBool)
- return(xmlXPathCompOpEvalToBoolean(ctxt,
- &comp->steps[comp->last], 0));
- else
+ if (toBool) {
+ int ret = xmlXPathCompOpEvalToBoolean(ctxt,
+ &comp->steps[comp->last], 0);
+ ctxt->context->depth = oldDepth;
+ return(ret);
+ } else {
xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
- ctxt->context->depth = oldDepth;
+ ctxt->context->depth = oldDepth;
+ }
return(0);
}
--
2.47.3
From e0315a0e773982b10220cfbad25b92bc97119d80 Mon Sep 17 00:00:00 2001
From: RHEL Packaging Agent <jotnar@redhat.com>
Date: Tue, 18 Nov 2025 14:33:12 +0000
Subject: [PATCH 09/12] Revert incorrect depth restoration in toBool branch
The manual fix that added depth restoration to the toBool branch of
xmlXPathRunEval was incorrect. The toBool branch should return directly
from xmlXPathCompOpEvalToBoolean without restoring depth, as
xmlXPathCompOpEvalToBoolean either doesn't modify depth or calls
xmlXPathCompOpEval which properly manages depth internally.
This matches the implementation in upstream master branch.
---
xpath.c | 13 +++++--------
1 file changed, 5 insertions(+), 8 deletions(-)
diff --git a/xpath.c b/xpath.c
index 90d624a2..bca0ba77 100644
--- a/xpath.c
+++ b/xpath.c
@@ -14751,15 +14751,12 @@ xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
return(-1);
}
oldDepth = ctxt->context->depth;
- if (toBool) {
- int ret = xmlXPathCompOpEvalToBoolean(ctxt,
- &comp->steps[comp->last], 0);
- ctxt->context->depth = oldDepth;
- return(ret);
- } else {
+ if (toBool)
+ return(xmlXPathCompOpEvalToBoolean(ctxt,
+ &comp->steps[comp->last], 0));
+ else
xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
- ctxt->context->depth = oldDepth;
- }
+ ctxt->context->depth = oldDepth;
return(0);
}
--
2.47.3
From cb9a07705374ae359bddde2ed7f8a578b2315e93 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Wed, 8 May 2019 12:00:51 +0200
Subject: [PATCH 10/12] Limit recursion depth in xmlXPathCompOpEvalPredicate
---
xpath.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/xpath.c b/xpath.c
index bca0ba77..9406d05f 100644
--- a/xpath.c
+++ b/xpath.c
@@ -11740,8 +11740,12 @@ xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
* TODO: raise an internal error.
*/
}
+ if (ctxt->context->depth >= ctxt->context->maxDepth)
+ XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
+ ctxt->context->depth += 1;
contextSize = xmlXPathCompOpEvalPredicate(ctxt,
&comp->steps[op->ch1], set, contextSize, hasNsNodes);
+ ctxt->context->depth -= 1;
CHECK_ERROR0;
if (contextSize <= 0)
return(0);
--
2.47.3
From 0e1013a03a95d5791ace90fd072a72f85ee82676 Mon Sep 17 00:00:00 2001
From: RHEL Packaging Agent <jotnar@redhat.com>
Date: Tue, 18 Nov 2025 15:03:03 +0000
Subject: [PATCH 11/12] Fix missing braces in XPATH_OP_AND and XPATH_OP_OR
cases
The depth decrement and return statement must be inside the if block,
otherwise depth is not decremented when the condition is false, causing
depth to accumulate and eventually exceed the limit.
This fixes test failures where XPath evaluation was failing with
'Error: unable to evaluate xpath expression'.
---
xpath.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/xpath.c b/xpath.c
index 9406d05f..691cbd02 100644
--- a/xpath.c
+++ b/xpath.c
@@ -13443,9 +13443,10 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
CHECK_ERROR0;
xmlXPathBooleanFunction(ctxt, 1);
- if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
+ if ((ctxt->value == NULL) || (ctxt->value->boolval == 0)) {
ctxt->context->depth -= 1;
return (total);
+ }
arg2 = valuePop(ctxt);
ctxt->context->doc = bakd;
ctxt->context->node = bak;
@@ -13470,9 +13471,10 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
CHECK_ERROR0;
xmlXPathBooleanFunction(ctxt, 1);
- if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
+ if ((ctxt->value == NULL) || (ctxt->value->boolval == 1)) {
ctxt->context->depth -= 1;
return (total);
+ }
arg2 = valuePop(ctxt);
ctxt->context->doc = bakd;
ctxt->context->node = bak;
--
2.47.3
From 368c7c8da85446ca7ba3ddb1cc7f2ed3a3b36865 Mon Sep 17 00:00:00 2001
From: RHEL Packaging Agent <jotnar@redhat.com>
Date: Tue, 18 Nov 2025 15:13:35 +0000
Subject: [PATCH 12/12] Fix missing braces in XPATH_OP_COLLECT,
XPATH_OP_PREDICATE/FILTER, and XPATH_OP_RANGETO cases
The depth decrement and return statement must be inside the if block,
otherwise depth is not decremented when the condition is false, causing
depth to accumulate and eventually exceed the limit.
This fixes test failures where XPath evaluation was failing with
'Error: unable to evaluate xpath expression'.
---
xpath.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/xpath.c b/xpath.c
index 691cbd02..07685880 100644
--- a/xpath.c
+++ b/xpath.c
@@ -13648,9 +13648,10 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
ctxt->context->depth -= 1;
return (total);
case XPATH_OP_COLLECT:{
- if (op->ch1 == -1)
+ if (op->ch1 == -1) {
ctxt->context->depth -= 1;
return (total);
+ }
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
CHECK_ERROR0;
@@ -13904,12 +13905,14 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
total +=
xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
CHECK_ERROR0;
- if (op->ch2 == -1)
+ if (op->ch2 == -1) {
ctxt->context->depth -= 1;
return (total);
- if (ctxt->value == NULL)
+ }
+ if (ctxt->value == NULL) {
ctxt->context->depth -= 1;
return (total);
+ }
oldnode = ctxt->context->node;
@@ -14190,9 +14193,10 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
if (ctxt->value == NULL) {
XP_ERROR0(XPATH_INVALID_OPERAND);
}
- if (op->ch2 == -1)
+ if (op->ch2 == -1) {
ctxt->context->depth -= 1;
return (total);
+ }
if (ctxt->value->type == XPATH_LOCATIONSET) {
/*
--
2.47.3