From: Yichong Chen <chenyichong@uniontech.com> mainline inclusion from mainline-v7.2-rc5 commit f6f5ee2aa33b350c671721b965251c42cebb962e category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/17157 CVE: CVE-2026-68343 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- parse_dfs_referrals() validates that the response contains the fixed referral entry array and, on for-next, the per-referral string offsets. However, the response also contains a PathConsumed value that is later used for DFS path parsing. If a malformed response provides a PathConsumed value larger than the search name, later DFS parsing can advance beyond the end of the path. Validate PathConsumed against the search name length before storing it in the parsed referral. Fixes: 4ecce920e13a ("CIFS: move DFS response parsing out of SMB1 code") Reviewed-by: Paulo Alcantara (Red Hat) <pc@manguebit.org> Signed-off-by: Yichong Chen <chenyichong@uniontech.com> Signed-off-by: Steve French <stfrench@microsoft.com> Conflicts: fs/cifs/misc.c [fs/cifs/misc.c: resolved via git 3-way merge of upstream f6f5ee2aa33b (clone base/theirs vs local); no overlap with local divergence] Signed-off-by: Lu Chentao <luchentao1@huawei.com> --- fs/cifs/misc.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 802d792306a3..e8e8a862bfdb 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -691,10 +691,12 @@ parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size, const char *searchName, bool is_unicode) { int i, rc = 0; char *data_end; struct dfs_referral_level_3 *ref; + unsigned int path_consumed; + size_t search_name_len; *num_of_nodes = le16_to_cpu(rsp->NumberOfReferrals); if (*num_of_nodes < 1) { cifs_dbg(VFS, "num_referrals: must be at least > 0, but we get num_referrals = %d\n", @@ -721,33 +723,47 @@ parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size, GFP_KERNEL); if (*target_nodes == NULL) { rc = -ENOMEM; goto parse_DFS_referrals_exit; } + search_name_len = strlen(searchName); /* collect necessary data from referrals */ for (i = 0; i < *num_of_nodes; i++) { char *temp; int max_len; struct dfs_info3_param *node = (*target_nodes)+i; node->flags = le32_to_cpu(rsp->DFSFlags); + path_consumed = le16_to_cpu(rsp->PathConsumed); if (is_unicode) { - __le16 *tmp = kmalloc(strlen(searchName)*2 + 2, - GFP_KERNEL); - if (tmp == NULL) { + size_t search_name_utf16_len = search_name_len * 2 + 2; + __le16 *tmp; + + if (path_consumed > search_name_utf16_len) { + rc = -EINVAL; + goto parse_DFS_referrals_exit; + } + + tmp = kmalloc(search_name_utf16_len, GFP_KERNEL); + if (!tmp) { rc = -ENOMEM; goto parse_DFS_referrals_exit; } - cifsConvertToUTF16((__le16 *) tmp, searchName, + cifsConvertToUTF16((__le16 *)tmp, searchName, PATH_MAX, nls_codepage, remap); - node->path_consumed = cifs_utf16_bytes(tmp, - le16_to_cpu(rsp->PathConsumed), - nls_codepage); + node->path_consumed = cifs_utf16_bytes(tmp, path_consumed, + nls_codepage); kfree(tmp); - } else - node->path_consumed = le16_to_cpu(rsp->PathConsumed); + } else { + if (path_consumed > search_name_len) { + rc = -EINVAL; + goto parse_DFS_referrals_exit; + } + + node->path_consumed = path_consumed; + } node->server_type = le16_to_cpu(ref->ServerType); node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags); /* copy DfsPath */ -- 2.52.0