File 3081-ssh-Add-size-guards-for-pre-authentication-messages.patch of Package erlang

From 5e05ecc4307fb0299a5f0bc288c2553544108179 Mon Sep 17 00:00:00 2001
From: Jakub Witczak <kuba@erlang.org>
Date: Mon, 9 Mar 2026 12:00:54 +0100
Subject: [PATCH] ssh: Add size guards for pre-authentication messages
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Add explicit size validation for SSH messages decoded before user
authentication to improve defense-in-depth against DoS attacks.

Changes:
- Add size limit constants in ssh.hrl with RFC references
- Update MAX_HOST_KEY_SIZE (4096→8192) and MAX_SIGNATURE_SIZE (1536→2048)
  for general use beyond MLKEM
- Add size_error/1 helper for multi-field validation
- Add decode guards for pre-auth message types:
  * Transport: DISCONNECT, IGNORE, DEBUG
  * Key exchange: KEXINIT, DH (INIT/REPLY), DH-GEX (GROUP/INIT/REPLY),
    ECDH (INIT/REPLY), MLKEM (REPLY refactored)
  * Service: SERVICE_REQUEST, SERVICE_ACCEPT, EXT_INFO

All guards report specific error tuples with actual size and limit.
Backward compatibility maintained for ancient OpenSSH clients.
---
 lib/ssh/src/ssh.hrl         |  47 +++++++-
 lib/ssh/src/ssh_message.erl | 221 +++++++++++++++++++++---------------
 2 files changed, 172 insertions(+), 96 deletions(-)

diff --git a/lib/ssh/src/ssh.hrl b/lib/ssh/src/ssh.hrl
index ef911c5da4..f9e359bfb0 100644
--- a/lib/ssh/src/ssh.hrl
+++ b/lib/ssh/src/ssh.hrl
@@ -49,9 +49,52 @@
 -define(MLKEM768_INIT_SIZE, ?MLKEM768_PUBLICKEY_SIZE + ?X25519_PUBLICKEY_SIZE).   % NIST FIPS 203: 1184 + 32
 -define(MLKEM768_REPLY_SIZE, ?MLKEM768_CIPHERTEXT_SIZE + ?X25519_PUBLICKEY_SIZE). % NIST FIPS 203: 1088 + 32
 
+%% Pre-authentication message size limits
+%% Transport layer (RFC 4253 Section 11)
+
+%% OpenSSH uses 1024-byte C buffer (packet.c, commit d4a8b7e34);
+%% vsnprintf reserves 1 byte for null terminator, max wire length is
+%% 1023
+-define(MAX_DISCONNECT_DESC_SIZE, 1023).
+%% Practical limit (RFC 3066: subtags max 8 chars, no overall limit
+%% specified)
+-define(MAX_LANG_SIZE, 64).
+% RFC 4253 Section 6.1 (32768 byte payload)
+-define(MAX_IGNORE_DATA_SIZE, 32768).
+%% Limit for receiving debug messages from peers; intentionally larger
+%% than OpenSSH (1023 bytes, packet.c commit d4a8b7e34) to accommodate
+%% verbose diagnostics from various SSH implementations
+-define(MAX_DEBUG_MSG_SIZE, 4096).
+
+%% Key exchange (RFC 4253 Section 7-8, RFC 4419, RFC 5656, RFC 8270)
+
+%% RFC 4253 Section 6.1 (32768 byte payload, real-world: 500-2000 bytes)
+-define(MAX_KEXINIT_SIZE, 32768).
+% RFC 4253 Section 8 (8192-bit = 1024 bytes + mpint encoding overhead)
+-define(MAX_DH_MPINT_SIZE, 1032).
+%% RFC 5656 Section 4 (P-521 uncompressed: 133 bytes)
+-define(MAX_ECDH_POINT_SIZE, 256).
+
+%% Service request (RFC 4253 Section 10, RFC 8308)
+
+%% RFC 4251 Section 6 (SSH name limit)
+-define(MAX_SERVICE_NAME_SIZE, 64).
+% Practical limit (RFC 8308 defines no maximum)
+-define(MAX_EXT_INFO_SIZE, 8192).
+% Practical limit (typical: 200-400 bytes, allows future extensions)
+-define(MAX_EXT_VALUE_SIZE, 1024).
+
 %% Cryptographic limits
