Commit 7bb4d651 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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()
parents 0d7bee10 4012abe8
Loading
Loading
Loading
Loading
+9 −7
Original line number Diff line number Diff line
@@ -388,11 +388,11 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
			 * lease. Release one here, and the second below.
			 */
			cfid->has_lease = false;
			kref_put(&cfid->refcount, smb2_close_cached_fid);
			close_cached_dir(cfid);
		}
		spin_unlock(&cfids->cfid_list_lock);

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

static void
smb2_close_cached_fid(struct kref *ref)
__releases(&cfid->cfids->cfid_list_lock)
{
	struct cached_fid *cfid = container_of(ref, struct cached_fid,
					       refcount);
	int rc;

	spin_lock(&cfid->cfids->cfid_list_lock);
	lockdep_assert_held(&cfid->cfids->cfid_list_lock);

	if (cfid->on_list) {
		list_del(&cfid->entry);
		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);
	if (cfid->has_lease) {
		cfid->has_lease = false;
		kref_put(&cfid->refcount, smb2_close_cached_fid);
		close_cached_dir(cfid);
	}
	spin_unlock(&cfid->cfids->cfid_list_lock);
	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)
{
	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);

	kref_put(&cfid->refcount, smb2_close_cached_fid);
	close_cached_dir(cfid);
	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
			 * 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,
			   dir_cache_timeout * HZ);
+2 −0
Original line number Diff line number Diff line
@@ -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);
	if (smb2_to_name == NULL) {
		rc = -ENOMEM;
		if (cfile)
			cifsFileInfo_put(cfile);
		goto smb2_rename_path;
	}
	in_iov.iov_base = smb2_to_name;
+5 −2
Original line number Diff line number Diff line
@@ -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;

		smb2_validate_iov(le16_to_cpu(smb_rsp->OutputBufferOffset),
				le32_to_cpu(smb_rsp->OutputBufferLength), &rsp_iov,
		rc = smb2_validate_iov(le16_to_cpu(smb_rsp->OutputBufferOffset),
				le32_to_cpu(smb_rsp->OutputBufferLength),
				&rsp_iov,
				sizeof(struct file_notify_information));
		if (rc)
			goto cnotify_exit;

		*out_data = kmemdup((char *)smb_rsp + le16_to_cpu(smb_rsp->OutputBufferOffset),
				le32_to_cpu(smb_rsp->OutputBufferLength), GFP_KERNEL);