[libxml2] Optional recursion limit when evaluating XPath expressions



commit 64115ed62dd01dab81a9157a54738523fe117333
Author: Nick Wellnhofer <wellnhofer aevum de>
Date:   Mon Mar 18 11:34:26 2019 +0100

    Optional recursion limit when evaluating XPath expressions
    
    Useful to avoid call stack overflows when fuzzing.

 include/libxml/xpath.h |  5 ++++-
 xpath.c                | 17 +++++++++++++++++
 2 files changed, 21 insertions(+), 1 deletion(-)
---
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 ce2b437d..993e016f 100644
--- a/xpath.c
+++ b/xpath.c
@@ -611,6 +611,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) /        \
@@ -6180,6 +6181,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);
@@ -12724,6 +12727,9 @@ 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:
@@ -12835,6 +12841,7 @@ xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
             break;
     }
 
+    ctxt->context->depth -= 1;
     return(total);
 }
 
@@ -12860,6 +12867,9 @@ 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:
@@ -12965,6 +12975,7 @@ xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
             break;
     }
 
+    ctxt->context->depth -= 1;
     return (total);
 }
 
@@ -13257,6 +13268,9 @@ 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:
@@ -14028,6 +14042,7 @@ rangeto_error:
             break;
     }
 
+    ctxt->context->depth -= 1;
     return (total);
 }
 
@@ -14381,6 +14396,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 *)


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