--define(MAX_HOST_KEY_SIZE, 4096).       % RSA-4096 + ASN.1/SSH encoding
--define(MAX_SIGNATURE_SIZE, 1536).      % RSA-8192 (1044) + margin for future algorithms
+
+%% Accommodates RSA-8192 keys (~1046 bytes, largest supported key type)
+%% and post-quantum algorithms (Dilithium5: 2592 bytes). Other key
+%% types are much smaller: DSA-1024 (~431 bytes), ECDSA P-521 (~172
+%% bytes), Ed25519 (~51 bytes)
+-define(MAX_HOST_KEY_SIZE, 4096).
+%% Accommodates RSA-8192 signatures (~1039 bytes) and post-quantum
+%% algorithms (Dilithium5: 4595 bytes). Provides consistent PQ
+%% readiness with MAX_HOST_KEY_SIZE.
+-define(MAX_SIGNATURE_SIZE, 5120).
 
 -define(SUPPORTED_AUTH_METHODS, "publickey,keyboard-interactive,password").
 
diff --git a/lib/ssh/src/ssh_message.erl b/lib/ssh/src/ssh_message.erl
index 918560c84c..7de05f7052 100644
--- a/lib/ssh/src/ssh_message.erl
+++ b/lib/ssh/src/ssh_message.erl
@@ -469,32 +469,48 @@ decode(<<?BYTE(?SSH_MSG_USERAUTH_INFO_RESPONSE), ?UINT32(Num), Data/binary>>) ->
        num_responses = Num,
        data = Data};
 
-decode(<<?BYTE(?SSH_MSG_EXT_INFO), ?UINT32(N), BinData/binary>>) ->
+decode(<<?BYTE(?SSH_MSG_EXT_INFO), ?UINT32(N), BinData/binary>>)
+  when byte_size(BinData) =< ?MAX_EXT_INFO_SIZE ->
     Data = bin_foldr(
              fun(Bin,Acc) when length(Acc) == N ->
                      {Bin,Acc};
-                (<<?DEC_BIN(V0,__0), ?DEC_BIN(V1,__1), Rest/binary>>, Acc) -> 
-                     {Rest,[{binary_to_list(V0),binary_to_list(V1)}|Acc]}
+                (<<?DEC_BIN(V0, L0), ?DEC_BIN(V1, L1), Rest/binary>>, Acc)
+                   when L0 =< ?MAX_SERVICE_NAME_SIZE, L1 =< ?MAX_EXT_VALUE_SIZE ->
+                     {Rest,[{binary_to_list(V0),binary_to_list(V1)}|Acc]};
+                (<<?DEC_BIN(_, L0), ?DEC_BIN(_, L1), _/binary>>, _Acc) ->
+                     throw({error,
+                            size_error([{ext_info_name_too_large, L0, ?MAX_SERVICE_NAME_SIZE},
+                                        {ext_info_value_too_large, L1, ?MAX_EXT_VALUE_SIZE}])})
              end, [], BinData),
-    #ssh_msg_ext_info{
-       nr_extensions = N,
-       data = Data
-      };
+    #ssh_msg_ext_info{nr_extensions = N, data = Data};
+decode(<<?BYTE(?SSH_MSG_EXT_INFO), ?UINT32(_), BinData/binary>>) ->
+    throw({error, {ext_info_too_large, byte_size(BinData), ?MAX_EXT_INFO_SIZE}});
 
 %%% Keyexchange messages
