]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
cifs: validate DFS referral string offsets
authorGuangshuo Li <lgs201920130244@gmail.com>
Wed, 8 Jul 2026 11:27:10 +0000 (19:27 +0800)
committerSteve French <stfrench@microsoft.com>
Wed, 8 Jul 2026 15:10:38 +0000 (10:10 -0500)
parse_dfs_referrals() validates that the response header and referral
array fit in the received buffer, but each referral also contains string
offsets supplied by the server.

Those offsets are used to compute the DfsPath and NetworkAddress string
pointers without checking whether they still point inside the response
buffer. A malformed referral can therefore make the computed pointer
exceed the end of the buffer. The resulting negative max_len is then
passed to cifs_strndup_from_utf16(), and the non-Unicode path forwards it
to kstrndup() as a size_t, allowing strnlen() to read out of bounds.

Validate each string offset before deriving the string pointer.

Fixes: 4ecce920e13a ("CIFS: move DFS response parsing out of SMB1 code")
Signed-off-by: Guangshuo Li <lgs201920130244@gmail.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/client/misc.c

index 0c54b9b79a2ce5b40b2543277f0b299bed3b1251..ee1728eec8aa0a21d484b97a2928a3c8c6f556fd 100644 (file)
@@ -752,6 +752,10 @@ parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size,
                node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
 
                /* copy DfsPath */
+               if (le16_to_cpu(ref->DfsPathOffset) > data_end - (char *)ref) {
+                       rc = -EINVAL;
+                       goto parse_DFS_referrals_exit;
+               }
                temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
                max_len = data_end - temp;
                node->path_name = cifs_strndup_from_utf16(temp, max_len,
@@ -762,6 +766,10 @@ parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size,
                }
 
                /* copy link target UNC */
+               if (le16_to_cpu(ref->NetworkAddressOffset) > data_end - (char *)ref) {
+                       rc = -EINVAL;
+                       goto parse_DFS_referrals_exit;
+               }
                temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
                max_len = data_end - temp;
                node->node_name = cifs_strndup_from_utf16(temp, max_len,