From 807e53d990e80b3a279e80d261213be1e06cc635 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Mon, 7 Jul 2025 04:34:18 +0300 Subject: [PATCH] Limit conn: fixed counter leak on memory allocation errors. Previously, if ngx_pool_cleanup_add() failed, already incremented connection counter was left as is, eventually resulting in unexpected connection limiting or shared memory exhaustion. Fix is to decrement the counter by calling the cleanup handler with data on stack. Signed-off-by: Elijah Zupancic Origin: --- src/http/modules/ngx_http_limit_conn_module.c | 16 ++++++++++++++++ src/stream/ngx_stream_limit_conn_module.c | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/http/modules/ngx_http_limit_conn_module.c b/src/http/modules/ngx_http_limit_conn_module.c index 4e3e7d524..342d68e2a 100644 --- a/src/http/modules/ngx_http_limit_conn_module.c +++ b/src/http/modules/ngx_http_limit_conn_module.c @@ -60,6 +60,8 @@ static ngx_rbtree_node_t *ngx_http_limit_conn_lookup(ngx_rbtree_t *rbtree, ngx_str_t *key, uint32_t hash); static void ngx_http_limit_conn_cleanup(void *data); static ngx_inline void ngx_http_limit_conn_cleanup_all(ngx_pool_t *pool); +static void ngx_http_limit_conn_cleanup_node(ngx_shm_zone_t *shm_zone, + ngx_rbtree_node_t *node); static ngx_int_t ngx_http_limit_conn_status_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); @@ -294,6 +296,7 @@ ngx_http_limit_conn_handler(ngx_http_request_t *r) cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_http_limit_conn_cleanup_t)); if (cln == NULL) { + ngx_http_limit_conn_cleanup_node(limits[i].shm_zone, node); return NGX_HTTP_INTERNAL_SERVER_ERROR; } @@ -433,6 +436,19 @@ ngx_http_limit_conn_cleanup_all(ngx_pool_t *pool) } +static void +ngx_http_limit_conn_cleanup_node(ngx_shm_zone_t *shm_zone, + ngx_rbtree_node_t *node) +{ + ngx_http_limit_conn_cleanup_t lccln; + + lccln.shm_zone = shm_zone; + lccln.node = node; + + ngx_http_limit_conn_cleanup(&lccln); +} + + static ngx_int_t ngx_http_limit_conn_init_zone(ngx_shm_zone_t *shm_zone, void *data) { diff --git a/src/stream/ngx_stream_limit_conn_module.c b/src/stream/ngx_stream_limit_conn_module.c index bae034ad3..ff97e1635 100644 --- a/src/stream/ngx_stream_limit_conn_module.c +++ b/src/stream/ngx_stream_limit_conn_module.c @@ -59,6 +59,8 @@ static ngx_rbtree_node_t *ngx_stream_limit_conn_lookup(ngx_rbtree_t *rbtree, ngx_str_t *key, uint32_t hash); static void ngx_stream_limit_conn_cleanup(void *data); static ngx_inline void ngx_stream_limit_conn_cleanup_all(ngx_pool_t *pool); +static void ngx_stream_limit_conn_cleanup_node(ngx_shm_zone_t *shm_zone, + ngx_rbtree_node_t *node); static ngx_int_t ngx_stream_limit_conn_status_variable(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); @@ -274,6 +276,7 @@ ngx_stream_limit_conn_handler(ngx_stream_session_t *s) cln = ngx_pool_cleanup_add(s->connection->pool, sizeof(ngx_stream_limit_conn_cleanup_t)); if (cln == NULL) { + ngx_stream_limit_conn_cleanup_node(limits[i].shm_zone, node); return NGX_ERROR; } @@ -414,6 +417,19 @@ ngx_stream_limit_conn_cleanup_all(ngx_pool_t *pool) } +static void +ngx_stream_limit_conn_cleanup_node(ngx_shm_zone_t *shm_zone, + ngx_rbtree_node_t *node) +{ + ngx_stream_limit_conn_cleanup_t lccln; + + lccln.shm_zone = shm_zone; + lccln.node = node; + + ngx_stream_limit_conn_cleanup(&lccln); +} + + static ngx_int_t ngx_stream_limit_conn_init_zone(ngx_shm_zone_t *shm_zone, void *data) {