-decode(<<?BYTE(?SSH_MSG_KEXINIT), Cookie:128, Data/binary>>) ->
+decode(<<?BYTE(?SSH_MSG_KEXINIT), Cookie:128, Data/binary>>)
+  when byte_size(Data) =< ?MAX_KEXINIT_SIZE ->
     decode_kex_init(Data, [Cookie, ssh_msg_kexinit], 10);
+decode(<<?BYTE(?SSH_MSG_KEXINIT), _Cookie:128, Data/binary>>) ->
+    throw({error, {kexinit_too_large, byte_size(Data), ?MAX_KEXINIT_SIZE}});
 
-decode(<<"dh",?BYTE(?SSH_MSG_KEXDH_INIT), ?DEC_MPINT(E,__0)>>) ->
-    #ssh_msg_kexdh_init{e = E
-		       };
+decode(<<"dh",?BYTE(?SSH_MSG_KEXDH_INIT), ?DEC_MPINT(E, ELen)>>)
+  when ELen =< ?MAX_DH_MPINT_SIZE ->
+    #ssh_msg_kexdh_init{e = E};
+decode(<<"dh",?BYTE(?SSH_MSG_KEXDH_INIT), ?DEC_MPINT(_, ELen)>>) ->
+    throw({error, {kexdh_init_e_too_large, ELen, ?MAX_DH_MPINT_SIZE}});
 
-decode(<<"dh", ?BYTE(?SSH_MSG_KEXDH_REPLY), ?DEC_BIN(Key,__0), ?DEC_MPINT(F,__1), ?DEC_BIN(Hashsign,__2)>>) ->
-    #ssh_msg_kexdh_reply{
-       public_host_key = ssh2_pubkey_decode(Key),
-       f = F,
-       h_sig = decode_signature(Hashsign)
-      };
+decode(<<"dh", ?BYTE(?SSH_MSG_KEXDH_REPLY),
+         ?DEC_BIN(Key, KLen), ?DEC_MPINT(F, FLen), ?DEC_BIN(Hashsign, HLen)>>)
+  when KLen =< ?MAX_HOST_KEY_SIZE,
+       FLen =< ?MAX_DH_MPINT_SIZE,
+       HLen =< ?MAX_SIGNATURE_SIZE ->
+    #ssh_msg_kexdh_reply{public_host_key = ssh2_pubkey_decode(Key), f = F,
+                         h_sig = decode_signature(Hashsign)};
+decode(<<"dh",?BYTE(?SSH_MSG_KEXDH_REPLY),
+         ?DEC_BIN(_, KLen), ?DEC_MPINT(_, FLen), ?DEC_BIN(_, HLen)>>) ->
+    throw({error, size_error([{kexdh_host_key_too_large, KLen, ?MAX_HOST_KEY_SIZE},
+                              {kexdh_f_too_large, FLen, ?MAX_DH_MPINT_SIZE},
+                              {kexdh_signature_too_large, HLen, ?MAX_SIGNATURE_SIZE}])});
 
 decode(<<?BYTE(?SSH_MSG_KEX_DH_GEX_REQUEST), ?UINT32(Min), ?UINT32(N), ?UINT32(Max)>>) ->
     #ssh_msg_kex_dh_gex_request{
@@ -508,42 +524,55 @@ decode(<<"dh_gex",?BYTE(?SSH_MSG_KEX_DH_GEX_REQUEST_OLD), ?UINT32(N)>>) ->
        n = N
       };
 
