Skip to content

Commit 2acc329

Browse files
Merge pull request #12503 from rabbitmq/rabbitmq-server-12499-check-stream-publisher-reference-length
Return error if stream publisher/consumer reference is longer than 255 characters
2 parents 1726064 + 622dec0 commit 2acc329

File tree

2 files changed

+109
-3
lines changed

2 files changed

+109
-3
lines changed

deps/rabbitmq_stream/src/rabbit_stream_reader.erl

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@
8080
peer_cert_validity]).
8181
-define(UNKNOWN_FIELD, unknown_field).
8282
-define(SILENT_CLOSE_DELAY, 3_000).
83+
-define(MAX_REFERENCE_SIZE, 255).
84+
85+
-import(rabbit_stream_utils, [check_write_permitted/2,
86+
check_read_permitted/3]).
8387

8488
%% client API
8589
-export([start_link/4,
@@ -1655,6 +1659,26 @@ handle_frame_post_auth(Transport,
16551659
{C1#stream_connection{connection_step = failure}, S1}
16561660
end,
16571661
{Connection1, State1};
1662+
handle_frame_post_auth(Transport,
1663+
#stream_connection{user = User,
1664+
resource_alarm = false} = C,
1665+
State,
1666+
{request, CorrelationId,
1667+
{declare_publisher, _PublisherId, WriterRef, S}})
1668+
when is_binary(WriterRef), byte_size(WriterRef) > ?MAX_REFERENCE_SIZE ->
1669+
{Code, Counter} = case check_write_permitted(stream_r(S, C), User) of
1670+
ok ->
1671+
{?RESPONSE_CODE_PRECONDITION_FAILED, ?PRECONDITION_FAILED};
1672+
error ->
1673+
{?RESPONSE_CODE_ACCESS_REFUSED, ?ACCESS_REFUSED}
1674+
end,
1675+
response(Transport,
1676+
C,
1677+
declare_publisher,
1678+
CorrelationId,
1679+
Code),
1680+
rabbit_global_counters:increase_protocol_counter(stream, Counter, 1),
1681+
{C, State};
16581682
handle_frame_post_auth(Transport,
16591683
#stream_connection{user = User,
16601684
publishers = Publishers0,
@@ -1664,7 +1688,7 @@ handle_frame_post_auth(Transport,
16641688
State,
16651689
{request, CorrelationId,
16661690
{declare_publisher, PublisherId, WriterRef, Stream}}) ->
1667-
case rabbit_stream_utils:check_write_permitted(stream_r(Stream,
1691+
case check_write_permitted(stream_r(Stream,
16681692
Connection0),
16691693
User)
16701694
of
@@ -1895,6 +1919,19 @@ handle_frame_post_auth(Transport, #stream_connection{} = Connection, State,
18951919
{subscribe,
18961920
_, _, _, _, _}} = Request) ->
18971921
handle_frame_post_auth(Transport, {ok, Connection}, State, Request);
1922+
handle_frame_post_auth(Transport, {ok, #stream_connection{user = User} = C}, State,
1923+
{request, CorrelationId,
1924+
{subscribe, _, S, _, _, #{ <<"name">> := N}}})
1925+
when is_binary(N), byte_size(N) > ?MAX_REFERENCE_SIZE ->
1926+
{Code, Counter} = case check_read_permitted(stream_r(S, C), User,#{}) of
1927+
ok ->
1928+
{?RESPONSE_CODE_PRECONDITION_FAILED, ?PRECONDITION_FAILED};
1929+
error ->
1930+
{?RESPONSE_CODE_ACCESS_REFUSED, ?ACCESS_REFUSED}
1931+
end,
1932+
response(Transport, C, subscribe, CorrelationId, Code),
1933+
rabbit_global_counters:increase_protocol_counter(stream, Counter, 1),
1934+
{C, State};
18981935
handle_frame_post_auth(Transport,
18991936
{ok, #stream_connection{
19001937
name = ConnName,
@@ -3102,7 +3139,7 @@ evaluate_state_after_secret_update(Transport,
31023139
{_, Conn1} = ensure_token_expiry_timer(User, Conn0),
31033140
PublisherStreams =
31043141
lists:foldl(fun(#publisher{stream = Str}, Acc) ->
3105-
case rabbit_stream_utils:check_write_permitted(stream_r(Str, Conn0), User) of
3142+
case check_write_permitted(stream_r(Str, Conn0), User) of
31063143
ok ->
31073144
Acc;
31083145
_ ->
@@ -3426,6 +3463,9 @@ clean_state_after_stream_deletion_or_failure(MemberPid, Stream,
34263463
{not_cleaned, C2#stream_connection{stream_leaders = Leaders1}, S2}
34273464
end.
34283465

3466+
store_offset(Reference, _, _, C) when is_binary(Reference), byte_size(Reference) > ?MAX_REFERENCE_SIZE ->
3467+
rabbit_log:warning("Reference is too long to store offset: ~p", [byte_size(Reference)]),
3468+
C;
34293469
store_offset(Reference, Stream, Offset, Connection0) ->
34303470
case lookup_leader(Stream, Connection0) of
34313471
{error, Error} ->

deps/rabbitmq_stream/test/rabbit_stream_SUITE.erl

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,9 @@ groups() ->
6464
test_super_stream_duplicate_partitions,
6565
authentication_error_should_close_with_delay,
6666
unauthorized_vhost_access_should_close_with_delay,
67-
sasl_anonymous
67+
sasl_anonymous,
68+
test_publisher_with_too_long_reference_errors,
69+
test_consumer_with_too_long_reference_errors
6870
]},
6971
%% Run `test_global_counters` on its own so the global metrics are
7072
%% initialised to 0 for each testcase
@@ -945,6 +947,70 @@ unauthorized_vhost_access_should_close_with_delay(Config) ->
945947
closed = wait_for_socket_close(T, S, 10),
946948
ok.
947949

950+
test_publisher_with_too_long_reference_errors(Config) ->
951+
FunctionName = atom_to_binary(?FUNCTION_NAME, utf8),
952+
T = gen_tcp,
953+
Port = get_port(T, Config),
954+
Opts = get_opts(T),
955+
{ok, S} = T:connect("localhost", Port, Opts),
956+
C = rabbit_stream_core:init(0),
957+
ConnectionName = FunctionName,
958+
test_peer_properties(T, S, #{<<"connection_name">> => ConnectionName}, C),
959+
test_authenticate(T, S, C),
960+
961+
Stream = FunctionName,
962+
test_create_stream(T, S, Stream, C),
963+
964+
MaxSize = 255,
965+
ReferenceOK = iolist_to_binary(lists:duplicate(MaxSize, <<"a">>)),
966+
ReferenceKO = iolist_to_binary(lists:duplicate(MaxSize + 1, <<"a">>)),
967+
968+
Tests = [{1, ReferenceOK, ?RESPONSE_CODE_OK},
969+
{2, ReferenceKO, ?RESPONSE_CODE_PRECONDITION_FAILED}],
970+
971+
[begin
972+
F = request({declare_publisher, PubId, Ref, Stream}),
973+
ok = T:send(S, F),
974+
{Cmd, C} = receive_commands(T, S, C),
975+
?assertMatch({response, 1, {declare_publisher, ExpectedResponseCode}}, Cmd)
976+
end || {PubId, Ref, ExpectedResponseCode} <- Tests],
977+
978+
test_delete_stream(T, S, Stream, C),
979+
test_close(T, S, C),
980+
ok.
981+
982+
test_consumer_with_too_long_reference_errors(Config) ->
983+
FunctionName = atom_to_binary(?FUNCTION_NAME, utf8),
984+
T = gen_tcp,
985+
Port = get_port(T, Config),
986+
Opts = get_opts(T),
987+
{ok, S} = T:connect("localhost", Port, Opts),
988+
C = rabbit_stream_core:init(0),
989+
ConnectionName = FunctionName,
990+
test_peer_properties(T, S, #{<<"connection_name">> => ConnectionName}, C),
991+
test_authenticate(T, S, C),
992+
993+
Stream = FunctionName,
994+
test_create_stream(T, S, Stream, C),
995+
996+
MaxSize = 255,
997+
ReferenceOK = iolist_to_binary(lists:duplicate(MaxSize, <<"a">>)),
998+
ReferenceKO = iolist_to_binary(lists:duplicate(MaxSize + 1, <<"a">>)),
999+
1000+
Tests = [{1, ReferenceOK, ?RESPONSE_CODE_OK},
1001+
{2, ReferenceKO, ?RESPONSE_CODE_PRECONDITION_FAILED}],
1002+
1003+
[begin
1004+
F = request({subscribe, SubId, Stream, first, 1, #{<<"name">> => Ref}}),
1005+
ok = T:send(S, F),
1006+
{Cmd, C} = receive_commands(T, S, C),
1007+
?assertMatch({response, 1, {subscribe, ExpectedResponseCode}}, Cmd)
1008+
end || {SubId, Ref, ExpectedResponseCode} <- Tests],
1009+
1010+
test_delete_stream(T, S, Stream, C),
1011+
test_close(T, S, C),
1012+
ok.
1013+
9481014
consumer_offset_info(Config, ConnectionName) ->
9491015
[[{offset, Offset},
9501016
{offset_lag, Lag}]] = rpc(Config, 0, ?MODULE,

0 commit comments

Comments
 (0)