Commit 766e9cf3 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag '6.7-rc-smb3-client-fixes-part1' of git://git.samba.org/sfrench/cifs-2.6

Pull smb client updates from Steve French:

 - use after free fixes and deadlock fix

 - symlink timestamp fix

 - hashing perf improvement

 - multichannel fixes

 - minor debugging improvements

 - fix creating fifos when using "sfu" mounts

 - NTLMSSP authentication improvement

 - minor fixes to include some missing create flags and structures from
   recently updated protocol documentation

* tag '6.7-rc-smb3-client-fixes-part1' of git://git.samba.org/sfrench/cifs-2.6:
  cifs: force interface update before a fresh session setup
  cifs: do not reset chan_max if multichannel is not supported at mount
  cifs: reconnect helper should set reconnect for the right channel
  smb: client: fix use-after-free in smb2_query_info_compound()
  smb: client: remove extra @chan_count check in __cifs_put_smb_ses()
  cifs: add xid to query server interface call
  cifs: print server capabilities in DebugData
  smb: use crypto_shash_digest() in symlink_hash()
  smb: client: fix use-after-free bug in cifs_debug_data_proc_show()
  smb: client: fix potential deadlock when releasing mids
  smb3: fix creating FIFOs when mounting with "sfu" mount option
  Add definition for new smb3.1.1 command type
  SMB3: clarify some of the unused CreateOption flags
  cifs: Add client version details to NTLM authenticate message
  smb3: fix touch -h of symlink
