]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ksmbd: fix stack buffer overflow in multichannel session-key copy
authorGil Portnoy <dddhkts1@gmail.com>
Sun, 12 Jul 2026 00:00:00 +0000 (00:00 +0000)
committerSteve French <stfrench@microsoft.com>
Thu, 16 Jul 2026 15:18:25 +0000 (10:18 -0500)
Commit 4b706360ffb7 ("ksmbd: fix multichannel binding and enforce channel
limit") moved the binding-path session key out of the session-wide
sess->sess_key (CIFS_KEY_SIZE = 40) into a new per-channel buffer, and
sized both that buffer and the on-stack copy used during binding with
SMB2_NTLMV2_SESSKEY_SIZE (16):

struct channel {
char sess_key[SMB2_NTLMV2_SESSKEY_SIZE]; /* 16 */
...
};

ntlm_authenticate() / krb5_authenticate():
char channel_key[SMB2_NTLMV2_SESSKEY_SIZE] = {}; /* 16 */
char *auth_key = conn->binding ? channel_key : sess->sess_key;

The two writers that fill this destination still bound the copy length
against CIFS_KEY_SIZE (40), not against the 16-byte buffer:

ksmbd_decode_ntlmssp_auth_blob() (NTLM key exchange):
if (sess_key_len > CIFS_KEY_SIZE) /* 40 */
return -EINVAL;
arc4_crypt(ctx_arc4, sess_key,
   (char *)authblob + sess_key_off, sess_key_len);

ksmbd_krb5_authenticate():
if (resp->session_key_len > sizeof(sess->sess_key)) /* 40 */
...
memcpy(sess_key, resp->payload, resp->session_key_len);

On a binding SESSION_SETUP, auth_key points at the 16-byte channel_key,
so a client that supplies an NTLM EncryptedRandomSessionKey of up to 40
bytes (with NTLMSSP_NEGOTIATE_KEY_EXCH), or a Kerberos ticket whose
session key is longer than 16 bytes (a normal AES256 key is 32), writes
past the 16-byte stack buffer -- up to a 24-byte kernel stack overflow.
KASAN reports it as a stack-out-of-bounds write in arc4_crypt() called
from ksmbd_decode_ntlmssp_auth_blob().

The destinations must be able to hold the full session key the length
checks already permit. Size the per-channel key buffer and the two
on-stack channel_key buffers with CIFS_KEY_SIZE, matching sess->sess_key.

Fixes: 4b706360ffb7 ("ksmbd: fix multichannel binding and enforce channel limit")
Signed-off-by: Gil Portnoy <dddhkts1@gmail.com>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/server/mgmt/user_session.h
fs/smb/server/smb2pdu.c

index 8893a9aaede795ac23ed0f57d5e6cbb45ffe00f8..4637a8c8436d0212caf2dd4246ccc65d688fab40 100644 (file)
@@ -19,7 +19,7 @@
 struct ksmbd_file_table;
 
 struct channel {
-       char                    sess_key[SMB2_NTLMV2_SESSKEY_SIZE];
+       char                    sess_key[CIFS_KEY_SIZE];
        __u8                    smb3signingkey[SMB3_SIGN_KEY_SIZE];
        struct ksmbd_conn       *conn;
 };
index c8acf9f04e45405c3a4c5f038c433f83ff102593..8686b9a4a6969a6c4e610c968d603d79958df250 100644 (file)
@@ -1689,7 +1689,7 @@ static int ntlm_authenticate(struct ksmbd_work *work,
        struct ksmbd_conn *conn = work->conn;
        struct ksmbd_session *sess = work->sess;
        struct ksmbd_user *user;
-       char channel_key[SMB2_NTLMV2_SESSKEY_SIZE] = {};
+       char channel_key[CIFS_KEY_SIZE] = {};
        char *auth_key = conn->binding ? channel_key : sess->sess_key;
        u64 prev_id;
        bool binding = conn->binding;
@@ -1826,7 +1826,7 @@ static int krb5_authenticate(struct ksmbd_work *work,
        struct ksmbd_conn *conn = work->conn;
        struct ksmbd_session *sess = work->sess;
        char *in_blob, *out_blob;
-       char channel_key[SMB2_NTLMV2_SESSKEY_SIZE] = {};
+       char channel_key[CIFS_KEY_SIZE] = {};
        char *auth_key = conn->binding ? channel_key : sess->sess_key;
        u64 prev_sess_id;
        bool binding = conn->binding;