-decode(<<"dh_gex",?BYTE(?SSH_MSG_KEX_DH_GEX_GROUP), ?DEC_MPINT(Prime,__0), ?DEC_MPINT(Generator,__1) >>) ->
-    #ssh_msg_kex_dh_gex_group{
-       p = Prime,
-       g = Generator
-      };
-
-decode(<<?BYTE(?SSH_MSG_KEX_DH_GEX_INIT), ?DEC_MPINT(E,__0)>>) ->
-    #ssh_msg_kex_dh_gex_init{
-       e = E
-      };
-
-decode(<<?BYTE(?SSH_MSG_KEX_DH_GEX_REPLY), ?DEC_BIN(Key,__0), ?DEC_MPINT(F,__1), ?DEC_BIN(Hashsign,__2)>>) ->
-    #ssh_msg_kex_dh_gex_reply{
-       public_host_key = ssh2_pubkey_decode(Key),
-       f = F,
-       h_sig = decode_signature(Hashsign)
-      };
-
-decode(<<"ecdh",?BYTE(?SSH_MSG_KEX_ECDH_INIT), ?DEC_BIN(Q_c,__0)>>) ->
-    #ssh_msg_kex_ecdh_init{
-       q_c = Q_c
-      };
+decode(<<"dh_gex",?BYTE(?SSH_MSG_KEX_DH_GEX_GROUP),
+         ?DEC_MPINT(Prime, PLen), ?DEC_MPINT(Generator, GLen)>>)
+  when PLen =< ?MAX_DH_MPINT_SIZE, GLen =< ?MAX_DH_MPINT_SIZE ->
+    #ssh_msg_kex_dh_gex_group{p = Prime, g = Generator};
+decode(<<"dh_gex",?BYTE(?SSH_MSG_KEX_DH_GEX_GROUP), ?DEC_MPINT(_, PLen), ?DEC_MPINT(_, GLen)>>) ->
+    throw({error, size_error([{gex_p_too_large, PLen, ?MAX_DH_MPINT_SIZE},
+                              {gex_g_too_large, GLen, ?MAX_DH_MPINT_SIZE}])});
+
+decode(<<?BYTE(?SSH_MSG_KEX_DH_GEX_INIT), ?DEC_MPINT(E, ELen)>>)
+  when ELen =< ?MAX_DH_MPINT_SIZE ->
+    #ssh_msg_kex_dh_gex_init{e = E};
+decode(<<?BYTE(?SSH_MSG_KEX_DH_GEX_INIT), ?DEC_MPINT(_, ELen)>>) ->
+    throw({error, {gex_init_e_too_large, ELen, ?MAX_DH_MPINT_SIZE}});
+
+decode(<<?BYTE(?SSH_MSG_KEX_DH_GEX_REPLY),
+         ?DEC_BIN(Key, KLen), ?DEC_MPINT(F, FLen), ?DEC_BIN(Hashsign, SLen)>>)
+  when KLen =< ?MAX_HOST_KEY_SIZE,
+       FLen =< ?MAX_DH_MPINT_SIZE,
+       SLen =< ?MAX_SIGNATURE_SIZE ->
+    #ssh_msg_kex_dh_gex_reply{public_host_key = ssh2_pubkey_decode(Key), f = F,
+                              h_sig = decode_signature(Hashsign)};
+decode(<<"dh_gex",?BYTE(?SSH_MSG_KEX_DH_GEX_REPLY),
+         ?DEC_BIN(_, KLen), ?DEC_MPINT(_, FLen), ?DEC_BIN(_, SLen)>>) ->
+    throw({error, size_error([{gex_host_key_too_large, KLen, ?MAX_HOST_KEY_SIZE},
+                              {gex_f_too_large, FLen, ?MAX_DH_MPINT_SIZE},
+                              {gex_signature_too_large, SLen, ?MAX_SIGNATURE_SIZE}])});
+
+decode(<<"ecdh",?BYTE(?SSH_MSG_KEX_ECDH_INIT), ?DEC_BIN(Q_c, QLen)>>)
+  when QLen =< ?MAX_ECDH_POINT_SIZE ->
+    #ssh_msg_kex_ecdh_init{q_c = Q_c};
+decode(<<"ecdh",?BYTE(?SSH_MSG_KEX_ECDH_INIT), ?DEC_BIN(_, QLen)>>) ->
+    throw({error, {ecdh_init_point_too_large, QLen, ?MAX_ECDH_POINT_SIZE}});
 
 decode(<<"ecdh",?BYTE(?SSH_MSG_KEX_ECDH_REPLY),
-	 ?DEC_BIN(Key,__1), ?DEC_BIN(Q_s,__2), ?DEC_BIN(Sig,__3)>>) ->
-    #ssh_msg_kex_ecdh_reply{
-       public_host_key = ssh2_pubkey_decode(Key),
-       q_s = Q_s,
-       h_sig = decode_signature(Sig)
-      };
+         ?DEC_BIN(Key, KLen), ?DEC_BIN(Q_s, QLen), ?DEC_BIN(Sig, SLen)>>)
+  when KLen =< ?MAX_HOST_KEY_SIZE,
+       QLen =< ?MAX_ECDH_POINT_SIZE,
+       SLen =< ?MAX_SIGNATURE_SIZE ->
+    #ssh_msg_kex_ecdh_reply{public_host_key = ssh2_pubkey_decode(Key), q_s = Q_s,
+                            h_sig = decode_signature(Sig)};
+decode(<<"ecdh",?BYTE(?SSH_MSG_KEX_ECDH_REPLY),
+         ?DEC_BIN(_, KLen), ?DEC_BIN(_, QLen), ?DEC_BIN(_, SLen)>>) ->
+    throw({error, size_error([{ecdh_host_key_too_large, KLen, ?MAX_HOST_KEY_SIZE},
+                              {ecdh_point_too_large, QLen, ?MAX_ECDH_POINT_SIZE},
+                              {ecdh_signature_too_large, SLen, ?MAX_SIGNATURE_SIZE}])});
 
 decode(<<"mlkem",?BYTE(?SSH_MSG_KEX_HYBRID_INIT), ?DEC_BIN(C_init, CLen)>>)
   when CLen =:= ?MLKEM768_INIT_SIZE->
