diff --git a/SOURCES/0016-Rewrite-fix-buffer-overflow-with-overlapping-capture.patch b/SOURCES/0016-Rewrite-fix-buffer-overflow-with-overlapping-capture.patch new file mode 100644 index 0000000..ea6bccd --- /dev/null +++ b/SOURCES/0016-Rewrite-fix-buffer-overflow-with-overlapping-capture.patch @@ -0,0 +1,72 @@ +From 52083cb29080a0f01a6254aeb8ab2afaebe0ba00 Mon Sep 17 00:00:00 2001 +From: Roman Arutyunyan +Date: Thu, 14 May 2026 18:42:18 +0400 +Subject: [PATCH] Rewrite: fix buffer overflow with overlapping captures + +When the rewrite replacement string had no variables, but had +overlapping captures, the length of the allocated buffer could be +smaller than the replacement string. This could happen either +when the "redirect" parameter is specified, or when arguments are +present in the replacement string. + +The following configurations resulted in heap buffer overflow when +using URI "/++++++++++++++++++++++++++++++": + + location / { + rewrite ^/((.*))$ http://127.0.0.1:8080/$1$2 redirect; + return 200 foo; + } + + location / { + rewrite ^/((.*))$ http://127.0.0.1:8080/?$1$2; + return 200 foo; + } + +Reported by Mufeed VH of Winfunc Research. +--- + src/http/ngx_http_script.c | 20 +++++++++++++------- + 1 file changed, 13 insertions(+), 7 deletions(-) + +diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c +index 2ea6113..8a28e23 100644 +--- a/src/http/ngx_http_script.c ++++ b/src/http/ngx_http_script.c +@@ -1037,6 +1037,8 @@ ngx_http_script_start_args_code(ngx_http_script_engine_t *e) + void + ngx_http_script_regex_start_code(ngx_http_script_engine_t *e) + { ++ int *cap; ++ u_char *p; + size_t len; + ngx_int_t rc; + ngx_uint_t n; +@@ -1143,15 +1145,19 @@ ngx_http_script_regex_start_code(ngx_http_script_engine_t *e) + if (code->lengths == NULL) { + e->buf.len = code->size; + +- if (code->uri) { +- if (r->ncaptures && (r->quoted_uri || r->plus_in_uri)) { +- e->buf.len += 2 * ngx_escape_uri(NULL, r->uri.data, r->uri.len, +- NGX_ESCAPE_ARGS); +- } +- } ++ cap = r->captures; ++ p = r->captures_data; + + for (n = 2; n < r->ncaptures; n += 2) { +- e->buf.len += r->captures[n + 1] - r->captures[n]; ++ e->buf.len += cap[n + 1] - cap[n]; ++ ++ if (code->uri) { ++ if (r->quoted_uri || r->plus_in_uri) { ++ e->buf.len += 2 * ngx_escape_uri(NULL, &p[cap[n]], ++ cap[n + 1] - cap[n], ++ NGX_ESCAPE_ARGS); ++ } ++ } + } + + } else { +-- +2.44.0 + diff --git a/SOURCES/0017-Added-max_headers-directive.patch b/SOURCES/0017-Added-max_headers-directive.patch new file mode 100644 index 0000000..ce85bb9 --- /dev/null +++ b/SOURCES/0017-Added-max_headers-directive.patch @@ -0,0 +1,147 @@ +From 4a660705825ddbcef98265a1bac0af31dd6565ce Mon Sep 17 00:00:00 2001 +From: Maxim Dounin +Date: Fri, 24 May 2024 00:20:01 +0300 +Subject: [PATCH] Added max_headers directive. + +The directive limits the number of request headers accepted from clients. +While the total amount of headers is believed to be sufficiently limited +by the existing buffer size limits (client_header_buffer_size and +large_client_header_buffers), the additional limit on the number of headers +might be beneficial to better protect backend servers. + +Requested by Maksim Yevmenkin. + +Signed-off-by: Elijah Zupancic +Origin: +--- + src/http/ngx_http_core_module.c | 10 ++++++++++ + src/http/ngx_http_core_module.h | 2 ++ + src/http/ngx_http_request.c | 9 +++++++++ + src/http/ngx_http_request.h | 1 + + src/http/v2/ngx_http_v2.c | 9 +++++++++ + src/http/v3/ngx_http_v3_request.c | 9 +++++++++ + 6 files changed, 40 insertions(+) + +diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c +index 033a3bf..4d11eb3 100644 +--- a/src/http/ngx_http_core_module.c ++++ b/src/http/ngx_http_core_module.c +@@ -252,6 +252,13 @@ static ngx_command_t ngx_http_core_commands[] = { + offsetof(ngx_http_core_srv_conf_t, large_client_header_buffers), + NULL }, + ++ { ngx_string("max_headers"), ++ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, ++ ngx_conf_set_num_slot, ++ NGX_HTTP_SRV_CONF_OFFSET, ++ offsetof(ngx_http_core_srv_conf_t, max_headers), ++ NULL }, ++ + { ngx_string("ignore_invalid_headers"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, +@@ -3460,6 +3467,7 @@ ngx_http_core_create_srv_conf(ngx_conf_t *cf) + cscf->request_pool_size = NGX_CONF_UNSET_SIZE; + cscf->client_header_timeout = NGX_CONF_UNSET_MSEC; + cscf->client_header_buffer_size = NGX_CONF_UNSET_SIZE; ++ cscf->max_headers = NGX_CONF_UNSET_UINT; + cscf->ignore_invalid_headers = NGX_CONF_UNSET; + cscf->merge_slashes = NGX_CONF_UNSET; + cscf->underscores_in_headers = NGX_CONF_UNSET; +@@ -3501,6 +3509,8 @@ ngx_http_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) + return NGX_CONF_ERROR; + } + ++ ngx_conf_merge_uint_value(conf->max_headers, prev->max_headers, 1000); ++ + ngx_conf_merge_value(conf->ignore_invalid_headers, + prev->ignore_invalid_headers, 1); + +diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h +index 765e7ff..5af748e 100644 +--- a/src/http/ngx_http_core_module.h ++++ b/src/http/ngx_http_core_module.h +@@ -198,6 +198,8 @@ typedef struct { + + ngx_msec_t client_header_timeout; + ++ ngx_uint_t max_headers; ++ + ngx_flag_t ignore_invalid_headers; + ngx_flag_t merge_slashes; + ngx_flag_t underscores_in_headers; +diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c +index 9593b7f..97ed5a3 100644 +--- a/src/http/ngx_http_request.c ++++ b/src/http/ngx_http_request.c +@@ -1489,6 +1489,15 @@ ngx_http_process_request_headers(ngx_event_t *rev) + + /* a header line has been parsed successfully */ + ++ if (r->headers_in.count++ >= cscf->max_headers) { ++ r->lingering_close = 1; ++ ngx_log_error(NGX_LOG_INFO, c->log, 0, ++ "client sent too many header lines"); ++ ngx_http_finalize_request(r, ++ NGX_HTTP_REQUEST_HEADER_TOO_LARGE); ++ break; ++ } ++ + h = ngx_list_push(&r->headers_in.headers); + if (h == NULL) { + ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); +diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h +index 65c8333..2245280 100644 +--- a/src/http/ngx_http_request.h ++++ b/src/http/ngx_http_request.h +@@ -182,6 +182,7 @@ typedef struct { + + typedef struct { + ngx_list_t headers; ++ ngx_uint_t count; + + ngx_table_elt_t *host; + ngx_table_elt_t *connection; +diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c +index 0f5bd3d..a4cce4f 100644 +--- a/src/http/v2/ngx_http_v2.c ++++ b/src/http/v2/ngx_http_v2.c +@@ -1817,6 +1817,15 @@ ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c, u_char *pos, + } + + } else { ++ cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); ++ ++ if (r->headers_in.count++ >= cscf->max_headers) { ++ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, ++ "client sent too many header lines"); ++ ngx_http_finalize_request(r, NGX_HTTP_REQUEST_HEADER_TOO_LARGE); ++ goto error; ++ } ++ + h = ngx_list_push(&r->headers_in.headers); + if (h == NULL) { + return ngx_http_v2_connection_error(h2c, +diff --git a/src/http/v3/ngx_http_v3_request.c b/src/http/v3/ngx_http_v3_request.c +index 0faddd2..75fecbb 100644 +--- a/src/http/v3/ngx_http_v3_request.c ++++ b/src/http/v3/ngx_http_v3_request.c +@@ -665,6 +665,15 @@ ngx_http_v3_process_header(ngx_http_request_t *r, ngx_str_t *name, + } + + } else { ++ cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); ++ ++ if (r->headers_in.count++ >= cscf->max_headers) { ++ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, ++ "client sent too many header lines"); ++ ngx_http_finalize_request(r, NGX_HTTP_REQUEST_HEADER_TOO_LARGE); ++ return NGX_ERROR; ++ } ++ + h = ngx_list_push(&r->headers_in.headers); + if (h == NULL) { + ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); +-- +2.44.0 + diff --git a/SPECS/nginx.spec b/SPECS/nginx.spec index a178054..cbdc7b2 100644 --- a/SPECS/nginx.spec +++ b/SPECS/nginx.spec @@ -1,11 +1,6 @@ ## START: Set by rpmautospec ## (rpmautospec version 0.6.5) -## RPMAUTOSPEC: autorelease, autochangelog -%define autorelease(e:s:pb:n) %{?-p:0.}%{lua: - release_number = 9; - base_release_number = tonumber(rpm.expand("%{?-b*}%{!?-b:1}")); - print(release_number + base_release_number - 1); -}%{?-e:.%{-e*}}%{?-s:.%{-s*}}%{!?-n:%{?dist}} +## RPMAUTOSPEC: autochangelog ## END: Set by rpmautospec %global _hardened_build 1 @@ -72,7 +67,7 @@ Name: nginx Epoch: 2 Version: 1.26.3 -Release: %autorelease +Release: 9%{?dist}.1 Summary: A high performance web server and reverse proxy server License: BSD-2-Clause @@ -158,6 +153,14 @@ Patch13: 0014-Mp4-avoid-zero-size-buffers-in-output.patch # upstream patch - https://github.com/nginx/nginx/commit/524977e7 Patch14: 0015-Rewrite-fixed-escaping-and-possible-buffer-overrun.patch +# https://redhat.atlassian.net/browse/RHEL-178669 +# upstream patch - https://github.com/nginx/nginx/commit/ca4f92a27464ae6c2082245e4f67048c633aa032 +Patch15: 0016-Rewrite-fix-buffer-overflow-with-overlapping-capture.patch + +# https://redhat.atlassian.net/browse/RHEL-182544 +# upstream patch - https://github.com/nginx/nginx/commit/365694160a85229a7cb006738de9260d49ff5fa2 +Patch16: 0017-Added-max_headers-directive.patch + BuildRequires: make BuildRequires: gcc BuildRequires: gnupg2 @@ -684,6 +687,13 @@ fi %changelog ## START: Generated by rpmautospec +* Mon Jun 08 2026 Luboš Uhliarik - 2:1.26.3-11 +- nginx:1.26/nginx: HTTP/2: Remote Denial of Service via compression bomb + and Slowloris-style attack + +* Mon Jun 08 2026 Luboš Uhliarik - 2:1.26.3-10 +- nginx: code execution and denial of service (CVE-2026-9256) + * Thu May 14 2026 Luboš Uhliarik - 2:1.26.3-9 - Resolves: RHEL-176218 - nginx:1.26/nginx: NGINX: Arbitrary Code Execution Vulnerability (CVE-2026-42945)