Skip to content

Commit

Permalink
Merge tag '5.19-rc-smb3-client-fixes-part2' of git://git.samba.org/sf…
Browse files Browse the repository at this point in the history
…rench/cifs-2.6

Pull cifs client fixes from Steve French:
 "Nine cifs/smb3 client fixes.

  Includes DFS fixes, some cleanup of leagcy SMB1 code, duplicated
  message cleanup and a double free and deadlock fix"

* tag '5.19-rc-smb3-client-fixes-part2' of git://git.samba.org/sfrench/cifs-2.6:
  cifs: fix uninitialized pointer in error case in dfs_cache_get_tgt_share
  cifs: skip trailing separators of prefix paths
  cifs: update internal module number
  cifs: version operations for smb20 unneeded when legacy support disabled
  cifs: do not build smb1ops if legacy support is disabled
  cifs: fix potential deadlock in direct reclaim
  cifs: when extending a file with falloc we should make files not-sparse
  cifs: remove repeated debug message on cifs_put_smb_ses()
  cifs: fix potential double free during failed mount
  • Loading branch information
torvalds committed Jun 5, 2022
2 parents d0e60d4 + ee3c801 commit d66016c
Show file tree
Hide file tree
Showing 14 changed files with 143 additions and 100 deletions.
4 changes: 3 additions & 1 deletion fs/cifs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ obj-$(CONFIG_CIFS) += cifs.o
cifs-y := trace.o cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o \
inode.o link.o misc.o netmisc.o smbencrypt.o transport.o \
cifs_unicode.o nterr.o cifsencrypt.o \
readdir.o ioctl.o sess.o export.o smb1ops.o unc.o winucase.o \
readdir.o ioctl.o sess.o export.o unc.o winucase.o \
smb2ops.o smb2maperror.o smb2transport.o \
smb2misc.o smb2pdu.o smb2inode.o smb2file.o cifsacl.o fs_context.o \
dns_resolve.o cifs_spnego_negtokeninit.asn1.o asn1.o
Expand All @@ -30,3 +30,5 @@ cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o
cifs-$(CONFIG_CIFS_SMB_DIRECT) += smbdirect.o

cifs-$(CONFIG_CIFS_ROOT) += cifsroot.o

