]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
smb: client: Zero-pad short GSS session keys per MS-SMB2
authorPiyush Sachdeva <s.piyush1024@gmail.com>
Thu, 7 May 2026 16:52:14 +0000 (22:22 +0530)
committerSteve French <stfrench@microsoft.com>
Thu, 7 May 2026 19:09:01 +0000 (14:09 -0500)
Per MS-SMB2 section 3.2.5.3, Session.SessionKey is the first 16 bytes
of the GSS cryptographic key, right-padded with zero bytes if the key
is shorter than 16 bytes.

SMB2_auth_kerberos() copies the GSS session key from the cifs.upcall
response using kmemdup(msg->data, msg->sesskey_len, ...) and stores
the GSS-reported length verbatim in ses->auth_key.len. generate_key()
reads SMB2_NTLMV2_SESSKEY_SIZE bytes from this buffer when feeding the
HMAC-SHA256 KDF for signing key derivation. If a GSS mechanism returns
a session key shorter than 16 bytes (e.g. a deprecated single-DES
Kerberos enctype with an 8-byte session key), the KDF call performs an
out-of-bounds slab read and derives keys that do not match the server,
which pads per the spec.

Modern KDCs disable short-key enctypes by default, so this is latent
rather than reachable in production, but it is still a kernel heap
over-read.

Allocate auth_key.response with kzalloc() at a length of
max(msg->sesskey_len, SMB2_NTLMV2_SESSKEY_SIZE), copy the GSS key in,
and rely on kzalloc()'s zero initialization for the spec-mandated
padding. Set ses->auth_key.len to the padded length. Larger GSS keys
(e.g. the 32-byte aes256-cts-hmac-sha1-96 session key) continue to be
stored at their natural length, preserving the FullSessionKey path.

Emit a cifs_dbg(VFS, ...) message when a short key is encountered to
surface deprecated-enctype usage.

NTLMv2 and NTLMSSP code paths produce a 16-byte session key by
construction and are unaffected.

Signed-off-by: Piyush Sachdeva <psachdeva@microsoft.com>
Signed-off-by: Piyush Sachdeva <s.piyush1024@gmail.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/client/smb2pdu.c

index cb61051f9af3b378708a079408d8e9c3f012e0ec..995fcdd306815fa55828009e59fcba22e7f6dc5a 100644 (file)
@@ -1713,17 +1713,30 @@ SMB2_auth_kerberos(struct SMB2_sess_data *sess_data)
        is_binding = (ses->ses_status == SES_GOOD);
        spin_unlock(&ses->ses_lock);
 
+       /*
+        * Per MS-SMB2 3.2.5.3, Session.SessionKey is the first 16 bytes of the
+        * GSS cryptographic key, right-padded with zero bytes if shorter.
+        * Allocate at least SMB2_NTLMV2_SESSKEY_SIZE bytes (zeroed) so the KDF
+        * input buffer is always valid for HMAC-SHA256 even with deprecated
+        * Kerberos enctypes that return a short session key.
+        */
+       if (unlikely(msg->sesskey_len < SMB2_NTLMV2_SESSKEY_SIZE))
+               cifs_dbg(VFS,
+                        "short GSS session key (%u bytes); zero-padding per MS-SMB2 3.2.5.3\n",
+                        msg->sesskey_len);
+
        kfree_sensitive(ses->auth_key.response);
-       ses->auth_key.response = kmemdup(msg->data,
-                                        msg->sesskey_len,
-                                        GFP_KERNEL);
+       ses->auth_key.len = max_t(unsigned int, msg->sesskey_len,
+                                 SMB2_NTLMV2_SESSKEY_SIZE);
+       ses->auth_key.response = kzalloc(ses->auth_key.len, GFP_KERNEL);
        if (!ses->auth_key.response) {
                cifs_dbg(VFS, "%s: can't allocate (%u bytes) memory\n",
-                        __func__, msg->sesskey_len);
+                        __func__, ses->auth_key.len);
+               ses->auth_key.len = 0;
                rc = -ENOMEM;
                goto out_put_spnego_key;
        }
-       ses->auth_key.len = msg->sesskey_len;
+       memcpy(ses->auth_key.response, msg->data, msg->sesskey_len);
 
        sess_data->iov[1].iov_base = msg->data + msg->sesskey_len;
        sess_data->iov[1].iov_len = msg->secblob_len;