From: Diego Oliva <diego@bynar.io>
To: Paulo Alcantara <pc@manguebit.org>, Namjae Jeon <linkinjeon@kernel.org>
Cc: Ronnie Sahlberg <ronniesahlberg@gmail.com>,
Shyam Prasad N <sprasad@microsoft.com>,
Tom Talpey <tom@talpey.com>, Bharath SM <bharathsm@microsoft.com>,
linux-cifs@vger.kernel.org, samba-technical@lists.samba.org,
linux-kernel@vger.kernel.org
Subject: [PATCH] smb: client: reject out-of-bounds DataOffset in CIFSSMBRead()
Date: Fri, 28 Aug 2026 16:02:03 +0100 [thread overview]
Message-ID: <20260828150203.1419003-1-diego@bynar.io> (raw)
The SMB1 synchronous read helper CIFSSMBRead() validates the server's
DataLength against CIFSMaxBufSize and the caller's count, but never
validates DataOffset. The copy source is formed as
&pSMBr->hdr.Protocol + le16_to_cpu(pSMBr->DataOffset)
and memcpy()'d for DataLength bytes with no check that the
[DataOffset, DataOffset + DataLength) range lies within the response
actually received from the server.
A malicious or compromised SMB1 server can return a short response
carrying an in-range DataLength and a large DataOffset, driving the
source pointer past the end of the response buffer. The memcpy() then
copies adjacent kernel heap into the caller's read buffer (information
disclosure), or reads unmapped memory and oopses (denial of service).
SMB1 is not negotiated by default; reaching this code requires an
explicit vers=1.0 mount.
Both DataOffset and the received response length recorded in
rsp_iov.iov_len are relative to the start of the SMB header, so reject
the response unless DataOffset + DataLength fits within that length,
using overflow-safe arithmetic, before forming the source pointer.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Assisted-by: Bynario AI
Signed-off-by: Diego Oliva <diego@bynar.io>
---
Note for backporting: this uses the smb_EIO2() tracepoint helper added
in v6.19 with f80ac7eda1cf5. For older kernels, the call can be
replaced with a simple return of -EIO.
fs/smb/client/cifssmb.c | 11 +++++++++--
fs/smb/client/trace.h | 1 +
2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c
index f5aad5f61dce..1a822121a883 100644
--- a/fs/smb/client/cifssmb.c
+++ b/fs/smb/client/cifssmb.c
@@ -1721,6 +1721,7 @@ CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
cifs_dbg(VFS, "Send error in read = %d\n", rc);
} else {
int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
+ __u16 data_offset = le16_to_cpu(pSMBr->DataOffset);
data_length = data_length << 16;
data_length += le16_to_cpu(pSMBr->DataLength);
*nbytes = data_length;
@@ -1733,9 +1734,15 @@ CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
rc = smb_EIO2(smb_eio_trace_read_overlarge,
data_length, count);
*nbytes = 0;
+ } else if ((size_t)data_offset + data_length > rsp_iov.iov_len) {
+ /* check that the data lies within the received response */
+ cifs_dbg(FYI, "bad data offset %u length %d for read response of %zu\n",
+ data_offset, data_length, rsp_iov.iov_len);
+ rc = smb_EIO2(smb_eio_trace_read_bad_offset,
+ data_offset, data_length);
+ *nbytes = 0;
} else {
- pReadData = (char *) (&pSMBr->hdr.Protocol) +
- le16_to_cpu(pSMBr->DataOffset);
+ pReadData = (char *) (&pSMBr->hdr.Protocol) + data_offset;
/* if (rc = copy_to_user(buf, pReadData, data_length)) {
cifs_dbg(VFS, "Faulting on read rc = %d\n",rc);
rc = -EFAULT;
diff --git a/fs/smb/client/trace.h b/fs/smb/client/trace.h
index 12241abb8e2e..982b6ba1e429 100644
--- a/fs/smb/client/trace.h
+++ b/fs/smb/client/trace.h
@@ -79,6 +79,7 @@
EM(smb_eio_trace_qreparse_setup_count, "qreparse_setup_count") \
EM(smb_eio_trace_qreparse_sizes_wrong, "qreparse_sizes_wrong") \
EM(smb_eio_trace_qsym_bcc_too_small, "qsym_bcc_too_small") \
+ EM(smb_eio_trace_read_bad_offset, "read_bad_offset") \
EM(smb_eio_trace_read_mid_state_unknown, "read_mid_state_unknown") \
EM(smb_eio_trace_read_overlarge, "read_overlarge") \
EM(smb_eio_trace_read_rsp_malformed, "read_rsp_malformed") \
base-commit: 1b78070aaef63512688aebfbc82365ef9d6660f1
--
2.39.5
next reply other threads:[~2026-08-28 15:02 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-28 15:02 Diego Oliva [this message]
2026-08-29 2:35 ` [PATCH] smb: client: reject out-of-bounds DataOffset in CIFSSMBRead() Namjae Jeon
2026-08-31 12:50 ` [PATCH v2] " Diego Oliva
2026-08-31 22:15 ` Paulo Alcantara
2026-09-01 14:05 ` Diego Oliva
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260828150203.1419003-1-diego@bynar.io \
--to=diego@bynar.io \
--cc=bharathsm@microsoft.com \
--cc=linkinjeon@kernel.org \
--cc=linux-cifs@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=pc@manguebit.org \
--cc=ronniesahlberg@gmail.com \
--cc=samba-technical@lists.samba.org \
--cc=sprasad@microsoft.com \
--cc=tom@talpey.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).