mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-06 10:00:17 +00:00
smb: client: fix potential UAF in smb2_close_cached_fid()
commit734e99623cupstream. 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:ebe98f1447("cifs: enable caching of directories for which a lease is held") Cc: stable@vger.kernel.org Reported-by: Jay Shin <jaeshin@redhat.com> Reviewed-by: Paulo Alcantara (Red Hat) <pc@manguebit.org> Signed-off-by: Henrique Carvalho <henrique.carvalho@suse.com> Signed-off-by: Steve French <stfrench@microsoft.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
3d82cb8465
commit
065bd62412
@@ -362,11 +362,11 @@ out:
|
|||||||
* lease. Release one here, and the second below.
|
* lease. Release one here, and the second below.
|
||||||
*/
|
*/
|
||||||
cfid->has_lease = false;
|
cfid->has_lease = false;
|
||||||
kref_put(&cfid->refcount, smb2_close_cached_fid);
|
close_cached_dir(cfid);
|
||||||
}
|
}
|
||||||
spin_unlock(&cfids->cfid_list_lock);
|
spin_unlock(&cfids->cfid_list_lock);
|
||||||
|
|
||||||
kref_put(&cfid->refcount, smb2_close_cached_fid);
|
close_cached_dir(cfid);
|
||||||
} else {
|
} else {
|
||||||
*ret_cfid = cfid;
|
*ret_cfid = cfid;
|
||||||
atomic_inc(&tcon->num_remote_opens);
|
atomic_inc(&tcon->num_remote_opens);
|
||||||
@@ -406,12 +406,14 @@ int open_cached_dir_by_dentry(struct cifs_tcon *tcon,
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
smb2_close_cached_fid(struct kref *ref)
|
smb2_close_cached_fid(struct kref *ref)
|
||||||
|
__releases(&cfid->cfids->cfid_list_lock)
|
||||||
{
|
{
|
||||||
struct cached_fid *cfid = container_of(ref, struct cached_fid,
|
struct cached_fid *cfid = container_of(ref, struct cached_fid,
|
||||||
refcount);
|
refcount);
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
spin_lock(&cfid->cfids->cfid_list_lock);
|
lockdep_assert_held(&cfid->cfids->cfid_list_lock);
|
||||||
|
|
||||||
if (cfid->on_list) {
|
if (cfid->on_list) {
|
||||||
list_del(&cfid->entry);
|
list_del(&cfid->entry);
|
||||||
cfid->on_list = false;
|
cfid->on_list = false;
|
||||||
@@ -446,7 +448,7 @@ void drop_cached_dir_by_name(const unsigned int xid, struct cifs_tcon *tcon,
|
|||||||
spin_lock(&cfid->cfids->cfid_list_lock);
|
spin_lock(&cfid->cfids->cfid_list_lock);
|
||||||
if (cfid->has_lease) {
|
if (cfid->has_lease) {
|
||||||
cfid->has_lease = false;
|
cfid->has_lease = false;
|
||||||
kref_put(&cfid->refcount, smb2_close_cached_fid);
|
close_cached_dir(cfid);
|
||||||
}
|
}
|
||||||
spin_unlock(&cfid->cfids->cfid_list_lock);
|
spin_unlock(&cfid->cfids->cfid_list_lock);
|
||||||
close_cached_dir(cfid);
|
close_cached_dir(cfid);
|
||||||
@@ -455,7 +457,7 @@ void drop_cached_dir_by_name(const unsigned int xid, struct cifs_tcon *tcon,
|
|||||||
|
|
||||||
void close_cached_dir(struct cached_fid *cfid)
|
void close_cached_dir(struct cached_fid *cfid)
|
||||||
{
|
{
|
||||||
kref_put(&cfid->refcount, smb2_close_cached_fid);
|
kref_put_lock(&cfid->refcount, smb2_close_cached_fid, &cfid->cfids->cfid_list_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -566,7 +568,7 @@ cached_dir_offload_close(struct work_struct *work)
|
|||||||
|
|
||||||
WARN_ON(cfid->on_list);
|
WARN_ON(cfid->on_list);
|
||||||
|
|
||||||
kref_put(&cfid->refcount, smb2_close_cached_fid);
|
close_cached_dir(cfid);
|
||||||
cifs_put_tcon(tcon, netfs_trace_tcon_ref_put_cached_close);
|
cifs_put_tcon(tcon, netfs_trace_tcon_ref_put_cached_close);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -743,7 +745,7 @@ static void cfids_laundromat_worker(struct work_struct *work)
|
|||||||
* Drop the ref-count from above, either the lease-ref (if there
|
* Drop the ref-count from above, either the lease-ref (if there
|
||||||
* was one) or the extra one acquired.
|
* was one) or the extra one acquired.
|
||||||
*/
|
*/
|
||||||
kref_put(&cfid->refcount, smb2_close_cached_fid);
|
close_cached_dir(cfid);
|
||||||
}
|
}
|
||||||
queue_delayed_work(cfid_put_wq, &cfids->laundromat_work,
|
queue_delayed_work(cfid_put_wq, &cfids->laundromat_work,
|
||||||
dir_cache_timeout * HZ);
|
dir_cache_timeout * HZ);
|
||||||
|
|||||||
Reference in New Issue
Block a user