]> git.kaiwu.me - nginx.git/commitdiff
Limited recursion when evaluating variables.
authorRuslan Ermilov <ru@nginx.com>
Wed, 21 Dec 2016 19:01:24 +0000 (22:01 +0300)
committerRuslan Ermilov <ru@nginx.com>
Wed, 21 Dec 2016 19:01:24 +0000 (22:01 +0300)
Unlimited recursion might cause stack exhaustion in some misconfigurations.

src/http/ngx_http_variables.c
src/stream/ngx_stream_variables.c

index 7e65b2e507e687dc50b92a914308d1253129f454..62006ba9354559ae088d8824e15106b29f8f8459 100644 (file)
@@ -366,6 +366,9 @@ ngx_http_variable_value_t  ngx_http_variable_true_value =
     ngx_http_variable("1");
 
 
+static ngx_uint_t  ngx_http_variable_depth = 100;
+
+
 ngx_http_variable_t *
 ngx_http_add_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t flags)
 {
@@ -517,9 +520,20 @@ ngx_http_get_indexed_variable(ngx_http_request_t *r, ngx_uint_t index)
 
     v = cmcf->variables.elts;
 
+    if (ngx_http_variable_depth == 0) {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      "cycle while evaluating variable \"%V\"",
+                      &v[index].name);
+        return NULL;
+    }
+
+    ngx_http_variable_depth--;
+
     if (v[index].get_handler(r, &r->variables[index], v[index].data)
         == NGX_OK)
     {
+        ngx_http_variable_depth++;
+
         if (v[index].flags & NGX_HTTP_VAR_NOCACHEABLE) {
             r->variables[index].no_cacheable = 1;
         }
@@ -527,6 +541,8 @@ ngx_http_get_indexed_variable(ngx_http_request_t *r, ngx_uint_t index)
         return &r->variables[index];
     }
 
+    ngx_http_variable_depth++;
+
     r->variables[index].valid = 0;
     r->variables[index].not_found = 1;
 
@@ -568,17 +584,25 @@ ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name, ngx_uint_t key)
     if (v) {
         if (v->flags & NGX_HTTP_VAR_INDEXED) {
             return ngx_http_get_flushed_variable(r, v->index);
+        }
 
-        } else {
+        if (ngx_http_variable_depth == 0) {
+            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                          "cycle while evaluating variable \"%V\"", name);
+            return NULL;
+        }
 
-            vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
+        ngx_http_variable_depth--;
 
-            if (vv && v->get_handler(r, vv, v->data) == NGX_OK) {
-                return vv;
-            }
+        vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
 
-            return NULL;
+        if (vv && v->get_handler(r, vv, v->data) == NGX_OK) {
+            ngx_http_variable_depth++;
+            return vv;
         }
+
+        ngx_http_variable_depth++;
+        return NULL;
     }
 
     vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
index aa5361d18b035573dff145ff3bfa40e384476afb..9dc93ee5750a3d190fa917a5ce27be40534b9c39 100644 (file)
@@ -119,6 +119,9 @@ ngx_stream_variable_value_t  ngx_stream_variable_true_value =
     ngx_stream_variable("1");
 
 
+static ngx_uint_t  ngx_stream_variable_depth = 100;
+
+
 ngx_stream_variable_t *
 ngx_stream_add_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t flags)
 {
@@ -270,9 +273,20 @@ ngx_stream_get_indexed_variable(ngx_stream_session_t *s, ngx_uint_t index)
 
     v = cmcf->variables.elts;
 
+    if (ngx_stream_variable_depth == 0) {
+        ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
+                      "cycle while evaluating variable \"%V\"",
+                      &v[index].name);
+        return NULL;
+    }
+
+    ngx_stream_variable_depth--;
+
     if (v[index].get_handler(s, &s->variables[index], v[index].data)
         == NGX_OK)
     {
+        ngx_stream_variable_depth++;
+
         if (v[index].flags & NGX_STREAM_VAR_NOCACHEABLE) {
             s->variables[index].no_cacheable = 1;
         }
@@ -280,6 +294,8 @@ ngx_stream_get_indexed_variable(ngx_stream_session_t *s, ngx_uint_t index)
         return &s->variables[index];
     }
 
+    ngx_stream_variable_depth++;
+
     s->variables[index].valid = 0;
     s->variables[index].not_found = 1;
 
@@ -322,18 +338,26 @@ ngx_stream_get_variable(ngx_stream_session_t *s, ngx_str_t *name,
     if (v) {
         if (v->flags & NGX_STREAM_VAR_INDEXED) {
             return ngx_stream_get_flushed_variable(s, v->index);
+        }
 
-        } else {
+        if (ngx_stream_variable_depth == 0) {
+            ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
+                          "cycle while evaluating variable \"%V\"", name);
+            return NULL;
+        }
 
-            vv = ngx_palloc(s->connection->pool,
-                            sizeof(ngx_stream_variable_value_t));
+        ngx_stream_variable_depth--;
 
-            if (vv && v->get_handler(s, vv, v->data) == NGX_OK) {
-                return vv;
-            }
+        vv = ngx_palloc(s->connection->pool,
+                        sizeof(ngx_stream_variable_value_t));
 
-            return NULL;
+        if (vv && v->get_handler(s, vv, v->data) == NGX_OK) {
+            ngx_stream_variable_depth++;
+            return vv;
         }
+
+        ngx_stream_variable_depth++;
+        return NULL;
     }
 
     vv = ngx_palloc(s->connection->pool, sizeof(ngx_stream_variable_value_t));