From ef0f19c55b3aa2084421701c587c613d8e45d8f9 Mon Sep 17 00:00:00 2001 From: kh-lee Date: Mon, 11 May 2026 19:49:56 +0900 Subject: [PATCH] Request body: reject client_body_buffer_size 0. A zero value caused ngx_http_do_read_client_request_body() to spin in userspace without calling recv(): the inner loop hits "size == 0" and breaks, and the outer for(;;) re-enters as long as c->read->ready is true and rb->rest > 0. The regression was introduced in 67d160bf25e02 (released in 1.21.2), which added "if (size == 0) break;" to the inner loop. Prior to that, c->recv was called even with size == 0, which led to NGX_HTTP_BAD_REQUEST instead of spinning (the exact return value depending on the transport). The directive itself has no meaningful interpretation at zero: it sets the buffer size for reading the request body, and the read path needs a non-zero capacity to receive body data via recv(). This patch rejects "client_body_buffer_size 0" at configuration time with NGX_LOG_EMERG, matching the convention used by other directives such as "http2_chunk_size". --- src/http/ngx_http_core_module.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index 4e1c67282..563032d2c 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -90,6 +90,8 @@ static char *ngx_http_disable_symlinks(ngx_conf_t *cf, ngx_command_t *cmd, static char *ngx_http_core_lowat_check(ngx_conf_t *cf, void *post, void *data); static char *ngx_http_core_pool_size(ngx_conf_t *cf, void *post, void *data); +static char *ngx_http_core_client_body_buffer_size(ngx_conf_t *cf, void *post, + void *data); static ngx_conf_post_t ngx_http_core_lowat_post = { ngx_http_core_lowat_check }; @@ -97,6 +99,9 @@ static ngx_conf_post_t ngx_http_core_lowat_post = static ngx_conf_post_handler_pt ngx_http_core_pool_size_p = ngx_http_core_pool_size; +static ngx_conf_post_t ngx_http_core_client_body_buffer_size_post = + { ngx_http_core_client_body_buffer_size }; + static ngx_conf_enum_t ngx_http_core_request_body_in_file[] = { { ngx_string("off"), NGX_HTTP_REQUEST_BODY_FILE_OFF }, @@ -364,7 +369,7 @@ static ngx_command_t ngx_http_core_commands[] = { ngx_conf_set_size_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_core_loc_conf_t, client_body_buffer_size), - NULL }, + &ngx_http_core_client_body_buffer_size_post }, { ngx_string("client_body_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, @@ -5460,3 +5465,19 @@ ngx_http_core_pool_size(ngx_conf_t *cf, void *post, void *data) return NGX_CONF_OK; } + + +static char * +ngx_http_core_client_body_buffer_size(ngx_conf_t *cf, void *post, void *data) +{ + size_t *sp = data; + + if (*sp == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the client body buffer size cannot be zero"); + + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +}