diff options
| author | Michael Klishin <michael@clojurewerkz.org> | 2021-04-07 10:57:59 +0300 |
|---|---|---|
| committer | Michael Klishin <michael@clojurewerkz.org> | 2021-04-08 12:02:54 +0300 |
| commit | 3e91cc3562403d1466e683f84f55ac8caf3a593c (patch) | |
| tree | 92e10d9dc1777adae97c9822cc3d58b2ba0c497b | |
| parent | 57cc5bfb3c44a65aef25f2d23d4bb9bda487c712 (diff) | |
| download | rabbitmq-server-git-3e91cc3562403d1466e683f84f55ac8caf3a593c.tar.gz | |
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.
| -rw-r--r-- | deps/amqp10_common/src/amqp10_binary_parser.erl | 26 | ||||
| -rw-r--r-- | deps/amqp10_common/test/binary_parser_SUITE.erl | 59 |
2 files changed, 78 insertions, 7 deletions
diff --git a/deps/amqp10_common/src/amqp10_binary_parser.erl b/deps/amqp10_common/src/amqp10_binary_parser.erl index b936f9f4ca..2ea5774c01 100644 --- a/deps/amqp10_common/src/amqp10_binary_parser.erl +++ b/deps/amqp10_common/src/amqp10_binary_parser.erl @@ -31,15 +31,15 @@ parse_described(Bin) -> {Value, Rest2} = parse(Rest1), {{described, Descriptor, Value}, Rest2}. -parse_primitive0(<<Type,Rest/binary>>) -> +parse_primitive0(<<Type, Rest/binary>>) -> parse_primitive(Type, Rest). %% Constants -parse_primitive(16#40, Rest) -> {null, Rest}; -parse_primitive(16#41, Rest) -> {true, Rest}; -parse_primitive(16#42, Rest) -> {false, Rest}; -parse_primitive(16#43, Rest) -> {{uint, 0}, Rest}; -parse_primitive(16#44, Rest) -> {{ulong, 0}, Rest}; +parse_primitive(16#40, R) -> {null, R}; +parse_primitive(16#41, R) -> {true, R}; +parse_primitive(16#42, R) -> {false, R}; +parse_primitive(16#43, R) -> {{uint, 0}, R}; +parse_primitive(16#44, R) -> {{ulong, 0}, R}; %% Fixed-widths. Most integral types have a compact encoding as a byte. parse_primitive(16#50, <<V:8/unsigned, R/binary>>) -> {{ubyte, V}, R}; @@ -122,6 +122,14 @@ parse_compound1(Count, Bin, Acc) -> {Value, Rest} = parse(Bin), parse_compound1(Count - 1, Rest, [Value | Acc]). +parse_array_primitive(16#40, <<_:8/unsigned, R/binary>>) -> {null, R}; +parse_array_primitive(16#41, <<_:8/unsigned, R/binary>>) -> {true, R}; +parse_array_primitive(16#42, <<_:8/unsigned, R/binary>>) -> {false, R}; +parse_array_primitive(16#43, <<_:8/unsigned, R/binary>>) -> {{uint, 0}, R}; +parse_array_primitive(16#44, <<_:8/unsigned, R/binary>>) -> {{ulong, 0}, R}; +parse_array_primitive(Marker, Data) -> + parse_primitive(Marker, Data). + %% array structure is {array, Ctor, [Data]} %% e.g. {array, symbol, [<<"amqp:accepted:list">>]} parse_array(UnitSize, Bin) -> @@ -141,8 +149,12 @@ parse_array1(Count, <<Type, ArrayBin/binary>>) -> parse_array2(0, Type, <<>>, Acc) -> {array, parse_constructor(Type), lists:reverse(Acc)}; +parse_array2(0, Type, Bin, Acc) -> + exit({failed_to_parse_array_extra_input_remaining, Type, Bin, Acc}); +parse_array2(Count, Type, <<>>, Acc) when Count > 0 -> + exit({failed_to_parse_array_insufficient_input, Type, Count, Acc}); parse_array2(Count, Type, Bin, Acc) -> - {Value, Rest} = parse_primitive(Type, Bin), + {Value, Rest} = parse_array_primitive(Type, Bin), parse_array2(Count - 1, Type, Rest, [Value | Acc]). parse_constructor(16#a3) -> symbol; diff --git a/deps/amqp10_common/test/binary_parser_SUITE.erl b/deps/amqp10_common/test/binary_parser_SUITE.erl new file mode 100644 index 0000000000..b391cdb100 --- /dev/null +++ b/deps/amqp10_common/test/binary_parser_SUITE.erl @@ -0,0 +1,59 @@ +-module(binary_parser_SUITE). + +-compile(export_all). + +-export([ + ]). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("eunit/include/eunit.hrl"). + +%%%=================================================================== +%%% Common Test callbacks +%%%=================================================================== + +all() -> + [ + {group, tests} + ]. + + +all_tests() -> + [ + array_with_extra_input + ]. + +groups() -> + [ + {tests, [], all_tests()} + ]. + +init_per_suite(Config) -> + Config. + +end_per_suite(_Config) -> + ok. + +init_per_group(_Group, Config) -> + Config. + +end_per_group(_Group, _Config) -> + ok. + +init_per_testcase(_TestCase, Config) -> + Config. + +end_per_testcase(_TestCase, _Config) -> + ok. + +%%%=================================================================== +%%% Test cases +%%%=================================================================== + +array_with_extra_input(_Config) -> + 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>>, + ?assertExit({failed_to_parse_array_extra_input_remaining, + %% element type, input, accumulated result + 65, <<105,45,70,73,5,101,110,45,85,83>>, [true,true]}, + amqp10_binary_parser:parse_all(Bin)), + ok. |
