# HG changeset patch # User Ruslan Ermilov # Date 1482346884 -10800 # Node ID 8cd97c14b0e2a1184550661831e02b0a1cabf572 # Parent 41cb1b64561df81f3f3715171691ff704bd33732 Limited recursion when evaluating variables. Unlimited recursion might cause stack exhaustion in some misconfigurations. diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c --- a/src/http/ngx_http_variables.c +++ b/src/http/ngx_http_variables.c @@ -366,6 +366,9 @@ ngx_http_variable_value_t ngx_http_vari 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_r 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_r 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 if (v) { if (v->flags & NGX_HTTP_VAR_INDEXED) { return ngx_http_get_flushed_variable(r, v->index); - - } else { - - vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); - - if (vv && v->get_handler(r, vv, v->data) == NGX_OK) { - return vv; - } - + } + + if (ngx_http_variable_depth == 0) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "cycle while evaluating variable \"%V\"", name); return NULL; } + + ngx_http_variable_depth--; + + vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); + + 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)); diff --git a/src/stream/ngx_stream_variables.c b/src/stream/ngx_stream_variables.c --- a/src/stream/ngx_stream_variables.c +++ b/src/stream/ngx_stream_variables.c @@ -119,6 +119,9 @@ ngx_stream_variable_value_t ngx_stream_ 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_stre 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_stre 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_sessi if (v) { if (v->flags & NGX_STREAM_VAR_INDEXED) { return ngx_stream_get_flushed_variable(s, v->index); - - } else { + } - vv = ngx_palloc(s->connection->pool, - sizeof(ngx_stream_variable_value_t)); - - if (vv && v->get_handler(s, vv, v->data) == NGX_OK) { - return vv; - } - + if (ngx_stream_variable_depth == 0) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "cycle while evaluating variable \"%V\"", name); return NULL; } + + ngx_stream_variable_depth--; + + vv = ngx_palloc(s->connection->pool, + sizeof(ngx_stream_variable_value_t)); + + 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));