]> git.kaiwu.me - nginx.git/commitdiff
Limited the number of pending operations per request
authorVadim Zhestikov <v.zhestikov@f5.com>
Mon, 17 Aug 2026 16:19:46 +0000 (09:19 -0700)
committerSergey Kandaurov <pluknet@nginx.com>
Thu, 1 Oct 2026 17:18:52 +0000 (21:18 +0400)
Each pending asynchronous operation holds a reference in
r->main->blocked, an 8-bit field, and the increments were not checked.
With 256 operations pending on a single request the counter wrapped to
zero, after which the request could be freed while those operations
still referenced its pool.  This is the same overflow that 4ec67cf86
addressed for r->main->count, and left unaddressed for r->main->blocked.

Operations beyond the limit are now performed synchronously where a
synchronous path exists, and refused otherwise, so that the counter
cannot overflow.

Reported by cyberlancer.

src/http/ngx_http_copy_filter_module.c
src/http/ngx_http_file_cache.c
src/http/ngx_http_request.h
src/http/ngx_http_upstream.c

index 8e5de2bf70102d2a31f8cf7eef246d0469886e83..6b233c48ccd9885cfa0889c6f1bcbf1cdc993048 100644 (file)
@@ -87,6 +87,13 @@ ngx_http_copy_filter(ngx_http_request_t *r, ngx_chain_t *in)
     ngx_output_chain_ctx_t       *ctx;
     ngx_http_core_loc_conf_t     *clcf;
     ngx_http_copy_filter_conf_t  *conf;
+#if (NGX_HAVE_FILE_AIO)
+    ngx_output_chain_aio_pt       aio_handler;
+#endif
+#if (NGX_THREADS)
+    ngx_int_t                   (*thread_handler)(ngx_thread_task_t *task,
+                                                  ngx_file_t *file);
+#endif
 
     c = r->connection;
 
@@ -140,10 +147,39 @@ ngx_http_copy_filter(ngx_http_request_t *r, ngx_chain_t *in)
 
 #if (NGX_HAVE_FILE_AIO || NGX_THREADS)
     ctx->aio = r->aio;
+
+#if (NGX_HAVE_FILE_AIO)
+    aio_handler = ctx->aio_handler;
+#endif
+#if (NGX_THREADS)
+    thread_handler = ctx->thread_handler;
+#endif
+
+    /*
+     * each pending operation holds a reference in r->main->blocked;
+     * with the counter close to its limit the file is read
+     * synchronously instead, so that it cannot overflow
+     */
+
+    if (r->main->blocked >= NGX_HTTP_MAX_BLOCKED) {
+#if (NGX_HAVE_FILE_AIO)
+        ctx->aio_handler = NULL;
+#endif
+#if (NGX_THREADS)
+        ctx->thread_handler = NULL;
+#endif
+    }
 #endif
 
     rc = ngx_output_chain(ctx, in);
 
+#if (NGX_HAVE_FILE_AIO)
+    ctx->aio_handler = aio_handler;
+#endif
+#if (NGX_THREADS)
+    ctx->thread_handler = thread_handler;
+#endif
+
     if (ctx->in == NULL) {
         r->buffered &= ~NGX_HTTP_COPY_BUFFERED;
 
index 5209f003b0a29771d0303b40f26070e5a5263a4c..d3d0f039cdd9867f2d42ad8ff069c43b06086e13 100644 (file)
@@ -440,6 +440,10 @@ ngx_http_file_cache_lock(ngx_http_request_t *r, ngx_http_cache_t *c)
         return NGX_HTTP_CACHE_SCARCE;
     }
 
+    if (r->main->blocked >= NGX_HTTP_MAX_BLOCKED) {
+        return NGX_HTTP_CACHE_SCARCE;
+    }
+
     c->waiting = 1;
 
     if (c->wait_time == 0) {
@@ -692,7 +696,9 @@ ngx_http_file_cache_aio_read(ngx_http_request_t *r, ngx_http_cache_t *c)
 
 #if (NGX_HAVE_FILE_AIO)
 
-    if (clcf->aio == NGX_HTTP_AIO_ON && ngx_file_aio) {
+    if (clcf->aio == NGX_HTTP_AIO_ON && ngx_file_aio
+        && r->main->blocked < NGX_HTTP_MAX_BLOCKED)
+    {
         n = ngx_file_aio_read(&c->file, c->buf->pos, c->body_start, 0, r->pool);
 
         if (n != NGX_AGAIN) {
@@ -717,7 +723,9 @@ ngx_http_file_cache_aio_read(ngx_http_request_t *r, ngx_http_cache_t *c)
 
 #if (NGX_THREADS)
 
-    if (clcf->aio == NGX_HTTP_AIO_THREADS) {
+    if (clcf->aio == NGX_HTTP_AIO_THREADS
+        && r->main->blocked < NGX_HTTP_MAX_BLOCKED)
+    {
         c->file.thread_task = c->thread_task;
         c->file.thread_handler = ngx_http_cache_thread_handler;
         c->file.thread_ctx = r;
index 6d18cc3c6cc6d7f03aa30a8b6380e19fb20d3e8b..a2049628345919b4e72c7d16a52698a283c52c3b 100644 (file)
@@ -11,6 +11,7 @@
 
 #define NGX_HTTP_MAX_URI_CHANGES           10
 #define NGX_HTTP_MAX_SUBREQUESTS           50
+#define NGX_HTTP_MAX_BLOCKED               250
 
 /* must be 2^n */
 #define NGX_HTTP_LC_HEADER_LEN             32
index 0d76800715ea0b6c07fcc08333cdfb473927f1c0..c45b75fe8d0ec75da793838401bb99c8874fcb7e 100644 (file)
@@ -4216,6 +4216,12 @@ ngx_http_upstream_thread_handler(ngx_thread_task_t *task, ngx_file_t *file)
     task->event.data = r;
     task->event.handler = ngx_http_upstream_thread_event_handler;
 
+    if (r->main->blocked >= NGX_HTTP_MAX_BLOCKED) {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      "too many operations pending");
+        return NGX_ERROR;
+    }
+
     if (ngx_thread_task_post(tp, task) != NGX_OK) {
         return NGX_ERROR;
     }