12 cifs/smb3 fixes, half for stable
-----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAmNSM84ACgkQiiy9cAdy T1Ev1gv/boWdv/ihnWEpdlAT4wqMQt9Q7dlfSZmNlcoSst1QGbTHjBrUNncBcRCZ +9PRqH0umGMx1dFBzPNp5AzgGK2hbCL5hfveZlxsZoAohFTkOCK4714vXyoI0dJM akbq3VMjljkrHS+biC4NwZgQyPFWnDVzI1rESI9iIooRiVlIQWRToWwyDDxHP7b8 LiDdh62uj6aAirGBnGK8qrXnIgXcFlowNGDT4JsUuXqEavNBBcl0VH/6C1E3Zhmn a/w2NwCWnAxcRl5nO8v/yl/awV9hQ5Ma8mR5v6de1BDxsGUyHKxxI6+/iO31ZxzM 4XzIdta7TNGPvWsHXEBfBZqNIt2XbEAKagNXsNwar5Py05Tb/JK1F4S5gUxVblRq Ro3JoP5gjdMvKVZGoQeG414g3b+z+58VP5DIVBIkCOu7ODoxCqbavneh9IUOsW0e 3xrHPceoiN+q9pCfRYfjep6D53hkASzGihQM2rGBgPzyOATO6U7SaYosEVYuDkIW Li2ObspV =ZV02 -----END PGP SIGNATURE----- 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()
This commit is contained in:
Коммит
bd8e963412
|
@ -253,9 +253,11 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
|
|||
dentry = dget(cifs_sb->root);
|
||||
else {
|
||||
dentry = path_to_dentry(cifs_sb, path);
|
||||
if (IS_ERR(dentry))
|
||||
if (IS_ERR(dentry)) {
|
||||
rc = -ENOENT;
|
||||
goto oshr_free;
|
||||
}
|
||||
}
|
||||
cfid->dentry = dentry;
|
||||
cfid->tcon = tcon;
|
||||
cfid->time = jiffies;
|
||||
|
@ -338,6 +340,27 @@ smb2_close_cached_fid(struct kref *ref)
|
|||
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)
|
||||
{
|
||||
kref_put(&cfid->refcount, smb2_close_cached_fid);
|
||||
|
@ -378,22 +401,20 @@ void invalidate_all_cached_dirs(struct cifs_tcon *tcon)
|
|||
{
|
||||
struct cached_fids *cfids = tcon->cfids;
|
||||
struct cached_fid *cfid, *q;
|
||||
struct list_head entry;
|
||||
LIST_HEAD(entry);
|
||||
|
||||
INIT_LIST_HEAD(&entry);
|
||||
spin_lock(&cfids->cfid_list_lock);
|
||||
list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
|
||||
list_del(&cfid->entry);
|
||||
list_add(&cfid->entry, &entry);
|
||||
list_move(&cfid->entry, &entry);
|
||||
cfids->num_entries--;
|
||||
cfid->is_open = false;
|
||||
cfid->on_list = false;
|
||||
/* To prevent race with smb2_cached_lease_break() */
|
||||
kref_get(&cfid->refcount);
|
||||
}
|
||||
spin_unlock(&cfids->cfid_list_lock);
|
||||
|
||||
list_for_each_entry_safe(cfid, q, &entry, entry) {
|
||||
cfid->on_list = false;
|
||||
list_del(&cfid->entry);
|
||||
cancel_work_sync(&cfid->lease_break);
|
||||
if (cfid->has_lease) {
|
||||
|
@ -518,15 +539,13 @@ struct cached_fids *init_cached_dirs(void)
|
|||
void free_cached_dirs(struct cached_fids *cfids)
|
||||
{
|
||||
struct cached_fid *cfid, *q;
|
||||
struct list_head entry;
|
||||
LIST_HEAD(entry);
|
||||
|
||||
INIT_LIST_HEAD(&entry);
|
||||
spin_lock(&cfids->cfid_list_lock);
|
||||
list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
|
||||
cfid->on_list = false;
|
||||
cfid->is_open = false;
|
||||
list_del(&cfid->entry);
|
||||
list_add(&cfid->entry, &entry);
|
||||
list_move(&cfid->entry, &entry);
|
||||
}
|
||||
spin_unlock(&cfids->cfid_list_lock);
|
||||
|
||||
|
|
|
@ -69,6 +69,10 @@ extern int open_cached_dir_by_dentry(struct cifs_tcon *tcon,
|
|||
struct dentry *dentry,
|
||||
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 invalidate_all_cached_dirs(struct cifs_tcon *tcon);
|
||||
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,
|
|||
ssize_t rc;
|
||||
struct cifsFileInfo *cfile = dst_file->private_data;
|
||||
|
||||
if (cfile->swapfile)
|
||||
return -EOPNOTSUPP;
|
||||
if (cfile->swapfile) {
|
||||
rc = -EOPNOTSUPP;
|
||||
free_xid(xid);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = cifs_file_copychunk_range(xid, src_file, off, dst_file, destoff,
|
||||
len, flags);
|
||||
|
|
|
@ -153,6 +153,6 @@ extern const struct export_operations cifs_export_ops;
|
|||
#endif /* CONFIG_CIFS_NFSD_EXPORT */
|
||||
|
||||
/* when changing internal version - update following two lines at same time */
|
||||
#define SMB3_PRODUCT_BUILD 39
|
||||
#define CIFS_VERSION "2.39"
|
||||
#define SMB3_PRODUCT_BUILD 40
|
||||
#define CIFS_VERSION "2.40"
|
||||
#endif /* _CIFSFS_H */
|
||||
|
|
|
@ -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",
|
||||
inode, direntry, direntry);
|
||||
|
||||
if (unlikely(cifs_forced_shutdown(CIFS_SB(inode->i_sb))))
|
||||
return -EIO;
|
||||
if (unlikely(cifs_forced_shutdown(CIFS_SB(inode->i_sb)))) {
|
||||
rc = -EIO;
|
||||
goto out_free_xid;
|
||||
}
|
||||
|
||||
tlink = cifs_sb_tlink(CIFS_SB(inode->i_sb));
|
||||
rc = PTR_ERR(tlink);
|
||||
|
|
|
@ -1885,11 +1885,13 @@ int cifs_flock(struct file *file, int cmd, struct file_lock *fl)
|
|||
struct cifsFileInfo *cfile;
|
||||
__u32 type;
|
||||
|
||||
rc = -EACCES;
|
||||
xid = get_xid();
|
||||
|
||||
if (!(fl->fl_flags & FL_FLOCK))
|
||||
return -ENOLCK;
|
||||
if (!(fl->fl_flags & FL_FLOCK)) {
|
||||
rc = -ENOLCK;
|
||||
free_xid(xid);
|
||||
return rc;
|
||||
}
|
||||
|
||||
cfile = (struct cifsFileInfo *)file->private_data;
|
||||
tcon = tlink_tcon(cfile->tlink);
|
||||
|
@ -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
|
||||
* know what it is
|
||||
*/
|
||||
rc = -EOPNOTSUPP;
|
||||
free_xid(xid);
|
||||
return -EOPNOTSUPP;
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = cifs_setlk(file, fl, type, wait_flag, posix_lck, lock, unlock,
|
||||
|
|
|
@ -368,8 +368,10 @@ cifs_get_file_info_unix(struct file *filp)
|
|||
|
||||
if (cfile->symlink_target) {
|
||||
fattr.cf_symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);
|
||||
if (!fattr.cf_symlink_target)
|
||||
return -ENOMEM;
|
||||
if (!fattr.cf_symlink_target) {
|
||||
rc = -ENOMEM;
|
||||
goto cifs_gfiunix_out;
|
||||
}
|
||||
}
|
||||
|
||||
rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->fid.netfid, &find_data);
|
||||
|
|
|
@ -496,6 +496,7 @@ out:
|
|||
cifs_put_tcp_session(chan->server, 0);
|
||||
}
|
||||
|
||||
free_xid(xid);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
@ -655,6 +655,7 @@ int
|
|||
smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
|
||||
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,
|
||||
CREATE_NOT_FILE, ACL_NO_MODE,
|
||||
NULL, SMB2_OP_RMDIR, NULL, NULL, NULL);
|
||||
|
@ -698,6 +699,7 @@ smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
{
|
||||
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);
|
||||
|
||||
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,
|
|||
p = buf;
|
||||
|
||||
spin_lock(&ses->iface_lock);
|
||||
ses->iface_count = 0;
|
||||
/*
|
||||
* Go through iface_list and do kref_put to remove
|
||||
* any unused ifaces. ifaces in use will be removed
|
||||
|
@ -651,9 +652,9 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
|
|||
kref_put(&iface->refcount, release_iface);
|
||||
} else
|
||||
list_add_tail(&info->iface_head, &ses->iface_list);
|
||||
spin_unlock(&ses->iface_lock);
|
||||
|
||||
ses->iface_count++;
|
||||
spin_unlock(&ses->iface_lock);
|
||||
ses->iface_last_update = jiffies;
|
||||
next_iface:
|
||||
nb_iface++;
|
||||
|
|
|
@ -1341,14 +1341,13 @@ SMB2_sess_alloc_buffer(struct SMB2_sess_data *sess_data)
|
|||
static void
|
||||
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) */
|
||||
for (i = 0; i < 2; i++)
|
||||
if (sess_data->iov[i].iov_base)
|
||||
memzero_explicit(sess_data->iov[i].iov_base, sess_data->iov[i].iov_len);
|
||||
/* iov[1] is already freed by caller */
|
||||
if (sess_data->buf0_type != CIFS_NO_BUFFER && iov[0].iov_base)
|
||||
memzero_explicit(iov[0].iov_base, iov[0].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;
|
||||
}
|
||||
|
||||
|
@ -1531,7 +1530,7 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data)
|
|||
&blob_length, ses, server,
|
||||
sess_data->nls_cp);
|
||||
if (rc)
|
||||
goto out_err;
|
||||
goto out;
|
||||
|
||||
if (use_spnego) {
|
||||
/* BB eventually need to add this */
|
||||
|
@ -1578,7 +1577,7 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data)
|
|||
}
|
||||
|
||||
out:
|
||||
memzero_explicit(ntlmssp_blob, blob_length);
|
||||
kfree_sensitive(ntlmssp_blob);
|
||||
SMB2_sess_free_buffer(sess_data);
|
||||
if (!rc) {
|
||||
sess_data->result = 0;
|
||||
|
@ -1662,7 +1661,7 @@ SMB2_sess_auth_rawntlmssp_authenticate(struct SMB2_sess_data *sess_data)
|
|||
}
|
||||
#endif
|
||||
out:
|
||||
memzero_explicit(ntlmssp_blob, blob_length);
|
||||
kfree_sensitive(ntlmssp_blob);
|
||||
SMB2_sess_free_buffer(sess_data);
|
||||
kfree_sensitive(ses->ntlmssp);
|
||||
ses->ntlmssp = NULL;
|
||||
|
|
Загрузка…
Ссылка в новой задаче