Skip to content

Commit 26f3334

Browse files
author
Erlang/OTP
committed
Merge branch 'kuba/ssh/kex_robustness_fix/OTP-19741' into maint-27
* kuba/ssh/kex_robustness_fix/OTP-19741: ssh: refactor select_all function ssh: key exchange robustness improvements
2 parents 3095b6f + 98656d0 commit 26f3334

File tree

6 files changed

+173
-119
lines changed

6 files changed

+173
-119
lines changed

lib/ssh/src/ssh_connection.erl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -769,10 +769,9 @@ handle_msg(Msg, Connection, server, Ssh = #ssh{authenticated = false}) ->
769769
%% respond by disconnecting, preferably with a proper disconnect message
770770
%% sent to ease troubleshooting.
771771
MsgFun = fun(M) ->
772-
MaxLogItemLen = ?GET_OPT(max_log_item_len, Ssh#ssh.opts),
773772
io_lib:format("Connection terminated. Unexpected message for unauthenticated user."
774773
" Message: ~w", [M],
775-
[{chars_limit, MaxLogItemLen}])
774+
[{chars_limit, ssh_lib:max_log_len(Ssh)}])
776775
end,
777776
?LOG_DEBUG(MsgFun, [Msg]),
778777
{disconnect, {?SSH_DISCONNECT_PROTOCOL_ERROR, "Connection refused"}, handle_stop(Connection)};

lib/ssh/src/ssh_connection_handler.erl

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1186,12 +1186,21 @@ handle_event(info, {Proto, Sock, NewData}, StateName,
11861186
{next_event, internal, Msg}
11871187
]}
11881188
catch
1189-
C:E:ST ->
1190-
MaxLogItemLen = ?GET_OPT(max_log_item_len,SshParams#ssh.opts),
1189+
Class:Reason0:Stacktrace ->
1190+
Reason = ssh_lib:trim_reason(Reason0),
1191+
MsgFun =
1192+
fun(debug) ->
1193+
io_lib:format("Bad packet: Decrypted, but can't decode~n~p:~p~n~p",
1194+
[Class,Reason,Stacktrace],
1195+
[{chars_limit, ssh_lib:max_log_len(SshParams)}]);
1196+
(_) ->
1197+
io_lib:format("Bad packet: Decrypted, but can't decode ~p:~p",
1198+
[Class, Reason],
1199+
[{chars_limit, ssh_lib:max_log_len(SshParams)}])
1200+
end,
11911201
{Shutdown, D} =
11921202
?send_disconnect(?SSH_DISCONNECT_PROTOCOL_ERROR,
1193-
io_lib:format("Bad packet: Decrypted, but can't decode~n~p:~p~n~p",
1194-
[C,E,ST], [{chars_limit, MaxLogItemLen}]),
1203+
?SELECT_MSG(MsgFun),
11951204
StateName, D1),
11961205
{stop, Shutdown, D}
11971206
end;
@@ -1221,12 +1230,20 @@ handle_event(info, {Proto, Sock, NewData}, StateName,
12211230
StateName, D0),
12221231
{stop, Shutdown, D}
12231232
catch
1224-
C:E:ST ->
1225-
MaxLogItemLen = ?GET_OPT(max_log_item_len,SshParams#ssh.opts),
1233+
Class:Reason0:Stacktrace ->
1234+
MsgFun =
1235+
fun(debug) ->
1236+
io_lib:format("Bad packet: Couldn't decrypt~n~p:~p~n~p",
1237+
[Class,Reason0,Stacktrace],
1238+
[{chars_limit, ssh_lib:max_log_len(SshParams)}]);
1239+
(_) ->
1240+
Reason = ssh_lib:trim_reason(Reason0),
1241+
io_lib:format("Bad packet: Couldn't decrypt~n~p:~p",
1242+
[Class,Reason],
1243+
[{chars_limit, ssh_lib:max_log_len(SshParams)}])
1244+
end,
12261245
{Shutdown, D} =
1227-
?send_disconnect(?SSH_DISCONNECT_PROTOCOL_ERROR,
1228-
io_lib:format("Bad packet: Couldn't decrypt~n~p:~p~n~p",
1229-
[C,E,ST], [{chars_limit, MaxLogItemLen}]),
1246+
?send_disconnect(?SSH_DISCONNECT_PROTOCOL_ERROR, ?SELECT_MSG(MsgFun),
12301247
StateName, D0),
12311248
{stop, Shutdown, D}
12321249
end;

lib/ssh/src/ssh_lib.erl

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@
3131
format_time_ms/1,
3232
comp/2,
3333
set_label/1,
34-
set_label/2
34+
set_label/2,
35+
trim_reason/1,
36+
max_log_len/1
3537
]).
3638

3739
-include("ssh.hrl").
@@ -97,3 +99,17 @@ set_label(client, Details) ->
9799
proc_lib:set_label({sshc, Details});
98100
set_label(server, Details) ->
99101
proc_lib:set_label({sshd, Details}).
102+
103+
%% We don't want to process badmatch details, potentially containing
104+
%% malicious data of unknown size
105+
trim_reason({badmatch, V}) when is_binary(V) ->
106+
badmatch;
107+
trim_reason(E) ->
108+
E.
109+
110+
max_log_len(#ssh{opts = Opts}) ->
111+
?GET_OPT(max_log_item_len, Opts);
112+
max_log_len(Opts) when is_map(Opts) ->
113+
?GET_OPT(max_log_item_len, Opts).
114+
115+

lib/ssh/src/ssh_message.erl

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444

4545
-behaviour(ssh_dbg).
4646
-export([ssh_dbg_trace_points/0, ssh_dbg_flags/1, ssh_dbg_on/1, ssh_dbg_off/1, ssh_dbg_format/2]).
47-
-define(ALG_NAME_LIMIT, 64).
47+
-define(ALG_NAME_LIMIT, 64). % RFC4251 sec6
4848

4949
ucl(B) ->
5050
try unicode:characters_to_list(B) of
@@ -822,23 +822,33 @@ decode_kex_init(<<?BYTE(Bool)>>, Acc, 0) ->
822822
%% See rfc 4253 7.1
823823
X = 0,
824824
list_to_tuple(lists:reverse([X, erl_boolean(Bool) | Acc]));
825-
decode_kex_init(<<?DEC_BIN(Data,__0), Rest/binary>>, Acc, N) ->
825+
decode_kex_init(<<?DEC_BIN(Data,__0), Rest/binary>>, Acc, N) when
826+
byte_size(Data) < ?MAX_NUM_ALGORITHMS * ?ALG_NAME_LIMIT ->
826827
BinParts = binary:split(Data, <<$,>>, [global]),
827-
Process =
828-
fun(<<>>, PAcc) ->
829-
PAcc;
830-
(Part, PAcc) ->
831-
case byte_size(Part) > ?ALG_NAME_LIMIT of
832-
true ->
833-
?LOG_DEBUG("Ignoring too long name", []),
828+
AlgCount = length(BinParts),
829+
case AlgCount =< ?MAX_NUM_ALGORITHMS of
830+
true ->
831+
Process =
832+
fun(<<>>, PAcc) ->
834833
PAcc;
835-
false ->
836-
Name = binary:bin_to_list(Part),
837-
[Name | PAcc]
838-
end
839-
end,
840-
Names = lists:foldr(Process, [], BinParts),
841-
decode_kex_init(Rest, [Names | Acc], N - 1).
834+
(Part, PAcc) ->
835+
case byte_size(Part) =< ?ALG_NAME_LIMIT of
836+
true ->
837+
Name = binary:bin_to_list(Part),
838+
[Name | PAcc];
839+
false ->
840+
?LOG_DEBUG("Ignoring too long name", []),
841+
PAcc
842+
end
843+
end,
844+
Names = lists:foldr(Process, [], BinParts),
845+
decode_kex_init(Rest, [Names | Acc], N - 1);
846+
false ->
847+
throw({error, {kexinit_error, N, {alg_count, AlgCount}}})
848+
end;
849+
decode_kex_init(<<?DEC_BIN(Data,__0), _Rest/binary>>, _Acc, N) ->
850+
throw({error, {kexinit, N, {string_size, byte_size(Data)}}}).
851+
842852

843853

844854
%%%================================================================

0 commit comments

Comments
 (0)