three smb client fixes

-----BEGIN PGP SIGNATURE-----
 
 iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAmkPhxAACgkQiiy9cAdy
 T1H0jQv+Ixfm//dkrOfJ6xGFVUaJFRyscy9bX6rGTnUpUWxRSdHtaiufClqW2QvZ
 f4fsLC1e7VFeXM/BxaXrC2XM9Ltmzpb4n4phoL3cLT+NjQDiUM7veJBfsJCGMICc
 CVxnczjr+QGx8sl2bCliNWYojsUTkcm6jagBrozfBdSl802C23xaNny6KeNkivxY
 QvNbNTl5+63KeQZhM/5QWEzDBFON+5xRCKRMFExySHtMS6h5hn7fdRPScLfD9TOo
 MrJ4VbZ0V3qQ6R2PQhIykq6/FMg9qO3NildZegE5C12a5NPaupPeIlEwZgzdQ/jf
 S49UGjpNTniRoeBRFyNy4OSDzeD1G6ikb5sU/NRnnD8VPaiW+7OqqyJCFKTIA2aI
 FGl7W5qcuW/WSR1Uvcsfco/hCcxN0I6cqpOF+4Q/oSZFGgSuaj4nX+/Vtg4wpTCE
 uUP2K3f5vwcAIMPXUg22k4iu4XHPt2ZKzqQ5LyNpO5tpPBYkUxf+6XzNdvn4qjpN
 zJZ/0wfW
 =fdZF
 -----END PGP SIGNATURE-----

Merge tag 'v6.18rc4-SMB-client-fixes' of git://git.samba.org/sfrench/cifs-2.6

Pull smb client fixes from Steve French:

 - Fix change notify packet validation check

 - Refcount fix (e.g. rename error paths)

 - Fix potential UAF due to missing locks on directory lease refcount

* tag 'v6.18rc4-SMB-client-fixes' of git://git.samba.org/sfrench/cifs-2.6:
  smb: client: validate change notify buffer before copy
  smb: client: fix refcount leak in smb2_set_path_attr
  smb: client: fix potential UAF in smb2_close_cached_fid()
This commit is contained in:
Linus Torvalds 2025-11-08 10:17:30 -08:00
commit 7bb4d65125
3 changed files with 16 additions and 9 deletions

View File

@ -388,11 +388,11 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
* 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);
@ -438,12 +438,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;
@ -478,7 +480,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);
@ -487,7 +489,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);
} }
/* /*
@ -596,7 +598,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);
} }
@ -762,7 +764,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);

View File

@ -1294,6 +1294,8 @@ static int smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
smb2_to_name = cifs_convert_path_to_utf16(to_name, cifs_sb); smb2_to_name = cifs_convert_path_to_utf16(to_name, cifs_sb);
if (smb2_to_name == NULL) { if (smb2_to_name == NULL) {
rc = -ENOMEM; rc = -ENOMEM;
if (cfile)
cifsFileInfo_put(cfile);
goto smb2_rename_path; goto smb2_rename_path;
} }
in_iov.iov_base = smb2_to_name; in_iov.iov_base = smb2_to_name;

View File

@ -4054,9 +4054,12 @@ SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon,
smb_rsp = (struct smb2_change_notify_rsp *)rsp_iov.iov_base; smb_rsp = (struct smb2_change_notify_rsp *)rsp_iov.iov_base;
smb2_validate_iov(le16_to_cpu(smb_rsp->OutputBufferOffset), rc = smb2_validate_iov(le16_to_cpu(smb_rsp->OutputBufferOffset),
le32_to_cpu(smb_rsp->OutputBufferLength), &rsp_iov, le32_to_cpu(smb_rsp->OutputBufferLength),
&rsp_iov,
sizeof(struct file_notify_information)); sizeof(struct file_notify_information));
if (rc)
goto cnotify_exit;
*out_data = kmemdup((char *)smb_rsp + le16_to_cpu(smb_rsp->OutputBufferOffset), *out_data = kmemdup((char *)smb_rsp + le16_to_cpu(smb_rsp->OutputBufferOffset),
le32_to_cpu(smb_rsp->OutputBufferLength), GFP_KERNEL); le32_to_cpu(smb_rsp->OutputBufferLength), GFP_KERNEL);