cifs-$(CONFIG_CIFS_ALLOW_INSECURE_LEGACY) += smb1ops.o
4 changes: 2 additions & 2 deletions fs/cifs/cifs_swn.c
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,7 @@ static int cifs_swn_reconnect(struct cifs_tcon *tcon, struct sockaddr_storage *a
int ret = 0;

/* Store the reconnect address */
mutex_lock(&tcon->ses->server->srv_mutex);
cifs_server_lock(tcon->ses->server);
if (cifs_sockaddr_equal(&tcon->ses->server->dstaddr, addr))
goto unlock;

Expand Down Expand Up @@ -501,7 +501,7 @@ static int cifs_swn_reconnect(struct cifs_tcon *tcon, struct sockaddr_storage *a
cifs_signal_cifsd_for_reconnect(tcon->ses->server, false);

unlock:
mutex_unlock(&tcon->ses->server->srv_mutex);
cifs_server_unlock(tcon->ses->server);

return ret;
}
Expand Down
8 changes: 4 additions & 4 deletions fs/cifs/cifsencrypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -236,9 +236,9 @@ int cifs_verify_signature(struct smb_rqst *rqst,
cpu_to_le32(expected_sequence_number);
cifs_pdu->Signature.Sequence.Reserved = 0;

mutex_lock(&server->srv_mutex);
cifs_server_lock(server);
rc = cifs_calc_signature(rqst, server, what_we_think_sig_should_be);
mutex_unlock(&server->srv_mutex);
cifs_server_unlock(server);

if (rc)
return rc;
Expand Down Expand Up @@ -626,7 +626,7 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)

memcpy(ses->auth_key.response + baselen, tiblob, tilen);

mutex_lock(&ses->server->srv_mutex);
cifs_server_lock(ses->server);

rc = cifs_alloc_hash("hmac(md5)",
&ses->server->secmech.hmacmd5,
Expand Down Expand Up @@ -678,7 +678,7 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__);

unlock:
mutex_unlock(&ses->server->srv_mutex);
cifs_server_unlock(ses->server);
setup_ntlmv2_rsp_ret:
kfree(tiblob);

Expand Down
10 changes: 6 additions & 4 deletions fs/cifs/cifsfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -838,7 +838,7 @@ cifs_smb3_do_mount(struct file_system_type *fs_type,
int flags, struct smb3_fs_context *old_ctx)
{
int rc;
struct super_block *sb;
struct super_block *sb = NULL;
struct cifs_sb_info *cifs_sb = NULL;
struct cifs_mnt_data mnt_data;
struct dentry *root;
Expand Down Expand Up @@ -934,9 +934,11 @@ cifs_smb3_do_mount(struct file_system_type *fs_type,
return root;
out:
if (cifs_sb) {
kfree(cifs_sb->prepath);
smb3_cleanup_fs_context(cifs_sb->ctx);
kfree(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;
}
Expand Down
5 changes: 3 additions & 2 deletions fs/cifs/cifsfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ extern struct dentry *cifs_smb3_do_mount(struct file_system_type *fs_type,
extern const struct export_operations cifs_export_ops;
#endif /* CONFIG_CIFS_NFSD_EXPORT */

#define SMB3_PRODUCT_BUILD 35
#define CIFS_VERSION "2.36"
/* when changing internal version - update following two lines at same time */
#define SMB3_PRODUCT_BUILD 37
#define CIFS_VERSION "2.37"
#endif /* _CIFSFS_H */
24 changes: 22 additions & 2 deletions fs/cifs/cifsglob.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <linux/mempool.h>
#include <linux/workqueue.h>
#include <linux/utsname.h>
#include <linux/sched/mm.h>
#include <linux/netfs.h>
#include "cifs_fs_sb.h"
#include "cifsacl.h"
Expand Down Expand Up @@ -628,7 +629,8 @@ struct TCP_Server_Info {
unsigned int in_flight; /* number of requests on the wire to server */
unsigned int max_in_flight; /* max number of requests that were on wire */
spinlock_t req_lock; /* protect the two values above */
struct mutex srv_mutex;
struct mutex _srv_mutex;
unsigned int nofs_flag;
struct task_struct *tsk;
char server_GUID[16];
__u16 sec_mode;
Expand Down Expand Up @@ -743,6 +745,22 @@ struct TCP_Server_Info {
#endif
};

static inline void cifs_server_lock(struct TCP_Server_Info *server)
{
unsigned int nofs_flag = memalloc_nofs_save();

mutex_lock(&server->_srv_mutex);
server->nofs_flag = nofs_flag;
}

static inline void cifs_server_unlock(struct TCP_Server_Info *server)
{
unsigned int nofs_flag = server->nofs_flag;

mutex_unlock(&server->_srv_mutex);
memalloc_nofs_restore(nofs_flag);
}

struct cifs_credits {
unsigned int value;
unsigned int instance;
Expand Down Expand Up @@ -1945,11 +1963,13 @@ extern mempool_t *cifs_mid_poolp;

/* Operations for different SMB versions */
#define SMB1_VERSION_STRING "1.0"
#define SMB20_VERSION_STRING "2.0"
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
extern struct smb_version_operations smb1_operations;
extern struct smb_version_values smb1_values;
#define SMB20_VERSION_STRING "2.0"
extern struct smb_version_operations smb20_operations;
extern struct smb_version_values smb20_values;
#endif /* CIFS_ALLOW_INSECURE_LEGACY */
#define SMB21_VERSION_STRING "2.1"
extern struct smb_version_operations smb21_operations;
extern struct smb_version_values smb21_values;
Expand Down
27 changes: 13 additions & 14 deletions fs/cifs/connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ static void cifs_resolve_server(struct work_struct *work)
struct TCP_Server_Info *server = container_of(work,
struct TCP_Server_Info, resolve.work);

mutex_lock(&server->srv_mutex);
cifs_server_lock(server);

/*
* Resolve the hostname again to make sure that IP address is up-to-date.
Expand All @@ -159,7 +159,7 @@ static void cifs_resolve_server(struct work_struct *work)
__func__, rc);
}

mutex_unlock(&server->srv_mutex);
cifs_server_unlock(server);
}

/*
Expand Down Expand Up @@ -267,7 +267,7 @@ cifs_abort_connection(struct TCP_Server_Info *server)

/* do not want to be sending data on a socket we are freeing */
cifs_dbg(FYI, "%s: tearing down socket\n", __func__);
mutex_lock(&server->srv_mutex);
cifs_server_lock(server);
if (server->ssocket) {
cifs_dbg(FYI, "State: 0x%x Flags: 0x%lx\n", server->ssocket->state,
server->ssocket->flags);
Expand Down Expand Up @@ -296,7 +296,7 @@ cifs_abort_connection(struct TCP_Server_Info *server)
mid->mid_flags |= MID_DELETED;
}
spin_unlock(&GlobalMid_Lock);
mutex_unlock(&server->srv_mutex);
cifs_server_unlock(server);

cifs_dbg(FYI, "%s: issuing mid callbacks\n", __func__);
list_for_each_entry_safe(mid, nmid, &retry_list, qhead) {
Expand All @@ -306,9 +306,9 @@ cifs_abort_connection(struct TCP_Server_Info *server)
}

if (cifs_rdma_enabled(server)) {
mutex_lock(&server->srv_mutex);
cifs_server_lock(server);
smbd_destroy(server);
mutex_unlock(&server->srv_mutex);
cifs_server_unlock(server);
}
}

Expand Down Expand Up @@ -359,7 +359,7 @@ static int __cifs_reconnect(struct TCP_Server_Info *server,

do {
try_to_freeze();
mutex_lock(&server->srv_mutex);
cifs_server_lock(server);

if (!cifs_swn_set_server_dstaddr(server)) {
/* resolve the hostname again to make sure that IP address is up-to-date */
Expand All @@ -372,7 +372,7 @@ static int __cifs_reconnect(struct TCP_Server_Info *server,
else
rc = generic_ip_connect(server);
if (rc) {
mutex_unlock(&server->srv_mutex);
cifs_server_unlock(server);
cifs_dbg(FYI, "%s: reconnect error %d\n", __func__, rc);
msleep(3000);
} else {
Expand All @@ -383,7 +383,7 @@ static int __cifs_reconnect(struct TCP_Server_Info *server,
server->tcpStatus = CifsNeedNegotiate;
spin_unlock(&cifs_tcp_ses_lock);
cifs_swn_reset_server_dstaddr(server);
mutex_unlock(&server->srv_mutex);
cifs_server_unlock(server);
mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
}
} while (server->tcpStatus == CifsNeedReconnect);
Expand Down Expand Up @@ -488,12 +488,12 @@ static int reconnect_dfs_server(struct TCP_Server_Info *server)

do {
try_to_freeze();
mutex_lock(&server->srv_mutex);
cifs_server_lock(server);

rc = reconnect_target_unlocked(server, &tl, &target_hint);
if (rc) {
/* Failed to reconnect socket */
mutex_unlock(&server->srv_mutex);
cifs_server_unlock(server);
cifs_dbg(FYI, "%s: reconnect error %d\n", __func__, rc);
msleep(3000);
continue;
Expand All @@ -510,7 +510,7 @@ static int reconnect_dfs_server(struct TCP_Server_Info *server)
server->tcpStatus = CifsNeedNegotiate;
spin_unlock(&cifs_tcp_ses_lock);
cifs_swn_reset_server_dstaddr(server);
mutex_unlock(&server->srv_mutex);
cifs_server_unlock(server);
mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
} while (server->tcpStatus == CifsNeedReconnect);

Expand Down Expand Up @@ -1565,7 +1565,7 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx,
init_waitqueue_head(&tcp_ses->response_q);
init_waitqueue_head(&tcp_ses->request_q);
INIT_LIST_HEAD(&tcp_ses->pending_mid_q);
mutex_init(&tcp_ses->srv_mutex);
mutex_init(&tcp_ses->_srv_mutex);
memcpy(tcp_ses->workstation_RFC1001_name,
ctx->source_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
memcpy(tcp_ses->server_RFC1001_name,
Expand Down Expand Up @@ -1845,7 +1845,6 @@ void cifs_put_smb_ses(struct cifs_ses *ses)
unsigned int rc, xid;
unsigned int chan_count;
struct TCP_Server_Info *server = ses->server;
cifs_dbg(FYI, "%s: ses_count=%d\n", __func__, ses->ses_count);

spin_lock(&cifs_tcp_ses_lock);
if (ses->ses_status == SES_EXITING) {
Expand Down
90 changes: 52 additions & 38 deletions fs/cifs/dfs_cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -1229,6 +1229,30 @@ void dfs_cache_put_refsrv_sessions(const uuid_t *mount_id)
kref_put(&mg->refcount, mount_group_release);
}

/* Extract share from DFS target and return a pointer to prefix path or NULL */
static const char *parse_target_share(const char *target, char **share)
{
const char *s, *seps = "/\\";
size_t len;

s = strpbrk(target + 1, seps);
if (!s)
return ERR_PTR(-EINVAL);

len = strcspn(s + 1, seps);
if (!len)
return ERR_PTR(-EINVAL);
s += len;

len = s - target + 1;
*share = kstrndup(target, len, GFP_KERNEL);
if (!*share)
return ERR_PTR(-ENOMEM);

s = target + len;
return s + strspn(s, seps);
}

/**
* dfs_cache_get_tgt_share - parse a DFS target
*
Expand All @@ -1242,56 +1266,46 @@ void dfs_cache_put_refsrv_sessions(const uuid_t *mount_id)
int dfs_cache_get_tgt_share(char *path, const struct dfs_cache_tgt_iterator *it, char **share,
char **prefix)
{
char *s, sep, *p;
size_t len;
size_t plen1, plen2;
char sep;
char *target_share;
char *ppath = NULL;
const char *target_ppath, *dfsref_ppath;
size_t target_pplen, dfsref_pplen;
size_t len, c;

if (!it || !path || !share || !prefix || strlen(path) < it->it_path_consumed)
return -EINVAL;

*share = NULL;
*prefix = NULL;

sep = it->it_name[0];
if (sep != '\\' && sep != '/')
return -EINVAL;

s = strchr(it->it_name + 1, sep);
if (!s)
return -EINVAL;
target_ppath = parse_target_share(it->it_name, &target_share);
if (IS_ERR(target_ppath))
return PTR_ERR(target_ppath);

/* point to prefix in target node */
s = strchrnul(s + 1, sep);
/* point to prefix in DFS referral path */
dfsref_ppath = path + it->it_path_consumed;
dfsref_ppath += strspn(dfsref_ppath, "/\\");

/* extract target share */
*share = kstrndup(it->it_name, s - it->it_name, GFP_KERNEL);
if (!*share)
return -ENOMEM;
target_pplen = strlen(target_ppath);
dfsref_pplen = strlen(dfsref_ppath);

/* skip separator */
if (*s)
s++;
/* point to prefix in DFS path */
p = path + it->it_path_consumed;
if (*p == sep)
p++;

/* merge prefix paths from DFS path and target node */
plen1 = it->it_name + strlen(it->it_name) - s;
plen2 = path + strlen(path) - p;
if (plen1 || plen2) {
len = plen1 + plen2 + 2;
*prefix = kmalloc(len, GFP_KERNEL);
if (!*prefix) {
kfree(*share);
*share = NULL;
/* merge prefix paths from DFS referral path and target node */
if (target_pplen || dfsref_pplen) {
len = target_pplen + dfsref_pplen + 2;
ppath = kzalloc(len, GFP_KERNEL);
if (!ppath) {
kfree(target_share);
return -ENOMEM;
}
if (plen1)
scnprintf(*prefix, len, "%.*s%c%.*s", (int)plen1, s, sep, (int)plen2, p);
else
strscpy(*prefix, p, len);
c = strscpy(ppath, target_ppath, len);
if (c && dfsref_pplen)
ppath[c] = sep;
strlcat(ppath, dfsref_ppath, len);
}
*share = target_share;
*prefix = ppath;
return 0;
}

Expand Down Expand Up @@ -1327,9 +1341,9 @@ static bool target_share_equal(struct TCP_Server_Info *server, const char *s1, c
cifs_dbg(VFS, "%s: failed to convert address \'%s\'. skip address matching.\n",
__func__, ip);
} else {
mutex_lock(&server->srv_mutex);
cifs_server_lock(server);
match = cifs_match_ipaddr((struct sockaddr *)&server->dstaddr, &sa);
mutex_unlock(&server->srv_mutex);
cifs_server_unlock(server);
}

kfree(ip);
Expand Down
Loading

0 comments on commit d66016c

Please sign in to comment.