From: Dairui Zhang <zhangdairui@gmail.com>
To: linux-cifs@vger.kernel.org
Cc: Namjae Jeon <linkinjeon@kernel.org>,
Steve French <smfrench@gmail.com>,
Sergey Senozhatsky <senozhatsky@chromium.org>,
Tom Talpey <tom@talpey.com>, Paulo Alcantara <pc@manguebit.org>,
Dairui Zhang <zhangdairui@gmail.com>,
stable@vger.kernel.org
Subject: [PATCH] ksmbd: verify transform SessionId matches the decrypted header
Date: Sun, 27 Sep 2026 14:16:39 +0800 [thread overview]
Message-ID: <20260927061639.1722520-1-zhangdairui@gmail.com> (raw)
The decryption key for an encrypted request is selected by the
SessionId in the encryption transform header, but the request is
then authorized under the session named in the decrypted inner SMB2
header. Nothing compares the two, so on a connection carrying more
than one session a client can have a request decrypted with one
session's key and executed under another session's identity. Since
encrypted requests are also exempt from the signing requirement, the
AEAD tag is the only proof of session identity, and it is checked
against the wrong session.
Per MS-SMB2 the server must verify that the SessionId in the
transform header matches the one in the decrypted SMB2 header and
treat a mismatch as a protocol error. Compare them after decryption
and drop the connection on mismatch. When the encrypted payload is a
compression transform, the transform SessionId is saved and verified
against the decompressed SMB2 header instead, since a compression
transform header carries no SessionId.
Reported-by: Dairui Zhang <zhangdairui@gmail.com>
Assisted-by: LLM
Cc: stable@vger.kernel.org
Signed-off-by: Dairui Zhang <zhangdairui@gmail.com>
---
v1 -> v2:
- Also cover the compression-transform case, per Namjae's review:
save the transform SessionId during decryption and check it
against the decompressed SMB2 header.
- Reject a decrypted SMB2 message smaller than the fixed header
before reading its SessionId (a crafted short OriginalMessageSize
would otherwise make the check itself read out of bounds).
- v1: https://lore.kernel.org/linux-cifs/20260926080224.1671214-1-zhangdairui@gmail.com/
---
fs/smb/server/compress.c | 14 ++++++++++++++
fs/smb/server/ksmbd_work.h | 4 ++++
fs/smb/server/smb2pdu.c | 25 +++++++++++++++++++++++++
3 files changed, 43 insertions(+)
diff --git a/fs/smb/server/compress.c b/fs/smb/server/compress.c
index 5162fb8..1c5a070 100644
--- a/fs/smb/server/compress.c
+++ b/fs/smb/server/compress.c
@@ -125,6 +125,20 @@ int ksmbd_decompress_work_request(struct ksmbd_work *work)
if (rc)
return rc;
+ /*
+ * The SessionId of the encryption transform header was saved
+ * before the compression transform was parsed; the decompressed
+ * SMB2 header must carry the same one. Per MS-SMB2 a mismatch is
+ * a protocol error.
+ */
+ if (work->tr_sess_id &&
+ le64_to_cpu(((struct smb2_hdr *)smb_get_msg(out_buf))->SessionId) !=
+ work->tr_sess_id) {
+ pr_err_ratelimited("SessionId mismatch between transform and decompressed header\n");
+ kvfree(out_buf);
+ return -ECONNABORTED;
+ }
+
kvfree(work->request_buf);
work->request_buf = out_buf;
return 0;
diff --git a/fs/smb/server/ksmbd_work.h b/fs/smb/server/ksmbd_work.h
index 5f1d3eb..3e8bf2a 100644
--- a/fs/smb/server/ksmbd_work.h
+++ b/fs/smb/server/ksmbd_work.h
@@ -82,6 +82,10 @@ struct ksmbd_work {
/* Contiguous SMB2 compression transform owned by this work item. */
void *compress_buf;
+ /* SessionId from the encryption transform header, for the
+ * post-decompression SessionId check. Zero when unset. */
+ __u64 tr_sess_id;
+
unsigned char state;
/* No response for cancelled request */
bool send_no_response:1;
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 4cf7083..9eb13a8 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -10860,6 +10860,7 @@ int smb3_decrypt_req(struct ksmbd_work *work)
unsigned int buf_data_size;
struct smb2_transform_hdr *tr_hdr = smb_get_msg(buf);
unsigned int original_msg_size;
+ __le32 proto;
int rc = 0;
if (pdu_length < sizeof(struct smb2_transform_hdr)) {
@@ -10890,6 +10891,30 @@ int smb3_decrypt_req(struct ksmbd_work *work)
if (rc)
return rc;
+ /*
+ * The decryption key is selected by the transform header SessionId,
+ * while the request is authorized under the session named in the
+ * decrypted inner header. Per MS-SMB2 the two must match; verify
+ * that here and drop the connection on mismatch. A compression
+ * transform payload carries the session id only after
+ * decompression, so save the transform SessionId for the check
+ * after decompression instead.
+ */
+ proto = ((struct smb2_hdr *)iov[1].iov_base)->ProtocolId;
+ if (proto == SMB2_PROTO_NUMBER) {
+ if (original_msg_size < sizeof(struct smb2_hdr)) {
+ pr_err_ratelimited("Decrypted SMB2 message is too small\n");
+ return -ECONNABORTED;
+ }
+ if (le64_to_cpu(tr_hdr->SessionId) !=
+ le64_to_cpu(((struct smb2_hdr *)iov[1].iov_base)->SessionId)) {
+ pr_err_ratelimited("SessionId mismatch between transform and inner header\n");
+ return -ECONNABORTED;
+ }
+ } else if (proto == SMB2_COMPRESSION_TRANSFORM_ID) {
+ work->tr_sess_id = le64_to_cpu(tr_hdr->SessionId);
+ }
+
/* Drop the AEAD authentication tag from the inner RFC1002 frame. */
memmove(buf + 4, iov[1].iov_base, original_msg_size);
*(__be32 *)buf = cpu_to_be32(original_msg_size);
--
2.53.0
next reply other threads:[~2026-09-27 6:16 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-27 6:16 Dairui Zhang [this message]
2026-09-27 22:43 ` [PATCH] ksmbd: verify transform SessionId matches the decrypted header Namjae Jeon
-- strict thread matches above, loose matches on Subject: below --
2026-09-28 3:13 Dairui Zhang
2026-09-28 5:16 ` Greg KH
2026-09-28 5:17 ` Dairui Zhang
2026-09-28 16:20 ` Dairui Zhang
2026-09-29 1:32 ` Namjae Jeon
2026-09-26 8:02 Dairui Zhang
2026-09-27 1:32 ` Namjae Jeon
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260927061639.1722520-1-zhangdairui@gmail.com \
--to=zhangdairui@gmail.com \
--cc=linkinjeon@kernel.org \
--cc=linux-cifs@vger.kernel.org \
--cc=pc@manguebit.org \
--cc=senozhatsky@chromium.org \
--cc=smfrench@gmail.com \
--cc=stable@vger.kernel.org \
--cc=tom@talpey.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox