Commit 63342b1d authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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

Pull cifs fixes from Steve French:
 "smb3 client fixes, mostly DFS or reconnect related:

   - Two DFS connection sharing fixes

   - DFS refresh fix

   - Reconnect fix

   - Two potential use after free fixes

   - Also print prefix patch in mount debug msg

   - Two small cleanup fixes"

* tag '6.4-rc-smb3-client-fixes-part2' of git://git.samba.org/sfrench/cifs-2.6:
  cifs: Remove unneeded semicolon
  cifs: fix sharing of DFS connections
  cifs: avoid potential races when handling multiple dfs tcons
  cifs: protect access of TCP_Server_Info::{origin,leaf}_fullpath
  cifs: fix potential race when tree connecting ipc
  cifs: fix potential use-after-free bugs in TCP_Server_Info::hostname
  cifs: print smb3_fs_context::source when mounting
  cifs: protect session status check in smb2_reconnect()
  SMB3.1.1: correct definition for app_instance_id create contexts
parents d6b8a8c4 9ee04875
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -280,8 +280,10 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
		seq_printf(m, "\n%d) ConnectionId: 0x%llx ",
			c, server->conn_id);

		spin_lock(&server->srv_lock);
		if (server->hostname)
			seq_printf(m, "Hostname: %s ", server->hostname);
		spin_unlock(&server->srv_lock);
#ifdef CONFIG_CIFS_SMB_DIRECT
		if (!server->rdma)
			goto skip_rdma;
@@ -623,10 +625,13 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v)
				server->fastest_cmd[j],
				server->slowest_cmd[j]);
		for (j = 0; j < NUMBER_OF_SMB2_COMMANDS; j++)
			if (atomic_read(&server->smb2slowcmd[j]))
			if (atomic_read(&server->smb2slowcmd[j])) {
				spin_lock(&server->srv_lock);
				seq_printf(m, "  %d slow responses from %s for command %d\n",
					atomic_read(&server->smb2slowcmd[j]),
					server->hostname, j);
				spin_unlock(&server->srv_lock);
			}
#endif /* STATS2 */
		list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
			list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
