From 42d3358bf145f27d32350037e67d3527e9098c1e Mon Sep 17 00:00:00 2001 From: Fredric Cover Date: Wed, 2 Sep 2026 17:49:01 -0700 Subject: [PATCH] smb: client: fill cache fields after populating cache in copy_ref_data() 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 Signed-off-by: Paulo Alcantara --- fs/smb/client/dfs_cache.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/fs/smb/client/dfs_cache.c b/fs/smb/client/dfs_cache.c index 86dba25b7a5a..611e18fe8204 100644 --- a/fs/smb/client/dfs_cache.c +++ b/fs/smb/client/dfs_cache.c @@ -123,6 +123,7 @@ static inline void free_tgts(struct cache_entry *ce) kfree(t); } + ce->numtgts = 0; WRITE_ONCE(ce->tgthint, NULL); } @@ -388,13 +389,6 @@ static int copy_ref_data(const struct dfs_info3_param *refs, int numrefs, struct cache_dfs_tgt *target; int i; - ce->ttl = max_t(int, refs[0].ttl, CACHE_MIN_TTL); - ce->etime = get_expire_time(ce->ttl); - ce->srvtype = refs[0].server_type; - ce->hdr_flags = refs[0].flags; - ce->ref_flags = refs[0].ref_flag; - ce->path_consumed = refs[0].path_consumed; - for (i = 0; i < numrefs; i++) { struct cache_dfs_tgt *t; @@ -409,12 +403,19 @@ static int copy_ref_data(const struct dfs_info3_param *refs, int numrefs, } else { list_add_tail(&t->list, &ce->tlist); } - ce->numtgts++; } target = list_first_entry_or_null(&ce->tlist, struct cache_dfs_tgt, list); + WRITE_ONCE(ce->tgthint, target); + ce->ttl = max_t(int, refs[0].ttl, CACHE_MIN_TTL); + ce->etime = get_expire_time(ce->ttl); + ce->srvtype = refs[0].server_type; + ce->hdr_flags = refs[0].flags; + ce->ref_flags = refs[0].ref_flag; + ce->path_consumed = refs[0].path_consumed; + ce->numtgts = numrefs; return 0; } @@ -634,7 +635,6 @@ static int update_cache_entry_locked(struct cache_entry *ce, const struct dfs_in } free_tgts(ce); - ce->numtgts = 0; rc = copy_ref_data(refs, numrefs, ce, th);