Commit bd8e9634 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag '6.1-rc1-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6

Pull cifs fixes from Steve French:

 - memory leak fixes

 - fixes for directory leases, including an important one which fixes a
   problem noticed by git functional tests

 - fixes relating to missing free_xid calls (helpful for
   tracing/debugging of entry/exit into cifs.ko)

 - a multichannel fix

 - a small cleanup fix (use of list_move instead of list_del/list_add)

* tag '6.1-rc1-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6:
  cifs: update internal module number
  cifs: fix memory leaks in session setup
  cifs: drop the lease for cached directories on rmdir or rename
  smb3: interface count displayed incorrectly
  cifs: Fix memory leak when build ntlmssp negotiate blob failed
  cifs: set rc to -ENOENT if we can not get a dentry for the cached dir
  cifs: use LIST_HEAD() and list_move() to simplify code
  cifs: Fix xid leak in cifs_get_file_info_unix()
  cifs: Fix xid leak in cifs_ses_add_channel()
  cifs: Fix xid leak in cifs_flock()
  cifs: Fix xid leak in cifs_copy_file_range()
  cifs: Fix xid leak in cifs_create()
parents 022c028f 73b1b8d2
...@@ -253,8 +253,10 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, ...@@ -253,8 +253,10 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
dentry = dget(cifs_sb->root); dentry = dget(cifs_sb->root);
else { else {
dentry = path_to_dentry(cifs_sb, path); dentry = path_to_dentry(cifs_sb, path);
if (IS_ERR(dentry)) if (IS_ERR(dentry)) {
rc = -ENOENT;
goto oshr_free; goto oshr_free;
}
} }
cfid->dentry = dentry; cfid->dentry = dentry;
cfid->tcon = tcon; cfid->tcon = tcon;
...@@ -338,6 +340,27 @@ smb2_close_cached_fid(struct kref *ref) ...@@ -338,6 +340,27 @@ smb2_close_cached_fid(struct kref *ref)
free_cached_dir(cfid); free_cached_dir(cfid);
} }
void drop_cached_dir_by_name(const unsigned int xid, struct cifs_tcon *tcon,
const char *name, struct cifs_sb_info *cifs_sb)
{
struct cached_fid *cfid = NULL;
int rc;
rc = open_cached_dir(xid, tcon, name, cifs_sb, true, &cfid);
if (rc) {
cifs_dbg(FYI, "no cached dir found for rmdir(%s)\n", name);
return;
}
spin_lock(&cfid->cfids->cfid_list_lock);
if (cfid->has_lease) {
cfid->has_lease = false;
kref_put(&cfid->refcount, smb2_close_cached_fid);
}
spin_unlock(&cfid->cfids->cfid_list_lock);
close_cached_dir(cfid);
}
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(&cfid->refcount, smb2_close_cached_fid);
...@@ -378,22 +401,20 @@ void invalidate_all_cached_dirs(struct cifs_tcon *tcon) ...@@ -378,22 +401,20 @@ void invalidate_all_cached_dirs(struct cifs_tcon *tcon)
{ {
struct cached_fids *cfids = tcon->cfids; struct cached_fids *cfids = tcon->cfids;
struct cached_fid *cfid, *q; struct cached_fid *cfid, *q;
struct list_head entry; LIST_HEAD(entry);
INIT_LIST_HEAD(&entry);
spin_lock(&cfids->cfid_list_lock); spin_lock(&cfids->cfid_list_lock);
list_for_each_entry_safe(cfid, q, &cfids->entries, entry) { list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
list_del(&cfid->entry); list_move(&cfid->entry, &entry);
list_add(&cfid->entry, &entry);
cfids->num_entries--; cfids->num_entries--;
cfid->is_open = false; cfid->is_open = false;
cfid->on_list = false;
/* To prevent race with smb2_cached_lease_break() */ /* To prevent race with smb2_cached_lease_break() */
kref_get(&cfid->refcount); kref_get(&cfid->refcount);
} }
spin_unlock(&cfids->cfid_list_lock); spin_unlock(&cfids->cfid_list_lock);
list_for_each_entry_safe(cfid, q, &entry, entry) { list_for_each_entry_safe(cfid, q, &entry, entry) {
cfid->on_list = false;
list_del(&cfid->entry); list_del(&cfid->entry);
cancel_work_sync(&cfid->lease_break); cancel_work_sync(&cfid->lease_break);
if (cfid->has_lease) { if (cfid->has_lease) {
...@@ -518,15 +539,13 @@ struct cached_fids *init_cached_dirs(void) ...@@ -518,15 +539,13 @@ struct cached_fids *init_cached_dirs(void)
void free_cached_dirs(struct cached_fids *cfids) void free_cached_dirs(struct cached_fids *cfids)
{ {
struct cached_fid *cfid, *q; struct cached_fid *cfid, *q;
struct list_head entry; LIST_HEAD(entry);
INIT_LIST_HEAD(&entry);
spin_lock(&cfids->cfid_list_lock); spin_lock(&cfids->cfid_list_lock);
list_for_each_entry_safe(cfid, q, &cfids->entries, entry) { list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
cfid->on_list = false; cfid->on_list = false;
cfid->is_open = false; cfid->is_open = false;
list_del(&cfid->entry); list_move(&cfid->entry, &entry);
list_add(&cfid->entry, &entry);
} }
spin_unlock(&cfids->cfid_list_lock); spin_unlock(&cfids->cfid_list_lock);
......
...@@ -69,6 +69,10 @@ extern int open_cached_dir_by_dentry(struct cifs_tcon *tcon, ...@@ -69,6 +69,10 @@ extern int open_cached_dir_by_dentry(struct cifs_tcon *tcon,
struct dentry *dentry, struct dentry *dentry,
struct cached_fid **cfid); struct cached_fid **cfid);
extern void close_cached_dir(struct cached_fid *cfid); extern void close_cached_dir(struct cached_fid *cfid);
extern void drop_cached_dir_by_name(const unsigned int xid,
struct cifs_tcon *tcon,
const char *name,
struct cifs_sb_info *cifs_sb);
extern void close_all_cached_dirs(struct cifs_sb_info *cifs_sb); extern void close_all_cached_dirs(struct cifs_sb_info *cifs_sb);
extern void invalidate_all_cached_dirs(struct cifs_tcon *tcon); extern void invalidate_all_cached_dirs(struct cifs_tcon *tcon);
extern int cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16]); extern int cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16]);
......
...@@ -1302,8 +1302,11 @@ static ssize_t cifs_copy_file_range(struct file *src_file, loff_t off, ...@@ -1302,8 +1302,11 @@ static ssize_t cifs_copy_file_range(struct file *src_file, loff_t off,
ssize_t rc; ssize_t rc;
struct cifsFileInfo *cfile = dst_file->private_data; struct cifsFileInfo *cfile = dst_file->private_data;
if (cfile->swapfile) if (cfile->swapfile) {
return -EOPNOTSUPP; rc = -EOPNOTSUPP;
free_xid(xid);
return rc;
}
rc = cifs_file_copychunk_range(xid, src_file, off, dst_file, destoff, rc = cifs_file_copychunk_range(xid, src_file, off, dst_file, destoff,
len, flags); len, flags);
......
...@@ -153,6 +153,6 @@ extern const struct export_operations cifs_export_ops; ...@@ -153,6 +153,6 @@ extern const struct export_operations cifs_export_ops;
#endif /* CONFIG_CIFS_NFSD_EXPORT */ #endif /* CONFIG_CIFS_NFSD_EXPORT */
/* when changing internal version - update following two lines at same time */ /* when changing internal version - update following two lines at same time */
#define SMB3_PRODUCT_BUILD 39 #define SMB3_PRODUCT_BUILD 40
#define CIFS_VERSION "2.39" #define CIFS_VERSION "2.40"
#endif /* _CIFSFS_H */ #endif /* _CIFSFS_H */
...@@ -543,8 +543,10 @@ int cifs_create(struct user_namespace *mnt_userns, struct inode *inode, ...@@ -543,8 +543,10 @@ int cifs_create(struct user_namespace *mnt_userns, struct inode *inode,
cifs_dbg(FYI, "cifs_create parent inode = 0x%p name is: %pd and dentry = 0x%p\n", cifs_dbg(FYI, "cifs_create parent inode = 0x%p name is: %pd and dentry = 0x%p\n",
inode, direntry, direntry); inode, direntry, direntry);
if (unlikely(cifs_forced_shutdown(CIFS_SB(inode->i_sb)))) if (unlikely(cifs_forced_shutdown(CIFS_SB(inode->i_sb)))) {
return -EIO; rc = -EIO;
goto out_free_xid;
}
tlink = cifs_sb_tlink(CIFS_SB(inode->i_sb)); tlink = cifs_sb_tlink(CIFS_SB(inode->i_sb));
rc = PTR_ERR(tlink); rc = PTR_ERR(tlink);
......
...@@ -1885,11 +1885,13 @@ int cifs_flock(struct file *file, int cmd, struct file_lock *fl) ...@@ -1885,11 +1885,13 @@ int cifs_flock(struct file *file, int cmd, struct file_lock *fl)
struct cifsFileInfo *cfile; struct cifsFileInfo *cfile;
__u32 type; __u32 type;
rc = -EACCES;
xid = get_xid(); xid = get_xid();
if (!(fl->fl_flags & FL_FLOCK)) if (!(fl->fl_flags & FL_FLOCK)) {
return -ENOLCK; rc = -ENOLCK;
free_xid(xid);
return rc;
}
cfile = (struct cifsFileInfo *)file->private_data; cfile = (struct cifsFileInfo *)file->private_data;
tcon = tlink_tcon(cfile->tlink); tcon = tlink_tcon(cfile->tlink);
...@@ -1908,8 +1910,9 @@ int cifs_flock(struct file *file, int cmd, struct file_lock *fl) ...@@ -1908,8 +1910,9 @@ int cifs_flock(struct file *file, int cmd, struct file_lock *fl)
* if no lock or unlock then nothing to do since we do not * if no lock or unlock then nothing to do since we do not
* know what it is * know what it is
*/ */
rc = -EOPNOTSUPP;
free_xid(xid); free_xid(xid);
return -EOPNOTSUPP; return rc;
} }
rc = cifs_setlk(file, fl, type, wait_flag, posix_lck, lock, unlock, rc = cifs_setlk(file, fl, type, wait_flag, posix_lck, lock, unlock,
......
...@@ -368,8 +368,10 @@ cifs_get_file_info_unix(struct file *filp) ...@@ -368,8 +368,10 @@ cifs_get_file_info_unix(struct file *filp)
if (cfile->symlink_target) { if (cfile->symlink_target) {
fattr.cf_symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL); fattr.cf_symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);
if (!fattr.cf_symlink_target) if (!fattr.cf_symlink_target) {
return -ENOMEM; rc = -ENOMEM;
goto cifs_gfiunix_out;
}
} }
rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->fid.netfid, &find_data); rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->fid.netfid, &find_data);
......
...@@ -496,6 +496,7 @@ cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses, ...@@ -496,6 +496,7 @@ cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
cifs_put_tcp_session(chan->server, 0); cifs_put_tcp_session(chan->server, 0);
} }
free_xid(xid);
return rc; return rc;
} }
......
...@@ -655,6 +655,7 @@ int ...@@ -655,6 +655,7 @@ int
smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name, smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
struct cifs_sb_info *cifs_sb) struct cifs_sb_info *cifs_sb)
{ {
drop_cached_dir_by_name(xid, tcon, name, cifs_sb);
return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN, return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
CREATE_NOT_FILE, ACL_NO_MODE, CREATE_NOT_FILE, ACL_NO_MODE,
NULL, SMB2_OP_RMDIR, NULL, NULL, NULL); NULL, SMB2_OP_RMDIR, NULL, NULL, NULL);
...@@ -698,6 +699,7 @@ smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -698,6 +699,7 @@ smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
{ {
struct cifsFileInfo *cfile; struct cifsFileInfo *cfile;
drop_cached_dir_by_name(xid, tcon, from_name, cifs_sb);
cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile); cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile);
return smb2_set_path_attr(xid, tcon, from_name, to_name, return smb2_set_path_attr(xid, tcon, from_name, to_name,
......
...@@ -530,6 +530,7 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, ...@@ -530,6 +530,7 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
p = buf; p = buf;
spin_lock(&ses->iface_lock); spin_lock(&ses->iface_lock);
ses->iface_count = 0;
/* /*
* Go through iface_list and do kref_put to remove * Go through iface_list and do kref_put to remove
* any unused ifaces. ifaces in use will be removed * any unused ifaces. ifaces in use will be removed
...@@ -651,9 +652,9 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, ...@@ -651,9 +652,9 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
kref_put(&iface->refcount, release_iface); kref_put(&iface->refcount, release_iface);
} else } else
list_add_tail(&info->iface_head, &ses->iface_list); list_add_tail(&info->iface_head, &ses->iface_list);
spin_unlock(&ses->iface_lock);
ses->iface_count++; ses->iface_count++;
spin_unlock(&ses->iface_lock);
ses->iface_last_update = jiffies; ses->iface_last_update = jiffies;
next_iface: next_iface:
nb_iface++; nb_iface++;
......
...@@ -1341,14 +1341,13 @@ SMB2_sess_alloc_buffer(struct SMB2_sess_data *sess_data) ...@@ -1341,14 +1341,13 @@ SMB2_sess_alloc_buffer(struct SMB2_sess_data *sess_data)
static void static void
SMB2_sess_free_buffer(struct SMB2_sess_data *sess_data) SMB2_sess_free_buffer(struct SMB2_sess_data *sess_data)
{ {
int i; struct kvec *iov = sess_data->iov;
/* zero the session data before freeing, as it might contain sensitive info (keys, etc) */ /* iov[1] is already freed by caller */
for (i = 0; i < 2; i++) if (sess_data->buf0_type != CIFS_NO_BUFFER && iov[0].iov_base)
if (sess_data->iov[i].iov_base) memzero_explicit(iov[0].iov_base, iov[0].iov_len);
memzero_explicit(sess_data->iov[i].iov_base, sess_data->iov[i].iov_len);
free_rsp_buf(sess_data->buf0_type, sess_data->iov[0].iov_base); free_rsp_buf(sess_data->buf0_type, iov[0].iov_base);
sess_data->buf0_type = CIFS_NO_BUFFER; sess_data->buf0_type = CIFS_NO_BUFFER;
} }
...@@ -1531,7 +1530,7 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data) ...@@ -1531,7 +1530,7 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data)
&blob_length, ses, server, &blob_length, ses, server,
sess_data->nls_cp); sess_data->nls_cp);
if (rc) if (rc)
goto out_err; goto out;
if (use_spnego) { if (use_spnego) {
/* BB eventually need to add this */ /* BB eventually need to add this */
...@@ -1578,7 +1577,7 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data) ...@@ -1578,7 +1577,7 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data)
} }
out: out:
memzero_explicit(ntlmssp_blob, blob_length); kfree_sensitive(ntlmssp_blob);
SMB2_sess_free_buffer(sess_data); SMB2_sess_free_buffer(sess_data);
if (!rc) { if (!rc) {
sess_data->result = 0; sess_data->result = 0;
...@@ -1662,7 +1661,7 @@ SMB2_sess_auth_rawntlmssp_authenticate(struct SMB2_sess_data *sess_data) ...@@ -1662,7 +1661,7 @@ SMB2_sess_auth_rawntlmssp_authenticate(struct SMB2_sess_data *sess_data)
} }
#endif #endif
out: out:
memzero_explicit(ntlmssp_blob, blob_length); kfree_sensitive(ntlmssp_blob);
SMB2_sess_free_buffer(sess_data); SMB2_sess_free_buffer(sess_data);
kfree_sensitive(ses->ntlmssp); kfree_sensitive(ses->ntlmssp);
ses->ntlmssp = NULL; ses->ntlmssp = NULL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment