From 6adfc05ece48f92446383ec1f145446848694698 Mon Sep 17 00:00:00 2001 From: Vadim Zhestikov Date: Mon, 17 Aug 2026 09:19:46 -0700 Subject: [PATCH] Limited the number of pending operations per request 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 | 36 ++++++++++++++++++++++++++ src/http/ngx_http_file_cache.c | 12 +++++++-- src/http/ngx_http_request.h | 1 + src/http/ngx_http_upstream.c | 6 +++++ 4 files changed, 53 insertions(+), 2 deletions(-) diff --git a/src/http/ngx_http_copy_filter_module.c b/src/http/ngx_http_copy_filter_module.c index 8e5de2bf7..6b233c48c 100644 --- a/src/http/ngx_http_copy_filter_module.c +++ b/src/http/ngx_http_copy_filter_module.c @@ -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; diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c index 5209f003b..d3d0f039c 100644 --- a/src/http/ngx_http_file_cache.c +++ b/src/http/ngx_http_file_cache.c @@ -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; diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h index 6d18cc3c6..a20496283 100644 --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -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 diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index 0d7680071..c45b75fe8 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -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; }