parents 4c975a43 d9a6d780
Loading
Loading
Loading
Loading
+49 −35
Original line number Diff line number Diff line
@@ -32,7 +32,7 @@ static struct cached_fid *find_or_create_cached_dir(struct cached_fids *cfids,
			 * fully cached or it may be in the process of
			 * being deleted due to a lease break.
			 */
			if (!cfid->has_lease) {
			if (!cfid->time || !cfid->has_lease) {
				spin_unlock(&cfids->cfid_list_lock);
				return NULL;
			}
@@ -193,10 +193,20 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
	npath = path_no_prefix(cifs_sb, path);
	if (IS_ERR(npath)) {
		rc = PTR_ERR(npath);
		kfree(utf16_path);
		return rc;
		goto out;
	}

	if (!npath[0]) {
		dentry = dget(cifs_sb->root);
	} else {
		dentry = path_to_dentry(cifs_sb, npath);
		if (IS_ERR(dentry)) {
			rc = -ENOENT;
			goto out;
		}
	}
	cfid->dentry = dentry;

	/*
	 * We do not hold the lock for the open because in case
	 * SMB2_open needs to reconnect.
@@ -249,6 +259,15 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,

	smb2_set_related(&rqst[1]);

	/*
	 * Set @cfid->has_lease to true before sending out compounded request so
	 * its lease reference can be put in cached_dir_lease_break() due to a
	 * potential lease break right after the request is sent or while @cfid
	 * is still being cached.  Concurrent processes won't be to use it yet
	 * due to @cfid->time being zero.
	 */
	cfid->has_lease = true;

	rc = compound_send_recv(xid, ses, server,
				flags, 2, rqst,
				resp_buftype, rsp_iov);
@@ -263,6 +282,8 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
	cfid->tcon = tcon;
	cfid->is_open = true;

	spin_lock(&cfids->cfid_list_lock);

	o_rsp = (struct smb2_create_rsp *)rsp_iov[0].iov_base;
	oparms.fid->persistent_fid = o_rsp->PersistentFileId;
	oparms.fid->volatile_fid = o_rsp->VolatileFileId;
@@ -270,18 +291,25 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
	oparms.fid->mid = le64_to_cpu(o_rsp->hdr.MessageId);
#endif /* CIFS_DEBUG2 */

	if (o_rsp->OplockLevel != SMB2_OPLOCK_LEVEL_LEASE)
	rc = -EINVAL;
	if (o_rsp->OplockLevel != SMB2_OPLOCK_LEVEL_LEASE) {
		spin_unlock(&cfids->cfid_list_lock);
		goto oshr_free;
	}

	smb2_parse_contexts(server, o_rsp,
			    &oparms.fid->epoch,
			    oparms.fid->lease_key, &oplock,
			    NULL, NULL);
	if (!(oplock & SMB2_LEASE_READ_CACHING_HE))
	if (!(oplock & SMB2_LEASE_READ_CACHING_HE)) {
		spin_unlock(&cfids->cfid_list_lock);
		goto oshr_free;
	}
	qi_rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base;
	if (le32_to_cpu(qi_rsp->OutputBufferLength) < sizeof(struct smb2_file_all_info))
	if (le32_to_cpu(qi_rsp->OutputBufferLength) < sizeof(struct smb2_file_all_info)) {
		spin_unlock(&cfids->cfid_list_lock);
		goto oshr_free;
	}
	if (!smb2_validate_and_copy_iov(
				le16_to_cpu(qi_rsp->OutputBufferOffset),
				sizeof(struct smb2_file_all_info),
@@ -289,37 +317,24 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
				(char *)&cfid->file_all_info))
		cfid->file_all_info_is_valid = true;

	if (!npath[0])
		dentry = dget(cifs_sb->root);
	else {
		dentry = path_to_dentry(cifs_sb, npath);
		if (IS_ERR(dentry)) {
			rc = -ENOENT;
			goto oshr_free;
		}
	}
	spin_lock(&cfids->cfid_list_lock);
	cfid->dentry = dentry;
	cfid->time = jiffies;
	cfid->has_lease = true;
	spin_unlock(&cfids->cfid_list_lock);
	/* At this point the directory handle is fully cached */
	rc = 0;

oshr_free:
	kfree(utf16_path);
	SMB2_open_free(&rqst[0]);
	SMB2_query_info_free(&rqst[1]);
	free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
	free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
	spin_lock(&cfids->cfid_list_lock);
	if (!cfid->has_lease) {
	if (rc) {
		spin_lock(&cfids->cfid_list_lock);
		if (cfid->on_list) {
			list_del(&cfid->entry);
			cfid->on_list = false;
			cfids->num_entries--;
		}
			rc = -ENOENT;
		} else {
		if (cfid->has_lease) {
			/*
			 * We are guaranteed to have two references at this
			 * point. One for the caller and one for a potential
@@ -327,25 +342,24 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
			 * will be closed when the caller closes the cached
			 * handle.
			 */
			cfid->has_lease = false;
			spin_unlock(&cfids->cfid_list_lock);
			kref_put(&cfid->refcount, smb2_close_cached_fid);
			goto out;
		}
	}
		spin_unlock(&cfids->cfid_list_lock);
	}
out:
	if (rc) {
		if (cfid->is_open)
			SMB2_close(0, cfid->tcon, cfid->fid.persistent_fid,
				   cfid->fid.volatile_fid);
		free_cached_dir(cfid);
		cfid = NULL;
	}
out:
	if (rc == 0) {
	} else {
		*ret_cfid = cfid;
		atomic_inc(&tcon->num_remote_opens);
	}

	kfree(utf16_path);
	return rc;
}

+8 −0
Original line number Diff line number Diff line
@@ -427,6 +427,8 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
		if (server->nosharesock)
			seq_printf(m, " nosharesock");

		seq_printf(m, "\nServer capabilities: 0x%x", server->capabilities);

		if (server->rdma)
			seq_printf(m, "\nRDMA ");
		seq_printf(m, "\nTCP status: %d Instance: %d"
@@ -452,6 +454,11 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
		seq_printf(m, "\n\n\tSessions: ");
		i = 0;
		list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
			spin_lock(&ses->ses_lock);
			if (ses->ses_status == SES_EXITING) {
				spin_unlock(&ses->ses_lock);
				continue;
			}
			i++;
			if ((ses->serverDomain == NULL) ||
				(ses->serverOS == NULL) ||
@@ -472,6 +479,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
				ses->ses_count, ses->serverOS, ses->serverNOS,
				ses->capabilities, ses->ses_status);
			}
			spin_unlock(&ses->ses_lock);

			seq_printf(m, "\n\tSecurity type: %s ",
				get_security_type_str(server->ops->select_sectype(server, ses->sectype)));
+1 −0
Original line number Diff line number Diff line
@@ -1191,6 +1191,7 @@ const char *cifs_get_link(struct dentry *dentry, struct inode *inode,

const struct inode_operations cifs_symlink_inode_ops = {
	.get_link = cifs_get_link,
	.setattr = cifs_setattr,
	.permission = cifs_permission,
	.listxattr = cifs_listxattr,
};
+1 −1
Original line number Diff line number Diff line
@@ -2570,7 +2570,7 @@ typedef struct {


struct win_dev {
	unsigned char type[8]; /* IntxCHR or IntxBLK */
	unsigned char type[8]; /* IntxCHR or IntxBLK or LnxFIFO*/
	__le64 major;
	__le64 minor;
} __attribute__((packed));
+6 −1
Original line number Diff line number Diff line
@@ -81,7 +81,7 @@ extern char *cifs_build_path_to_root(struct smb3_fs_context *ctx,
extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
char *cifs_build_devname(char *nodename, const char *prepath);
extern void delete_mid(struct mid_q_entry *mid);
extern void release_mid(struct mid_q_entry *mid);
void __release_mid(struct kref *refcount);
extern void cifs_wake_up_task(struct mid_q_entry *mid);
extern int cifs_handle_standard(struct TCP_Server_Info *server,
				struct mid_q_entry *mid);
@@ -740,4 +740,9 @@ static inline bool dfs_src_pathname_equal(const char *s1, const char *s2)
	return true;
}

static inline void release_mid(struct mid_q_entry *mid)
{
	kref_put(&mid->refcount, __release_mid);
}

#endif			/* _CIFSPROTO_H */
Loading