[PATCH 1/2] smb: client: fix create context out-of-bounds reads

Ren Wei <[email protected]>
Newsgroups org.kernel.vger.linux-cifs
Message-ID <eb1bc35611f91bd10a4772400b37fac26f660956.1782579150.git.xizh2024@lzu.edu.cn>
From: Zihan Xi <[email protected]>

smb2_parse_contexts() validates generic create-context layout but does
not ensure each handler's minimum size before parsing. A malicious
server can supply a truncated QFid (Query On Disk ID) context with
DataLength zero; parse_query_id_ctxt() then reads fixed offsets past
the context boundary and triggers a slab out-of-bounds read.

Bound each context by its Next field and reject lease, QFid, and POSIX
contexts that are shorter than their parsers require.

Fixes: 89a5bfa350fa ("smb3: optimize open to not send query file internal info")
Cc: [email protected]
Reported-by: Yuan Tan <[email protected]>
Reported-by: Yifan Wu <[email protected]>
Reported-by: Juefei Pu <[email protected]>
Reported-by: Xin Liu <[email protected]>
Assisted-by: Codex:gpt-5.4
Signed-off-by: Zihan Xi <[email protected]>
Signed-off-by: Ren Wei <[email protected]>
---
 fs/smb/client/smb2pdu.c | 21 +++++++++++++++++++--
 1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
index 3bd300347f16..840bc81718da 100644
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -2405,6 +2405,7 @@ int smb2_parse_contexts(struct TCP_Server_Info *server,
 	struct smb2_create_rsp *rsp = rsp_iov->iov_base;
 	struct create_context *cc;
 	size_t rem, off, len;
+	size_t cc_len;
 	size_t doff, dlen;
 	size_t noff, nlen;
 	char *name;
@@ -2427,9 +2428,18 @@ int smb2_parse_contexts(struct TCP_Server_Info *server,
 		buf->IndexNumber = 0;
 
 	while (rem >= sizeof(*cc)) {
+		off = le32_to_cpu(cc->Next);
+		if (off) {
+			if ((off & 0x7) || off > rem)
+				return -EINVAL;
+			cc_len = off;
+		} else {
+			cc_len = rem;
+		}
+
 		doff = le16_to_cpu(cc->DataOffset);
 		dlen = le32_to_cpu(cc->DataLength);
-		if (check_add_overflow(doff, dlen, &len) || len > rem)
+		if (check_add_overflow(doff, dlen, &len) || len > cc_len)
 			return -EINVAL;
 
 		noff = le16_to_cpu(cc->NameOffset);
@@ -2441,16 +2451,23 @@ int smb2_parse_contexts(struct TCP_Server_Info *server,
 		switch (nlen) {
 		case 4:
 			if (!strncmp(name, SMB2_CREATE_REQUEST_LEASE, 4)) {
+				if (cc_len < server->vals->create_lease_size)
+					return -EINVAL;
 				*oplock = server->ops->parse_lease_buf(cc, epoch,
 								       lease_key);
 			} else if (buf &&
 				   !strncmp(name, SMB2_CREATE_QUERY_ON_DISK_ID, 4)) {
+				if (cc_len < sizeof(struct create_disk_id_rsp))
+					return -EINVAL;
 				parse_query_id_ctxt(cc, buf);
 			}
 			break;
 		case 16:
-			if (posix && !memcmp(name, smb3_create_tag_posix, 16))
+			if (posix && !memcmp(name, smb3_create_tag_posix, 16)) {
+				if (dlen < 3 * sizeof(__le32) + MIN_SID_LEN + 2)
+					return -EINVAL;
 				parse_posix_ctxt(cc, buf, posix);
+			}
 			break;
 		default:
 			cifs_dbg(FYI, "%s: unhandled context (nlen=%zu dlen=%zu)\n",
-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.