]> granicus.if.org Git - apache/commitdiff
Merge r1204087, 1204090:
authorStefan Fritsch <sf@apache.org>
Mon, 21 Nov 2011 22:24:12 +0000 (22:24 +0000)
committerStefan Fritsch <sf@apache.org>
Mon, 21 Nov 2011 22:24:12 +0000 (22:24 +0000)
Limit recursion in ap_expr evaluation to avoid unbounded stack usage
* evaluate chains of ||, &&, and string concatenation non-recursively
* limit other types of recursion to 20 levels
* avoid some string copies if concatenating more than 2 strings

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1204730 13f79535-47bb-0310-9956-ffa450edef68

include/ap_expr.h
include/ap_mmn.h
server/util_expr_eval.c
server/util_expr_parse.c
server/util_expr_parse.y

index 409c7acd4ced0f33db453fb08aaca27c25da0a0b..6d6506035a7b2959abea80345b56bda31ea89cde 100644 (file)
@@ -130,6 +130,8 @@ typedef struct {
     const char **result_string;
     /** Arbitrary context data provided by the caller for custom functions */
     void *data;
+    /** The current recursion level */
+    int reclvl;
 } ap_expr_eval_ctx_t;
 
 /**
index dac9c1f51171b1827b272bf61049955e587d8a88..4770d753d5d8a3fa9b7611d8ab9daa5d8d379482 100644 (file)
  * 20111025.1 (2.3.15-dev) Add ap_escape_urlencoded(), ap_escape_urlencoded_buffer()
  *                         and ap_unescape_urlencoded().
  * 20111025.2 (2.3.15-dev) Add ap_lua_ssl_val to mod_lua
+ * 20111025.3 (2.4.0-dev)  Add reclvl to ap_expr_eval_ctx_t
  */
 
 #define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */
 #ifndef MODULE_MAGIC_NUMBER_MAJOR
 #define MODULE_MAGIC_NUMBER_MAJOR 20111025
 #endif
