Re: [PATCH 1/2] smb: client: fix create context out-of-bounds reads
Steve French <[email protected]>
| Newsgroups | org.kernel.vger.linux-cifs |
|---|---|
| Message-ID | <CAH2r5mvzR7npgJirx9e4GAKdbva9YAJBj6P71bSxJ3SbpF9dGw@mail.gmail.com> |
This regresses all xfstests when I tried it. Looks like a bug in the patch so have not merged this one (although have merged smb-client-harden-POSIX-SID-length-parsing pending more testing). Let me know if you update it. On Sun, Jun 28, 2026 at 4:20 AM Ren Wei <[email protected]> wrote: > > 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 > > -- Thanks, Steve