1
0
mirror of https://gitlab.gnome.org/GNOME/libxml2.git synced 2025-03-19 14:50:07 +03:00

Hardcode maximum XPath recursion depth

Always limit nested functions calls to 5000. This avoids call stack
overflows with deeply nested expressions.

The expression parser produces about 10 nested function calls when
parsing a subexpression in parentheses, so the effective nesting limit
is about 500 which should be more than enough.

Use a lower limit when fuzzing to account for increased memory usage
when using sanitizers.
This commit is contained in:
Nick Wellnhofer 2020-08-25 18:50:45 +02:00
parent 8c3ef083ca
commit 6f1470a5d6
2 changed files with 18 additions and 10 deletions

View File

@ -33,8 +33,7 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) {
if (doc != NULL) {
xmlXPathContextPtr xpctxt = xmlXPathNewContext(doc);
/* Resource limits to avoid timeouts and call stack overflows */
xpctxt->maxDepth = 500;
/* Operation limit to avoid timeout */
xpctxt->opLimit = 500000;
xmlXPathFreeObject(xmlXPtrEval(BAD_CAST expr, xpctxt));

25
xpath.c
View File

@ -135,6 +135,17 @@
*/
#define XPATH_MAX_NODESET_LENGTH 10000000
/*
* XPATH_MAX_RECRUSION_DEPTH:
* Maximum amount of nested functions calls when parsing or evaluating
* expressions
*/
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
#define XPATH_MAX_RECURSION_DEPTH 500
#else
#define XPATH_MAX_RECURSION_DEPTH 5000
#endif
/*
* TODO:
* There are a few spots where some tests are done which depend upon ascii
@ -6118,8 +6129,6 @@ 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);
@ -10947,7 +10956,7 @@ xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
xmlXPathContextPtr xpctxt = ctxt->context;
if (xpctxt != NULL) {
if (xpctxt->depth >= xpctxt->maxDepth)
if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
/*
* Parsing a single '(' pushes about 10 functions on the call stack
@ -11883,7 +11892,7 @@ xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
"xmlXPathCompOpEvalPredicate: Expected a predicate\n");
XP_ERROR(XPATH_INVALID_OPERAND);
}
if (ctxt->context->depth >= ctxt->context->maxDepth)
if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
ctxt->context->depth += 1;
xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
@ -12599,7 +12608,7 @@ xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
CHECK_ERROR0;
if (OP_LIMIT_EXCEEDED(ctxt, 1))
return(0);
if (ctxt->context->depth >= ctxt->context->maxDepth)
if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
ctxt->context->depth += 1;
comp = ctxt->comp;
@ -12740,7 +12749,7 @@ xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
CHECK_ERROR0;
if (OP_LIMIT_EXCEEDED(ctxt, 1))
return(0);
if (ctxt->context->depth >= ctxt->context->maxDepth)
if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
ctxt->context->depth += 1;
comp = ctxt->comp;
@ -12958,7 +12967,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
CHECK_ERROR0;
if (OP_LIMIT_EXCEEDED(ctxt, 1))
return(0);
if (ctxt->context->depth >= ctxt->context->maxDepth)
if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
ctxt->context->depth += 1;
comp = ctxt->comp;
@ -14192,7 +14201,7 @@ xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
/* Recurse */
ctxt = pctxt->context;
if (ctxt != NULL) {
if (ctxt->depth >= ctxt->maxDepth)
if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
return;
ctxt->depth += 1;
}