Skip to content

Commit 87c9633

Browse files
AMQP 1.0 binary parser: treat arrays with extra or missing input as fatal errors
With some input it is possible that the terminating clause will never match. While at it, consume binary input when parsing short form primitives: null, true, false, as well as uint/ulong zero values. Pair: @lhoguin.
1 parent 6c5c5f5 commit 87c9633

File tree

2 files changed

+78
-7
lines changed

2 files changed

+78
-7
lines changed

deps/amqp10_common/src/amqp10_binary_parser.erl

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,15 @@ parse_described(Bin) ->
3131
{Value, Rest2} = parse(Rest1),
3232
{{described, Descriptor, Value}, Rest2}.
3333

34-
parse_primitive0(<<Type,Rest/binary>>) ->
34+
parse_primitive0(<<Type, Rest/binary>>) ->
3535
parse_primitive(Type, Rest).
3636

3737
%% Constants
38-
parse_primitive(16#40, Rest) -> {null, Rest};
39-
parse_primitive(16#41, Rest) -> {true, Rest};
40-
parse_primitive(16#42, Rest) -> {false, Rest};
41-
parse_primitive(16#43, Rest) -> {{uint, 0}, Rest};
42-
parse_primitive(16#44, Rest) -> {{ulong, 0}, Rest};
38+
parse_primitive(16#40, R) -> {null, R};
39+
parse_primitive(16#41, R) -> {true, R};
40+
parse_primitive(16#42, R) -> {false, R};
41+
parse_primitive(16#43, R) -> {{uint, 0}, R};
42+
parse_primitive(16#44, R) -> {{ulong, 0}, R};
4343

4444
%% Fixed-widths. Most integral types have a compact encoding as a byte.
4545
parse_primitive(16#50, <<V:8/unsigned, R/binary>>) -> {{ubyte, V}, R};
@@ -122,6 +122,14 @@ parse_compound1(Count, Bin, Acc) ->
122122
{Value, Rest} = parse(Bin),
123123
parse_compound1(Count - 1, Rest, [Value | Acc]).
124124

125+
parse_array_primitive(16#40, <<_:8/unsigned, R/binary>>) -> {null, R};
126+
parse_array_primitive(16#41, <<_:8/unsigned, R/binary>>) -> {true, R};
127+
parse_array_primitive(16#42, <<_:8/unsigned, R/binary>>) -> {false, R};
128+
parse_array_primitive(16#43, <<_:8/unsigned, R/binary>>) -> {{uint, 0}, R};
129+
parse_array_primitive(16#44, <<_:8/unsigned, R/binary>>) -> {{ulong, 0}, R};
130+
parse_array_primitive(Marker, Data) ->
131+
parse_primitive(Marker, Data).
132+
125133
%% array structure is {array, Ctor, [Data]}
126134
%% e.g. {array, symbol, [<<"amqp:accepted:list">>]}
127135
parse_array(UnitSize, Bin) ->
@@ -141,8 +149,12 @@ parse_array1(Count, <<Type, ArrayBin/binary>>) ->
141149

142150
parse_array2(0, Type, <<>>, Acc) ->
143151
{array, parse_constructor(Type), lists:reverse(Acc)};
152+
parse_array2(0, Type, Bin, Acc) ->
153+
exit({failed_to_parse_array_extra_input_remaining, Type, Bin, Acc});
154+
parse_array2(Count, Type, <<>>, Acc) when Count > 0 ->
155+
exit({failed_to_parse_array_insufficient_input, Type, Count, Acc});
144156
parse_array2(Count, Type, Bin, Acc) ->
145-
{Value, Rest} = parse_primitive(Type, Bin),
157+
{Value, Rest} = parse_array_primitive(Type, Bin),
146158
parse_array2(Count - 1, Type, Rest, [Value | Acc]).
147159

148160
parse_constructor(16#a3) -> symbol;
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
-module(binary_parser_SUITE).
2+
3+
-compile(export_all).
4+
5+
-export([
6+
]).
7+
8+
-include_lib("common_test/include/ct.hrl").
9+
-include_lib("eunit/include/eunit.hrl").
10+
11+
%%%===================================================================
12+
%%% Common Test callbacks
13+
%%%===================================================================
14+
15+
all() ->
16+
[
17+
{group, tests}
18+
].
19+
20+
21+
all_tests() ->
22+
[
23+
array_with_extra_input
24+
].
25+
26+
groups() ->
27+
[
28+
{tests, [], all_tests()}
29+
].
30+
31+
init_per_suite(Config) ->
32+
Config.
33+
34+
end_per_suite(_Config) ->
35+
ok.
36+
37+
init_per_group(_Group, Config) ->
38+
Config.
39+
40+
end_per_group(_Group, _Config) ->
41+
ok.
42+
43+
init_per_testcase(_TestCase, Config) ->
44+
Config.
45+
46+
end_per_testcase(_TestCase, _Config) ->
47+
ok.
48+
49+
%%%===================================================================
50+
%%% Test cases
51+
%%%===================================================================
52+
53+
array_with_extra_input(_Config) ->
54+
Bin = <<83,16,192,85,10,177,0,0,0,1,48,161,12,114,97,98,98,105,116, 109,113,45,98,111,120,112,255,255,0,0,96,0,50,112,0,0,19,136,163,5,101,110,45,85,83,224,14,2,65,5,102,105,45,70,73,5,101,110,45,85,83,64,64,193,24,2,163,20,68,69,70,69,78,83,73,67,83, 46,84,69,83,84,46,83,85,73,84,69,65>>,
55+
?assertExit({failed_to_parse_array_extra_input_remaining,
56+
%% element type, input, accumulated result
57+
65, <<105,45,70,73,5,101,110,45,85,83>>, [true,true]},
58+
amqp10_binary_parser:parse_all(Bin)),
59+
ok.

0 commit comments

Comments
 (0)