-#define MODULE_MAGIC_NUMBER_MINOR 2                   /* 0...n */
+#define MODULE_MAGIC_NUMBER_MINOR 3                   /* 0...n */
 
 /**
  * Determine if the server's current MODULE_MAGIC_NUMBER is at least a
index 3dd5863ae8f35d7b34b32c598d808336b0fcc837..81143e5ac4989b84bd030a8f899215b53b9f1703 100644 (file)
@@ -56,10 +56,30 @@ static void expr_dump_tree(const ap_expr_t *e, const server_rec *s,
                            int loglevel, int indent);
 #endif
 
+/*
+ * To reduce counting overhead, we only count calls to
+ * ap_expr_eval_word() and ap_expr_eval(). The max number of
+ * stack frames is larger by some factor.
+ */
+#define AP_EXPR_MAX_RECURSION   20
+static int inc_rec(ap_expr_eval_ctx_t *ctx)
+{
+    if (ctx->reclvl < AP_EXPR_MAX_RECURSION) {
+        ctx->reclvl++;
+        return 0;
+    }
+    *ctx->err = "Recursion limit reached";
+    /* short circuit further evaluation */
+    ctx->reclvl = INT_MAX;
+    return 1;
+}
+
 static const char *ap_expr_eval_word(ap_expr_eval_ctx_t *ctx,
                                      const ap_expr_t *node)
 {
     const char *result = "";
+    if (inc_rec(ctx))
+        return result;
     switch (node->node_op) {
     case op_Digit:
     case op_String:
@@ -68,17 +88,41 @@ static const char *ap_expr_eval_word(ap_expr_eval_ctx_t *ctx,
     case op_Var:
         result = ap_expr_eval_var(ctx, node->node_arg1, node->node_arg2);
         break;
-    case op_Concat: {
-        const char *s1 = ap_expr_eval_word(ctx, node->node_arg1);
-        const char *s2 = ap_expr_eval_word(ctx, node->node_arg2);
-        if (!*s1)
-            result = s2;
-        else if (!*s2)
-            result = s1;
-        else
-            result = apr_pstrcat(ctx->p, s1, s2, NULL);
+    case op_Concat:
+        if (((ap_expr_t *)node->node_arg2)->node_op != op_Concat) {
+            const char *s1 = ap_expr_eval_word(ctx, node->node_arg1);
+            const char *s2 = ap_expr_eval_word(ctx, node->node_arg2);
+            if (!*s1)
+                result = s2;
+            else if (!*s2)
+                result = s1;
+            else
+                result = apr_pstrcat(ctx->p, s1, s2, NULL);
+        }
+        else {
+            const ap_expr_t *nodep = node;
+            int i = 1;
+            struct iovec *vec;
+            do {
+                nodep = nodep->node_arg2;
+                i++;
+            } while (nodep->node_op == op_Concat);
+            vec = apr_palloc(ctx->p, i * sizeof(struct iovec));
+            nodep = node;
+            i = 0;
+            do {
+                vec[i].iov_base = (void *)ap_expr_eval_word(ctx,
+                                                            nodep->node_arg1);
+                vec[i].iov_len = strlen(vec[i].iov_base);
+                i++;
+                nodep = nodep->node_arg2;
+            } while (nodep->node_op == op_Concat);
+            vec[i].iov_base = (void *)ap_expr_eval_word(ctx, nodep);
+            vec[i].iov_len = strlen(vec[i].iov_base);
+            i++;
+            result = apr_pstrcatv(ctx->p, vec, i, NULL);
+        }
         break;
-    }
     case op_StringFuncCall: {
         const ap_expr_t *info = node->node_arg1;
         const ap_expr_t *args = node->node_arg2;
@@ -96,6 +140,7 @@ static const char *ap_expr_eval_word(ap_expr_eval_ctx_t *ctx,
     }
     if (!result)
         result = "";
+    ctx->reclvl--;
     return result;
 }
 
@@ -657,30 +702,79 @@ static int ap_expr_eval(ap_expr_eval_ctx_t *ctx, const ap_expr_t *node)
 {
     const ap_expr_t *e1 = node->node_arg1;
     const ap_expr_t *e2 = node->node_arg2;
-    switch (node->node_op) {
-    case op_True:
-        return 1;
-    case op_False:
-        return 0;
-    case op_Not:
-        return (!ap_expr_eval(ctx, e1));
-    case op_Or:
-        return (ap_expr_eval(ctx, e1) || ap_expr_eval(ctx, e2));
-    case op_And:
-        return (ap_expr_eval(ctx, e1) && ap_expr_eval(ctx, e2));
-    case op_UnaryOpCall:
-        return ap_expr_eval_unary_op(ctx, e1, e2);
-    case op_BinaryOpCall:
-        return ap_expr_eval_binary_op(ctx, e1, e2);
-    case op_Comp:
-        if (ctx->info->flags & AP_EXPR_FLAG_SSL_EXPR_COMPAT)
-            return ssl_expr_eval_comp(ctx, e1);
-        else
-            return ap_expr_eval_comp(ctx, e1);
-    default:
-        *ctx->err = "Internal evaluation error: Unknown expression node";
-        return FALSE;
+    int result = FALSE;
+    if (inc_rec(ctx))
+        return result;
+    while (1) {
+        switch (node->node_op) {
+        case op_True:
+            result ^= TRUE;
+            goto out;
+        case op_False:
+            result ^= FALSE;
+            goto out;
+        case op_Not:
+            result = !result;
+            node = e1;
+            break;
+        case op_Or:
+            do {
+                if (e1->node_op == op_Not) {
+                    if (!ap_expr_eval(ctx, e1->node_arg1)) {
+                        result ^= TRUE;
+                        goto out;
+                    }
+                }
+                else {
+                    if (ap_expr_eval(ctx, e1)) {
+                        result ^= TRUE;
+                        goto out;
+                    }
+                }
+                node = node->node_arg2;
+                e1 = node->node_arg1;
+            } while (node->node_op == op_Or);
+            break;
+        case op_And:
+            do {
+                if (e1->node_op == op_Not) {
+                    if (ap_expr_eval(ctx, e1->node_arg1)) {
+                        result ^= FALSE;
+                        goto out;
+                    }
+                }
+                else {
+                    if (!ap_expr_eval(ctx, e1)) {
+                        result ^= FALSE;
+                        goto out;
+                    }
+                }
+                node = node->node_arg2;
+                e1 = node->node_arg1;
+            } while (node->node_op == op_And);
+            break;
+        case op_UnaryOpCall:
+            result ^= ap_expr_eval_unary_op(ctx, e1, e2);
+            goto out;
+        case op_BinaryOpCall:
+            result ^= ap_expr_eval_binary_op(ctx, e1, e2);
+            goto out;
+        case op_Comp:
+            if (ctx->info->flags & AP_EXPR_FLAG_SSL_EXPR_COMPAT)
+                result ^= ssl_expr_eval_comp(ctx, e1);
+            else
+                result ^= ap_expr_eval_comp(ctx, e1);
+            goto out;
+        default:
+            *ctx->err = "Internal evaluation error: Unknown expression node";
+            goto out;
+        }
+        e1 = node->node_arg1;
+        e2 = node->node_arg2;
     }
+out:
+    ctx->reclvl--;
+    return result;
 }
 
 AP_DECLARE(int) ap_expr_exec(request_rec *r, const ap_expr_info_t *info,
@@ -704,6 +798,7 @@ AP_DECLARE(int) ap_expr_exec_ctx(ap_expr_eval_ctx_t *ctx)
         AP_DEBUG_ASSERT(ctx->re_source != NULL);
         AP_DEBUG_ASSERT(ctx->re_nmatch > 0);
     }
+    ctx->reclvl = 0;
 
     *ctx->err = NULL;
     if (ctx->info->flags & AP_EXPR_FLAG_STRING_RESULT) {
index 80f47374e404a12362f4ea8fe932a999c5f99fbd..bcf0173b7321eff63fd510597a54722aadae4e01 100644 (file)
@@ -591,9 +591,9 @@ static const yytype_int8 yypact[] =
       25,   -35,    79,   -17,   -35,    -8,    60,    60,    43,    43,
       43,    43,    43,    43,    43,     5,     5,     0,    43,    43,
       43,    43,    43,    43,    43,   -35,   -27,   -35,   -35,    73,
-     -35,     3,   -35,    25,    25,    25,    25,    25,    25,    25,
+     -35,    86,     3,    25,    25,    25,    25,    25,    25,    25,
      -35,   -35,   -35,   -35,    23,    43,   -35,   -35,    25,    25,
-      25,    25,    25,    25,   -35,   -35,   106,    43,    85,    25,
+      25,    25,    25,    25,    25,   -35,   106,    43,    85,    25,
      -35,   -21,   -35,    43,   -35,    25
 };
 
index ffa1ec5a9ce2f25daa59ec9a497f640ff8e036cc..85ed12310455a1e60369183c80319546e9fd5e00 100644 (file)
 %token  T_OP_AND
 %token  T_OP_NOT
 
-%left   T_OP_OR
-%left   T_OP_AND
-%left   T_OP_NOT
-%left   T_OP_CONCAT
+%right  T_OP_OR
+%right  T_OP_AND
+%right  T_OP_NOT
+%right  T_OP_CONCAT
 
 %type   <exVal>   expr
 %type   <exVal>   comparison