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. The check only applies to plain SMB2 payloads; a compression transform payload carries the session id only after decompression and is left as-is for now. Reported-by: Dairui Zhang Assisted-by: LLM Cc: stable@vger.kernel.org Signed-off-by: Dairui Zhang --- fs/smb/server/smb2pdu.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 4cf7083..e4cfbe6 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -10890,6 +10890,22 @@ 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 it is not covered by this check. + */ + if (((struct smb2_hdr *)iov[1].iov_base)->ProtocolId == + SMB2_PROTO_NUMBER && + 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; + } + /* 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