smb: client: reject short READ responses in CIFSSMBRead()

CIFSSMBRead() reads DataLengthHigh, DataLength and DataOffset out of
the READ_RSP returned by the server without first checking that a
whole READ_RSP was actually received. The length of the response is
recorded in rsp_iov.iov_len, but nothing constrains it to be at least
read_rsp_size before those fields are dereferenced.

A malicious or compromised SMB1 server can return a response shorter
than the READ_RSP header, so that parsing the header itself reads past
the end of the receive buffer. SMB1 is not negotiated by default;
reaching this code requires an explicit vers=1.0 mount.

Reject the response unless it is at least read_rsp_size bytes long.

Fixes: 1da177e4c3 ("Linux-2.6.12-rc2")
Suggested-by: Paulo Alcantara <pc@manguebit.org>
Cc: stable@vger.kernel.org # 6.19.x
Assisted-by: Bynario AI
Signed-off-by: Diego Oliva <diego@bynar.io>
Reviewed-by: David Howells <dhowells@redhat.com>
Signed-off-by: Paulo Alcantara <pc@manguebit.org>
This commit is contained in:
Diego Oliva 2026-09-02 11:42:06 +01:00 committed by Paulo Alcantara
parent 89a312991d
commit e6142a8bfc

View File

@ -1719,6 +1719,14 @@ CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
pSMBr = (READ_RSP *)rsp_iov.iov_base;
if (rc) {
cifs_dbg(VFS, "Send error in read = %d\n", rc);
} else if (rsp_iov.iov_len < tcon->ses->server->vals->read_rsp_size) {
/* check that the received response can hold a whole READ_RSP */
cifs_dbg(FYI, "%s: server returned short header. got=%zu expected=%zu\n",
__func__, rsp_iov.iov_len,
tcon->ses->server->vals->read_rsp_size);
rc = smb_EIO2(smb_eio_trace_read_rsp_short,
rsp_iov.iov_len, tcon->ses->server->vals->read_rsp_size);
*nbytes = 0;
} else {
int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
data_length = data_length << 16;