aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMaxim Dounin <mdounin@mdounin.ru>2020-10-08 17:44:34 +0300
committerMaxim Dounin <mdounin@mdounin.ru>2020-10-08 17:44:34 +0300
commit9381ecb1854cca89a936ffbaeb82f40ec13d7f41 (patch)
tree004f1509a01ccab0906510ad589d72e5b257a729 /src
parent1e92a0a4cef98902aed35d7b402a6a402951aba4 (diff)
downloadnginx-9381ecb1854cca89a936ffbaeb82f40ec13d7f41.tar.gz
nginx-9381ecb1854cca89a936ffbaeb82f40ec13d7f41.zip
Limit req: unlocking of nodes on complex value errors.
Previously, if there were multiple limits configured, errors in ngx_http_complex_value() during processing of a non-first limit resulted in reference count leak in shared memory nodes of already processed limits. Fix is to explicity unlock relevant nodes, much like we do when rejecting requests.
Diffstat (limited to 'src')
-rw-r--r--src/http/modules/ngx_http_limit_req_module.c42
1 files changed, 27 insertions, 15 deletions
diff --git a/src/http/modules/ngx_http_limit_req_module.c b/src/http/modules/ngx_http_limit_req_module.c
index 6bd3e6a3b..dad5edb93 100644
--- a/src/http/modules/ngx_http_limit_req_module.c
+++ b/src/http/modules/ngx_http_limit_req_module.c
@@ -69,6 +69,8 @@ static ngx_int_t ngx_http_limit_req_lookup(ngx_http_limit_req_limit_t *limit,
ngx_uint_t hash, ngx_str_t *key, ngx_uint_t *ep, ngx_uint_t account);
static ngx_msec_t ngx_http_limit_req_account(ngx_http_limit_req_limit_t *limits,
ngx_uint_t n, ngx_uint_t *ep, ngx_http_limit_req_limit_t **limit);
+static void ngx_http_limit_req_unlock(ngx_http_limit_req_limit_t *limits,
+ ngx_uint_t n);
static void ngx_http_limit_req_expire(ngx_http_limit_req_ctx_t *ctx,
ngx_uint_t n);
@@ -223,6 +225,7 @@ ngx_http_limit_req_handler(ngx_http_request_t *r)
ctx = limit->shm_zone->data;
if (ngx_http_complex_value(r, &ctx->key, &key) != NGX_OK) {
+ ngx_http_limit_req_unlock(limits, n);
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
@@ -270,21 +273,7 @@ ngx_http_limit_req_handler(ngx_http_request_t *r)
&limit->shm_zone->shm.name);
}
- while (n--) {
- ctx = limits[n].shm_zone->data;
-
- if (ctx->node == NULL) {
- continue;
- }
-
- ngx_shmtx_lock(&ctx->shpool->mutex);
-
- ctx->node->count--;
-
- ngx_shmtx_unlock(&ctx->shpool->mutex);
-
- ctx->node = NULL;
- }
+ ngx_http_limit_req_unlock(limits, n);
if (lrcf->dry_run) {
r->main->limit_req_status = NGX_HTTP_LIMIT_REQ_REJECTED_DRY_RUN;
@@ -613,6 +602,29 @@ ngx_http_limit_req_account(ngx_http_limit_req_limit_t *limits, ngx_uint_t n,
static void
+ngx_http_limit_req_unlock(ngx_http_limit_req_limit_t *limits, ngx_uint_t n)
+{
+ ngx_http_limit_req_ctx_t *ctx;
+
+ while (n--) {
+ ctx = limits[n].shm_zone->data;
+
+ if (ctx->node == NULL) {
+ continue;
+ }
+
+ ngx_shmtx_lock(&ctx->shpool->mutex);
+
+ ctx->node->count--;
+
+ ngx_shmtx_unlock(&ctx->shpool->mutex);
+
+ ctx->node = NULL;
+ }
+}
+
+
+static void
ngx_http_limit_req_expire(ngx_http_limit_req_ctx_t *ctx, ngx_uint_t n)
{
ngx_int_t excess;