Compare commits
10 Commits
32c6103bc7
...
2f0d581fe4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2f0d581fe4 | ||
|
|
2851ed74d8 | ||
|
|
c1a75aac98 | ||
|
|
be599ceeea | ||
|
|
0743f11b62 | ||
|
|
b66f7bc190 | ||
|
|
498936ddc3 | ||
|
|
1598c62a6a | ||
|
|
77db3d9f2b | ||
|
|
bb6a9b689b |
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@ -0,0 +1 @@
|
||||
*.gz filter=lfs diff=lfs merge=lfs -text
|
||||
2
.lfsconfig
Normal file
2
.lfsconfig
Normal file
@ -0,0 +1,2 @@
|
||||
[lfs]
|
||||
url = https://artlfs.openeuler.openatom.cn/src-openEuler/erlang
|
||||
563
CVE-2023-48795-erlang21.patch
Normal file
563
CVE-2023-48795-erlang21.patch
Normal file
@ -0,0 +1,563 @@
|
||||
From ee67d46285394db95133709cef74b0c462d665aa Mon Sep 17 00:00:00 2001
|
||||
From: Jakub Witczak <kuba@erlang.org>
|
||||
Date: Fri, 15 Dec 2023 09:12:33 +0100
|
||||
Subject: [PATCH] ssh: KEX strict
|
||||
|
||||
Origin: https://github.com/erlang/otp/commit/ee67d46285394db95133709cef74b0c462d665aa
|
||||
|
||||
- negotiate "strict KEX" OpenSSH feature
|
||||
- when negotiated between peers apply strict KEX
|
||||
- related tests
|
||||
- print_seqnums fix in ssh_trtp test code
|
||||
|
||||
---
|
||||
lib/ssh/src/ssh.hrl | 5 +-
|
||||
lib/ssh/src/ssh_connection_handler.erl | 12 ++-
|
||||
lib/ssh/src/ssh_transport.erl | 101 ++++++++++++++++++++-----
|
||||
lib/ssh/src/ssh_transport.hrl | 4 +-
|
||||
lib/ssh/test/ssh_protocol_SUITE.erl | 97 +++++++++++++++++++++---
|
||||
lib/ssh/test/ssh_trpt_test_lib.erl | 34 +++++----
|
||||
6 files changed, 207 insertions(+), 46 deletions(-)
|
||||
|
||||
diff --git a/lib/ssh/src/ssh.hrl b/lib/ssh/src/ssh.hrl
|
||||
index 923e930..1f6c390 100644
|
||||
--- a/lib/ssh/src/ssh.hrl
|
||||
+++ b/lib/ssh/src/ssh.hrl
|
||||
@@ -385,6 +385,8 @@
|
||||
send_ext_info, %% May send ext-info to peer
|
||||
recv_ext_info, %% Expect ext-info from peer
|
||||
|
||||
+ kex_strict_negotiated = false,
|
||||
+
|
||||
algorithms, %% #alg{}
|
||||
|
||||
send_mac = none, %% send MAC algorithm
|
||||
@@ -454,7 +456,8 @@
|
||||
c_lng,
|
||||
s_lng,
|
||||
send_ext_info,
|
||||
- recv_ext_info
|
||||
+ recv_ext_info,
|
||||
+ kex_strict_negotiated = false
|
||||
}).
|
||||
|
||||
-record(ssh_key,
|
||||
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
|
||||
index 7c87591..88ee620 100644
|
||||
--- a/lib/ssh/src/ssh_connection_handler.erl
|
||||
+++ b/lib/ssh/src/ssh_connection_handler.erl
|
||||
@@ -640,7 +640,7 @@ handle_event(_, {version_exchange,Version}, {hello,Role}, D0) ->
|
||||
handle_event(_, {#ssh_msg_kexinit{}=Kex, Payload}, {kexinit,Role,ReNeg},
|
||||
D = #data{key_exchange_init_msg = OwnKex}) ->
|
||||
Ssh1 = ssh_transport:key_init(peer_role(Role), D#data.ssh_params, Payload),
|
||||
- Ssh = case ssh_transport:handle_kexinit_msg(Kex, OwnKex, Ssh1) of
|
||||
+ Ssh = case ssh_transport:handle_kexinit_msg(Kex, OwnKex, Ssh1, ReNeg) of
|
||||
{ok, NextKexMsg, Ssh2} when Role==client ->
|
||||
send_bytes(NextKexMsg, D),
|
||||
Ssh2;
|
||||
@@ -1000,6 +1000,16 @@ handle_event(_, #ssh_msg_disconnect{description=Desc} = Msg, StateName, D0) ->
|
||||
disconnect_fun("Received disconnect: "++Desc, D),
|
||||
{stop_and_reply, {shutdown,Desc}, Actions, D};
|
||||
|
||||
+handle_event(internal, #ssh_msg_ignore{}, {_StateName, _Role, init},
|
||||
+ #data{ssh_params = #ssh{kex_strict_negotiated = true,
|
||||
+ send_sequence = SendSeq,
|
||||
+ recv_sequence = RecvSeq}}) ->
|
||||
+ ?DISCONNECT(?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
|
||||
+ io_lib:format("strict KEX violation: unexpected SSH_MSG_IGNORE "
|
||||
+ "send_sequence = ~p recv_sequence = ~p",
|
||||
+ [SendSeq, RecvSeq])
|
||||
+ );
|
||||
+
|
||||
handle_event(_, #ssh_msg_ignore{}, _, _) ->
|
||||
keep_state_and_data;
|
||||
|
||||
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
|
||||
index 9ff2045..a001f86 100644
|
||||
--- a/lib/ssh/src/ssh_transport.erl
|
||||
+++ b/lib/ssh/src/ssh_transport.erl
|
||||
@@ -41,7 +41,7 @@
|
||||
key_exchange_init_msg/1,
|
||||
key_init/3, new_keys_message/1,
|
||||
ext_info_message/1,
|
||||
- handle_kexinit_msg/3, handle_kexdh_init/2,
|
||||
+ handle_kexinit_msg/4, handle_kexdh_init/2,
|
||||
handle_kex_dh_gex_group/2, handle_kex_dh_gex_init/2, handle_kex_dh_gex_reply/2,
|
||||
handle_new_keys/2, handle_kex_dh_gex_request/2,
|
||||
handle_kexdh_reply/2,
|
||||
@@ -161,7 +161,6 @@ supported_algorithms(cipher) ->
|
||||
same(
|
||||
select_crypto_supported(
|
||||
[
|
||||
- {'chacha20-poly1305@openssh.com', [{ciphers,chacha20}, {macs,poly1305}]},
|
||||
{'aes256-gcm@openssh.com', [{ciphers,{aes_gcm,256}}]},
|
||||
{'aes256-ctr', [{ciphers,{aes_ctr,256}}]},
|
||||
{'aes192-ctr', [{ciphers,{aes_ctr,192}}]},
|
||||
@@ -169,6 +168,7 @@ supported_algorithms(cipher) ->
|
||||
{'aes128-ctr', [{ciphers,{aes_ctr,128}}]},
|
||||
{'AEAD_AES_256_GCM', [{ciphers,{aes_gcm,256}}]},
|
||||
{'AEAD_AES_128_GCM', [{ciphers,{aes_gcm,128}}]},
|
||||
+ {'chacha20-poly1305@openssh.com', [{ciphers,chacha20}, {macs,poly1305}]},
|
||||
{'aes128-cbc', [{ciphers,aes_cbc128}]},
|
||||
{'3des-cbc', [{ciphers,des3_cbc}]}
|
||||
]
|
||||
@@ -295,7 +295,8 @@ kexinit_message(Role, Random, Algs, HostKeyAlgs, Opts) ->
|
||||
#ssh_msg_kexinit{
|
||||
cookie = Random,
|
||||
kex_algorithms = to_strings( get_algs(kex,Algs) )
|
||||
- ++ kex_ext_info(Role,Opts),
|
||||
+ ++ kex_ext_info(Role,Opts)
|
||||
+ ++ kex_strict_alg(Role),
|
||||
server_host_key_algorithms = HostKeyAlgs,
|
||||
encryption_algorithms_client_to_server = c2s(cipher,Algs),
|
||||
encryption_algorithms_server_to_client = s2c(cipher,Algs),
|
||||
@@ -323,10 +324,12 @@ new_keys_message(Ssh0) ->
|
||||
|
||||
|
||||
handle_kexinit_msg(#ssh_msg_kexinit{} = CounterPart, #ssh_msg_kexinit{} = Own,
|
||||
- #ssh{role = client} = Ssh) ->
|
||||
+ #ssh{role = client} = Ssh, ReNeg) ->
|
||||
try
|
||||
- {ok, Algorithms} = select_algorithm(client, Own, CounterPart, Ssh#ssh.opts),
|
||||
+ {ok, Algorithms} =
|
||||
+ select_algorithm(client, Own, CounterPart, Ssh, ReNeg),
|
||||
true = verify_algorithm(Algorithms),
|
||||
+ true = verify_kexinit_is_first_msg(Algorithms, Ssh, ReNeg),
|
||||
Algorithms
|
||||
of
|
||||
Algos ->
|
||||
@@ -341,10 +344,11 @@ handle_kexinit_msg(#ssh_msg_kexinit{} = CounterPart, #ssh_msg_kexinit{} = Own,
|
||||
end;
|
||||
|
||||
handle_kexinit_msg(#ssh_msg_kexinit{} = CounterPart, #ssh_msg_kexinit{} = Own,
|
||||
- #ssh{role = server} = Ssh) ->
|
||||
+ #ssh{role = server} = Ssh, ReNeg) ->
|
||||
try
|
||||
- {ok, Algorithms} = select_algorithm(server, CounterPart, Own, Ssh#ssh.opts),
|
||||
+ {ok, Algorithms} = select_algorithm(server, CounterPart, Own, Ssh, ReNeg),
|
||||
true = verify_algorithm(Algorithms),
|
||||
+ true = verify_kexinit_is_first_msg(Algorithms, Ssh, ReNeg),
|
||||
Algorithms
|
||||
of
|
||||
Algos ->
|
||||
@@ -374,6 +378,21 @@ verify_algorithm(#alg{kex = Kex}) ->
|
||||
false -> {false, "kex"}
|
||||
end.
|
||||
|
||||
+verify_kexinit_is_first_msg(#alg{kex_strict_negotiated = false}, _, _) ->
|
||||
+ true;
|
||||
+verify_kexinit_is_first_msg(#alg{kex_strict_negotiated = true}, _, renegotiate) ->
|
||||
+ true;
|
||||
+verify_kexinit_is_first_msg(#alg{kex_strict_negotiated = true},
|
||||
+ #ssh{send_sequence = 1, recv_sequence = 1},
|
||||
+ init) ->
|
||||
+ true;
|
||||
+verify_kexinit_is_first_msg(#alg{kex_strict_negotiated = true},
|
||||
+ #ssh{send_sequence = SendSequence,
|
||||
+ recv_sequence = RecvSequence}, init) ->
|
||||
+ error_logger:warning_report(
|
||||
+ lists:concat(["KEX strict violation (", SendSequence, ", ", RecvSequence, ")."])),
|
||||
+ {false, "kex_strict"}.
|
||||
+
|
||||
%%%----------------------------------------------------------------
|
||||
%%%
|
||||
%%% Key exchange initialization
|
||||
@@ -736,6 +755,9 @@ handle_new_keys(#ssh_msg_newkeys{}, Ssh0) ->
|
||||
)
|
||||
end.
|
||||
|
||||
+%%%----------------------------------------------------------------
|
||||
+kex_strict_alg(client) -> [?kex_strict_c];
|
||||
+kex_strict_alg(server) -> [?kex_strict_s].
|
||||
|
||||
%%%----------------------------------------------------------------
|
||||
kex_ext_info(Role, Opts) ->
|
||||
@@ -908,7 +930,35 @@ known_host_key(#ssh{opts = Opts, peer = {PeerName,_}} = Ssh,
|
||||
%%
|
||||
%% The first algorithm in each list MUST be the preferred (guessed)
|
||||
%% algorithm. Each string MUST contain at least one algorithm name.
|
||||
-select_algorithm(Role, Client, Server, Opts) ->
|
||||
+select_algorithm(Role, Client, Server,
|
||||
+ #ssh{opts = Opts,
|
||||
+ kex_strict_negotiated = KexStrictNegotiated0},
|
||||
+ ReNeg) ->
|
||||
+ KexStrictNegotiated =
|
||||
+ case ReNeg of
|
||||
+ %% KEX strict negotiated once per connection
|
||||
+ init ->
|
||||
+ Result =
|
||||
+ case Role of
|
||||
+ server ->
|
||||
+ lists:member(?kex_strict_c,
|
||||
+ Client#ssh_msg_kexinit.kex_algorithms);
|
||||
+ client ->
|
||||
+ lists:member(?kex_strict_s,
|
||||
+ Server#ssh_msg_kexinit.kex_algorithms)
|
||||
+ end,
|
||||
+ case Result of
|
||||
+ true ->
|
||||
+ error_logger:info_report(
|
||||
+ lists:concat([Role, " will use strict KEX ordering"]));
|
||||
+ _ ->
|
||||
+ ok
|
||||
+ end,
|
||||
+ Result;
|
||||
+ _ ->
|
||||
+ KexStrictNegotiated0
|
||||
+ end,
|
||||
+
|
||||
{Encrypt0, Decrypt0} = select_encrypt_decrypt(Role, Client, Server),
|
||||
{SendMac0, RecvMac0} = select_send_recv_mac(Role, Client, Server),
|
||||
|
||||
@@ -959,7 +1009,8 @@ select_algorithm(Role, Client, Server, Opts) ->
|
||||
c_lng = C_Lng,
|
||||
s_lng = S_Lng,
|
||||
send_ext_info = SendExtInfo,
|
||||
- recv_ext_info = RecvExtInfo
|
||||
+ recv_ext_info = RecvExtInfo,
|
||||
+ kex_strict_negotiated = KexStrictNegotiated
|
||||
}}.
|
||||
|
||||
|
||||
@@ -1057,7 +1108,8 @@ alg_setup(snd, SSH) ->
|
||||
c_lng = ALG#alg.c_lng,
|
||||
s_lng = ALG#alg.s_lng,
|
||||
send_ext_info = ALG#alg.send_ext_info,
|
||||
- recv_ext_info = ALG#alg.recv_ext_info
|
||||
+ recv_ext_info = ALG#alg.recv_ext_info,
|
||||
+ kex_strict_negotiated = ALG#alg.kex_strict_negotiated
|
||||
};
|
||||
|
||||
alg_setup(rcv, SSH) ->
|
||||
@@ -1069,22 +1121,23 @@ alg_setup(rcv, SSH) ->
|
||||
c_lng = ALG#alg.c_lng,
|
||||
s_lng = ALG#alg.s_lng,
|
||||
send_ext_info = ALG#alg.send_ext_info,
|
||||
- recv_ext_info = ALG#alg.recv_ext_info
|
||||
+ recv_ext_info = ALG#alg.recv_ext_info,
|
||||
+ kex_strict_negotiated = ALG#alg.kex_strict_negotiated
|
||||
}.
|
||||
|
||||
-
|
||||
-alg_init(snd, SSH0) ->
|
||||
+alg_init(Dir = snd, SSH0) ->
|
||||
{ok,SSH1} = send_mac_init(SSH0),
|
||||
{ok,SSH2} = encrypt_init(SSH1),
|
||||
{ok,SSH3} = compress_init(SSH2),
|
||||
- SSH3;
|
||||
+ {ok,SSH4} = maybe_reset_sequence(Dir, SSH3),
|
||||
+ SSH4;
|
||||
|
||||
-alg_init(rcv, SSH0) ->
|
||||
+alg_init(Dir = rcv, SSH0) ->
|
||||
{ok,SSH1} = recv_mac_init(SSH0),
|
||||
{ok,SSH2} = decrypt_init(SSH1),
|
||||
{ok,SSH3} = decompress_init(SSH2),
|
||||
- SSH3.
|
||||
-
|
||||
+ {ok,SSH4} = maybe_reset_sequence(Dir, SSH3),
|
||||
+ SSH4.
|
||||
|
||||
alg_final(snd, SSH0) ->
|
||||
{ok,SSH1} = send_mac_final(SSH0),
|
||||
@@ -2127,6 +2180,14 @@ len_supported(Name, Len) ->
|
||||
|
||||
same(Algs) -> [{client2server,Algs}, {server2client,Algs}].
|
||||
|
||||
+maybe_reset_sequence(snd, Ssh = #ssh{kex_strict_negotiated = true}) ->
|
||||
+ {ok, Ssh#ssh{send_sequence = 0}};
|
||||
+maybe_reset_sequence(rcv, Ssh = #ssh{kex_strict_negotiated = true}) ->
|
||||
+ {ok, Ssh#ssh{recv_sequence = 0}};
|
||||
+maybe_reset_sequence(_Dir, Ssh) ->
|
||||
+ {ok, Ssh}.
|
||||
+
|
||||
+
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%
|
||||
%% Other utils
|
||||
@@ -2169,8 +2230,8 @@ dbg_trace(C, raw_messages, A) -> dbg_trace(C, hello, A);
|
||||
dbg_trace(C, ssh_messages, A) -> dbg_trace(C, hello, A);
|
||||
|
||||
dbg_trace(flags, alg, _) -> [c];
|
||||
-dbg_trace(on, alg, _) -> dbg:tpl(?MODULE,select_algorithm,4,x);
|
||||
-dbg_trace(off, alg, _) -> dbg:ctpl(?MODULE,select_algorithm,4);
|
||||
+dbg_trace(on, alg, _) -> dbg:tpl(?MODULE,select_algorithm,5,x);
|
||||
+dbg_trace(off, alg, _) -> dbg:ctpl(?MODULE,select_algorithm,5);
|
||||
|
||||
|
||||
dbg_trace(format, hello, {return_from,{?MODULE,hello_version_msg,1},Hello}) ->
|
||||
@@ -2182,7 +2243,7 @@ dbg_trace(format, hello, {call,{?MODULE,handle_hello_version,[Hello]}}) ->
|
||||
Hello
|
||||
];
|
||||
|
||||
-dbg_trace(format, alg, {return_from,{?MODULE,select_algorithm,4},{ok,Alg}}) ->
|
||||
+dbg_trace(format, alg, {return_from,{?MODULE,select_algorithm,5},{ok,Alg}}) ->
|
||||
["Negotiated algorithms:\n",
|
||||
wr_record(Alg)
|
||||
].
|
||||
diff --git a/lib/ssh/src/ssh_transport.hrl b/lib/ssh/src/ssh_transport.hrl
|
||||
index f424a4f..59ac9db 100644
|
||||
--- a/lib/ssh/src/ssh_transport.hrl
|
||||
+++ b/lib/ssh/src/ssh_transport.hrl
|
||||
@@ -266,5 +266,7 @@
|
||||
-define(dh_group18,
|
||||
{2, 16#FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C93402849236C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AACC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E438777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F5683423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD922222E04A4037C0713EB57A81A23F0C73473FC646CEA306B4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A364597E899A0255DC164F31CC50846851DF9AB48195DED7EA1B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F924009438B481C6CD7889A002ED5EE382BC9190DA6FC026E479558E4475677E9AA9E3050E2765694DFC81F56E880B96E7160C980DD98EDD3DFFFFFFFFFFFFFFFFF}).
|
||||
|
||||
-
|
||||
+%%% OpenSSH KEX strict
|
||||
+-define(kex_strict_c, "kex-strict-c-v00@openssh.com").
|
||||
+-define(kex_strict_s, "kex-strict-s-v00@openssh.com").
|
||||
-endif. % -ifdef(ssh_transport).
|
||||
diff --git a/lib/ssh/test/ssh_protocol_SUITE.erl b/lib/ssh/test/ssh_protocol_SUITE.erl
|
||||
index 3e3e151..0f3cfbc 100644
|
||||
--- a/lib/ssh/test/ssh_protocol_SUITE.erl
|
||||
+++ b/lib/ssh/test/ssh_protocol_SUITE.erl
|
||||
@@ -83,8 +83,10 @@ groups() ->
|
||||
gex_client_init_option_groups_moduli_file,
|
||||
gex_client_init_option_groups_file,
|
||||
gex_client_old_request_exact,
|
||||
- gex_client_old_request_noexact
|
||||
- ]},
|
||||
+ gex_client_old_request_noexact,
|
||||
+ kex_strict_negotiated,
|
||||
+ kex_strict_msg_ignore,
|
||||
+ kex_strict_msg_unknown]},
|
||||
{service_requests, [], [bad_service_name,
|
||||
bad_long_service_name,
|
||||
bad_very_long_service_name,
|
||||
@@ -109,17 +111,16 @@ groups() ->
|
||||
|
||||
init_per_suite(Config) ->
|
||||
?CHECK_CRYPTO(start_std_daemon( setup_dirs( start_apps(Config)))).
|
||||
-
|
||||
+
|
||||
end_per_suite(Config) ->
|
||||
stop_apps(Config).
|
||||
|
||||
-
|
||||
-
|
||||
init_per_testcase(no_common_alg_server_disconnects, Config) ->
|
||||
start_std_daemon(Config, [{preferred_algorithms,[{public_key,['ssh-rsa']},
|
||||
{cipher,?DEFAULT_CIPHERS}
|
||||
]}]);
|
||||
-
|
||||
+init_per_testcase(kex_strict_negotiated, Config) ->
|
||||
+ Config;
|
||||
init_per_testcase(TC, Config) when TC == gex_client_init_option_groups ;
|
||||
TC == gex_client_init_option_groups_moduli_file ;
|
||||
TC == gex_client_init_option_groups_file ;
|
||||
@@ -162,6 +163,8 @@ init_per_testcase(_TestCase, Config) ->
|
||||
|
||||
end_per_testcase(no_common_alg_server_disconnects, Config) ->
|
||||
stop_std_daemon(Config);
|
||||
+end_per_testcase(kex_strict_negotiated, Config) ->
|
||||
+ Config;
|
||||
end_per_testcase(TC, Config) when TC == gex_client_init_option_groups ;
|
||||
TC == gex_client_init_option_groups_moduli_file ;
|
||||
TC == gex_client_init_option_groups_file ;
|
||||
@@ -763,6 +766,80 @@ ext_info_c(Config) ->
|
||||
{result, Pid, Error} -> ct:fail("Error: ~p",[Error])
|
||||
end.
|
||||
|
||||
+%%%--------------------------------------------------------------------
|
||||
+%%%
|
||||
+kex_strict_negotiated(Config0) ->
|
||||
+ {ok,Pid} = ssh_test_lib:add_report_handler(),
|
||||
+ Config = start_std_daemon(Config0, []),
|
||||
+ {Server, Host, Port} = proplists:get_value(server, Config),
|
||||
+ #{level := Level} = logger:get_primary_config(),
|
||||
+ logger:set_primary_config(level, notice),
|
||||
+ {ok, ConnRef} = std_connect({Host, Port}, Config, []),
|
||||
+ {algorithms, A} = ssh:connection_info(ConnRef, algorithms),
|
||||
+ ssh:stop_daemon(Server),
|
||||
+ {ok, Reports} = ssh_test_lib:get_reports(Pid),
|
||||
+ ct:log("Reports = ~p", [Reports]),
|
||||
+ true = ssh_test_lib:kex_strict_negotiated(client, Reports),
|
||||
+ true = ssh_test_lib:kex_strict_negotiated(server, Reports),
|
||||
+ logger:set_primary_config(Level),
|
||||
+ ok.
|
||||
+
|
||||
+%% Connect to an erlang server and inject unexpected SSH ignore
|
||||
+kex_strict_msg_ignore(Config) ->
|
||||
+ ct:log("START: ~p~n=================================", [?FUNCTION_NAME]),
|
||||
+ ExpectedReason = "strict KEX violation: unexpected SSH_MSG_IGNORE",
|
||||
+ TestMessages =
|
||||
+ [{send, ssh_msg_ignore},
|
||||
+ {match, #ssh_msg_kexdh_reply{_='_'}, receive_msg},
|
||||
+ {match, disconnect(?SSH_DISCONNECT_KEY_EXCHANGE_FAILED), receive_msg}],
|
||||
+ kex_strict_helper(Config, TestMessages, ExpectedReason).
|
||||
+
|
||||
+%% Connect to an erlang server and inject unexpected non-SSH binary
|
||||
+kex_strict_msg_unknown(Config) ->
|
||||
+ ct:log("START: ~p~n=================================", [?FUNCTION_NAME]),
|
||||
+ ExpectedReason = "Bad packet: Size",
|
||||
+ TestMessages =
|
||||
+ [{send, ssh_msg_unknown},
|
||||
+ {match, #ssh_msg_kexdh_reply{_='_'}, receive_msg},
|
||||
+ {match, disconnect(?SSH_DISCONNECT_KEY_EXCHANGE_FAILED), receive_msg}],
|
||||
+ kex_strict_helper(Config, TestMessages, ExpectedReason).
|
||||
+
|
||||
+kex_strict_helper(Config, TestMessages, ExpectedReason) ->
|
||||
+ {ok,HandlerPid} = ssh_test_lib:add_report_handler(),
|
||||
+ #{level := Level} = logger:get_primary_config(),
|
||||
+ logger:set_primary_config(level, notice),
|
||||
+ %% Connect and negotiate keys
|
||||
+ {ok, InitialState} = ssh_trpt_test_lib:exec(
|
||||
+ [{set_options, [print_ops, print_seqnums, print_messages]}]
|
||||
+ ),
|
||||
+ {ok, _AfterKexState} =
|
||||
+ ssh_trpt_test_lib:exec(
|
||||
+ [{connect,
|
||||
+ server_host(Config),server_port(Config),
|
||||
+ [{preferred_algorithms,[{kex,[?DEFAULT_KEX]},
|
||||
+ {cipher,?DEFAULT_CIPHERS}
|
||||
+ ]},
|
||||
+ {silently_accept_hosts, true},
|
||||
+ {recv_ext_info, false},
|
||||
+ {user_dir, user_dir(Config)},
|
||||
+ {user_interaction, false}
|
||||
+ | proplists:get_value(extra_options,Config,[])
|
||||
+ ]},
|
||||
+ receive_hello,
|
||||
+ {send, hello},
|
||||
+ {send, ssh_msg_kexinit},
|
||||
+ {match, #ssh_msg_kexinit{_='_'}, receive_msg},
|
||||
+ {send, ssh_msg_kexdh_init}] ++
|
||||
+ TestMessages,
|
||||
+ InitialState),
|
||||
+ ct:sleep(100),
|
||||
+ {ok, Reports} = ssh_test_lib:get_reports(HandlerPid),
|
||||
+ ct:log("HandlerPid = ~p~nReports = ~p", [HandlerPid, Reports]),
|
||||
+ true = ssh_test_lib:kex_strict_negotiated(client, Reports),
|
||||
+ true = ssh_test_lib:kex_strict_negotiated(server, Reports),
|
||||
+ true = ssh_test_lib:event_logged(server, Reports, ExpectedReason),
|
||||
+ logger:set_primary_config(Level),
|
||||
+ ok.
|
||||
|
||||
%%%----------------------------------------------------------------
|
||||
%%%
|
||||
@@ -784,7 +861,7 @@ modify_append(Config) ->
|
||||
Ciphers = filter_supported(cipher, ?CIPHERS),
|
||||
{ok,_} =
|
||||
chk_pref_algs(Config,
|
||||
- [?DEFAULT_KEX, ?EXTRA_KEX],
|
||||
+ [?DEFAULT_KEX, ?EXTRA_KEX, list_to_atom(?kex_strict_s)],
|
||||
Ciphers,
|
||||
[{preferred_algorithms, [{kex,[?DEFAULT_KEX]},
|
||||
{cipher,Ciphers}
|
||||
@@ -798,7 +875,7 @@ modify_prepend(Config) ->
|
||||
Ciphers = filter_supported(cipher, ?CIPHERS),
|
||||
{ok,_} =
|
||||
chk_pref_algs(Config,
|
||||
- [?EXTRA_KEX, ?DEFAULT_KEX],
|
||||
+ [?EXTRA_KEX, ?DEFAULT_KEX, list_to_atom(?kex_strict_s)],
|
||||
Ciphers,
|
||||
[{preferred_algorithms, [{kex,[?DEFAULT_KEX]},
|
||||
{cipher,Ciphers}
|
||||
@@ -812,7 +889,7 @@ modify_rm(Config) ->
|
||||
Ciphers = filter_supported(cipher, ?CIPHERS),
|
||||
{ok,_} =
|
||||
chk_pref_algs(Config,
|
||||
- [?DEFAULT_KEX],
|
||||
+ [?DEFAULT_KEX, list_to_atom(?kex_strict_s)],
|
||||
tl(Ciphers),
|
||||
[{preferred_algorithms, [{kex,[?DEFAULT_KEX,?EXTRA_KEX]},
|
||||
{cipher,Ciphers}
|
||||
@@ -831,7 +908,7 @@ modify_combo(Config) ->
|
||||
LastC = lists:last(Ciphers),
|
||||
{ok,_} =
|
||||
chk_pref_algs(Config,
|
||||
- [?DEFAULT_KEX],
|
||||
+ [?DEFAULT_KEX, list_to_atom(?kex_strict_s)],
|
||||
[LastC] ++ (tl(Ciphers)--[LastC]) ++ [hd(Ciphers)],
|
||||
[{preferred_algorithms, [{kex,[?DEFAULT_KEX,?EXTRA_KEX]},
|
||||
{cipher,Ciphers}
|
||||
diff --git a/lib/ssh/test/ssh_trpt_test_lib.erl b/lib/ssh/test/ssh_trpt_test_lib.erl
|
||||
index f2c9892..1b60ea4 100644
|
||||
--- a/lib/ssh/test/ssh_trpt_test_lib.erl
|
||||
+++ b/lib/ssh/test/ssh_trpt_test_lib.erl
|
||||
@@ -75,7 +75,7 @@ exec(L, S) when is_list(L) -> lists:foldl(fun exec/2, S, L);
|
||||
exec(Op, S0=#s{}) ->
|
||||
S1 = init_op_traces(Op, S0),
|
||||
try seqnum_trace(
|
||||
- op(Op, S1))
|
||||
+ op(Op, S1), S1)
|
||||
of
|
||||
S = #s{} ->
|
||||
case proplists:get_value(silent,S#s.opts) of
|
||||
@@ -333,12 +333,20 @@ send(S0, ssh_msg_kexinit) ->
|
||||
{Msg, _Bytes, _C0} = ssh_transport:key_exchange_init_msg(S0#s.ssh),
|
||||
send(S0, Msg);
|
||||
|
||||
+send(S0, ssh_msg_ignore) ->
|
||||
+ Msg = #ssh_msg_ignore{data = "unexpected_ignore_message"},
|
||||
+ send(S0, Msg);
|
||||
+
|
||||
+send(S0, ssh_msg_unknown) ->
|
||||
+ Msg = binary:encode_hex(<<"0000000C060900000000000000000000">>),
|
||||
+ send(S0, Msg);
|
||||
+
|
||||
send(S0=#s{alg_neg={undefined,PeerMsg}}, Msg=#ssh_msg_kexinit{}) ->
|
||||
S1 = opt(print_messages, S0,
|
||||
fun(X) when X==true;X==detail -> {"Send~n~s~n",[format_msg(Msg)]} end),
|
||||
S2 = case PeerMsg of
|
||||
#ssh_msg_kexinit{} ->
|
||||
- try ssh_transport:handle_kexinit_msg(PeerMsg, Msg, S1#s.ssh) of
|
||||
+ try ssh_transport:handle_kexinit_msg(PeerMsg, Msg, S1#s.ssh, init) of
|
||||
{ok,Cx} when ?role(S1) == server ->
|
||||
S1#s{alg = Cx#ssh.algorithms};
|
||||
{ok,_NextKexMsgBin,Cx} when ?role(S1) == client ->
|
||||
@@ -360,7 +368,7 @@ send(S0=#s{alg_neg={undefined,PeerMsg}}, Msg=#ssh_msg_kexinit{}) ->
|
||||
send(S0, ssh_msg_kexdh_init) when ?role(S0) == client ->
|
||||
{OwnMsg, PeerMsg} = S0#s.alg_neg,
|
||||
{ok, NextKexMsgBin, C} =
|
||||
- try ssh_transport:handle_kexinit_msg(PeerMsg, OwnMsg, S0#s.ssh)
|
||||
+ try ssh_transport:handle_kexinit_msg(PeerMsg, OwnMsg, S0#s.ssh, init)
|
||||
catch
|
||||
Class:Exc ->
|
||||
fail("Algoritm negotiation failed!",
|
||||
@@ -443,7 +451,7 @@ recv(S0 = #s{}) ->
|
||||
fail("2 kexint received!!", S);
|
||||
|
||||
{OwnMsg, _} ->
|
||||
- try ssh_transport:handle_kexinit_msg(PeerMsg, OwnMsg, S#s.ssh) of
|
||||
+ try ssh_transport:handle_kexinit_msg(PeerMsg, OwnMsg, S#s.ssh, init) of
|
||||
{ok,C} when ?role(S) == server ->
|
||||
S#s{alg_neg = {OwnMsg, PeerMsg},
|
||||
alg = C#ssh.algorithms,
|
||||
@@ -796,23 +804,23 @@ report_trace(Class, Term, S) ->
|
||||
fun(true) -> {"~s ~p",[Class,Term]} end)
|
||||
).
|
||||
|
||||
-seqnum_trace(S) ->
|
||||
+seqnum_trace(S, S0) ->
|
||||
opt(print_seqnums, S,
|
||||
- fun(true) when S#s.ssh#ssh.send_sequence =/= S#s.ssh#ssh.send_sequence,
|
||||
- S#s.ssh#ssh.recv_sequence =/= S#s.ssh#ssh.recv_sequence ->
|
||||
+ fun(true) when S0#s.ssh#ssh.send_sequence =/= S#s.ssh#ssh.send_sequence,
|
||||
+ S0#s.ssh#ssh.recv_sequence =/= S#s.ssh#ssh.recv_sequence ->
|
||||
{"~p seq num: send ~p->~p, recv ~p->~p~n",
|
||||
[?role(S),
|
||||
- S#s.ssh#ssh.send_sequence, S#s.ssh#ssh.send_sequence,
|
||||
- S#s.ssh#ssh.recv_sequence, S#s.ssh#ssh.recv_sequence
|
||||
+ S0#s.ssh#ssh.send_sequence, S#s.ssh#ssh.send_sequence,
|
||||
+ S0#s.ssh#ssh.recv_sequence, S#s.ssh#ssh.recv_sequence
|
||||
]};
|
||||
- (true) when S#s.ssh#ssh.send_sequence =/= S#s.ssh#ssh.send_sequence ->
|
||||
+ (true) when S0#s.ssh#ssh.send_sequence =/= S#s.ssh#ssh.send_sequence ->
|
||||
{"~p seq num: send ~p->~p~n",
|
||||
[?role(S),
|
||||
- S#s.ssh#ssh.send_sequence, S#s.ssh#ssh.send_sequence]};
|
||||
- (true) when S#s.ssh#ssh.recv_sequence =/= S#s.ssh#ssh.recv_sequence ->
|
||||
+ S0#s.ssh#ssh.send_sequence, S#s.ssh#ssh.send_sequence]};
|
||||
+ (true) when S0#s.ssh#ssh.recv_sequence =/= S#s.ssh#ssh.recv_sequence ->
|
||||
{"~p seq num: recv ~p->~p~n",
|
||||
[?role(S),
|
||||
- S#s.ssh#ssh.recv_sequence, S#s.ssh#ssh.recv_sequence]}
|
||||
+ S0#s.ssh#ssh.recv_sequence, S#s.ssh#ssh.recv_sequence]}
|
||||
end).
|
||||
|
||||
print_traces(S) when S#s.prints == [] -> S;
|
||||
--
|
||||
2.33.0
|
||||
|
||||
89
CVE-2025-26618.patch
Normal file
89
CVE-2025-26618.patch
Normal file
@ -0,0 +1,89 @@
|
||||
From 0ed2573cbd55c92e9125c9dc70fa1ca7fed82872 Mon Sep 17 00:00:00 2001
|
||||
From: Jakub Witczak <kuba@erlang.org>
|
||||
Date: Thu, 6 Feb 2025 19:00:44 +0100
|
||||
Subject: [PATCH] ssh: sftp reject packets exceeding limit
|
||||
|
||||
origin: https://github.com/erlang/otp/commit/0ed2573cbd55c92e9125c9dc70fa1ca7fed82872
|
||||
---
|
||||
lib/ssh/src/ssh_sftpd.erl | 47 ++++++++++++++++++++++++++-------------
|
||||
1 file changed, 32 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/lib/ssh/src/ssh_sftpd.erl b/lib/ssh/src/ssh_sftpd.erl
|
||||
index c86ed2cb8199..6bcad0d056e7 100644
|
||||
--- a/lib/ssh/src/ssh_sftpd.erl
|
||||
+++ b/lib/ssh/src/ssh_sftpd.erl
|
||||
@@ -27,7 +27,7 @@
|
||||
-behaviour(ssh_server_channel).
|
||||
|
||||
-include_lib("kernel/include/file.hrl").
|
||||
-
|
||||
+-include_lib("kernel/include/logger.hrl").
|
||||
-include("ssh.hrl").
|
||||
-include("ssh_xfer.hrl").
|
||||
-include("ssh_connect.hrl"). %% For ?DEFAULT_PACKET_SIZE and ?DEFAULT_WINDOW_SIZE
|
||||
@@ -128,9 +128,8 @@ init(Options) ->
|
||||
%% Description: Handles channel messages
|
||||
%%--------------------------------------------------------------------
|
||||
handle_ssh_msg({ssh_cm, _ConnectionManager,
|
||||
- {data, _ChannelId, Type, Data}}, State) ->
|
||||
- State1 = handle_data(Type, Data, State),
|
||||
- {ok, State1};
|
||||
+ {data, ChannelId, Type, Data}}, State) ->
|
||||
+ handle_data(Type, ChannelId, Data, State);
|
||||
|
||||
handle_ssh_msg({ssh_cm, _, {eof, ChannelId}}, State) ->
|
||||
{stop, ChannelId, State};
|
||||
@@ -187,24 +186,42 @@ terminate(_, #state{handles=Handles, file_handler=FileMod, file_state=FS}) ->
|
||||
%%--------------------------------------------------------------------
|
||||
%%% Internal functions
|
||||
%%--------------------------------------------------------------------
|
||||
-handle_data(0, <<?UINT32(Len), Msg:Len/binary, Rest/binary>>,
|
||||
+handle_data(0, ChannelId, <<?UINT32(Len), Msg:Len/binary, Rest/binary>>,
|
||||
State = #state{pending = <<>>}) ->
|
||||
<<Op, ?UINT32(ReqId), Data/binary>> = Msg,
|
||||
NewState = handle_op(Op, ReqId, Data, State),
|
||||
case Rest of
|
||||
<<>> ->
|
||||
- NewState;
|
||||
+ {ok, NewState};
|
||||
_ ->
|
||||
- handle_data(0, Rest, NewState)
|
||||
+ handle_data(0, ChannelId, Rest, NewState)
|
||||
end;
|
||||
-
|
||||
-handle_data(0, Data, State = #state{pending = <<>>}) ->
|
||||
- State#state{pending = Data};
|
||||
-
|
||||
-handle_data(Type, Data, State = #state{pending = Pending}) ->
|
||||
- handle_data(Type, <<Pending/binary, Data/binary>>,
|
||||
- State#state{pending = <<>>}).
|
||||
-
|
||||
+handle_data(0, _ChannelId, Data, State = #state{pending = <<>>}) ->
|
||||
+ {ok, State#state{pending = Data}};
|
||||
+handle_data(Type, ChannelId, Data0, State = #state{pending = Pending}) ->
|
||||
+ Data = <<Pending/binary, Data0/binary>>,
|
||||
+ Size = byte_size(Data),
|
||||
+ case Size > ?SSH_MAX_PACKET_SIZE of
|
||||
+ true ->
|
||||
+ ReportFun =
|
||||
+ fun([S]) ->
|
||||
+ Report =
|
||||
+ #{label => {error_logger, error_report},
|
||||
+ report =>
|
||||
+ io_lib:format("SFTP packet size (~B) exceeds the limit!",
|
||||
+ [S])},
|
||||
+ Meta =
|
||||
+ #{error_logger =>
|
||||
+ #{tag => error_report,type => std_error},
|
||||
+ report_cb => fun(#{report := Msg}) -> {Msg, []} end},
|
||||
+ {Report, Meta}
|
||||
+ end,
|
||||
+ ?LOG_ERROR(ReportFun, [Size]),
|
||||
+ {stop, ChannelId, State};
|
||||
+ _ ->
|
||||
+ handle_data(Type, ChannelId, Data, State#state{pending = <<>>})
|
||||
+ end.
|
||||
+
|
||||
handle_op(?SSH_FXP_INIT, Version, B, State) when is_binary(B) ->
|
||||
XF = State#state.xf,
|
||||
Vsn = lists:min([XF#ssh_xfer.vsn, Version]),
|
||||
45
CVE-2025-30211-1.patch
Normal file
45
CVE-2025-30211-1.patch
Normal file
@ -0,0 +1,45 @@
|
||||
diff --git a/lib/ssh/src/ssh_message.erl b/lib/ssh/src/ssh_message.erl
|
||||
index 65f3c21..8cf18b1 100644
|
||||
--- a/lib/ssh/src/ssh_message.erl
|
||||
+++ b/lib/ssh/src/ssh_message.erl
|
||||
@@ -24,6 +24,7 @@
|
||||
-module(ssh_message).
|
||||
|
||||
-include_lib("public_key/include/public_key.hrl").
|
||||
+-include_lib("kernel/include/logger.hrl").
|
||||
|
||||
-include("ssh.hrl").
|
||||
-include("ssh_connect.hrl").
|
||||
@@ -51,6 +52,7 @@
|
||||
-define(Ename_list(X), ?STRING(ssh_bits:name_list(X)) ).
|
||||
-define(Empint(X), (ssh_bits:mpint(X))/binary ).
|
||||
-define(Ebinary(X), ?STRING(X) ).
|
||||
+-define(ALG_NAME_LIMIT, 64).
|
||||
|
||||
ucl(B) ->
|
||||
try unicode:characters_to_list(B) of
|
||||
@@ -591,8 +593,22 @@ decode_kex_init(<<?BYTE(Bool)>>, Acc, 0) ->
|
||||
X = 0,
|
||||
list_to_tuple(lists:reverse([X, erl_boolean(Bool) | Acc]));
|
||||
decode_kex_init(<<?DEC_BIN(Data,__0), Rest/binary>>, Acc, N) ->
|
||||
- Names = string:tokens(?unicode_list(Data), ","),
|
||||
- decode_kex_init(Rest, [Names | Acc], N -1).
|
||||
+ BinParts = binary:split(Data, <<$,>>, [global]),
|
||||
+ Process =
|
||||
+ fun(<<>>, PAcc) ->
|
||||
+ PAcc;
|
||||
+ (Part, PAcc) ->
|
||||
+ case byte_size(Part) > ?ALG_NAME_LIMIT of
|
||||
+ true ->
|
||||
+ ?LOG_DEBUG("Ignoring too long name", []),
|
||||
+ PAcc;
|
||||
+ false ->
|
||||
+ Name = binary:bin_to_list(Part),
|
||||
+ [Name | PAcc]
|
||||
+ end
|
||||
+ end,
|
||||
+ Names = lists:foldr(Process, [], BinParts),
|
||||
+ decode_kex_init(Rest, [Names | Acc], N - 1).
|
||||
|
||||
|
||||
%%%================================================================
|
||||
37
CVE-2025-30211-2.patch
Normal file
37
CVE-2025-30211-2.patch
Normal file
@ -0,0 +1,37 @@
|
||||
From: Jakub Witczak <kuba@erlang.org>
|
||||
Date: Fri, 21 Mar 2025 17:50:21 +0100
|
||||
Subject: [PATCH] ssh: use chars_limit for bad packets error messages
|
||||
|
||||
origin: backport, https://github.com/erlang/otp/commit/d64d9fb0688092356a336e38a8717499113312a0
|
||||
bug: https://github.com/erlang/otp/security/advisories/GHSA-vvr3-fjhh-cfwc
|
||||
bug-debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1101713
|
||||
---
|
||||
lib/ssh/src/ssh_connection_handler.erl | 8 ++++----
|
||||
1 file changed, 4 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
|
||||
index 1d9151b..859db8e 100644
|
||||
--- a/lib/ssh/src/ssh_connection_handler.erl
|
||||
+++ b/lib/ssh/src/ssh_connection_handler.erl
|
||||
@@ -1379,8 +1379,8 @@ handle_event(info, {Proto, Sock, NewData}, StateName,
|
||||
MaxLogItemLen = ?GET_OPT(max_log_item_len,SshParams#ssh.opts),
|
||||
{Shutdown, D} =
|
||||
?send_disconnect(?SSH_DISCONNECT_PROTOCOL_ERROR,
|
||||
- io_lib:format("Bad packet: Decrypted, but can't decode~n~p:~p~n~P",
|
||||
- [C,E,ST,MaxLogItemLen]),
|
||||
+ io_lib:format("Bad packet: Decrypted, but can't decode~n~p:~p~n~p",
|
||||
+ [C,E,ST], [{chars_limit, MaxLogItemLen}]),
|
||||
StateName, D1),
|
||||
{stop, Shutdown, D}
|
||||
end;
|
||||
@@ -1414,8 +1414,8 @@ handle_event(info, {Proto, Sock, NewData}, StateName,
|
||||
MaxLogItemLen = ?GET_OPT(max_log_item_len,SshParams#ssh.opts),
|
||||
{Shutdown, D} =
|
||||
?send_disconnect(?SSH_DISCONNECT_PROTOCOL_ERROR,
|
||||
- io_lib:format("Bad packet: Couldn't decrypt~n~p:~p~n~P",
|
||||
- [C,E,ST,MaxLogItemLen]),
|
||||
+ io_lib:format("Bad packet: Couldn't decrypt~n~p:~p~n~p",
|
||||
+ [C,E,ST], [{chars_limit, MaxLogItemLen}]),
|
||||
StateName, D0),
|
||||
{stop, Shutdown, D}
|
||||
end;
|
||||
132
CVE-2025-30211-3.patch
Normal file
132
CVE-2025-30211-3.patch
Normal file
@ -0,0 +1,132 @@
|
||||
From: Jakub Witczak <kuba@erlang.org>
|
||||
Date: Mon, 24 Mar 2025 11:31:39 +0100
|
||||
Subject: [PATCH] ssh: custom_kexinit test added
|
||||
|
||||
origin: backport, https://github.com/erlang/otp/commit/5ee26eb412a76ba1c6afdf4524b62939a48d1bce
|
||||
bug: https://github.com/erlang/otp/security/advisories/GHSA-vvr3-fjhh-cfwc
|
||||
bug-debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1101713
|
||||
---
|
||||
lib/ssh/test/ssh_protocol_SUITE.erl | 89 +++++++++++++++++++++++++++++++++++--
|
||||
1 file changed, 86 insertions(+), 3 deletions(-)
|
||||
|
||||
Index: erlang-22.2.7+dfsg/lib/ssh/test/ssh_protocol_SUITE.erl
|
||||
===================================================================
|
||||
--- erlang-22.2.7+dfsg.orig/lib/ssh/test/ssh_protocol_SUITE.erl
|
||||
+++ erlang-22.2.7+dfsg/lib/ssh/test/ssh_protocol_SUITE.erl
|
||||
@@ -80,7 +80,8 @@ groups() ->
|
||||
{field_size_error, [], [service_name_length_too_large,
|
||||
service_name_length_too_short]},
|
||||
|
||||
- {kex, [], [no_common_alg_server_disconnects,
|
||||
+ {kex, [], [custom_kexinit,
|
||||
+ no_common_alg_server_disconnects,
|
||||
no_common_alg_client_disconnects,
|
||||
gex_client_init_option_groups,
|
||||
gex_server_gex_limit,
|
||||
@@ -119,7 +120,7 @@ init_per_suite(Config) ->
|
||||
end_per_suite(Config) ->
|
||||
stop_apps(Config).
|
||||
|
||||
-init_per_testcase(no_common_alg_server_disconnects, Config) ->
|
||||
+init_per_testcase(Tc, Config) when Tc == no_common_alg_server_disconnects; Tc == custom_kexinit ->
|
||||
start_std_daemon(Config, [{preferred_algorithms,[{public_key,['ssh-rsa']},
|
||||
{cipher,?DEFAULT_CIPHERS}
|
||||
]}]);
|
||||
@@ -165,7 +166,7 @@ init_per_testcase(TC, Config) when TC ==
|
||||
init_per_testcase(_TestCase, Config) ->
|
||||
check_std_daemon_works(Config, ?LINE).
|
||||
|
||||
-end_per_testcase(no_common_alg_server_disconnects, Config) ->
|
||||
+end_per_testcase(Tc, Config) when Tc == no_common_alg_server_disconnects; Tc == custom_kexinit ->
|
||||
stop_std_daemon(Config);
|
||||
end_per_testcase(kex_strict_negotiated, Config) ->
|
||||
Config;
|
||||
@@ -326,6 +327,88 @@ no_common_alg_server_disconnects(Config)
|
||||
]
|
||||
).
|
||||
|
||||
+custom_kexinit(Config) ->
|
||||
+ %% 16#C0 value causes unicode:characters_to_list to return a big error value
|
||||
+ Trash = lists:duplicate(260000, 16#C0),
|
||||
+ FunnyAlg = "curve25519-sha256",
|
||||
+ KexInit =
|
||||
+ #ssh_msg_kexinit{cookie = <<"Ã/Ï!9zñKá:ñÀv¿JÜ">>,
|
||||
+ kex_algorithms =
|
||||
+ [FunnyAlg ++ Trash],
|
||||
+ server_host_key_algorithms = ["ssh-rsa"],
|
||||
+ encryption_algorithms_client_to_server =
|
||||
+ ["aes256-ctr","aes192-ctr","aes128-ctr","aes128-cbc","3des-cbc"],
|
||||
+ encryption_algorithms_server_to_client =
|
||||
+ ["aes256-ctr","aes192-ctr","aes128-ctr","aes128-cbc","3des-cbc"],
|
||||
+ mac_algorithms_client_to_server =
|
||||
+ ["hmac-sha2-512-etm@openssh.com","hmac-sha2-256-etm@openssh.com",
|
||||
+ "hmac-sha2-512","hmac-sha2-256","hmac-sha1-etm@openssh.com","hmac-sha1"],
|
||||
+ mac_algorithms_server_to_client =
|
||||
+ ["hmac-sha2-512-etm@openssh.com","hmac-sha2-256-etm@openssh.com",
|
||||
+ "hmac-sha2-512","hmac-sha2-256","hmac-sha1-etm@openssh.com","hmac-sha1"],
|
||||
+ compression_algorithms_client_to_server = ["none","zlib@openssh.com","zlib"],
|
||||
+ compression_algorithms_server_to_client = ["none","zlib@openssh.com","zlib"],
|
||||
+ languages_client_to_server = [],
|
||||
+ languages_server_to_client = [],
|
||||
+ first_kex_packet_follows = false,
|
||||
+ reserved = 0
|
||||
+ },
|
||||
+ PacketFun =
|
||||
+ fun(Msg, Ssh) ->
|
||||
+ BinMsg = custom_encode(Msg),
|
||||
+ ssh_transport:pack(BinMsg, Ssh, 0)
|
||||
+ end,
|
||||
+ {ok,_} =
|
||||
+ ssh_trpt_test_lib:exec(
|
||||
+ [{set_options, [print_ops, {print_messages,detail}]},
|
||||
+ {connect,
|
||||
+ server_host(Config),server_port(Config),
|
||||
+ [{silently_accept_hosts, true},
|
||||
+ {user_dir, user_dir(Config)},
|
||||
+ {user_interaction, false},
|
||||
+ {preferred_algorithms,[{public_key,['ssh-rsa']},
|
||||
+ {cipher,?DEFAULT_CIPHERS}
|
||||
+ ]}
|
||||
+ ]},
|
||||
+ receive_hello,
|
||||
+ {send, hello},
|
||||
+ {match, #ssh_msg_kexinit{_='_'}, receive_msg},
|
||||
+ {send, {special, KexInit, PacketFun}}, % with server unsupported 'ssh-dss' !
|
||||
+ {match, disconnect(), receive_msg}
|
||||
+ ]
|
||||
+ ).
|
||||
+
|
||||
+custom_encode(#ssh_msg_kexinit{
|
||||
+ cookie = Cookie,
|
||||
+ kex_algorithms = KeyAlgs,
|
||||
+ server_host_key_algorithms = HostKeyAlgs,
|
||||
+ encryption_algorithms_client_to_server = EncAlgC2S,
|
||||
+ encryption_algorithms_server_to_client = EncAlgS2C,
|
||||
+ mac_algorithms_client_to_server = MacAlgC2S,
|
||||
+ mac_algorithms_server_to_client = MacAlgS2C,
|
||||
+ compression_algorithms_client_to_server = CompAlgS2C,
|
||||
+ compression_algorithms_server_to_client = CompAlgC2S,
|
||||
+ languages_client_to_server = LangC2S,
|
||||
+ languages_server_to_client = LangS2C,
|
||||
+ first_kex_packet_follows = Bool,
|
||||
+ reserved = Reserved
|
||||
+ }) ->
|
||||
+ KeyAlgsBin0 = <<?Ename_list(KeyAlgs)>>,
|
||||
+ <<?UINT32(Len0), Data:Len0/binary>> = KeyAlgsBin0,
|
||||
+ KeyAlgsBin = <<?UINT32(Len0), Data/binary>>,
|
||||
+ <<?Ebyte(?SSH_MSG_KEXINIT), Cookie/binary,
|
||||
+ KeyAlgsBin/binary,
|
||||
+ ?Ename_list(HostKeyAlgs),
|
||||
+ ?Ename_list(EncAlgC2S),
|
||||
+ ?Ename_list(EncAlgS2C),
|
||||
+ ?Ename_list(MacAlgC2S),
|
||||
+ ?Ename_list(MacAlgS2C),
|
||||
+ ?Ename_list(CompAlgS2C),
|
||||
+ ?Ename_list(CompAlgC2S),
|
||||
+ ?Ename_list(LangC2S),
|
||||
+ ?Ename_list(LangS2C),
|
||||
+ ?Eboolean(Bool), ?Euint32(Reserved)>>.
|
||||
+
|
||||
%%--------------------------------------------------------------------
|
||||
%%% Algo negotiation fail. This should result in a ssh_msg_disconnect
|
||||
%%% being sent from the client.
|
||||
57
CVE-2025-30211-pre1.patch
Normal file
57
CVE-2025-30211-pre1.patch
Normal file
@ -0,0 +1,57 @@
|
||||
From: Jakub Witczak <kuba@erlang.org>
|
||||
Date: Fri, 27 Jan 2023 17:13:31 +0100
|
||||
Subject: [PATCH] ssh: reduce log length
|
||||
|
||||
origin: backport, https://github.com/erlang/otp/commit/e93e40cf8150539338e7320b9fd9bad825b0a6d0
|
||||
bug: https://github.com/erlang/otp/security/advisories/GHSA-vvr3-fjhh-cfwc
|
||||
bug-debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1101713
|
||||
---
|
||||
lib/ssh/src/ssh_connection_handler.erl | 19 ++++++++++++-------
|
||||
1 file changed, 12 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
|
||||
index ee397ac..1d9151b 100644
|
||||
--- a/lib/ssh/src/ssh_connection_handler.erl
|
||||
+++ b/lib/ssh/src/ssh_connection_handler.erl
|
||||
@@ -1329,8 +1329,10 @@ handle_event(info, {Proto, Sock, Info}, {hello,_}, #data{socket = Sock,
|
||||
end;
|
||||
|
||||
|
||||
-handle_event(info, {Proto, Sock, NewData}, StateName, D0 = #data{socket = Sock,
|
||||
- transport_protocol = Proto}) ->
|
||||
+handle_event(info, {Proto, Sock, NewData}, StateName,
|
||||
+ D0 = #data{socket = Sock,
|
||||
+ transport_protocol = Proto,
|
||||
+ ssh_params = SshParams}) ->
|
||||
try ssh_transport:handle_packet_part(
|
||||
D0#data.decrypted_data_buffer,
|
||||
<<(D0#data.encrypted_data_buffer)/binary, NewData/binary>>,
|
||||
@@ -1374,10 +1376,11 @@ handle_event(info, {Proto, Sock, NewData}, StateName, D0 = #data{socket = Sock,
|
||||
]}
|
||||
catch
|
||||
C:E:ST ->
|
||||
- {Shutdown, D} =
|
||||
+ MaxLogItemLen = ?GET_OPT(max_log_item_len,SshParams#ssh.opts),
|
||||
+ {Shutdown, D} =
|
||||
?send_disconnect(?SSH_DISCONNECT_PROTOCOL_ERROR,
|
||||
- io_lib:format("Bad packet: Decrypted, but can't decode~n~p:~p~n~p",
|
||||
- [C,E,ST]),
|
||||
+ io_lib:format("Bad packet: Decrypted, but can't decode~n~p:~p~n~P",
|
||||
+ [C,E,ST,MaxLogItemLen]),
|
||||
StateName, D1),
|
||||
{stop, Shutdown, D}
|
||||
end;
|
||||
@@ -1408,9 +1411,11 @@ handle_event(info, {Proto, Sock, NewData}, StateName, D0 = #data{socket = Sock,
|
||||
{stop, Shutdown, D}
|
||||
catch
|
||||
C:E:ST ->
|
||||
- {Shutdown, D} =
|
||||
+ MaxLogItemLen = ?GET_OPT(max_log_item_len,SshParams#ssh.opts),
|
||||
+ {Shutdown, D} =
|
||||
?send_disconnect(?SSH_DISCONNECT_PROTOCOL_ERROR,
|
||||
- io_lib:format("Bad packet: Couldn't decrypt~n~p:~p~n~p",[C,E,ST]),
|
||||
+ io_lib:format("Bad packet: Couldn't decrypt~n~p:~p~n~P",
|
||||
+ [C,E,ST,MaxLogItemLen]),
|
||||
StateName, D0),
|
||||
{stop, Shutdown, D}
|
||||
end;
|
||||
302
CVE-2025-32433-pre1.patch
Normal file
302
CVE-2025-32433-pre1.patch
Normal file
@ -0,0 +1,302 @@
|
||||
Origin: https://github.com/erlang/otp/commit/c9e4b22bc4b1faffef07c94ef8e4751b1a36870d
|
||||
Reviewed-by: Sylvain Beucler <beuc@debian.org>
|
||||
Last-Update: 2025-04-22
|
||||
|
||||
From c9e4b22bc4b1faffef07c94ef8e4751b1a36870d Mon Sep 17 00:00:00 2001
|
||||
From: Hans Nilsson <hans@erlang.org>
|
||||
Date: Thu, 14 Jan 2021 17:25:39 +0100
|
||||
Subject: [PATCH] ssh: Add 4th argument (#ssh) to ssh_connection:handl_msg
|
||||
|
||||
to be able to use the hello-string whens settting pty options.
|
||||
---
|
||||
lib/ssh/src/ssh_connection.erl | 76 +++++++++++++-------------
|
||||
lib/ssh/src/ssh_connection_handler.erl | 4 +-
|
||||
2 files changed, 40 insertions(+), 40 deletions(-)
|
||||
|
||||
Index: erlang-22.2.7+dfsg/lib/ssh/src/ssh_connection.erl
|
||||
===================================================================
|
||||
--- erlang-22.2.7+dfsg.orig/lib/ssh/src/ssh_connection.erl
|
||||
+++ erlang-22.2.7+dfsg/lib/ssh/src/ssh_connection.erl
|
||||
@@ -42,7 +42,7 @@
|
||||
|
||||
%% Internal SSH application API
|
||||
-export([channel_data/5,
|
||||
- handle_msg/3,
|
||||
+ handle_msg/4,
|
||||
handle_stop/1,
|
||||
|
||||
channel_adjust_window_msg/2,
|
||||
@@ -450,7 +450,7 @@ handle_msg(#ssh_msg_channel_open_confirm
|
||||
sender_channel = RemoteId,
|
||||
initial_window_size = WindowSz,
|
||||
maximum_packet_size = PacketSz},
|
||||
- #connection{channel_cache = Cache} = Connection0, _) ->
|
||||
+ #connection{channel_cache = Cache} = Connection0, _, _SSH) ->
|
||||
|
||||
#channel{remote_id = undefined} = Channel =
|
||||
ssh_client_channel:cache_lookup(Cache, ChannelId),
|
||||
@@ -468,22 +468,22 @@ handle_msg(#ssh_msg_channel_open_failure
|
||||
reason = Reason,
|
||||
description = Descr,
|
||||
lang = Lang},
|
||||
- #connection{channel_cache = Cache} = Connection0, _) ->
|
||||
+ #connection{channel_cache = Cache} = Connection0, _, _SSH) ->
|
||||
Channel = ssh_client_channel:cache_lookup(Cache, ChannelId),
|
||||
ssh_client_channel:cache_delete(Cache, ChannelId),
|
||||
reply_msg(Channel, Connection0, {open_error, Reason, Descr, Lang});
|
||||
|
||||
-handle_msg(#ssh_msg_channel_success{recipient_channel = ChannelId}, Connection, _) ->
|
||||
+handle_msg(#ssh_msg_channel_success{recipient_channel = ChannelId}, Connection, _, _SSH) ->
|
||||
reply_msg(ChannelId, Connection, success);
|
||||
|
||||
-handle_msg(#ssh_msg_channel_failure{recipient_channel = ChannelId}, Connection, _) ->
|
||||
+handle_msg(#ssh_msg_channel_failure{recipient_channel = ChannelId}, Connection, _, _SSH) ->
|
||||
reply_msg(ChannelId, Connection, failure);
|
||||
|
||||
-handle_msg(#ssh_msg_channel_eof{recipient_channel = ChannelId}, Connection, _) ->
|
||||
+handle_msg(#ssh_msg_channel_eof{recipient_channel = ChannelId}, Connection, _, _SSH) ->
|
||||
reply_msg(ChannelId, Connection, {eof, ChannelId});
|
||||
|
||||
handle_msg(#ssh_msg_channel_close{recipient_channel = ChannelId},
|
||||
- #connection{channel_cache = Cache} = Connection0, _) ->
|
||||
+ #connection{channel_cache = Cache} = Connection0, _, _SSH) ->
|
||||
|
||||
case ssh_client_channel:cache_lookup(Cache, ChannelId) of
|
||||
#channel{sent_close = Closed, remote_id = RemoteId,
|
||||
@@ -516,18 +516,18 @@ handle_msg(#ssh_msg_channel_close{recipi
|
||||
|
||||
handle_msg(#ssh_msg_channel_data{recipient_channel = ChannelId,
|
||||
data = Data},
|
||||
- Connection, _) ->
|
||||
+ Connection, _, _SSH) ->
|
||||
channel_data_reply_msg(ChannelId, Connection, 0, Data);
|
||||
|
||||
handle_msg(#ssh_msg_channel_extended_data{recipient_channel = ChannelId,
|
||||
data_type_code = DataType,
|
||||
data = Data},
|
||||
- Connection, _) ->
|
||||
+ Connection, _, _SSH) ->
|
||||
channel_data_reply_msg(ChannelId, Connection, DataType, Data);
|
||||
|
||||
handle_msg(#ssh_msg_channel_window_adjust{recipient_channel = ChannelId,
|
||||
bytes_to_add = Add},
|
||||
- #connection{channel_cache = Cache} = Connection, _) ->
|
||||
+ #connection{channel_cache = Cache} = Connection, _, _SSH) ->
|
||||
#channel{send_window_size = Size, remote_id = RemoteId} =
|
||||
Channel0 = ssh_client_channel:cache_lookup(Cache, ChannelId),
|
||||
|
||||
@@ -546,7 +546,7 @@ handle_msg(#ssh_msg_channel_open{channel
|
||||
initial_window_size = WindowSz,
|
||||
maximum_packet_size = PacketSz},
|
||||
#connection{options = SSHopts} = Connection0,
|
||||
- server) ->
|
||||
+ server, _SSH) ->
|
||||
MinAcceptedPackSz =
|
||||
?GET_OPT(minimal_remote_max_packet_size, SSHopts),
|
||||
|
||||
@@ -574,7 +574,7 @@ handle_msg(#ssh_msg_channel_open{channel
|
||||
handle_msg(#ssh_msg_channel_open{channel_type = "session",
|
||||
sender_channel = RemoteId},
|
||||
Connection,
|
||||
- client) ->
|
||||
+ client, _SSH) ->
|
||||
%% Client implementations SHOULD reject any session channel open
|
||||
%% requests to make it more difficult for a corrupt server to attack the
|
||||
%% client. See See RFC 4254 6.1.
|
||||
@@ -583,7 +583,7 @@ handle_msg(#ssh_msg_channel_open{channel
|
||||
"Connection refused", "en"),
|
||||
{[{connection_reply, FailMsg}], Connection};
|
||||
|
||||
-handle_msg(#ssh_msg_channel_open{sender_channel = RemoteId}, Connection, _) ->
|
||||
+handle_msg(#ssh_msg_channel_open{sender_channel = RemoteId}, Connection, _, _SSH) ->
|
||||
FailMsg = channel_open_failure_msg(RemoteId,
|
||||
?SSH_OPEN_ADMINISTRATIVELY_PROHIBITED,
|
||||
"Not allowed", "en"),
|
||||
@@ -592,7 +592,7 @@ handle_msg(#ssh_msg_channel_open{sender_
|
||||
handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId,
|
||||
request_type = "exit-status",
|
||||
data = Data},
|
||||
- Connection, _) ->
|
||||
+ Connection, _, _SSH) ->
|
||||
<<?UINT32(Status)>> = Data,
|
||||
reply_msg(ChannelId, Connection, {exit_status, ChannelId, Status});
|
||||
|
||||
@@ -600,7 +600,7 @@ handle_msg(#ssh_msg_channel_request{reci
|
||||
request_type = "exit-signal",
|
||||
want_reply = false,
|
||||
data = Data},
|
||||
- #connection{channel_cache = Cache} = Connection0, _) ->
|
||||
+ #connection{channel_cache = Cache} = Connection0, _, _SSH) ->
|
||||
<<?DEC_BIN(SigName, _SigLen),
|
||||
?BOOLEAN(_Core),
|
||||
?DEC_BIN(Err, _ErrLen),
|
||||
@@ -619,7 +619,7 @@ handle_msg(#ssh_msg_channel_request{reci
|
||||
request_type = "xon-xoff",
|
||||
want_reply = false,
|
||||
data = Data},
|
||||
- Connection, _) ->
|
||||
+ Connection, _, _SSH) ->
|
||||
<<?BOOLEAN(CDo)>> = Data,
|
||||
reply_msg(ChannelId, Connection, {xon_xoff, ChannelId, CDo=/= 0});
|
||||
|
||||
@@ -627,7 +627,7 @@ handle_msg(#ssh_msg_channel_request{reci
|
||||
request_type = "window-change",
|
||||
want_reply = false,
|
||||
data = Data},
|
||||
- Connection0, _) ->
|
||||
+ Connection0, _, _SSH) ->
|
||||
<<?UINT32(Width),?UINT32(Height),
|
||||
?UINT32(PixWidth), ?UINT32(PixHeight)>> = Data,
|
||||
reply_msg(ChannelId, Connection0, {window_change, ChannelId,
|
||||
@@ -637,7 +637,7 @@ handle_msg(#ssh_msg_channel_request{reci
|
||||
handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId,
|
||||
request_type = "signal",
|
||||
data = Data},
|
||||
- Connection0, _) ->
|
||||
+ Connection0, _, _SSH) ->
|
||||
<<?DEC_BIN(SigName, _SigLen)>> = Data,
|
||||
reply_msg(ChannelId, Connection0, {signal, ChannelId,
|
||||
binary_to_list(SigName)});
|
||||
@@ -646,7 +646,7 @@ handle_msg(#ssh_msg_channel_request{reci
|
||||
request_type = "subsystem",
|
||||
want_reply = WantReply,
|
||||
data = Data},
|
||||
- #connection{channel_cache = Cache} = Connection, server) ->
|
||||
+ #connection{channel_cache = Cache} = Connection, server, _SSH) ->
|
||||
<<?DEC_BIN(SsName,_SsLen)>> = Data,
|
||||
#channel{remote_id=RemoteId} = Channel =
|
||||
ssh_client_channel:cache_lookup(Cache, ChannelId),
|
||||
@@ -668,7 +668,7 @@ handle_msg(#ssh_msg_channel_request{reci
|
||||
{[{connection_reply,Reply}], Connection};
|
||||
|
||||
handle_msg(#ssh_msg_channel_request{request_type = "subsystem"},
|
||||
- Connection, client) ->
|
||||
+ Connection, client, _SSH) ->
|
||||
%% The client SHOULD ignore subsystem requests. See RFC 4254 6.5.
|
||||
{[], Connection};
|
||||
|
||||
@@ -676,7 +676,7 @@ handle_msg(#ssh_msg_channel_request{reci
|
||||
request_type = "pty-req",
|
||||
want_reply = WantReply,
|
||||
data = Data},
|
||||
- Connection, server) ->
|
||||
+ Connection, server, _SSH) ->
|
||||
<<?DEC_BIN(BTermName,_TermLen),
|
||||
?UINT32(Width),?UINT32(Height),
|
||||
?UINT32(PixWidth), ?UINT32(PixHeight),
|
||||
@@ -688,19 +688,19 @@ handle_msg(#ssh_msg_channel_request{reci
|
||||
{pty, ChannelId, WantReply, PtyRequest});
|
||||
|
||||
handle_msg(#ssh_msg_channel_request{request_type = "pty-req"},
|
||||
- Connection, client) ->
|
||||
+ Connection, client, _SSH) ->
|
||||
%% The client SHOULD ignore pty requests. See RFC 4254 6.2.
|
||||
{[], Connection};
|
||||
|
||||
handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId,
|
||||
request_type = "shell",
|
||||
want_reply = WantReply},
|
||||
- Connection, server) ->
|
||||
+ Connection, server, _SSH) ->
|
||||
handle_cli_msg(Connection, ChannelId,
|
||||
{shell, ChannelId, WantReply});
|
||||
|
||||
handle_msg(#ssh_msg_channel_request{request_type = "shell"},
|
||||
- Connection, client) ->
|
||||
+ Connection, client, _SSH) ->
|
||||
%% The client SHOULD ignore shell requests. See RFC 4254 6.5.
|
||||
{[], Connection};
|
||||
|
||||
@@ -708,13 +708,13 @@ handle_msg(#ssh_msg_channel_request{reci
|
||||
request_type = "exec",
|
||||
want_reply = WantReply,
|
||||
data = Data},
|
||||
- Connection, server) ->
|
||||
+ Connection, server, _SSH) ->
|
||||
<<?DEC_BIN(Command, _Len)>> = Data,
|
||||
handle_cli_msg(Connection, ChannelId,
|
||||
{exec, ChannelId, WantReply, binary_to_list(Command)});
|
||||
|
||||
handle_msg(#ssh_msg_channel_request{request_type = "exec"},
|
||||
- Connection, client) ->
|
||||
+ Connection, client, _SSH) ->
|
||||
%% The client SHOULD ignore exec requests. See RFC 4254 6.5.
|
||||
{[], Connection};
|
||||
|
||||
@@ -722,20 +722,20 @@ handle_msg(#ssh_msg_channel_request{reci
|
||||
request_type = "env",
|
||||
want_reply = WantReply,
|
||||
data = Data},
|
||||
- Connection, server) ->
|
||||
+ Connection, server, _SSH) ->
|
||||
<<?DEC_BIN(Var,_VarLen), ?DEC_BIN(Value,_ValLen)>> = Data,
|
||||
handle_cli_msg(Connection, ChannelId,
|
||||
{env, ChannelId, WantReply, Var, Value});
|
||||
|
||||
handle_msg(#ssh_msg_channel_request{request_type = "env"},
|
||||
- Connection, client) ->
|
||||
+ Connection, client, _SSH) ->
|
||||
%% The client SHOULD ignore env requests.
|
||||
{[], Connection};
|
||||
|
||||
handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId,
|
||||
request_type = _Other,
|
||||
want_reply = WantReply},
|
||||
- #connection{channel_cache = Cache} = Connection, _) ->
|
||||
+ #connection{channel_cache = Cache} = Connection, _, _SSH) ->
|
||||
if WantReply == true ->
|
||||
case ssh_client_channel:cache_lookup(Cache, ChannelId) of
|
||||
#channel{remote_id = RemoteId} ->
|
||||
@@ -750,7 +750,7 @@ handle_msg(#ssh_msg_channel_request{reci
|
||||
|
||||
handle_msg(#ssh_msg_global_request{name = _Type,
|
||||
want_reply = WantReply,
|
||||
- data = _Data}, Connection, _) ->
|
||||
+ data = _Data}, Connection, _, _SSH) ->
|
||||
if WantReply == true ->
|
||||
FailMsg = request_failure_msg(),
|
||||
{[{connection_reply, FailMsg}], Connection};
|
||||
@@ -759,18 +759,18 @@ handle_msg(#ssh_msg_global_request{name
|
||||
end;
|
||||
|
||||
handle_msg(#ssh_msg_request_failure{},
|
||||
- #connection{requests = [{_, From} | Rest]} = Connection, _) ->
|
||||
+ #connection{requests = [{_, From} | Rest]} = Connection, _, _SSH) ->
|
||||
{[{channel_request_reply, From, {failure, <<>>}}],
|
||||
Connection#connection{requests = Rest}};
|
||||
|
||||
handle_msg(#ssh_msg_request_success{data = Data},
|
||||
- #connection{requests = [{_, From} | Rest]} = Connection, _) ->
|
||||
+ #connection{requests = [{_, From} | Rest]} = Connection, _, _SSH) ->
|
||||
{[{channel_request_reply, From, {success, Data}}],
|
||||
Connection#connection{requests = Rest}};
|
||||
|
||||
handle_msg(#ssh_msg_disconnect{code = Code,
|
||||
description = Description},
|
||||
- Connection, _) ->
|
||||
+ Connection, _, _SSH) ->
|
||||
{disconnect, {Code, Description}, handle_stop(Connection)}.
|
||||
|
||||
|
||||
Index: erlang-22.2.7+dfsg/lib/ssh/src/ssh_connection_handler.erl
|
||||
===================================================================
|
||||
--- erlang-22.2.7+dfsg.orig/lib/ssh/src/ssh_connection_handler.erl
|
||||
+++ erlang-22.2.7+dfsg/lib/ssh/src/ssh_connection_handler.erl
|
||||
@@ -1006,7 +1006,7 @@ handle_event(_, {#ssh_msg_kexinit{},_},
|
||||
|
||||
handle_event(_, #ssh_msg_disconnect{description=Desc} = Msg, StateName, D0) ->
|
||||
{disconnect, _, RepliesCon} =
|
||||
- ssh_connection:handle_msg(Msg, D0#data.connection_state, role(StateName)),
|
||||
+ ssh_connection:handle_msg(Msg, D0#data.connection_state, role(StateName), D0#data.ssh_params),
|
||||
{Actions,D} = send_replies(RepliesCon, D0),
|
||||
disconnect_fun("Received disconnect: "++Desc, D),
|
||||
{stop_and_reply, {shutdown,Desc}, Actions, D};
|
||||
@@ -1036,7 +1036,7 @@ handle_event(internal, {conn_msg,Msg}, S
|
||||
event_queue = Qev0} = D0) ->
|
||||
Role = role(StateName),
|
||||
Rengotation = renegotiation(StateName),
|
||||
- try ssh_connection:handle_msg(Msg, Connection0, Role) of
|
||||
+ try ssh_connection:handle_msg(Msg, Connection0, Role, D0#data.ssh_params) of
|
||||
{disconnect, Reason0, RepliesConn} ->
|
||||
{Repls, D} = send_replies(RepliesConn, D0),
|
||||
case {Reason0,Role} of
|
||||
214
CVE-2025-32433.patch
Normal file
214
CVE-2025-32433.patch
Normal file
@ -0,0 +1,214 @@
|
||||
Origin: https://github.com/erlang/otp/commit/0fcd9c56524b28615e8ece65fc0c3f66ef6e4c12
|
||||
Reviewed-by: Sylvain Beucler <beuc@debian.org>
|
||||
Last-Update: 2025-04-22
|
||||
|
||||
From 0fcd9c56524b28615e8ece65fc0c3f66ef6e4c12 Mon Sep 17 00:00:00 2001
|
||||
From: Jakub Witczak <kuba@erlang.org>
|
||||
Date: Mon, 14 Apr 2025 16:33:21 +0200
|
||||
Subject: [PATCH] ssh: early RCE fix
|
||||
|
||||
- disconnect when connection protocol message arrives
|
||||
- when user is not authenticated for connection
|
||||
- see RFC4252 sec.6
|
||||
---
|
||||
lib/ssh/src/ssh_connection.erl | 28 ++++++++--
|
||||
lib/ssh/test/ssh_protocol_SUITE.erl | 86 +++++++++++++++--------------
|
||||
2 files changed, 67 insertions(+), 47 deletions(-)
|
||||
|
||||
Index: erlang-22.2.7+dfsg/lib/ssh/src/ssh_connection.erl
|
||||
===================================================================
|
||||
--- erlang-22.2.7+dfsg.orig/lib/ssh/src/ssh_connection.erl
|
||||
+++ erlang-22.2.7+dfsg/lib/ssh/src/ssh_connection.erl
|
||||
@@ -26,6 +26,8 @@
|
||||
|
||||
-module(ssh_connection).
|
||||
|
||||
+-include_lib("kernel/include/logger.hrl").
|
||||
+
|
||||
-include("ssh.hrl").
|
||||
-include("ssh_connect.hrl").
|
||||
-include("ssh_transport.hrl").
|
||||
@@ -446,6 +448,25 @@ channel_data(ChannelId, DataType, Data0,
|
||||
%%% Replies {Reply, UpdatedConnection}
|
||||
%%%
|
||||
|
||||
+handle_msg(#ssh_msg_disconnect{code = Code, description = Description}, Connection, _, _SSH) ->
|
||||
+ {disconnect, {Code, Description}, handle_stop(Connection)};
|
||||
+
|
||||
+handle_msg(Msg, Connection, server, Ssh = #ssh{authenticated = false}) ->
|
||||
+ %% See RFC4252 6.
|
||||
+ %% Message numbers of 80 and higher are reserved for protocols running
|
||||
+ %% after this authentication protocol, so receiving one of them before
|
||||
+ %% authentication is complete is an error, to which the server MUST
|
||||
+ %% respond by disconnecting, preferably with a proper disconnect message
|
||||
+ %% sent to ease troubleshooting.
|
||||
+ MsgFun = fun(M) ->
|
||||
+ MaxLogItemLen = ?GET_OPT(max_log_item_len, Ssh#ssh.opts),
|
||||
+ io_lib:format("Connection terminated. Unexpected message for unauthenticated user."
|
||||
+ " Message: ~w", [M],
|
||||
+ [{chars_limit, MaxLogItemLen}])
|
||||
+ end,
|
||||
+ ?LOG_DEBUG(MsgFun, [Msg]),
|
||||
+ {disconnect, {?SSH_DISCONNECT_PROTOCOL_ERROR, "Connection refused"}, handle_stop(Connection)};
|
||||
+
|
||||
handle_msg(#ssh_msg_channel_open_confirmation{recipient_channel = ChannelId,
|
||||
sender_channel = RemoteId,
|
||||
initial_window_size = WindowSz,
|
||||
@@ -766,12 +787,7 @@ handle_msg(#ssh_msg_request_failure{},
|
||||
handle_msg(#ssh_msg_request_success{data = Data},
|
||||
#connection{requests = [{_, From} | Rest]} = Connection, _, _SSH) ->
|
||||
{[{channel_request_reply, From, {success, Data}}],
|
||||
- Connection#connection{requests = Rest}};
|
||||
-
|
||||
-handle_msg(#ssh_msg_disconnect{code = Code,
|
||||
- description = Description},
|
||||
- Connection, _, _SSH) ->
|
||||
- {disconnect, {Code, Description}, handle_stop(Connection)}.
|
||||
+ Connection#connection{requests = Rest}}.
|
||||
|
||||
|
||||
%%%----------------------------------------------------------------
|
||||
Index: erlang-22.2.7+dfsg/lib/ssh/test/ssh_protocol_SUITE.erl
|
||||
===================================================================
|
||||
--- erlang-22.2.7+dfsg.orig/lib/ssh/test/ssh_protocol_SUITE.erl
|
||||
+++ erlang-22.2.7+dfsg/lib/ssh/test/ssh_protocol_SUITE.erl
|
||||
@@ -59,6 +59,7 @@ suite() ->
|
||||
all() ->
|
||||
[{group,tool_tests},
|
||||
client_info_line,
|
||||
+ early_rce,
|
||||
{group,kex},
|
||||
{group,service_requests},
|
||||
{group,authentication},
|
||||
@@ -76,10 +77,8 @@ groups() ->
|
||||
]},
|
||||
{packet_size_error, [], [packet_length_too_large,
|
||||
packet_length_too_short]},
|
||||
-
|
||||
{field_size_error, [], [service_name_length_too_large,
|
||||
service_name_length_too_short]},
|
||||
-
|
||||
{kex, [], [custom_kexinit,
|
||||
no_common_alg_server_disconnects,
|
||||
no_common_alg_client_disconnects,
|
||||
@@ -120,7 +119,8 @@ init_per_suite(Config) ->
|
||||
end_per_suite(Config) ->
|
||||
stop_apps(Config).
|
||||
|
||||
-init_per_testcase(Tc, Config) when Tc == no_common_alg_server_disconnects; Tc == custom_kexinit ->
|
||||
+init_per_testcase(Tc, Config) when Tc == no_common_alg_server_disconnects;
|
||||
+ Tc == custom_kexinit ->
|
||||
start_std_daemon(Config, [{preferred_algorithms,[{public_key,['ssh-rsa']},
|
||||
{cipher,?DEFAULT_CIPHERS}
|
||||
]}]);
|
||||
@@ -166,7 +166,8 @@ init_per_testcase(TC, Config) when TC ==
|
||||
init_per_testcase(_TestCase, Config) ->
|
||||
check_std_daemon_works(Config, ?LINE).
|
||||
|
||||
-end_per_testcase(Tc, Config) when Tc == no_common_alg_server_disconnects; Tc == custom_kexinit ->
|
||||
+end_per_testcase(Tc, Config) when Tc == no_common_alg_server_disconnects;
|
||||
+ Tc == custom_kexinit ->
|
||||
stop_std_daemon(Config);
|
||||
end_per_testcase(kex_strict_negotiated, Config) ->
|
||||
Config;
|
||||
@@ -327,6 +328,44 @@ no_common_alg_server_disconnects(Config)
|
||||
]
|
||||
).
|
||||
|
||||
+early_rce(Config) ->
|
||||
+ {ok,InitialState} =
|
||||
+ ssh_trpt_test_lib:exec([{set_options, [print_ops, print_seqnums, print_messages]}]),
|
||||
+ TypeOpen = "session",
|
||||
+ ChannelId = 0,
|
||||
+ WinSz = 425984,
|
||||
+ PktSz = 65536,
|
||||
+ DataOpen = <<>>,
|
||||
+ SshMsgChannelOpen = ssh_connection:channel_open_msg(TypeOpen, ChannelId, WinSz, PktSz, DataOpen),
|
||||
+
|
||||
+ Id = 0,
|
||||
+ TypeReq = "exec",
|
||||
+ WantReply = true,
|
||||
+ DataReq = <<?STRING(<<"lists:seq(1,10).">>)>>,
|
||||
+ SshMsgChannelRequest =
|
||||
+ ssh_connection:channel_request_msg(Id, TypeReq, WantReply, DataReq),
|
||||
+ {ok,AfterKexState} =
|
||||
+ ssh_trpt_test_lib:exec(
|
||||
+ [{connect,
|
||||
+ server_host(Config),server_port(Config),
|
||||
+ [{preferred_algorithms,[{kex,[?DEFAULT_KEX]},
|
||||
+ {cipher,?DEFAULT_CIPHERS}
|
||||
+ ]},
|
||||
+ {silently_accept_hosts, true},
|
||||
+ {recv_ext_info, false},
|
||||
+ {user_dir, user_dir(Config)},
|
||||
+ {user_interaction, false}
|
||||
+ | proplists:get_value(extra_options,Config,[])]},
|
||||
+ receive_hello,
|
||||
+ {send, hello},
|
||||
+ {send, ssh_msg_kexinit},
|
||||
+ {match, #ssh_msg_kexinit{_='_'}, receive_msg},
|
||||
+ {send, SshMsgChannelOpen},
|
||||
+ {send, SshMsgChannelRequest},
|
||||
+ {match, disconnect(), receive_msg}
|
||||
+ ], InitialState),
|
||||
+ ok.
|
||||
+
|
||||
custom_kexinit(Config) ->
|
||||
%% 16#C0 value causes unicode:characters_to_list to return a big error value
|
||||
Trash = lists:duplicate(260000, 16#C0),
|
||||
@@ -353,11 +392,6 @@ custom_kexinit(Config) ->
|
||||
first_kex_packet_follows = false,
|
||||
reserved = 0
|
||||
},
|
||||
- PacketFun =
|
||||
- fun(Msg, Ssh) ->
|
||||
- BinMsg = custom_encode(Msg),
|
||||
- ssh_transport:pack(BinMsg, Ssh, 0)
|
||||
- end,
|
||||
{ok,_} =
|
||||
ssh_trpt_test_lib:exec(
|
||||
[{set_options, [print_ops, {print_messages,detail}]},
|
||||
@@ -373,42 +407,11 @@ custom_kexinit(Config) ->
|
||||
receive_hello,
|
||||
{send, hello},
|
||||
{match, #ssh_msg_kexinit{_='_'}, receive_msg},
|
||||
- {send, {special, KexInit, PacketFun}}, % with server unsupported 'ssh-dss' !
|
||||
+ {send, KexInit}, % with server unsupported 'ssh-dss' !
|
||||
{match, disconnect(), receive_msg}
|
||||
]
|
||||
).
|
||||
|
||||
-custom_encode(#ssh_msg_kexinit{
|
||||
- cookie = Cookie,
|
||||
- kex_algorithms = KeyAlgs,
|
||||
- server_host_key_algorithms = HostKeyAlgs,
|
||||
- encryption_algorithms_client_to_server = EncAlgC2S,
|
||||
- encryption_algorithms_server_to_client = EncAlgS2C,
|
||||
- mac_algorithms_client_to_server = MacAlgC2S,
|
||||
- mac_algorithms_server_to_client = MacAlgS2C,
|
||||
- compression_algorithms_client_to_server = CompAlgS2C,
|
||||
- compression_algorithms_server_to_client = CompAlgC2S,
|
||||
- languages_client_to_server = LangC2S,
|
||||
- languages_server_to_client = LangS2C,
|
||||
- first_kex_packet_follows = Bool,
|
||||
- reserved = Reserved
|
||||
- }) ->
|
||||
- KeyAlgsBin0 = <<?Ename_list(KeyAlgs)>>,
|
||||
- <<?UINT32(Len0), Data:Len0/binary>> = KeyAlgsBin0,
|
||||
- KeyAlgsBin = <<?UINT32(Len0), Data/binary>>,
|
||||
- <<?Ebyte(?SSH_MSG_KEXINIT), Cookie/binary,
|
||||
- KeyAlgsBin/binary,
|
||||
- ?Ename_list(HostKeyAlgs),
|
||||
- ?Ename_list(EncAlgC2S),
|
||||
- ?Ename_list(EncAlgS2C),
|
||||
- ?Ename_list(MacAlgC2S),
|
||||
- ?Ename_list(MacAlgS2C),
|
||||
- ?Ename_list(CompAlgS2C),
|
||||
- ?Ename_list(CompAlgC2S),
|
||||
- ?Ename_list(LangC2S),
|
||||
- ?Ename_list(LangS2C),
|
||||
- ?Eboolean(Bool), ?Euint32(Reserved)>>.
|
||||
-
|
||||
%%--------------------------------------------------------------------
|
||||
%%% Algo negotiation fail. This should result in a ssh_msg_disconnect
|
||||
%%% being sent from the client.
|
||||
34
erlang.spec
34
erlang.spec
@ -11,9 +11,9 @@
|
||||
%global __with_wxwidgets 1
|
||||
Name: erlang
|
||||
Version: 21.3.3
|
||||
Release: 1
|
||||
Release: 6
|
||||
Summary: General-purpose programming language and runtime environment
|
||||
License: ASL 2.0
|
||||
License: Apache-2.0
|
||||
URL: https://www.erlang.org
|
||||
VCS: scm:git:https://github.com/erlang/otp
|
||||
Source0: https://github.com/erlang/otp/archive/OTP-%{version}/otp-OTP-%{version}.tar.gz
|
||||
@ -31,6 +31,16 @@ Patch7: otp-0007-Add-extra-search-directory.patch
|
||||
Patch8: otp-0008-Avoid-forking-sed-to-get-basename.patch
|
||||
Patch9: otp-0009-Load-man-pages-from-system-wide-directory.patch
|
||||
Patch10: otp-0010-Improve-nodes-querying.patch
|
||||
Patch11: CVE-2023-48795-erlang21.patch
|
||||
Patch12: CVE-2025-26618.patch
|
||||
# Patch13...18 comes from debian
|
||||
# https://salsa.debian.org/erlang-team/packages/erlang/-/tree/buster/debian/patches
|
||||
Patch13: CVE-2025-30211-pre1.patch
|
||||
Patch14: CVE-2025-30211-1.patch
|
||||
Patch15: CVE-2025-30211-2.patch
|
||||
Patch16: CVE-2025-30211-3.patch
|
||||
Patch17: CVE-2025-32433-pre1.patch
|
||||
Patch18: CVE-2025-32433.patch
|
||||
BuildRequires: gcc gcc-c++ flex
|
||||
%if %{with doc}
|
||||
%if 0%{?need_bootstrap} < 1
|
||||
@ -627,14 +637,15 @@ pushd xemacs-erlang
|
||||
%{_xemacs_bytecompile} *.el
|
||||
popd
|
||||
%endif %{__with_xemacs}
|
||||
make
|
||||
export CCACHE_DISABLE=1
|
||||
make %{?_smp_mflags}
|
||||
%if %{with doc}
|
||||
%ifnarch ppc %{power64}
|
||||
export BASE_OPTIONS=-Xmx1024m
|
||||
%else
|
||||
export BASE_OPTIONS=-Xmx1536m
|
||||
%endif
|
||||
make docs
|
||||
make %{?_smp_mflags} docs
|
||||
%endif
|
||||
|
||||
%install
|
||||
@ -1723,5 +1734,20 @@ useradd -r -g epmd -d /dev/null -s /sbin/nologin \
|
||||
%endif
|
||||
|
||||
%changelog
|
||||
* Sat Apr 26 2025 Funda Wang <fundawang@yeah.net> - 21.3.3-6
|
||||
- fix CVE-2025-30211, CVE-2025-32433
|
||||
|
||||
* Mon Feb 24 2025 yaoxin <1024769339@qq.com> - 21.3.3-5
|
||||
- Fix CVE-2025-26618
|
||||
|
||||
* Thu Jan 25 2024 wangkai <13474090681@163.com> - 21.3.3-4
|
||||
- Fix CVE-2023-48795
|
||||
|
||||
* Tue Nov 28 2023 wangkai <13474090681@163.com> - 21.3.3-3
|
||||
- Disable ccache to fix build error
|
||||
|
||||
* Mon Mar 29 2021 weishengjing <weishengjing1@huawei.com> - 21.3.3-2
|
||||
- Support parallel compilation
|
||||
|
||||
* Mon Aug 24 2020 chengzihan <chengzihan2@huawei.com> - 21.3.3-1
|
||||
- Package init
|
||||
|
||||
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user