# HG changeset patch # User Maxim Dounin # Date 1711764575 -10800 # Node ID f3df785649aebf967a428b4d736b1317a94f815b # Parent b2e16e8639c80ce1cc8342c71043794c81b41367 Request body: limited chunk extensions and trailer headers. Previously, arbitrary amounts of chunk extensions and trailer headers were accepted and skipped. Despite being under limit_conn / limit_req limits (if configured), this can be a DoS vector, so it is now limited by the client_max_body_size limit. Reported by Bartek Nowotarski. diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h --- a/src/http/ngx_http.h +++ b/src/http/ngx_http.h @@ -65,6 +65,7 @@ struct ngx_http_chunked_s { ngx_uint_t state; off_t size; off_t length; + off_t skipped; }; diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c --- a/src/http/ngx_http_parse.c +++ b/src/http/ngx_http_parse.c @@ -2257,6 +2257,9 @@ ngx_http_parse_chunked(ngx_http_request_ break; case LF: state = sw_chunk_data; + break; + default: + ctx->skipped++; } break; @@ -2298,6 +2301,9 @@ ngx_http_parse_chunked(ngx_http_request_ break; case LF: state = sw_trailer; + break; + default: + ctx->skipped++; } break; @@ -2333,6 +2339,9 @@ ngx_http_parse_chunked(ngx_http_request_ break; case LF: state = sw_trailer; + break; + default: + ctx->skipped++; } break; diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c --- a/src/http/ngx_http_request_body.c +++ b/src/http/ngx_http_request_body.c @@ -1141,6 +1141,17 @@ ngx_http_request_body_chunked_filter(ngx clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (clcf->client_max_body_size + && clcf->client_max_body_size < rb->chunked->skipped) + { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "client sent too many chunk extensions"); + + r->lingering_close = 1; + + return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE; + } + + if (clcf->client_max_body_size && clcf->client_max_body_size - r->headers_in.content_length_n < rb->chunked->size) { @@ -1241,6 +1252,20 @@ ngx_http_request_body_chunked_filter(ngx if (rc == NGX_AGAIN) { + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + if (clcf->client_max_body_size + && clcf->client_max_body_size < rb->chunked->skipped) + { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "client sent too many chunk extensions " + "or trailer headers"); + + r->lingering_close = 1; + + return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE; + } + /* set rb->rest, amount of data we want to see next time */ cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);