[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