Merge pull request #10009 from sstrigler/EMQX-7994-get-trace-name-log-bytes-xxx-does-not-do-input-validation

get trace name log bytes xxx does not do input validation
This commit is contained in:
Stefan Strigler 2023-02-21 14:12:57 +01:00 committed by GitHub
commit bf978efc83
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 50 additions and 19 deletions

View File

@ -47,9 +47,11 @@
get_trace_size/0 get_trace_size/0
]). ]).
-define(MAX_SINT32, 2147483647).
-define(TO_BIN(_B_), iolist_to_binary(_B_)). -define(TO_BIN(_B_), iolist_to_binary(_B_)).
-define(NOT_FOUND(N), {404, #{code => 'NOT_FOUND', message => ?TO_BIN([N, " NOT FOUND"])}}). -define(NOT_FOUND(N), {404, #{code => 'NOT_FOUND', message => ?TO_BIN([N, " NOT FOUND"])}}).
-define(BAD_REQUEST(C, M), {400, #{code => C, message => ?TO_BIN(M)}}). -define(SERVICE_UNAVAILABLE(C, M), {503, #{code => C, message => ?TO_BIN(M)}}).
-define(TAGS, [<<"Trace">>]). -define(TAGS, [<<"Trace">>]).
namespace() -> "trace". namespace() -> "trace".
@ -148,8 +150,9 @@ schema("/trace/:name/download") ->
#{schema => #{type => "string", format => "binary"}} #{schema => #{type => "string", format => "binary"}}
} }
}, },
400 => emqx_dashboard_swagger:error_codes(['NODE_ERROR'], <<"Node Not Found">>), 404 => emqx_dashboard_swagger:error_codes(
404 => emqx_dashboard_swagger:error_codes(['NOT_FOUND'], <<"Trace Name Not Found">>) ['NOT_FOUND', 'NODE_ERROR'], <<"Trace Name or Node Not Found">>
)
} }
} }
}; };
@ -184,8 +187,15 @@ schema("/trace/:name/log") ->
{items, hoconsc:mk(binary(), #{example => "TEXT-LOG-ITEMS"})}, {items, hoconsc:mk(binary(), #{example => "TEXT-LOG-ITEMS"})},
{meta, fields(bytes) ++ fields(position)} {meta, fields(bytes) ++ fields(position)}
], ],
400 => emqx_dashboard_swagger:error_codes(['NODE_ERROR'], <<"Trace Log Failed">>), 400 => emqx_dashboard_swagger:error_codes(
404 => emqx_dashboard_swagger:error_codes(['NOT_FOUND'], <<"Trace Name Not Found">>) ['BAD_REQUEST'], <<"Bad input parameter">>
),
404 => emqx_dashboard_swagger:error_codes(
['NOT_FOUND', 'NODE_ERROR'], <<"Trace Name or Node Not Found">>
),
503 => emqx_dashboard_swagger:error_codes(
['SERVICE_UNAVAILABLE'], <<"Requested chunk size too big">>
)
} }
} }
}. }.
@ -313,12 +323,16 @@ fields(bytes) ->
[ [
{bytes, {bytes,
hoconsc:mk( hoconsc:mk(
integer(), %% This seems to be the minimum max value we may encounter
%% across different OS
range(0, ?MAX_SINT32),
#{ #{
desc => "Maximum number of bytes to store in request", desc => "Maximum number of bytes to send in response",
in => query, in => query,
required => false, required => false,
default => 1000 default => 1000,
minimum => 0,
maximum => ?MAX_SINT32
} }
)} )}
]; ];
@ -495,7 +509,7 @@ download_trace_log(get, #{bindings := #{name := Name}, query_string := Query}) -
}, },
{200, Headers, {file_binary, ZipName, Binary}}; {200, Headers, {file_binary, ZipName, Binary}};
{error, not_found} -> {error, not_found} ->
?BAD_REQUEST('NODE_ERROR', <<"Node not found">>) ?NOT_FOUND(<<"Node">>)
end; end;
{error, not_found} -> {error, not_found} ->
?NOT_FOUND(Name) ?NOT_FOUND(Name)
@ -579,11 +593,19 @@ stream_log_file(get, #{bindings := #{name := Name}, query_string := Query}) ->
{200, #{meta => Meta, items => <<"">>}}; {200, #{meta => Meta, items => <<"">>}};
{error, not_found} -> {error, not_found} ->
?NOT_FOUND(Name); ?NOT_FOUND(Name);
{error, enomem} ->
?SLOG(warning, #{
code => not_enough_mem,
msg => "Requested chunk size too big",
bytes => Bytes,
name => Name
}),
?SERVICE_UNAVAILABLE('SERVICE_UNAVAILABLE', <<"Requested chunk size too big">>);
{badrpc, nodedown} -> {badrpc, nodedown} ->
?BAD_REQUEST('NODE_ERROR', <<"Node not found">>) ?NOT_FOUND(<<"Node">>)
end; end;
{error, not_found} -> {error, not_found} ->
?BAD_REQUEST('NODE_ERROR', <<"Node not found">>) ?NOT_FOUND(<<"Node">>)
end. end.
-spec get_trace_size() -> #{{node(), file:name_all()} => non_neg_integer()}. -spec get_trace_size() -> #{{node(), file:name_all()} => non_neg_integer()}.

View File

@ -19,9 +19,7 @@
-compile(export_all). -compile(export_all).
-compile(nowarn_export_all). -compile(nowarn_export_all).
-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl"). -include_lib("eunit/include/eunit.hrl").
-include_lib("emqx/include/emqx.hrl").
-include_lib("kernel/include/file.hrl"). -include_lib("kernel/include/file.hrl").
-include_lib("stdlib/include/zip.hrl"). -include_lib("stdlib/include/zip.hrl").
-include_lib("snabbkaffe/include/snabbkaffe.hrl"). -include_lib("snabbkaffe/include/snabbkaffe.hrl").
@ -225,12 +223,12 @@ t_log_file(_Config) ->
]}, ]},
zip:table(Binary2) zip:table(Binary2)
), ),
{error, {_, 400, _}} = {error, {_, 404, _}} =
request_api( request_api(
get, get,
api_path("trace/test_client_id/download?node=unknonwn_node") api_path("trace/test_client_id/download?node=unknown_node")
), ),
{error, {_, 400, _}} = {error, {_, 404, _}} =
request_api( request_api(
get, get,
% known atom but unknown node % known atom but unknown node
@ -296,12 +294,21 @@ t_stream_log(_Config) ->
#{<<"meta">> := Meta1, <<"items">> := Bin1} = json(Binary1), #{<<"meta">> := Meta1, <<"items">> := Bin1} = json(Binary1),
?assertEqual(#{<<"position">> => 30, <<"bytes">> => 10}, Meta1), ?assertEqual(#{<<"position">> => 30, <<"bytes">> => 10}, Meta1),
?assertEqual(10, byte_size(Bin1)), ?assertEqual(10, byte_size(Bin1)),
{error, {_, 400, _}} = ct:pal("~p vs ~p", [Bin, Bin1]),
%% in theory they could be the same but we know they shouldn't
?assertNotEqual(Bin, Bin1),
BadReqPath = api_path("trace/test_stream_log/log?&bytes=1000000000000"),
{error, {_, 400, _}} = request_api(get, BadReqPath),
meck:new(file, [passthrough, unstick]),
meck:expect(file, read, 2, {error, enomem}),
{error, {_, 503, _}} = request_api(get, Path),
meck:unload(file),
{error, {_, 404, _}} =
request_api( request_api(
get, get,
api_path("trace/test_stream_log/log?node=unknonwn_node") api_path("trace/test_stream_log/log?node=unknown_node")
), ),
{error, {_, 400, _}} = {error, {_, 404, _}} =
request_api( request_api(
get, get,
% known atom but not a node % known atom but not a node

View File

@ -0,0 +1 @@
Validate `bytes` param to `GET /trace/:name/log` to not exceed signed 32bit integer.

View File

@ -0,0 +1 @@
验证 `GET /trace/:name/log``bytes` 参数使其不超过有符号的32位整数。