[PATCH v2 OLK-5.10 0/3] CVE-2026-89636
Fredric Cover (3): smb: client: harden DFS cache against invalid target hints smb: client: clear ce->tgthint in free_tgts() smb: client: fill cache fields after populating cache in copy_ref_data() fs/cifs/dfs_cache.c | 61 ++++++++++++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 17 deletions(-) -- 2.52.0
From: Fredric Cover <fredric.cover.lkernel@gmail.com> mainline inclusion from mainline-v7.3-rc1 commit bf86c08123c6ab8c61cc0be1dad7540db93738ff category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/18921 CVE: CVE-2026-89636 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- 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> Conflicts: fs/cifs/dfs_cache.c fs/smb/client/dfs_cache.c [different files] Signed-off-by: Yifan Qiao <qiaoyifan4@huawei.com> --- fs/cifs/dfs_cache.c | 43 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/fs/cifs/dfs_cache.c b/fs/cifs/dfs_cache.c index 7b6db272fd0b..9d02372d5b03 100644 --- a/fs/cifs/dfs_cache.c +++ b/fs/cifs/dfs_cache.c @@ -900,13 +900,21 @@ int dfs_cache_find(const unsigned int xid, struct cifs_ses *ses, 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: @@ -951,10 +959,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); @@ -1013,7 +1028,8 @@ int dfs_cache_update_tgthint(const unsigned int xid, struct cifs_ses *ses, t = ce->tgthint; - if (likely(!strcasecmp(it->it_name, t->name))) + /* Check 't' in case ce->tgthint was cleared by free_tgts() */ + if (t && likely(!strcasecmp(it->it_name, t->name))) goto out_unlock; list_for_each_entry(t, &ce->tlist, list) { @@ -1075,7 +1091,8 @@ int dfs_cache_noreq_update_tgthint(const char *path, rc = 0; t = 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) { @@ -1471,6 +1488,7 @@ static struct cifs_ses *find_root_ses(struct vol_info *vi, const char *path) { char *rpath; + char *target; int rc; struct cache_entry *ce; struct dfs_info3_param ref = {0}; @@ -1492,7 +1510,14 @@ static struct cifs_ses *find_root_ses(struct vol_info *vi, goto out; } - rc = setup_referral(path, ce, &ref, get_tgt_name(ce)); + target = get_tgt_name(ce); + + if (IS_ERR(target)) { + up_read(&htable_rw_lock); + ses = ERR_CAST(target); + goto out; + } + rc = setup_referral(path, ce, &ref, target); if (rc) { up_read(&htable_rw_lock); ses = ERR_PTR(rc); -- 2.52.0
From: Fredric Cover <fredric.cover.lkernel@gmail.com> mainline inclusion from mainline-v7.3-rc1 commit b1b741cf8e7ce1b91d937e23decd3d3358748700 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/18921 CVE: CVE-2026-89636 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- When free_tgts() frees all structures in ce->tlist, ce->tgthint is left pointing to one of the freed cache_dfs_tgt structures. If ce->tgthint is not reset before it is used later, it results in a use-after-free. Set ce->tgthint to NULL in free_tgts() after the elements are freed to reflect that no elements remain. Fixes: 54be1f6c1c37 ("cifs: Add DFS cache routines") Cc: stable@vger.kernel.org # depends on: smb: client: harden DFS cache against invalid target hints 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> Conflicts: fs/cifs/dfs_cache.c fs/smb/client/dfs_cache.c [different files] Signed-off-by: Yifan Qiao <qiaoyifan4@huawei.com> --- fs/cifs/dfs_cache.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/cifs/dfs_cache.c b/fs/cifs/dfs_cache.c index 9d02372d5b03..01e82cb516bb 100644 --- a/fs/cifs/dfs_cache.c +++ b/fs/cifs/dfs_cache.c @@ -118,6 +118,8 @@ static inline void free_tgts(struct cache_entry *ce) kfree(t->name); kfree(t); } + + WRITE_ONCE(ce->tgthint, NULL); } static inline void flush_cache_ent(struct cache_entry *ce) -- 2.52.0
From: Fredric Cover <fredric.cover.lkernel@gmail.com> mainline inclusion from mainline-v7.3-rc3 commit 42d3358bf145f27d32350037e67d3527e9098c1e category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/18921 CVE: CVE-2026-89636 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- In copy_ref_data(), struct cache_entry *ce has its fields populated at the beginning of the function. Later, if alloc_target fails with an ERR_PTR, free_tgts() is called on the cache, leaving the cache metadata populated without any targets. Critically, this extends ce->etime, making the cache appear valid for longer without any targets. Also, free_tgts() does not set ce->numtgts to zero. On error, when the cache is freed, ce->numtgts is not zeroed, and other cache users may attempt to access nonexistent entries. Update fields after copying targets to prevent partial-state updates. Set ce->numtgts to zero at the end of free_tgts(). Signed-off-by: Fredric Cover <fredric.cover.lkernel@gmail.com> Signed-off-by: Paulo Alcantara <pc@manguebit.org> Conflicts: fs/cifs/dfs_cache.c fs/smb/client/dfs_cache.c [Context differences.] Signed-off-by: Yifan Qiao <qiaoyifan4@huawei.com> --- fs/cifs/dfs_cache.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/fs/cifs/dfs_cache.c b/fs/cifs/dfs_cache.c index 01e82cb516bb..b2b6ab803c75 100644 --- a/fs/cifs/dfs_cache.c +++ b/fs/cifs/dfs_cache.c @@ -119,6 +119,7 @@ static inline void free_tgts(struct cache_entry *ce) kfree(t); } + ce->numtgts = 0; WRITE_ONCE(ce->tgthint, NULL); } @@ -379,12 +380,6 @@ static int copy_ref_data(const struct dfs_info3_param *refs, int numrefs, { int i; - ce->ttl = refs[0].ttl; - ce->etime = get_expire_time(ce->ttl); - ce->srvtype = refs[0].server_type; - ce->flags = refs[0].ref_flag; - ce->path_consumed = refs[0].path_consumed; - for (i = 0; i < numrefs; i++) { struct cache_dfs_tgt *t; @@ -399,12 +394,18 @@ static int copy_ref_data(const struct dfs_info3_param *refs, int numrefs, } else { list_add_tail(&t->list, &ce->tlist); } - ce->numtgts++; } ce->tgthint = list_first_entry_or_null(&ce->tlist, struct cache_dfs_tgt, list); + ce->ttl = refs[0].ttl; + ce->etime = get_expire_time(ce->ttl); + ce->srvtype = refs[0].server_type; + ce->flags = refs[0].ref_flag; + ce->path_consumed = refs[0].path_consumed; + ce->numtgts = numrefs; + return 0; } @@ -648,7 +649,6 @@ static int __update_cache_entry(const char *path, } free_tgts(ce); - ce->numtgts = 0; rc = copy_ref_data(refs, numrefs, ce, th); -- 2.52.0
反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://atomgit.com/openeuler/kernel/merge_requests/28355 邮件列表地址:https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/V5G... FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://atomgit.com/openeuler/kernel/merge_requests/28355 Mailing list address: https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/V5G...
participants (2)
-
patchwork bot -
Yifan Qiao