]> git.kaiwu.me - nginx.git/commitdiff
Limit conn: fixed counter leak on memory allocation errors.
authorMaxim Dounin <mdounin@mdounin.ru>
Mon, 7 Jul 2025 01:34:18 +0000 (04:34 +0300)
committerRoman Arutyunyan <arutyunyan.roman@gmail.com>
Thu, 22 Oct 2026 11:59:04 +0000 (15:59 +0400)
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 <e.zupancic@f5.com>
Origin: <https://freenginx.org/hg/nginx/rev/722e252fcabe6413eb63555890273d7b0e7fc132>

src/http/modules/ngx_http_limit_conn_module.c
src/stream/ngx_stream_limit_conn_module.c

index 4e3e7d524c5decfd3987432a3c36ef344f5a717d..342d68e2a10418d0512e3d1b8ee91b1ce7fdb0c0 100644 (file)
@@ -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)
 {
index bae034ad3a8176ed82229acfbcb48bb50588c74b..ff97e163572b6156f85df5b7975c430da2835fdb 100644 (file)
@@ -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)
 {