smb: client: harden DFS cache against invalid target hints

Currently, get_tgt_name() returns ERR_PTR(-ENOENT) when ce->tgthint is
NULL, and dfs_cache_noreq_update_tgthint() assumes ce->tgthint is always
valid.

In preparation for clearing ce->tgthint in free_tgts(), harden callers
of get_tgt_name() against ERR_PTR results and harden
dfs_cache_noreq_update_tgthint() against NULL pointer dereferences.

Cc: stable@vger.kernel.org
Signed-off-by: Fredric Cover <fredric.cover.lkernel@gmail.com>
Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Paulo Alcantara <pc@manguebit.org>
This commit is contained in:
Fredric Cover 2026-07-24 15:01:45 -07:00 committed by Paulo Alcantara
parent b8e5dc4f95
commit bf86c08123

View File

@ -869,13 +869,22 @@ int dfs_cache_find(const unsigned int xid, struct cifs_ses *ses, const struct nl
goto out_free_path;
}
if (ref)
rc = setup_referral(path, ce, ref, get_tgt_name(ce));
else
if (ref) {
char *target = get_tgt_name(ce);
if (IS_ERR(target)) {
rc = PTR_ERR(target);
goto out_unlock;
}
rc = setup_referral(path, ce, ref, target);
} else {
rc = 0;
}
if (!rc && tgt_list)
rc = get_targets(ce, tgt_list);
out_unlock:
up_read(&htable_rw_lock);
out_free_path:
@ -915,10 +924,17 @@ int dfs_cache_noreq_find(const char *path, struct dfs_info3_param *ref,
goto out_unlock;
}
if (ref)
rc = setup_referral(path, ce, ref, get_tgt_name(ce));
else
if (ref) {
char *target = get_tgt_name(ce);
if (IS_ERR(target)) {
rc = PTR_ERR(target);
goto out_unlock;
}
rc = setup_referral(path, ce, ref, target);
} else {
rc = 0;
}
if (!rc && tgt_list)
rc = get_targets(ce, tgt_list);
@ -959,7 +975,8 @@ void dfs_cache_noreq_update_tgthint(const char *path, const struct dfs_cache_tgt
t = READ_ONCE(ce->tgthint);
if (unlikely(!strcasecmp(it->it_name, t->name)))
/* Check 't' in case ce->tgthint was cleared by free_tgts() */
if (t && unlikely(!strcasecmp(it->it_name, t->name)))
goto out_unlock;
list_for_each_entry(t, &ce->tlist, list) {