diff --git a/SPECS/rabbitmq-server/CVE-2026-59248.patch b/SPECS/rabbitmq-server/CVE-2026-59248.patch new file mode 100644 index 00000000000..af3c83cec6e --- /dev/null +++ b/SPECS/rabbitmq-server/CVE-2026-59248.patch @@ -0,0 +1,54 @@ +From cc1e1e57ed9060646f6daafa5f898acb4cdd3e18 Mon Sep 17 00:00:00 2001 +From: AllSpark +Date: Fri, 31 Jul 2026 07:19:42 +0000 +Subject: [PATCH] Add a hard limit for HPACK integer decoding + +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: AI Backport of https://github.com/ninenines/cowlib/commit/f582430498072a0c65ad338030321576dc13a343.patch +--- + deps/cowlib/src/cow_hpack.erl | 15 ++++++++++++++- + 1 file changed, 14 insertions(+), 1 deletion(-) + +diff --git a/deps/cowlib/src/cow_hpack.erl b/deps/cowlib/src/cow_hpack.erl +index d7ae475..c2790eb 100644 +--- a/deps/cowlib/src/cow_hpack.erl ++++ b/deps/cowlib/src/cow_hpack.erl +@@ -187,6 +187,10 @@ dec_lit_no_index(Rest, State, Acc, Name) -> + %% The HPACK format has 4 different integer prefixes length (from 4 to 7) + %% and each can be used to create an indefinite length integer if all bits + %% of the prefix are set to 1. ++%% ++%% We hard limit indefinite length integers to 38bits. The maximum ++%% possible value is large enough for normal use cases and does ++%% not produce an Erlang big int. + + dec_int5(<< 2#11111:5, Rest/bits >>) -> + dec_big_int(Rest, 31, 0); +@@ -195,7 +199,7 @@ dec_int5(<< Int:5, Rest/bits >>) -> + + dec_big_int(<< 0:1, Value:7, Rest/bits >>, Int, M) -> + {Int + (Value bsl M), Rest}; +-dec_big_int(<< 1:1, Value:7, Rest/bits >>, Int, M) -> ++dec_big_int(<< 1:1, Value:7, Rest/bits >>, Int, M) when M < 32 -> + dec_big_int(Rest, Int + (Value bsl M), M + 7). + + %% Decode a string. +@@ -254,6 +258,15 @@ decode_reject_eos_test() -> + {'EXIT', _} = (catch decode(<<16#0085f2b24a84ff874951fffffffa7f:120>>)), + ok. + ++decode_reject_very_big_int_test() -> ++ VeryBigInt0 = binary:copy(<<16#ff>>, 32767), ++ VeryBigInt = <>, ++ garbage_collect(), ++ Prev = process_flag(max_heap_size, #{size => 10_000, kill => true}), ++ {'EXIT', _} = (catch decode(VeryBigInt)), ++ process_flag(max_heap_size, Prev), ++ ok. ++ + req_decode_test() -> + %% First request (raw then huffman). + {Headers1, State1} = decode(<< 16#828684410f7777772e6578616d706c652e636f6d:160 >>), +-- +2.45.4 + diff --git a/SPECS/rabbitmq-server/CVE-2026-65624.patch b/SPECS/rabbitmq-server/CVE-2026-65624.patch new file mode 100644 index 00000000000..98865a900fc --- /dev/null +++ b/SPECS/rabbitmq-server/CVE-2026-65624.patch @@ -0,0 +1,192 @@ +From b0730f399a023dccd7b94c3af2196f13bc339763 Mon Sep 17 00:00:00 2001 +From: AllSpark +Date: Fri, 31 Jul 2026 07:21:10 +0000 +Subject: [PATCH] Fix HTTP/1.1 max_headers with duplicate headers + +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: AI Backport of https://github.com/ninenines/cowboy/commit/3a34d8c1cfd94326466aa16a9017236691dc9c55.patch +--- + deps/cowboy/src/cowboy_http.erl | 95 +++++++++++++++++++------------- + 1 file changed, 56 insertions(+), 39 deletions(-) + +diff --git a/deps/cowboy/src/cowboy_http.erl b/deps/cowboy/src/cowboy_http.erl +index a3bfd5b..3ca786d 100644 +--- a/deps/cowboy/src/cowboy_http.erl ++++ b/deps/cowboy/src/cowboy_http.erl +@@ -71,6 +71,7 @@ + qs = undefined :: binary(), + version = undefined :: cowboy:http_version(), + headers = undefined :: cowboy:http_headers() | undefined, ++ num_headers = 0 :: non_neg_integer(), + name = undefined :: binary() | undefined + }). + +@@ -355,14 +356,16 @@ parse(_, State=#state{in_streamid=InStreamID, in_state=#ps_request_line{}, + loop(State#state{buffer= <<>>}); + parse(Buffer, State=#state{in_state=#ps_request_line{empty_lines=EmptyLines}}) -> + after_parse(parse_request(Buffer, State, EmptyLines)); +-parse(Buffer, State=#state{in_state=PS=#ps_header{headers=Headers, name=undefined}}) -> ++parse(Buffer, State=#state{in_state=PS=#ps_header{ ++ headers=Headers, num_headers=Num, name=undefined}}) -> + after_parse(parse_header(Buffer, + State#state{in_state=PS#ps_header{headers=undefined}}, +- Headers)); +-parse(Buffer, State=#state{in_state=PS=#ps_header{headers=Headers, name=Name}}) -> ++ Headers, Num)); ++parse(Buffer, State=#state{in_state=PS=#ps_header{ ++ headers=Headers, num_headers=Num, name=Name}}) -> + after_parse(parse_hd_before_value(Buffer, + State#state{in_state=PS#ps_header{headers=undefined, name=undefined}}, +- Headers, Name)); ++ Headers, Num, Name)); + parse(Buffer, State=#state{in_state=#ps_body{}}) -> + after_parse(parse_body(Buffer, State)). + +@@ -604,32 +607,33 @@ parse_version(_, State, _, _, _, _) -> + + before_parse_headers(Rest, State, M, A, P, Q, V) -> + parse_header(Rest, State#state{in_state=#ps_header{ +- method=M, authority=A, path=P, qs=Q, version=V}}, #{}). ++ method=M, authority=A, path=P, qs=Q, version=V}}, #{}, 0). + + %% Headers. + + %% We need two or more bytes in the buffer to continue. +-parse_header(Rest, State=#state{in_state=PS}, Headers) when byte_size(Rest) < 2 -> +- {more, State#state{buffer=Rest, in_state=PS#ps_header{headers=Headers}}}; +-parse_header(<< $\r, $\n, Rest/bits >>, S, Headers) -> ++parse_header(Rest, State=#state{in_state=PS}, Headers, Num) when byte_size(Rest) < 2 -> ++ {more, State#state{buffer=Rest, in_state=PS#ps_header{ ++ headers=Headers, num_headers=Num}}}; ++parse_header(<< $\r, $\n, Rest/bits >>, S, Headers, _) -> + request(Rest, S, Headers); +-parse_header(Buffer, State=#state{opts=Opts, in_state=PS}, Headers) -> ++parse_header(Buffer, State=#state{opts=Opts, in_state=PS}, Headers, Num) -> + MaxHeaders = maps:get(max_headers, Opts, 100), +- NumHeaders = maps:size(Headers), + if +- NumHeaders >= MaxHeaders -> +- error_terminate(431, State#state{in_state=PS#ps_header{headers=Headers}}, ++ Num >= MaxHeaders -> ++ error_terminate(431, State#state{in_state=PS#ps_header{ ++ headers=Headers, num_headers=Num}}, + {connection_error, limit_reached, + 'The number of headers is larger than configuration allows. (RFC7230 3.2.5, RFC6585 5)'}); + true -> +- parse_header_colon(Buffer, State, Headers) ++ parse_header_colon(Buffer, State, Headers, Num) + end. + +-parse_header_colon(Buffer, State=#state{opts=Opts, in_state=PS}, Headers) -> ++parse_header_colon(Buffer, State=#state{opts=Opts, in_state=PS}, Headers, Num) -> + MaxLength = maps:get(max_header_name_length, Opts, 64), + case match_colon(Buffer, 0) of + nomatch when byte_size(Buffer) > MaxLength -> +- error_terminate(431, State#state{in_state=PS#ps_header{headers=Headers}}, ++ error_terminate(431, State#state{in_state=PS#ps_header{headers=Headers, num_headers=Num}}, + {connection_error, limit_reached, + 'A header name is larger than configuration allows. (RFC7230 3.2.5, RFC6585 5)'}); + nomatch -> +@@ -637,14 +641,14 @@ parse_header_colon(Buffer, State=#state{opts=Opts, in_state=PS}, Headers) -> + %% so check if we have an LF and abort with an error if we do. + case match_eol(Buffer, 0) of + nomatch -> +- {more, State#state{buffer=Buffer, in_state=PS#ps_header{headers=Headers}}}; ++ {more, State#state{buffer=Buffer, in_state=PS#ps_header{headers=Headers, num_headers=Num}}}; + _ -> +- error_terminate(400, State#state{in_state=PS#ps_header{headers=Headers}}, ++ error_terminate(400, State#state{in_state=PS#ps_header{headers=Headers, num_headers=Num}}, + {connection_error, protocol_error, + 'A header line is missing a colon separator. (RFC7230 3.2.4)'}) + end; + _ -> +- parse_hd_name(Buffer, State, Headers, <<>>) ++ parse_hd_name(Buffer, State, Headers, Num, <<>>) + end. + + match_colon(<< $:, _/bits >>, N) -> +@@ -654,37 +658,46 @@ match_colon(<< _, Rest/bits >>, N) -> + match_colon(_, _) -> + nomatch. + +-parse_hd_name(<< $:, Rest/bits >>, State, H, SoFar) -> +- parse_hd_before_value(Rest, State, H, SoFar); +-parse_hd_name(<< C, _/bits >>, State=#state{in_state=PS}, H, <<>>) when ?IS_WS(C) -> +- error_terminate(400, State#state{in_state=PS#ps_header{headers=H}}, ++parse_hd_name(<< $:, Rest/bits >>, State, H, Num, SoFar) -> ++ parse_hd_before_value(Rest, State, H, Num, SoFar); ++parse_hd_name(<< C, _/bits >>, State=#state{in_state=PS}, H, Num, <<>>) when ?IS_WS(C) -> ++ error_terminate(400, State#state{in_state=PS#ps_header{headers=H, num_headers=Num}}, + {connection_error, protocol_error, + 'Whitespace is not allowed before the header name. (RFC7230 3.2)'}); +-parse_hd_name(<< C, _/bits >>, State=#state{in_state=PS}, H, _) when ?IS_WS(C) -> +- error_terminate(400, State#state{in_state=PS#ps_header{headers=H}}, ++parse_hd_name(<< C, _/bits >>, State=#state{in_state=PS}, H, Num, _) when ?IS_WS(C) -> ++ error_terminate(400, State#state{in_state=PS#ps_header{headers=H, num_headers=Num}}, + {connection_error, protocol_error, + 'Whitespace is not allowed between the header name and the colon. (RFC7230 3.2.4)'}); +-parse_hd_name(<< C, Rest/bits >>, State, H, SoFar) -> +- ?LOWER(parse_hd_name, Rest, State, H, SoFar). +- +-parse_hd_before_value(<< $\s, Rest/bits >>, S, H, N) -> +- parse_hd_before_value(Rest, S, H, N); +-parse_hd_before_value(<< $\t, Rest/bits >>, S, H, N) -> +- parse_hd_before_value(Rest, S, H, N); +-parse_hd_before_value(Buffer, State=#state{opts=Opts, in_state=PS}, H, N) -> ++parse_hd_name(<< C, _/bits >>, State=#state{in_state=PS}, H, Num, _) ++ when C =:= $\r; C =:= $\n -> ++ error_terminate(400, State#state{in_state=PS#ps_header{headers=H, num_headers=Num}}, ++ {connection_error, protocol_error, ++ 'A header line is missing a colon separator. (RFC7230 3.2.4)'}); ++parse_hd_name(<< $\0, _/bits >>, State=#state{in_state=PS}, H, Num, _) -> ++ error_terminate(400, State#state{in_state=PS#ps_header{headers=H, num_headers=Num}}, ++ {connection_error, protocol_error, ++ 'NUL byte is not allowed in header name. (RFC9110 5.5)'}); ++parse_hd_name(<< C, Rest/bits >>, State, H, Num, SoFar) -> ++ ?LOWER(parse_hd_name, Rest, State, H, Num, SoFar). ++ ++parse_hd_before_value(<< $\s, Rest/bits >>, S, H, Num, N) -> ++ parse_hd_before_value(Rest, S, H, Num, N); ++parse_hd_before_value(<< $\t, Rest/bits >>, S, H, Num, N) -> ++ parse_hd_before_value(Rest, S, H, Num, N); ++parse_hd_before_value(Buffer, State=#state{opts=Opts, in_state=PS}, H, Num, N) -> + MaxLength = maps:get(max_header_value_length, Opts, 4096), + case match_eol(Buffer, 0) of + nomatch when byte_size(Buffer) > MaxLength -> +- error_terminate(431, State#state{in_state=PS#ps_header{headers=H}}, ++ error_terminate(431, State#state{in_state=PS#ps_header{headers=H, num_headers=Num}}, + {connection_error, limit_reached, + 'A header value is larger than configuration allows. (RFC7230 3.2.5, RFC6585 5)'}); + nomatch -> +- {more, State#state{buffer=Buffer, in_state=PS#ps_header{headers=H, name=N}}}; ++ {more, State#state{buffer=Buffer, in_state=PS#ps_header{headers=H, num_headers=Num, name=N}}}; + _ -> +- parse_hd_value(Buffer, State, H, N, <<>>) ++ parse_hd_value(Buffer, State, H, Num, N, <<>>) + end. + +-parse_hd_value(<< $\r, $\n, Rest/bits >>, S, Headers0, Name, SoFar) -> ++parse_hd_value(<< $\r, $\n, Rest/bits >>, S, Headers0, Num, Name, SoFar) -> + Value = clean_value_ws_end(SoFar, byte_size(SoFar) - 1), + Headers = case maps:get(Name, Headers0, undefined) of + undefined -> Headers0#{Name => Value}; +@@ -692,9 +705,13 @@ parse_hd_value(<< $\r, $\n, Rest/bits >>, S, Headers0, Name, SoFar) -> + Value0 when Name =:= <<"cookie">> -> Headers0#{Name => << Value0/binary, "; ", Value/binary >>}; + Value0 -> Headers0#{Name => << Value0/binary, ", ", Value/binary >>} + end, +- parse_header(Rest, S, Headers); +-parse_hd_value(<< C, Rest/bits >>, S, H, N, SoFar) -> +- parse_hd_value(Rest, S, H, N, << SoFar/binary, C >>). ++ parse_header(Rest, S, Headers, Num + 1); ++parse_hd_value(<< $\0, _/bits >>, S=#state{in_state=PS}, H, Num, _, _) -> ++ error_terminate(400, S#state{in_state=PS#ps_header{headers=H, num_headers=Num}}, ++ {connection_error, protocol_error, ++ 'NUL byte is not allowed in header value. (RFC9110 5.5)'}); ++parse_hd_value(<< C, Rest/bits >>, S, H, Num, N, SoFar) -> ++ parse_hd_value(Rest, S, H, Num, N, << SoFar/binary, C >>). + + clean_value_ws_end(_, -1) -> + <<>>; +-- +2.45.4 + diff --git a/SPECS/rabbitmq-server/rabbitmq-server.spec b/SPECS/rabbitmq-server/rabbitmq-server.spec index cd7cddc7eea..7e91195e17c 100644 --- a/SPECS/rabbitmq-server/rabbitmq-server.spec +++ b/SPECS/rabbitmq-server/rabbitmq-server.spec @@ -2,7 +2,7 @@ Summary: rabbitmq-server Name: rabbitmq-server Version: 3.13.7 -Release: 7%{?dist} +Release: 8%{?dist} License: Apache-2.0 and MPL 2.0 Vendor: Microsoft Corporation Distribution: Azure Linux @@ -17,6 +17,8 @@ Patch4: CVE-2026-7790.patch Patch5: CVE-2026-43973.patch Patch6: CVE-2026-43966.patch Patch7: CVE-2026-44839.patch +Patch8: CVE-2026-59248.patch +Patch9: CVE-2026-65624.patch BuildRequires: elixir BuildRequires: erlang @@ -73,6 +75,9 @@ done %{_libdir}/rabbitmq/lib/rabbitmq_server-%{version}/* %changelog +* Fri Jul 31 2026 Azure Linux Security Servicing Account - 3.13.7-8 +- Patch for CVE-2026-65624, CVE-2026-59248 + * Mon Jul 06 2026 Azure Linux Security Servicing Account - 3.13.7-7 - Patch for CVE-2026-43966, CVE-2026-44839