Mercurial > hg > nginx
comparison src/http/modules/ngx_http_limit_req_module.c @ 7726:559d19037984
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.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Thu, 08 Oct 2020 17:44:34 +0300 |
parents | 776d1bebdca2 |
children | 1ebd78df4ce7 |
comparison
equal
deleted
inserted
replaced
7725:d63c5373b5ba | 7726:559d19037984 |
---|---|
67 static void ngx_http_limit_req_delay(ngx_http_request_t *r); | 67 static void ngx_http_limit_req_delay(ngx_http_request_t *r); |
68 static ngx_int_t ngx_http_limit_req_lookup(ngx_http_limit_req_limit_t *limit, | 68 static ngx_int_t ngx_http_limit_req_lookup(ngx_http_limit_req_limit_t *limit, |
69 ngx_uint_t hash, ngx_str_t *key, ngx_uint_t *ep, ngx_uint_t account); | 69 ngx_uint_t hash, ngx_str_t *key, ngx_uint_t *ep, ngx_uint_t account); |
70 static ngx_msec_t ngx_http_limit_req_account(ngx_http_limit_req_limit_t *limits, | 70 static ngx_msec_t ngx_http_limit_req_account(ngx_http_limit_req_limit_t *limits, |
71 ngx_uint_t n, ngx_uint_t *ep, ngx_http_limit_req_limit_t **limit); | 71 ngx_uint_t n, ngx_uint_t *ep, ngx_http_limit_req_limit_t **limit); |
72 static void ngx_http_limit_req_unlock(ngx_http_limit_req_limit_t *limits, | |
73 ngx_uint_t n); | |
72 static void ngx_http_limit_req_expire(ngx_http_limit_req_ctx_t *ctx, | 74 static void ngx_http_limit_req_expire(ngx_http_limit_req_ctx_t *ctx, |
73 ngx_uint_t n); | 75 ngx_uint_t n); |
74 | 76 |
75 static ngx_int_t ngx_http_limit_req_status_variable(ngx_http_request_t *r, | 77 static ngx_int_t ngx_http_limit_req_status_variable(ngx_http_request_t *r, |
76 ngx_http_variable_value_t *v, uintptr_t data); | 78 ngx_http_variable_value_t *v, uintptr_t data); |
221 limit = &limits[n]; | 223 limit = &limits[n]; |
222 | 224 |
223 ctx = limit->shm_zone->data; | 225 ctx = limit->shm_zone->data; |
224 | 226 |
225 if (ngx_http_complex_value(r, &ctx->key, &key) != NGX_OK) { | 227 if (ngx_http_complex_value(r, &ctx->key, &key) != NGX_OK) { |
228 ngx_http_limit_req_unlock(limits, n); | |
226 return NGX_HTTP_INTERNAL_SERVER_ERROR; | 229 return NGX_HTTP_INTERNAL_SERVER_ERROR; |
227 } | 230 } |
228 | 231 |
229 if (key.len == 0) { | 232 if (key.len == 0) { |
230 continue; | 233 continue; |
268 lrcf->dry_run ? ", dry run" : "", | 271 lrcf->dry_run ? ", dry run" : "", |
269 excess / 1000, excess % 1000, | 272 excess / 1000, excess % 1000, |
270 &limit->shm_zone->shm.name); | 273 &limit->shm_zone->shm.name); |
271 } | 274 } |
272 | 275 |
273 while (n--) { | 276 ngx_http_limit_req_unlock(limits, n); |
274 ctx = limits[n].shm_zone->data; | |
275 | |
276 if (ctx->node == NULL) { | |
277 continue; | |
278 } | |
279 | |
280 ngx_shmtx_lock(&ctx->shpool->mutex); | |
281 | |
282 ctx->node->count--; | |
283 | |
284 ngx_shmtx_unlock(&ctx->shpool->mutex); | |
285 | |
286 ctx->node = NULL; | |
287 } | |
288 | 277 |
289 if (lrcf->dry_run) { | 278 if (lrcf->dry_run) { |
290 r->main->limit_req_status = NGX_HTTP_LIMIT_REQ_REJECTED_DRY_RUN; | 279 r->main->limit_req_status = NGX_HTTP_LIMIT_REQ_REJECTED_DRY_RUN; |
291 return NGX_DECLINED; | 280 return NGX_DECLINED; |
292 } | 281 } |
607 *limit = &limits[n]; | 596 *limit = &limits[n]; |
608 } | 597 } |
609 } | 598 } |
610 | 599 |
611 return max_delay; | 600 return max_delay; |
601 } | |
602 | |
603 | |
604 static void | |
605 ngx_http_limit_req_unlock(ngx_http_limit_req_limit_t *limits, ngx_uint_t n) | |
606 { | |
607 ngx_http_limit_req_ctx_t *ctx; | |
608 | |
609 while (n--) { | |
610 ctx = limits[n].shm_zone->data; | |
611 | |
612 if (ctx->node == NULL) { | |
613 continue; | |
614 } | |
615 | |
616 ngx_shmtx_lock(&ctx->shpool->mutex); | |
617 | |
618 ctx->node->count--; | |
619 | |
620 ngx_shmtx_unlock(&ctx->shpool->mutex); | |
621 | |
622 ctx->node = NULL; | |
623 } | |
612 } | 624 } |
613 | 625 |
614 | 626 |
615 static void | 627 static void |
616 ngx_http_limit_req_expire(ngx_http_limit_req_ctx_t *ctx, ngx_uint_t n) | 628 ngx_http_limit_req_expire(ngx_http_limit_req_ctx_t *ctx, ngx_uint_t n) |