-    #ssh_msg_kex_hybrid_init{
-       c_init = C_init
-      };
+    #ssh_msg_kex_hybrid_init{c_init = C_init};
 %% Reject invalid ML-KEM messages with proper error
 decode(<<"mlkem", ?BYTE(?SSH_MSG_KEX_HYBRID_INIT), ?DEC_BIN(_, CLen)>>) ->
     throw({error, {mlkem_init_invalid_size, CLen, ?MLKEM768_INIT_SIZE}});
@@ -553,45 +582,41 @@ decode(<<"mlkem",?BYTE(?SSH_MSG_KEX_HYBRID_REPLY),
   when KLen =< ?MAX_HOST_KEY_SIZE,
        SLen =:= ?MLKEM768_REPLY_SIZE,
        SigLen =< ?MAX_SIGNATURE_SIZE ->
-    #ssh_msg_kex_hybrid_reply{
-       public_host_key = ssh2_pubkey_decode(Key),
-       s_reply = S_reply,
-       h_sig = decode_signature(Sig)
-      };
+    #ssh_msg_kex_hybrid_reply{public_host_key = ssh2_pubkey_decode(Key), s_reply = S_reply,
+                              h_sig = decode_signature(Sig)};
 decode(<<"mlkem",?BYTE(?SSH_MSG_KEX_HYBRID_REPLY),
-         ?DEC_BIN(_, KLen), ?DEC_BIN(_, SLen), ?DEC_BIN(_Sig, SigLen)>>) ->
-    Error = if
-                KLen > ?MAX_HOST_KEY_SIZE -> {mlkem_host_key_too_large, KLen, ?MAX_HOST_KEY_SIZE};
-                SLen =/= ?MLKEM768_REPLY_SIZE -> {mlkem_reply_invalid_size, SLen, ?MLKEM768_REPLY_SIZE};
-                SigLen > ?MAX_SIGNATURE_SIZE -> {mlkem_signature_too_large, SigLen, ?MAX_SIGNATURE_SIZE};
-                true -> {mlkem_reply_invalid, KLen, SLen, SigLen}
-            end,
-    throw({error, Error});
-
-decode(<<?SSH_MSG_SERVICE_REQUEST, ?DEC_BIN(Service,__0)>>) ->
-    #ssh_msg_service_request{
-       name = binary:bin_to_list(Service)
-      };
-
-decode(<<?SSH_MSG_SERVICE_ACCEPT, ?DEC_BIN(Service,__0)>>) ->
-    #ssh_msg_service_accept{
-       name = binary:bin_to_list(Service)
-      };
-
-decode(<<?BYTE(?SSH_MSG_DISCONNECT), ?UINT32(Code), ?DEC_BIN(Desc,__0), ?DEC_BIN(Lang,__1)>>) ->
-    #ssh_msg_disconnect{
-       code = Code,
-       description = ?unicode_list(Desc),
-       language = Lang
-      };
-
-%% Accept bad disconnects from ancient openssh clients that doesn't send language tag.  Use english as a work-around.
-decode(<<?BYTE(?SSH_MSG_DISCONNECT), ?UINT32(Code), ?DEC_BIN(Desc,__0)>>) ->
-    #ssh_msg_disconnect{
-       code = Code,
-       description = ?unicode_list(Desc),
-       language = <<"en">>
-      };
+         ?DEC_BIN(_, _KLen), ?DEC_BIN(_, SLen), ?DEC_BIN(_, _SigLen)>>)
+  when SLen =/= ?MLKEM768_REPLY_SIZE ->
+    throw({error, {mlkem_reply_invalid_size, SLen, ?MLKEM768_REPLY_SIZE}});
+decode(<<"mlkem",?BYTE(?SSH_MSG_KEX_HYBRID_REPLY),
+         ?DEC_BIN(_, KLen), ?DEC_BIN(_, _SLen), ?DEC_BIN(_, SigLen)>>) ->
+    throw({error, size_error([{mlkem_host_key_too_large, KLen, ?MAX_HOST_KEY_SIZE},
+                              {mlkem_signature_too_large, SigLen, ?MAX_SIGNATURE_SIZE}])});
+
+decode(<<?SSH_MSG_SERVICE_REQUEST, ?DEC_BIN(Service, Len)>>)
+  when Len =< ?MAX_SERVICE_NAME_SIZE ->
+    #ssh_msg_service_request{name = binary:bin_to_list(Service)};
+decode(<<?SSH_MSG_SERVICE_REQUEST, ?DEC_BIN(_, Len)>>) ->
+    throw({error, {service_request_name_too_large, Len, ?MAX_SERVICE_NAME_SIZE}});
+decode(<<?SSH_MSG_SERVICE_ACCEPT, ?DEC_BIN(Service, Len)>>)
+  when Len =< ?MAX_SERVICE_NAME_SIZE ->
+    #ssh_msg_service_accept{name = binary:bin_to_list(Service)};
+decode(<<?SSH_MSG_SERVICE_ACCEPT, ?DEC_BIN(_, Len)>>) ->
+    throw({error, {service_accept_name_too_large, Len, ?MAX_SERVICE_NAME_SIZE}});
+
+decode(<<?BYTE(?SSH_MSG_DISCONNECT), ?UINT32(Code), ?DEC_BIN(Desc, DLen), ?DEC_BIN(Lang, LLen)>>)
+    when DLen =< ?MAX_DISCONNECT_DESC_SIZE, LLen =< ?MAX_LANG_SIZE ->
+    #ssh_msg_disconnect{code = Code, description = ?unicode_list(Desc), language = Lang};
+decode(<<?BYTE(?SSH_MSG_DISCONNECT), ?UINT32(_), ?DEC_BIN(_, DLen), ?DEC_BIN(_, LLen)>>) ->
+    throw({error, size_error([{disconnect_desc_too_large, DLen, ?MAX_DISCONNECT_DESC_SIZE},
+                              {disconnect_lang_too_large, LLen, ?MAX_LANG_SIZE}])});
+
+%% Accept bad disconnects from ancient openssh clients that doesn't send language tag. Use english as a work-around.
+decode(<<?BYTE(?SSH_MSG_DISCONNECT), ?UINT32(Code), ?DEC_BIN(Desc, DLen)>>)
+  when DLen =< ?MAX_DISCONNECT_DESC_SIZE ->
+    #ssh_msg_disconnect{code = Code, description = ?unicode_list(Desc), language = <<"en">>};
+decode(<<?BYTE(?SSH_MSG_DISCONNECT), ?UINT32(_), ?DEC_BIN(_, DLen)>>) ->
+    throw({error, {disconnect_desc_too_large, DLen, ?MAX_DISCONNECT_DESC_SIZE}});
 
 decode(<<?SSH_MSG_NEWKEYS>>) ->
     #ssh_msg_newkeys{};