+6 −6
Original line number Diff line number Diff line
@@ -81,19 +81,19 @@ do { \

#define cifs_server_dbg_func(ratefunc, type, fmt, ...)			\
do {									\
	const char *sn = "";						\
	if (server && server->hostname)					\
		sn = server->hostname;					\
	spin_lock(&server->srv_lock);					\
	if ((type) & FYI && cifsFYI & CIFS_INFO) {			\
		pr_debug_ ## ratefunc("%s: \\\\%s " fmt,		\
				      __FILE__, sn, ##__VA_ARGS__);	\
				      __FILE__, server->hostname,	\
				      ##__VA_ARGS__);			\
	} else if ((type) & VFS) {					\
		pr_err_ ## ratefunc("VFS: \\\\%s " fmt,			\
				    sn, ##__VA_ARGS__);			\
				    server->hostname, ##__VA_ARGS__);	\
	} else if ((type) & NOISY && (NOISY != 0)) {			\
		pr_debug_ ## ratefunc("\\\\%s " fmt,			\
				      sn, ##__VA_ARGS__);		\
				      server->hostname, ##__VA_ARGS__);	\
	}								\
	spin_unlock(&server->srv_lock);					\
} while (0)

#define cifs_server_dbg(type, fmt, ...)					\
+6 −8
Original line number Diff line number Diff line
@@ -874,14 +874,12 @@ cifs_smb3_do_mount(struct file_system_type *fs_type,
	struct cifs_mnt_data mnt_data;
	struct dentry *root;

	/*
	 * Prints in Kernel / CIFS log the attempted mount operation
	 *	If CIFS_DEBUG && cifs_FYI
	 */
	if (cifsFYI)
		cifs_dbg(FYI, "Devname: %s flags: %d\n", old_ctx->UNC, flags);
	else
		cifs_info("Attempting to mount %s\n", old_ctx->UNC);
	if (cifsFYI) {
		cifs_dbg(FYI, "%s: devname=%s flags=0x%x\n", __func__,
			 old_ctx->source, flags);
	} else {
		cifs_info("Attempting to mount %s\n", old_ctx->source);
	}

	cifs_sb = kzalloc(sizeof(struct cifs_sb_info), GFP_KERNEL);
	if (cifs_sb == NULL) {
+14 −9
Original line number Diff line number Diff line
@@ -736,17 +736,23 @@ struct TCP_Server_Info {
#endif
	struct mutex refpath_lock; /* protects leaf_fullpath */
	/*
	 * Canonical DFS full paths that were used to chase referrals in mount and reconnect.
	 * origin_fullpath: Canonical copy of smb3_fs_context::source.
	 *                  It is used for matching existing DFS tcons.
	 *
	 * origin_fullpath: first or original referral path
	 * leaf_fullpath: last referral path (might be changed due to nested links in reconnect)
	 * 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.
	 *
	 * current_fullpath: pointer to either origin_fullpath or leaf_fullpath
	 * NOTE: cannot be accessed outside cifs_reconnect() and smb2_reconnect()
	 * Both protected by @refpath_lock and @srv_lock.  The @refpath_lock is
	 * mosly 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]
	 * format: \\HOST\SHARE[\OPTIONAL PATH]
	 */
	char *origin_fullpath, *leaf_fullpath, *current_fullpath;
	char *origin_fullpath, *leaf_fullpath;
};

static inline bool is_smb1(struct TCP_Server_Info *server)
@@ -1232,8 +1238,8 @@ struct cifs_tcon {
	struct cached_fids *cfids;
	/* BB add field for back pointer to sb struct(s)? */
#ifdef CONFIG_CIFS_DFS_UPCALL
	struct list_head ulist; /* cache update list */
	struct list_head dfs_ses_list;
	struct delayed_work dfs_cache_work;
#endif
	struct delayed_work	query_interfaces; /* query interfaces workqueue job */
};
@@ -1750,7 +1756,6 @@ struct cifs_mount_ctx {
	struct TCP_Server_Info *server;
	struct cifs_ses *ses;
	struct cifs_tcon *tcon;
	char *origin_fullpath, *leaf_fullpath;
	struct list_head dfs_ses_list;
};

+43 −1
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@
#ifndef _CIFSPROTO_H
#define _CIFSPROTO_H
#include <linux/nls.h>
#include <linux/ctype.h>
#include "trace.h"
#ifdef CONFIG_CIFS_DFS_UPCALL
#include "dfs_cache.h"
@@ -572,7 +573,7 @@ extern int E_md4hash(const unsigned char *passwd, unsigned char *p16,
extern struct TCP_Server_Info *
cifs_find_tcp_session(struct smb3_fs_context *ctx);

extern void cifs_put_smb_ses(struct cifs_ses *ses);
void __cifs_put_smb_ses(struct cifs_ses *ses);

extern struct cifs_ses *
cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx);
@@ -696,4 +697,45 @@ struct super_block *cifs_get_tcon_super(struct cifs_tcon *tcon);
void cifs_put_tcon_super(struct super_block *sb);
int cifs_wait_for_server_reconnect(struct TCP_Server_Info *server, bool retry);

/* Put references of @ses and @ses->dfs_root_ses */
static inline void cifs_put_smb_ses(struct cifs_ses *ses)
{
	struct cifs_ses *rses = ses->dfs_root_ses;

	__cifs_put_smb_ses(ses);
	if (rses)
		__cifs_put_smb_ses(rses);
}

/* Get an active reference of @ses and @ses->dfs_root_ses.
 *
 * NOTE: make sure to call this function when incrementing reference count of
 * @ses to ensure that any DFS root session attached to it (@ses->dfs_root_ses)
 * will also get its reference count incremented.
 *
 * cifs_put_smb_ses() will put both references, so call it when you're done.
 */
static inline void cifs_smb_ses_inc_refcount(struct cifs_ses *ses)
{
	lockdep_assert_held(&cifs_tcp_ses_lock);

	ses->ses_count++;
	if (ses->dfs_root_ses)
		ses->dfs_root_ses->ses_count++;
}

static inline bool dfs_src_pathname_equal(const char *s1, const char *s2)
{
	if (strlen(s1) != strlen(s2))
		return false;
	for (; *s1; s1++, s2++) {
		if (*s1 == '/' || *s1 == '\\') {
			if (*s2 != '/' && *s2 != '\\')
				return false;
		} else if (tolower(*s1) != tolower(*s2))
			return false;
	}
	return true;
}

#endif			/* _CIFSPROTO_H */
Loading