Skip to content

Commit 3ca02e6

Browse files
darkrain42Steve French
authored andcommitted
smb: client: Avoid race in open_cached_dir with lease breaks
A pre-existing valid cfid returned from find_or_create_cached_dir might race with a lease break, meaning open_cached_dir doesn't consider it valid, and thinks it's newly-constructed. This leaks a dentry reference if the allocation occurs before the queued lease break work runs. Avoid the race by extending holding the cfid_list_lock across find_or_create_cached_dir and when the result is checked. Cc: stable@vger.kernel.org Reviewed-by: Henrique Carvalho <henrique.carvalho@suse.com> Signed-off-by: Paul Aurich <paul@darkrain42.org> Signed-off-by: Steve French <stfrench@microsoft.com>
1 parent d90b023 commit 3ca02e6

File tree

1 file changed

+2
-8
lines changed

1 file changed

+2
-8
lines changed

fs/smb/client/cached_dir.c

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ static struct cached_fid *find_or_create_cached_dir(struct cached_fids *cfids,
2929
{
3030
struct cached_fid *cfid;
3131

32-
spin_lock(&cfids->cfid_list_lock);
3332
list_for_each_entry(cfid, &cfids->entries, entry) {
3433
if (!strcmp(cfid->path, path)) {
3534
/*
@@ -38,25 +37,20 @@ static struct cached_fid *find_or_create_cached_dir(struct cached_fids *cfids,
3837
* being deleted due to a lease break.
3938
*/
4039
if (!cfid->time || !cfid->has_lease) {
41-
spin_unlock(&cfids->cfid_list_lock);
4240
return NULL;
4341
}
4442
kref_get(&cfid->refcount);
45-
spin_unlock(&cfids->cfid_list_lock);
4643
return cfid;
4744
}
4845
}
4946
if (lookup_only) {
50-
spin_unlock(&cfids->cfid_list_lock);
5147
return NULL;
5248
}
5349
if (cfids->num_entries >= max_cached_dirs) {
54-
spin_unlock(&cfids->cfid_list_lock);
5550
return NULL;
5651
}
5752
cfid = init_cached_dir(path);
5853
if (cfid == NULL) {
59-
spin_unlock(&cfids->cfid_list_lock);
6054
return NULL;
6155
}
6256
cfid->cfids = cfids;
@@ -74,7 +68,6 @@ static struct cached_fid *find_or_create_cached_dir(struct cached_fids *cfids,
7468
*/
7569
cfid->has_lease = true;
7670

77-
spin_unlock(&cfids->cfid_list_lock);
7871
return cfid;
7972
}
8073

@@ -187,8 +180,10 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
187180
if (!utf16_path)
188181
return -ENOMEM;
189182

183+
spin_lock(&cfids->cfid_list_lock);
190184
cfid = find_or_create_cached_dir(cfids, path, lookup_only, tcon->max_cached_dirs);
191185
if (cfid == NULL) {
186+
spin_unlock(&cfids->cfid_list_lock);
192187
kfree(utf16_path);
193188
return -ENOENT;
194189
}
@@ -197,7 +192,6 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
197192
* Otherwise, it is either a new entry or laundromat worker removed it
198193
* from @cfids->entries. Caller will put last reference if the latter.
199194
*/
200-
spin_lock(&cfids->cfid_list_lock);
201195
if (cfid->has_lease && cfid->time) {
202196
spin_unlock(&cfids->cfid_list_lock);
203197
*ret_cfid = cfid;

0 commit comments

Comments
 (0)