Skip to content

Commit 634fb34

Browse files
author
Erlang/OTP
committed
Merge branch 'kuba/ssh/kex_robustness_fix/OTP-19741' into maint-28
* kuba/ssh/kex_robustness_fix/OTP-19741: ssh: refactor select_all function ssh: key exchange robustness improvements
2 parents 3e21de2 + 98656d0 commit 634fb34

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
@@ -766,10 +766,9 @@ handle_msg(Msg, Connection, server, Ssh = #ssh{authenticated = false}) ->
766766
%% respond by disconnecting, preferably with a proper disconnect message
767767
%% sent to ease troubleshooting.
768768
MsgFun = fun(M) ->
769-
MaxLogItemLen = ?GET_OPT(max_log_item_len, Ssh#ssh.opts),
770769
io_lib:format("Connection terminated. Unexpected message for unauthenticated user."
771770
" Message: ~w", [M],
772-
[{chars_limit, MaxLogItemLen}])
771+
[{chars_limit, ssh_lib:max_log_len(Ssh)}])
773772
end,
774773
?LOG_DEBUG(MsgFun, [Msg]),
775774
{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
@@ -1188,12 +1188,21 @@ handle_event(info, {Proto, Sock, NewData}, StateName,
11881188
{next_event, internal, Msg}
11891189
]}
11901190
catch
1191-
C:E:ST ->
1192-
MaxLogItemLen = ?GET_OPT(max_log_item_len,SshParams#ssh.opts),
1191+
Class:Reason0:Stacktrace ->
1192+
Reason = ssh_lib:trim_reason(Reason0),
1193+
MsgFun =
1194+
fun(debug) ->
1195+
io_lib:format("Bad packet: Decrypted, but can't decode~n~p:~p~n~p",
1196+
[Class,Reason,Stacktrace],
1197+
[{chars_limit, ssh_lib:max_log_len(SshParams)}]);
1198+
(_) ->
1199+
io_lib:format("Bad packet: Decrypted, but can't decode ~p:~p",
1200+
[Class, Reason],
1201+
[{chars_limit, ssh_lib:max_log_len(SshParams)}])
1202+
end,
11931203
{Shutdown, D} =
11941204
?send_disconnect(?SSH_DISCONNECT_PROTOCOL_ERROR,
1195-
io_lib:format("Bad packet: Decrypted, but can't decode~n~p:~p~n~p",
1196-
[C,E,ST], [{chars_limit, MaxLogItemLen}]),
1205+
?SELECT_MSG(MsgFun),
11971206
StateName, D1),
11981207
{stop, Shutdown, D}
11991208
end;
@@ -1223,12 +1232,20 @@ handle_event(info, {Proto, Sock, NewData}, StateName,
12231232
StateName, D0),
12241233
{stop, Shutdown, D}
12251234
catch
1226-
C:E:ST ->
1227-
MaxLogItemLen = ?GET_OPT(max_log_item_len,SshParams#ssh.opts),
1235+
Class:Reason0:Stacktrace ->
1236+
MsgFun =
1237+
fun(debug) ->
1238+
io_lib:format("Bad packet: Couldn't decrypt~n~p:~p~n~p",
1239+
[Class,Reason0,Stacktrace],
1240+
[{chars_limit, ssh_lib:max_log_len(SshParams)}]);
1241+
(_) ->
1242+
Reason = ssh_lib:trim_reason(Reason0),
1243+
io_lib:format("Bad packet: Couldn't decrypt~n~p:~p",
1244+
[Class,Reason],
1245+
[{chars_limit, ssh_lib:max_log_len(SshParams)}])
1246+
end,
12281247
{Shutdown, D} =
1229-
?send_disconnect(?SSH_DISCONNECT_PROTOCOL_ERROR,
1230-
io_lib:format("Bad packet: Couldn't decrypt~n~p:~p~n~p",
1231-
[C,E,ST], [{chars_limit, MaxLogItemLen}]),
1248+
?send_disconnect(?SSH_DISCONNECT_PROTOCOL_ERROR, ?SELECT_MSG(MsgFun),
12321249
StateName, D0),
12331250
{stop, Shutdown, D}
12341251
end;

lib/ssh/src/ssh_lib.erl

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@
3333
format_time_ms/1,
3434
comp/2,
3535
set_label/1,
36-
set_label/2
36+
set_label/2,
37+
trim_reason/1,
38+
max_log_len/1
3739
]).
3840

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

lib/ssh/src/ssh_message.erl

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

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

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

848858

849859
%%%================================================================

0 commit comments

Comments
 (0)