[libxml2] Hardcode maximum XPath recursion depth



commit 6f1470a5d6e3e369fe93f52d5760ba7c947f0cd1
Author: Nick Wellnhofer <wellnhofer aevum de>
Date:   Tue Aug 25 18:50:45 2020 +0200

    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.

 fuzz/xpath.c |  3 +--
 xpath.c      | 25 +++++++++++++++++--------
 2 files changed, 18 insertions(+), 10 deletions(-)
---
diff --git a/fuzz/xpath.c b/fuzz/xpath.c
index 097eb8ea1..767acb98b 100644
--- a/fuzz/xpath.c
+++ b/fuzz/xpath.c
@@ -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));
diff --git a/xpath.c b/xpath.c
index c018d0315..2850a1ac2 100644
--- a/xpath.c
+++ b/xpath.c
@@ -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;
     }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]