Commit a507db1d authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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

Pull smb client updates from Steve French:

 - Deferred close fix

 - Debugging improvements: display missing mount option, dump rc on
   invalidate inode failures, print client_guid in DebugData, log
   session id when matching session not found in reconnect, new dynamic
   tracepoint for session not found

 - Mount fixes including: potential null dereference, and possible
   memory leak and path name parsing when double slashes

 - Fix potential use after free in compounding

 - Two crediting (flow control) fixes: fix for crediting leak (stress
   scenario with excess lease credits) and better locking around
   updating credits

 - Three cleanups from issues pointed out by the kernel test robot

 - Session state check improvements (including for potential use after
   free)

 - DFS fixes: Fix for getattr on link when DFS disabled, fix for DFS
   mounts to same share with different prefix paths, DFS mount error
   checking improvement

* tag '6.5-rc-smb3-client-fixes-part1' of git://git.samba.org/sfrench/cifs-2.6:
  cifs: new dynamic tracepoint to track ses not found errors
  cifs: log session id when a matching ses is not found
  smb: client: improve DFS mount check
  smb: client: fix shared DFS root mounts with different prefixes
  smb: client: fix parsing of source mount option
  smb: client: fix broken file attrs with nodfs mounts
  cifs: print client_guid in DebugData
  cifs: fix session state check in smb2_find_smb_ses
  cifs: fix session state check in reconnect to avoid use-after-free issue
  cifs: do all necessary checks for credits within or before locking
  cifs: prevent use-after-free by freeing the cfile later
  smb: client: fix warning in generic_ip_connect()
  smb: client: fix warning in CIFSFindNext()
  smb: client: fix warning in CIFSFindFirst()
  smb3: do not reserve too many oplock credits
  cifs: print more detail when invalidate_inode_mapping fails
  smb: client: fix warning in cifs_smb3_do_mount()
  smb: client: fix warning in cifs_match_super()
  cifs: print nosharesock value while dumping mount options
  SMB3: Do not send lease break acknowledgment if all file handles have been closed
parents 8976e9d0 61986a58
Loading
Loading
Loading
Loading
+10 −7
Original line number Diff line number Diff line
@@ -122,6 +122,12 @@ static void cifs_debug_tcon(struct seq_file *m, struct cifs_tcon *tcon)
		seq_puts(m, " nosparse");
	if (tcon->need_reconnect)
		seq_puts(m, "\tDISCONNECTED ");
	spin_lock(&tcon->tc_lock);
	if (tcon->origin_fullpath) {
		seq_printf(m, "\n\tDFS origin fullpath: %s",
			   tcon->origin_fullpath);
	}
	spin_unlock(&tcon->tc_lock);
	seq_putc(m, '\n');
}

@@ -330,6 +336,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
		spin_lock(&server->srv_lock);
		if (server->hostname)
			seq_printf(m, "Hostname: %s ", server->hostname);
		seq_printf(m, "\nClientGUID: %pUL", server->client_guid);
		spin_unlock(&server->srv_lock);
#ifdef CONFIG_CIFS_SMB_DIRECT
		if (!server->rdma)
@@ -427,11 +434,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
		seq_printf(m, "\nIn Send: %d In MaxReq Wait: %d",
				atomic_read(&server->in_send),
				atomic_read(&server->num_waiters));
		if (IS_ENABLED(CONFIG_CIFS_DFS_UPCALL)) {
			if (server->origin_fullpath)
				seq_printf(m, "\nDFS origin full path: %s",
					   server->origin_fullpath);
			if (server->leaf_fullpath)
		if (server->leaf_fullpath) {
			seq_printf(m, "\nDFS leaf full path: %s",
				   server->leaf_fullpath);
		}
+14 −6
Original line number Diff line number Diff line
@@ -118,12 +118,12 @@ cifs_build_devname(char *nodename, const char *prepath)
	return dev;
}

static int set_dest_addr(struct smb3_fs_context *ctx, const char *full_path)
static int set_dest_addr(struct smb3_fs_context *ctx)
{
	struct sockaddr *addr = (struct sockaddr *)&ctx->dstaddr;
	int rc;

	rc = dns_resolve_server_name_to_ip(full_path, addr, NULL);
	rc = dns_resolve_server_name_to_ip(ctx->source, addr, NULL);
	if (!rc)
		cifs_set_port(addr, ctx->port);
	return rc;
@@ -171,10 +171,9 @@ static struct vfsmount *cifs_dfs_do_automount(struct path *path)
		mnt = ERR_CAST(full_path);
		goto out;
	}
	cifs_dbg(FYI, "%s: full_path: %s\n", __func__, full_path);

	tmp = *cur_ctx;
	tmp.source = full_path;
	tmp.source = NULL;
	tmp.leaf_fullpath = NULL;
	tmp.UNC = tmp.prepath = NULL;
	tmp.dfs_root_ses = NULL;
@@ -185,13 +184,22 @@ static struct vfsmount *cifs_dfs_do_automount(struct path *path)
		goto out;
	}

	rc = set_dest_addr(ctx, full_path);
	rc = smb3_parse_devname(full_path, ctx);
	if (rc) {
		mnt = ERR_PTR(rc);
		goto out;
	}

	rc = smb3_parse_devname(full_path, ctx);
	ctx->source = smb3_fs_context_fullpath(ctx, '/');
	if (IS_ERR(ctx->source)) {
		mnt = ERR_CAST(ctx->source);
		ctx->source = NULL;
		goto out;
	}
	cifs_dbg(FYI, "%s: ctx: source=%s UNC=%s prepath=%s dstaddr=%pISpc\n",
		 __func__, ctx->source, ctx->UNC, ctx->prepath, &ctx->dstaddr);

	rc = set_dest_addr(ctx);
	if (!rc)
		mnt = fc_mount(fc);
	else
