cifs: Fix validation of SMB1 query reparse point response
authorPali Rohár <pali@kernel.org>
Thu, 26 Dec 2024 18:55:13 +0000 (19:55 +0100)
committerSteve French <stfrench@microsoft.com>
Mon, 2 Jun 2025 01:43:57 +0000 (20:43 -0500)
Validate the SMB1 query reparse point response per [MS-CIFS] section
2.2.7.2 NT_TRANSACT_IOCTL.

NT_TRANSACT_IOCTL response contains one word long setup data after which is
ByteCount member. So check that SetupCount is 1 before trying to read and
use ByteCount member.

Output setup data contains ReturnedDataLen member which is the output
length of executed IOCTL command by remote system. So check that output was
not truncated before transferring over network.

Change MaxSetupCount of NT_TRANSACT_IOCTL request from 4 to 1 as io_rsp
structure already expects one word long output setup data. This should
prevent server sending incompatible structure (in case it would be extended
in future, which is unlikely).

Change MaxParameterCount of NT_TRANSACT_IOCTL request from 2 to 0 as
NT IOCTL does not have any documented output parameters and this function
does not parse any output parameters at all.

Fixes: ed3e0a149b58 ("smb: client: implement ->query_reparse_point() for SMB1")
Signed-off-by: Pali Rohár <pali@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/client/cifssmb.c

index f6ec0045c5138898805f1ccae886a98f4865aa4c..b5e98aa462a7c394111e85671f3de15f715f51e3 100644 (file)
@@ -2754,10 +2754,10 @@ int cifs_query_reparse_point(const unsigned int xid,
 
        io_req->TotalParameterCount = 0;
        io_req->TotalDataCount = 0;
-       io_req->MaxParameterCount = cpu_to_le32(2);
+       io_req->MaxParameterCount = cpu_to_le32(0);
        /* BB find exact data count max from sess structure BB */
        io_req->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
-       io_req->MaxSetupCount = 4;
+       io_req->MaxSetupCount = 1;
        io_req->Reserved = 0;
        io_req->ParameterOffset = 0;
        io_req->DataCount = 0;
@@ -2784,6 +2784,22 @@ int cifs_query_reparse_point(const unsigned int xid,
                goto error;
        }
 
+       /* SetupCount must be 1, otherwise offset to ByteCount is incorrect. */
+       if (io_rsp->SetupCount != 1) {
+               rc = -EIO;
+               goto error;
+       }
+
+       /*
+        * ReturnedDataLen is output length of executed IOCTL.
+        * DataCount is output length transferred over network.
+        * Check that we have full FSCTL_GET_REPARSE_POINT buffer.
+        */
+       if (data_count != le16_to_cpu(io_rsp->ReturnedDataLen)) {
+               rc = -EIO;
+               goto error;
+       }
+
        end = 2 + get_bcc(&io_rsp->hdr) + (__u8 *)&io_rsp->ByteCount;
        start = (__u8 *)&io_rsp->hdr.Protocol + data_offset;
        if (start >= end) {