David Disseldorp 5d87bb
From 44dfdf6c245622fc74c5f1941fd1900ac24734e3 Mon Sep 17 00:00:00 2001
David Disseldorp 5d87bb
From: David Disseldorp <ddiss@suse.de>
David Disseldorp 5d87bb
Date: Fri, 7 Apr 2023 00:34:11 +0200
David Disseldorp 5d87bb
Subject: [PATCH] cifs: fix negotiate context parsing
David Disseldorp 5d87bb
Git-commit: 5105a7ffce19160e7062aee67fb6b3b8a1b56d78
David Disseldorp 5d87bb
Patch-mainline: v6.3-rc7
David Disseldorp 5d87bb
References: bsc#1210301
David Disseldorp 5d87bb
David Disseldorp 5d87bb
smb311_decode_neg_context() doesn't properly check against SMB packet
David Disseldorp 5d87bb
boundaries prior to accessing individual negotiate context entries. This
David Disseldorp 5d87bb
is due to the length check omitting the eight byte smb2_neg_context
David Disseldorp 5d87bb
header, as well as incorrect decrementing of len_of_ctxts.
David Disseldorp 5d87bb
David Disseldorp 5d87bb
Fixes: 5100d8a3fe03 ("SMB311: Improve checking of negotiate security contexts")
David Disseldorp 5d87bb
Reported-by: Volker Lendecke <vl@samba.org>
David Disseldorp 5d87bb
Reviewed-by: Paulo Alcantara (SUSE) <pc@manguebit.com>
David Disseldorp 5d87bb
Signed-off-by: David Disseldorp <ddiss@suse.de>
David Disseldorp 5d87bb
Signed-off-by: Steve French <stfrench@microsoft.com>
David Disseldorp 5d87bb
[ddiss: rebase against 5.3 without d7173623bf0b15]
David Disseldorp 5d87bb
---
David Disseldorp 5d87bb
 fs/cifs/smb2pdu.c | 41 +++++++++++++++++++++++++++++++----------
David Disseldorp 5d87bb
 1 file changed, 31 insertions(+), 10 deletions(-)
David Disseldorp 5d87bb
David Disseldorp 5d87bb
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
David Disseldorp 5d87bb
index 7ca02350cbfc2..ac67615308e88 100644
David Disseldorp 5d87bb
--- a/fs/cifs/smb2pdu.c
David Disseldorp 5d87bb
+++ b/fs/cifs/smb2pdu.c
David Disseldorp 5d87bb
@@ -585,11 +585,15 @@ assemble_neg_contexts(struct smb2_negotiate_req *req,
David Disseldorp 5d87bb
 
David Disseldorp 5d87bb
 }
David Disseldorp 5d87bb
 
David Disseldorp 5d87bb
+/* If invalid preauth context warn but use what we requested, SHA-512 */
David Disseldorp 5d87bb
 static void decode_preauth_context(struct smb2_preauth_neg_context *ctxt)
