Skip to content

Commit a481c91

Browse files
committed
smb: client: fix potential UAF in smb2_close_cached_fid()
JIRA: https://issues.redhat.com/browse/RHEL-114699 commit 734e996 Author: Henrique Carvalho <[email protected]> Date: Mon Nov 3 19:52:55 2025 -0300 smb: client: fix potential UAF in smb2_close_cached_fid() find_or_create_cached_dir() could grab a new reference after kref_put() had seen the refcount drop to zero but before cfid_list_lock is acquired in smb2_close_cached_fid(), leading to use-after-free. Switch to kref_put_lock() so cfid_release() is called with cfid_list_lock held, closing that gap. Fixes: ebe98f1 ("cifs: enable caching of directories for which a lease is held") Cc: [email protected] Reported-by: Jay Shin <[email protected]> Reviewed-by: Paulo Alcantara (Red Hat) <[email protected]> Signed-off-by: Henrique Carvalho <[email protected]> Signed-off-by: Steve French <[email protected]> Signed-off-by: Paulo Alcantara <[email protected]>
1 parent 67ccdd5 commit a481c91

File tree

1 file changed

+9
-7
lines changed

1 file changed

+9
-7
lines changed

fs/smb/client/cached_dir.c

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -387,11 +387,11 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
387387
* lease. Release one here, and the second below.
388388
*/
389389
cfid->has_lease = false;
390-
kref_put(&cfid->refcount, smb2_close_cached_fid);
390+
close_cached_dir(cfid);
391391
}
392392
spin_unlock(&cfids->cfid_list_lock);
393393

394-
kref_put(&cfid->refcount, smb2_close_cached_fid);
394+
close_cached_dir(cfid);
395395
} else {
396396
*ret_cfid = cfid;
397397
atomic_inc(&tcon->num_remote_opens);
@@ -437,12 +437,14 @@ int open_cached_dir_by_dentry(struct cifs_tcon *tcon,
437437

438438
static void
439439
smb2_close_cached_fid(struct kref *ref)
440+
__releases(&cfid->cfids->cfid_list_lock)
440441
{
441442
struct cached_fid *cfid = container_of(ref, struct cached_fid,
442443
refcount);
443444
int rc;
444445

445-
spin_lock(&cfid->cfids->cfid_list_lock);
446+
lockdep_assert_held(&cfid->cfids->cfid_list_lock);
447+
446448
if (cfid->on_list) {
447449
list_del(&cfid->entry);
448450
cfid->on_list = false;
@@ -477,7 +479,7 @@ void drop_cached_dir_by_name(const unsigned int xid, struct cifs_tcon *tcon,
477479
spin_lock(&cfid->cfids->cfid_list_lock);
478480
if (cfid->has_lease) {
479481
cfid->has_lease = false;
480-
kref_put(&cfid->refcount, smb2_close_cached_fid);
482+
close_cached_dir(cfid);
481483
}
482484
spin_unlock(&cfid->cfids->cfid_list_lock);
483485
close_cached_dir(cfid);
@@ -486,7 +488,7 @@ void drop_cached_dir_by_name(const unsigned int xid, struct cifs_tcon *tcon,
486488

487489
void close_cached_dir(struct cached_fid *cfid)
488490
{
489-
kref_put(&cfid->refcount, smb2_close_cached_fid);
491+
kref_put_lock(&cfid->refcount, smb2_close_cached_fid, &cfid->cfids->cfid_list_lock);
490492
}
491493

492494
/*
@@ -595,7 +597,7 @@ cached_dir_offload_close(struct work_struct *work)
595597

596598
WARN_ON(cfid->on_list);
597599

598-
kref_put(&cfid->refcount, smb2_close_cached_fid);
600+
close_cached_dir(cfid);
599601
cifs_put_tcon(tcon, netfs_trace_tcon_ref_put_cached_close);
600602
}
601603

@@ -761,7 +763,7 @@ static void cfids_laundromat_worker(struct work_struct *work)
761763
* Drop the ref-count from above, either the lease-ref (if there
762764
* was one) or the extra one acquired.
763765
*/
764-
kref_put(&cfid->refcount, smb2_close_cached_fid);
766+
close_cached_dir(cfid);
765767
}
766768
queue_delayed_work(cfid_put_wq, &cfids->laundromat_work,
767769
dir_cache_timeout * HZ);

0 commit comments

Comments
 (0)