+12 −18
Original line number Diff line number Diff line
@@ -688,6 +688,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
		seq_puts(s, ",noautotune");
	if (tcon->ses->server->noblocksnd)
		seq_puts(s, ",noblocksend");
	if (tcon->ses->server->nosharesock)
		seq_puts(s, ",nosharesock");

	if (tcon->snapshot_time)
		seq_printf(s, ",snapshot=%llu", tcon->snapshot_time);
@@ -884,11 +886,11 @@ struct dentry *
cifs_smb3_do_mount(struct file_system_type *fs_type,
	      int flags, struct smb3_fs_context *old_ctx)
{
	int rc;
	struct super_block *sb = NULL;
	struct cifs_sb_info *cifs_sb = NULL;
	struct cifs_mnt_data mnt_data;
	struct cifs_sb_info *cifs_sb;
	struct super_block *sb;
	struct dentry *root;
	int rc;

	if (cifsFYI) {
		cifs_dbg(FYI, "%s: devname=%s flags=0x%x\n", __func__,
@@ -897,11 +899,9 @@ cifs_smb3_do_mount(struct file_system_type *fs_type,
		cifs_info("Attempting to mount %s\n", old_ctx->source);
	}

	cifs_sb = kzalloc(sizeof(struct cifs_sb_info), GFP_KERNEL);
	if (cifs_sb == NULL) {
		root = ERR_PTR(-ENOMEM);
		goto out;
	}
	cifs_sb = kzalloc(sizeof(*cifs_sb), GFP_KERNEL);
	if (!cifs_sb)
		return ERR_PTR(-ENOMEM);

	cifs_sb->ctx = kzalloc(sizeof(struct smb3_fs_context), GFP_KERNEL);
	if (!cifs_sb->ctx) {
@@ -938,10 +938,8 @@ cifs_smb3_do_mount(struct file_system_type *fs_type,

	sb = sget(fs_type, cifs_match_super, cifs_set_super, flags, &mnt_data);
	if (IS_ERR(sb)) {
		root = ERR_CAST(sb);
		cifs_umount(cifs_sb);
		cifs_sb = NULL;
		goto out;
		return ERR_CAST(sb);
	}

	if (sb->s_root) {
@@ -972,13 +970,9 @@ cifs_smb3_do_mount(struct file_system_type *fs_type,
	deactivate_locked_super(sb);
	return root;
out:
	if (cifs_sb) {
		if (!sb || IS_ERR(sb)) {  /* otherwise kill_sb will handle */
	kfree(cifs_sb->prepath);
	smb3_cleanup_fs_context(cifs_sb->ctx);
	kfree(cifs_sb);
		}
	}
	return root;
}

+4 −6
Original line number Diff line number Diff line
@@ -736,23 +736,20 @@ struct TCP_Server_Info {
#endif
	struct mutex refpath_lock; /* protects leaf_fullpath */
	/*
	 * origin_fullpath: Canonical copy of smb3_fs_context::source.
	 *                  It is used for matching existing DFS tcons.
	 *
	 * leaf_fullpath: Canonical DFS referral path related to this
	 *                connection.
	 *                It is used in DFS cache refresher, reconnect and may
	 *                change due to nested DFS links.
	 *
	 * Both protected by @refpath_lock and @srv_lock.  The @refpath_lock is
	 * mosly used for not requiring a copy of @leaf_fullpath when getting
	 * Protected by @refpath_lock and @srv_lock.  The @refpath_lock is
	 * mostly used for not requiring a copy of @leaf_fullpath when getting
	 * cached or new DFS referrals (which might also sleep during I/O).
	 * While @srv_lock is held for making string and NULL comparions against
	 * both fields as in mount(2) and cache refresh.
	 *
	 * format: \\HOST\SHARE[\OPTIONAL PATH]
	 */
	char *origin_fullpath, *leaf_fullpath;
	char *leaf_fullpath;
};

static inline bool is_smb1(struct TCP_Server_Info *server)
@@ -1205,6 +1202,7 @@ struct cifs_tcon {
	struct delayed_work dfs_cache_work;
#endif
	struct delayed_work	query_interfaces; /* query interfaces workqueue job */
	char *origin_fullpath; /* canonical copy of smb3_fs_context::source */
};

/*
+3 −1
Original line number Diff line number Diff line
@@ -85,6 +85,8 @@ extern void release_mid(struct mid_q_entry *mid);
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);
extern char *smb3_fs_context_fullpath(const struct smb3_fs_context *ctx,
				      char dirsep);
extern int smb3_parse_devname(const char *devname, struct smb3_fs_context *ctx);
extern int smb3_parse_opt(const char *options, const char *key, char **val);
extern int cifs_ipaddr_cmp(struct sockaddr *srcaddr, struct sockaddr *rhs);
@@ -650,7 +652,7 @@ int smb2_parse_query_directory(struct cifs_tcon *tcon, struct kvec *rsp_iov,
			       int resp_buftype,
			       struct cifs_search_info *srch_inf);

struct super_block *cifs_get_tcp_super(struct TCP_Server_Info *server);
struct super_block *cifs_get_dfs_tcon_super(struct cifs_tcon *tcon);
void cifs_put_tcp_super(struct super_block *sb);
int cifs_update_super_prepath(struct cifs_sb_info *cifs_sb, char *prefix);
char *extract_hostname(const char *unc);
Loading