David Disseldorp 5d87bb
 {
David Disseldorp 5d87bb
 	unsigned int len = le16_to_cpu(ctxt->DataLength);
David Disseldorp 5d87bb
 
David Disseldorp 5d87bb
-	/* If invalid preauth context warn but use what we requested, SHA-512 */
David Disseldorp 5d87bb
+	/*
David Disseldorp 5d87bb
+	 * Caller checked that DataLength remains within SMB boundary. We still
David Disseldorp 5d87bb
+	 * need to confirm that one HashAlgorithms member is accounted for.
David Disseldorp 5d87bb
+	 */
David Disseldorp 5d87bb
 	if (len < MIN_PREAUTH_CTXT_DATA_LEN) {
David Disseldorp 5d87bb
 		pr_warn_once("server sent bad preauth context\n");
David Disseldorp 5d87bb
 		return;
David Disseldorp 5d87bb
@@ -608,7 +612,11 @@ static void decode_compress_ctx(struct TCP_Server_Info *server,
David Disseldorp 5d87bb
 {
David Disseldorp 5d87bb
 	unsigned int len = le16_to_cpu(ctxt->DataLength);
David Disseldorp 5d87bb
 
David Disseldorp 5d87bb
-	/* sizeof compress context is a one element compression capbility struct */
David Disseldorp 5d87bb
+	/*
David Disseldorp 5d87bb
+	 * Caller checked that DataLength remains within SMB boundary. We still
David Disseldorp 5d87bb
+	 * need to confirm that one CompressionAlgorithms member is accounted
David Disseldorp 5d87bb
+	 * for.
David Disseldorp 5d87bb
+	 */
David Disseldorp 5d87bb
 	if (len < 10) {
David Disseldorp 5d87bb
 		pr_warn_once("server sent bad compression cntxt\n");
David Disseldorp 5d87bb
 		return;
David Disseldorp 5d87bb
@@ -630,6 +638,11 @@ static int decode_encrypt_ctx(struct TCP_Server_Info *server,
David Disseldorp 5d87bb
 	unsigned int len = le16_to_cpu(ctxt->DataLength);
David Disseldorp 5d87bb
 
David Disseldorp 5d87bb
 	cifs_dbg(FYI, "decode SMB3.11 encryption neg context of len %d\n", len);
David Disseldorp 5d87bb
+	/*
David Disseldorp 5d87bb
+	 * Caller checked that DataLength remains within SMB boundary. We still
David Disseldorp 5d87bb
+	 * need to confirm that one Cipher flexible array member is accounted
David Disseldorp 5d87bb
+	 * for.
David Disseldorp 5d87bb
+	 */
David Disseldorp 5d87bb
 	if (len < MIN_ENCRYPT_CTXT_DATA_LEN) {
David Disseldorp 5d87bb
 		pr_warn_once("server sent bad crypto ctxt len\n");
David Disseldorp 5d87bb
 		return -EINVAL;
David Disseldorp 5d87bb
@@ -676,6 +689,11 @@ static void decode_signing_ctx(struct TCP_Server_Info *server,
David Disseldorp 5d87bb
 {
David Disseldorp 5d87bb
 	unsigned int len = le16_to_cpu(pctxt->DataLength);
David Disseldorp 5d87bb
 
David Disseldorp 5d87bb
+	/*
David Disseldorp 5d87bb
+	 * Caller checked that DataLength remains within SMB boundary. We still
David Disseldorp 5d87bb
+	 * need to confirm that one SigningAlgorithms flexible array member is
David Disseldorp 5d87bb
+	 * accounted for.
David Disseldorp 5d87bb
+	 */
David Disseldorp 5d87bb
 	if ((len < 4) || (len > 16)) {
David Disseldorp 5d87bb
 		pr_warn_once("server sent bad signing negcontext\n");
David Disseldorp 5d87bb
 		return;
David Disseldorp 5d87bb
@@ -717,14 +735,19 @@ static int smb311_decode_neg_context(struct smb2_negotiate_rsp *rsp,
David Disseldorp 5d87bb
 	for (i = 0; i < ctxt_cnt; i++) {
David Disseldorp 5d87bb
 		int clen;
David Disseldorp 5d87bb
 		/* check that offset is not beyond end of SMB */
David Disseldorp 5d87bb
-		if (len_of_ctxts == 0)
David Disseldorp 5d87bb
-			break;
David Disseldorp 5d87bb
-
David Disseldorp 5d87bb
 		if (len_of_ctxts < sizeof(struct smb2_neg_context))
David Disseldorp 5d87bb
 			break;
David Disseldorp 5d87bb
 
David Disseldorp 5d87bb
 		pctx = (struct smb2_neg_context *)(offset + (char *)rsp);
David Disseldorp 5d87bb
-		clen = le16_to_cpu(pctx->DataLength);
David Disseldorp 5d87bb
+		clen = sizeof(struct smb2_neg_context)
David Disseldorp 5d87bb
+			+ le16_to_cpu(pctx->DataLength);
David Disseldorp 5d87bb
+		/*
David Disseldorp 5d87bb
+		 * 2.2.4 SMB2 NEGOTIATE Response
David Disseldorp 5d87bb
+		 * Subsequent negotiate contexts MUST appear at the first 8-byte
David Disseldorp 5d87bb
+		 * aligned offset following the previous negotiate context.
David Disseldorp 5d87bb
+		 */
David Disseldorp 5d87bb
+		if (i + 1 != ctxt_cnt)
David Disseldorp 5d87bb
+			clen = ALIGN(clen, 8);
David Disseldorp 5d87bb
 		if (clen > len_of_ctxts)
David Disseldorp 5d87bb
 			break;
David Disseldorp 5d87bb
 
David Disseldorp 5d87bb
@@ -745,12 +768,10 @@ static int smb311_decode_neg_context(struct smb2_negotiate_rsp *rsp,
David Disseldorp 5d87bb
 		else
David Disseldorp 5d87bb
 			cifs_server_dbg(VFS, "unknown negcontext of type %d ignored\n",
David Disseldorp 5d87bb
 				le16_to_cpu(pctx->ContextType));
David Disseldorp 5d87bb
-
David Disseldorp 5d87bb
 		if (rc)
David Disseldorp 5d87bb
 			break;
David Disseldorp 5d87bb
-		/* offsets must be 8 byte aligned */
David Disseldorp 5d87bb
-		clen = (clen + 7) & ~0x7;
David Disseldorp 5d87bb
-		offset += clen + sizeof(struct smb2_neg_context);
David Disseldorp 5d87bb
+
David Disseldorp 5d87bb
+		offset += clen;
David Disseldorp 5d87bb
 		len_of_ctxts -= clen;
David Disseldorp 5d87bb
 	}
David Disseldorp 5d87bb
 	return rc;
David Disseldorp 5d87bb
-- 
David Disseldorp 5d87bb
2.40.0
David Disseldorp 5d87bb