@@ -599,17 +624,21 @@ decode(<<?SSH_MSG_NEWKEYS>>) ->
 %% Accept SSH_MSG_IGNORE without data to have feature parity with other implementations like openssh
 decode(<<?BYTE(?SSH_MSG_IGNORE)>>) ->
     #ssh_msg_ignore{};
-decode(<<?BYTE(?SSH_MSG_IGNORE), ?DEC_BIN(Data,__0)>>) ->
+decode(<<?BYTE(?SSH_MSG_IGNORE), ?DEC_BIN(Data, Len)>>)
+  when Len =< ?MAX_IGNORE_DATA_SIZE ->
     #ssh_msg_ignore{data = Data};
+decode(<<?BYTE(?SSH_MSG_IGNORE), ?DEC_BIN(_, Len)>>) ->
+    throw({error, {ignore_data_too_large, Len, ?MAX_IGNORE_DATA_SIZE}});
 
 decode(<<?BYTE(?SSH_MSG_UNIMPLEMENTED), ?UINT32(Seq)>>) ->
     #ssh_msg_unimplemented{sequence = Seq};
 
-decode(<<?BYTE(?SSH_MSG_DEBUG), ?BYTE(Bool), ?DEC_BIN(Msg,__0), ?DEC_BIN(Lang,__1)>>) ->
-    #ssh_msg_debug{always_display = erl_boolean(Bool),
-		   message = Msg,
-		   language = Lang}.
-
+decode(<<?BYTE(?SSH_MSG_DEBUG), ?BYTE(Bool), ?DEC_BIN(Msg, MLen), ?DEC_BIN(Lang, LLen)>>)
+  when MLen =< ?MAX_DEBUG_MSG_SIZE, LLen =< ?MAX_LANG_SIZE ->
+    #ssh_msg_debug{always_display = erl_boolean(Bool), message = Msg, language = Lang};
+decode(<<?BYTE(?SSH_MSG_DEBUG), ?BYTE(_), ?DEC_BIN(_, MLen), ?DEC_BIN(_, LLen)>>) ->
+    throw({error, size_error([{debug_msg_too_large, MLen, ?MAX_DEBUG_MSG_SIZE},
+                              {debug_lang_too_large, LLen, ?MAX_LANG_SIZE}])}).
 
 %%%================================================================
 %%%
@@ -829,6 +858,12 @@ oid2ssh_curvename(?'secp521r1') -> {<<"ecdsa-sha2-nistp521">>, <<"nistp521">>}.
 %%%
 %%% Helper functions
 %%%
+size_error([{_, Actual, Max} | Rest]) when Actual =< Max ->
+    size_error(Rest);
+size_error([{Tag, Actual, Max} | _]) ->
+    {Tag, Actual, Max};
+size_error([]) ->
+    invalid_size_check.
 
 bin_foldr(Fun, Acc, Bin) ->
     lists:reverse(bin_foldl(Fun, Acc, Bin)).
@@ -892,8 +927,6 @@ decode_kex_init(<<?DEC_BIN(Data,__0), Rest/binary>>, Acc, N) when
 decode_kex_init(<<?DEC_BIN(Data,__0), _Rest/binary>>, _Acc, N) ->
     throw({error, {kexinit, N, {string_size, byte_size(Data)}}}).
 
-
-
 %%%================================================================
 %%%
 %%% Signature decode/encode
-- 
2.51.0

openSUSE Build Service is sponsored by