Skip to content

Commit d66016c

Browse files
committed
Merge tag '5.19-rc-smb3-client-fixes-part2' of git://git.samba.org/sfrench/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
2 parents d0e60d4 + ee3c801 commit d66016c

File tree

14 files changed

+143
-100
lines changed

14 files changed

+143
-100
lines changed

fs/cifs/Makefile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ obj-$(CONFIG_CIFS) += cifs.o
88
cifs-y := trace.o cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o \
99
inode.o link.o misc.o netmisc.o smbencrypt.o transport.o \
1010
cifs_unicode.o nterr.o cifsencrypt.o \
11-
readdir.o ioctl.o sess.o export.o smb1ops.o unc.o winucase.o \
11+
readdir.o ioctl.o sess.o export.o unc.o winucase.o \
1212
smb2ops.o smb2maperror.o smb2transport.o \
1313
smb2misc.o smb2pdu.o smb2inode.o smb2file.o cifsacl.o fs_context.o \
1414
dns_resolve.o cifs_spnego_negtokeninit.asn1.o asn1.o
@@ -30,3 +30,5 @@ cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o
3030
cifs-$(CONFIG_CIFS_SMB_DIRECT) += smbdirect.o
3131

3232
cifs-$(CONFIG_CIFS_ROOT) += cifsroot.o
33+
34+
cifs-$(CONFIG_CIFS_ALLOW_INSECURE_LEGACY) += smb1ops.o

fs/cifs/cifs_swn.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -465,7 +465,7 @@ static int cifs_swn_reconnect(struct cifs_tcon *tcon, struct sockaddr_storage *a
465465
int ret = 0;
466466

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

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

503503
unlock:
504-
mutex_unlock(&tcon->ses->server->srv_mutex);
504+
cifs_server_unlock(tcon->ses->server);
505505

506506
return ret;
507507
}

fs/cifs/cifsencrypt.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -236,9 +236,9 @@ int cifs_verify_signature(struct smb_rqst *rqst,
236236
cpu_to_le32(expected_sequence_number);
237237
cifs_pdu->Signature.Sequence.Reserved = 0;
238238

239-
mutex_lock(&server->srv_mutex);
239+
cifs_server_lock(server);
240240
rc = cifs_calc_signature(rqst, server, what_we_think_sig_should_be);
241-
mutex_unlock(&server->srv_mutex);
241+
cifs_server_unlock(server);
242242

243243
if (rc)
244244
return rc;
@@ -626,7 +626,7 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
626626

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

629-
mutex_lock(&ses->server->srv_mutex);
629+
cifs_server_lock(ses->server);
630630

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

680680
unlock:
681-
mutex_unlock(&ses->server->srv_mutex);
681+
cifs_server_unlock(ses->server);
682682
setup_ntlmv2_rsp_ret:
683683
kfree(tiblob);
684684

fs/cifs/cifsfs.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -838,7 +838,7 @@ cifs_smb3_do_mount(struct file_system_type *fs_type,
838838
int flags, struct smb3_fs_context *old_ctx)
839839
{
840840
int rc;
841-
struct super_block *sb;
841+
struct super_block *sb = NULL;
842842
struct cifs_sb_info *cifs_sb = NULL;
843843
struct cifs_mnt_data mnt_data;
844844
struct dentry *root;
@@ -934,9 +934,11 @@ cifs_smb3_do_mount(struct file_system_type *fs_type,
934934
return root;
935935
out:
936936
if (cifs_sb) {
937-
kfree(cifs_sb->prepath);
938-
smb3_cleanup_fs_context(cifs_sb->ctx);
939-
kfree(cifs_sb);
937+
if (!sb || IS_ERR(sb)) { /* otherwise kill_sb will handle */
938+
kfree(cifs_sb->prepath);
939+
smb3_cleanup_fs_context(cifs_sb->ctx);
940+
kfree(cifs_sb);
941+
}
940942
}
941943
return root;
942944
}

fs/cifs/cifsfs.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ extern struct dentry *cifs_smb3_do_mount(struct file_system_type *fs_type,
152152
extern const struct export_operations cifs_export_ops;
153153
#endif /* CONFIG_CIFS_NFSD_EXPORT */
154154

155-
#define SMB3_PRODUCT_BUILD 35
156-
#define CIFS_VERSION "2.36"
155+
/* when changing internal version - update following two lines at same time */
156+
#define SMB3_PRODUCT_BUILD 37
157+
#define CIFS_VERSION "2.37"
157158
#endif /* _CIFSFS_H */

fs/cifs/cifsglob.h

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <linux/mempool.h>
1717
#include <linux/workqueue.h>
1818
#include <linux/utsname.h>
19+
#include <linux/sched/mm.h>
1920
#include <linux/netfs.h>
2021
#include "cifs_fs_sb.h"
2122
#include "cifsacl.h"
@@ -628,7 +629,8 @@ struct TCP_Server_Info {
628629
unsigned int in_flight; /* number of requests on the wire to server */
629630
unsigned int max_in_flight; /* max number of requests that were on wire */
630631
spinlock_t req_lock; /* protect the two values above */
631-
struct mutex srv_mutex;
632+
struct mutex _srv_mutex;
633+
unsigned int nofs_flag;
632634
struct task_struct *tsk;
633635
char server_GUID[16];
634636
__u16 sec_mode;
@@ -743,6 +745,22 @@ struct TCP_Server_Info {
743745
#endif
744746
};
745747

748+
static inline void cifs_server_lock(struct TCP_Server_Info *server)
749+
{
750+
unsigned int nofs_flag = memalloc_nofs_save();
751+
752+
mutex_lock(&server->_srv_mutex);
753+
server->nofs_flag = nofs_flag;
754+
}
755+
756+
static inline void cifs_server_unlock(struct TCP_Server_Info *server)
757+
{
758+
unsigned int nofs_flag = server->nofs_flag;
759+
760+
mutex_unlock(&server->_srv_mutex);
761+
memalloc_nofs_restore(nofs_flag);
762+
}
763+
746764
struct cifs_credits {
747765
unsigned int value;
748766
unsigned int instance;
@@ -1945,11 +1963,13 @@ extern mempool_t *cifs_mid_poolp;
19451963

19461964
/* Operations for different SMB versions */
19471965
#define SMB1_VERSION_STRING "1.0"
1966+
#define SMB20_VERSION_STRING "2.0"
1967+
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
19481968
extern struct smb_version_operations smb1_operations;
19491969
extern struct smb_version_values smb1_values;
1950-
#define SMB20_VERSION_STRING "2.0"
19511970
extern struct smb_version_operations smb20_operations;
19521971
extern struct smb_version_values smb20_values;
1972+
#endif /* CIFS_ALLOW_INSECURE_LEGACY */
19531973
#define SMB21_VERSION_STRING "2.1"
19541974
extern struct smb_version_operations smb21_operations;
19551975
extern struct smb_version_values smb21_values;

fs/cifs/connect.c

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ static void cifs_resolve_server(struct work_struct *work)
148148
struct TCP_Server_Info *server = container_of(work,
149149
struct TCP_Server_Info, resolve.work);
150150

151-
mutex_lock(&server->srv_mutex);
151+
cifs_server_lock(server);
152152

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

162-
mutex_unlock(&server->srv_mutex);
162+
cifs_server_unlock(server);
163163
}
164164

165165
/*
@@ -267,7 +267,7 @@ cifs_abort_connection(struct TCP_Server_Info *server)
267267

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

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

308308
if (cifs_rdma_enabled(server)) {
309-
mutex_lock(&server->srv_mutex);
309+
cifs_server_lock(server);
310310
smbd_destroy(server);
311-
mutex_unlock(&server->srv_mutex);
311+
cifs_server_unlock(server);
312312
}
313313
}
314314

@@ -359,7 +359,7 @@ static int __cifs_reconnect(struct TCP_Server_Info *server,
359359

360360
do {
361361
try_to_freeze();
362-
mutex_lock(&server->srv_mutex);
362+
cifs_server_lock(server);
363363

364364
if (!cifs_swn_set_server_dstaddr(server)) {
365365
/* resolve the hostname again to make sure that IP address is up-to-date */
@@ -372,7 +372,7 @@ static int __cifs_reconnect(struct TCP_Server_Info *server,
372372
else
373373
rc = generic_ip_connect(server);
374374
if (rc) {
375-
mutex_unlock(&server->srv_mutex);
375+
cifs_server_unlock(server);
376376
cifs_dbg(FYI, "%s: reconnect error %d\n", __func__, rc);
377377
msleep(3000);
378378
} else {
@@ -383,7 +383,7 @@ static int __cifs_reconnect(struct TCP_Server_Info *server,
383383
server->tcpStatus = CifsNeedNegotiate;
384384
spin_unlock(&cifs_tcp_ses_lock);
385385
cifs_swn_reset_server_dstaddr(server);
386-
mutex_unlock(&server->srv_mutex);
386+
cifs_server_unlock(server);
387387
mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
388388
}
389389
} while (server->tcpStatus == CifsNeedReconnect);
@@ -488,12 +488,12 @@ static int reconnect_dfs_server(struct TCP_Server_Info *server)
488488

489489
do {
490490
try_to_freeze();
491-
mutex_lock(&server->srv_mutex);
491+
cifs_server_lock(server);
492492

493493
rc = reconnect_target_unlocked(server, &tl, &target_hint);
494494
if (rc) {
495495
/* Failed to reconnect socket */
496-
mutex_unlock(&server->srv_mutex);
496+
cifs_server_unlock(server);
497497
cifs_dbg(FYI, "%s: reconnect error %d\n", __func__, rc);
498498
msleep(3000);
499499
continue;
@@ -510,7 +510,7 @@ static int reconnect_dfs_server(struct TCP_Server_Info *server)
510510
server->tcpStatus = CifsNeedNegotiate;
511511
spin_unlock(&cifs_tcp_ses_lock);
512512
cifs_swn_reset_server_dstaddr(server);
513-
mutex_unlock(&server->srv_mutex);
513+
cifs_server_unlock(server);
514514
mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
515515
} while (server->tcpStatus == CifsNeedReconnect);
516516

@@ -1565,7 +1565,7 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx,
15651565
init_waitqueue_head(&tcp_ses->response_q);
15661566
init_waitqueue_head(&tcp_ses->request_q);
15671567
INIT_LIST_HEAD(&tcp_ses->pending_mid_q);
1568-
mutex_init(&tcp_ses->srv_mutex);
1568+
mutex_init(&tcp_ses->_srv_mutex);
15691569
memcpy(tcp_ses->workstation_RFC1001_name,
15701570
ctx->source_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
15711571
memcpy(tcp_ses->server_RFC1001_name,
@@ -1845,7 +1845,6 @@ void cifs_put_smb_ses(struct cifs_ses *ses)
18451845
unsigned int rc, xid;
18461846
unsigned int chan_count;
18471847
struct TCP_Server_Info *server = ses->server;
1848-
cifs_dbg(FYI, "%s: ses_count=%d\n", __func__, ses->ses_count);
18491848

18501849
spin_lock(&cifs_tcp_ses_lock);
18511850
if (ses->ses_status == SES_EXITING) {

fs/cifs/dfs_cache.c

Lines changed: 52 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1229,6 +1229,30 @@ void dfs_cache_put_refsrv_sessions(const uuid_t *mount_id)
12291229
kref_put(&mg->refcount, mount_group_release);
12301230
}
12311231

1232+
/* Extract share from DFS target and return a pointer to prefix path or NULL */
1233+
static const char *parse_target_share(const char *target, char **share)
1234+
{
1235+
const char *s, *seps = "/\\";
1236+
size_t len;
1237+
1238+
s = strpbrk(target + 1, seps);
1239+
if (!s)
1240+
return ERR_PTR(-EINVAL);
1241+
1242+
len = strcspn(s + 1, seps);
1243+
if (!len)
1244+
return ERR_PTR(-EINVAL);
1245+
s += len;
1246+
1247+
len = s - target + 1;
1248+
*share = kstrndup(target, len, GFP_KERNEL);
1249+
if (!*share)
1250+
return ERR_PTR(-ENOMEM);
1251+
1252+
s = target + len;
1253+
return s + strspn(s, seps);
1254+
}
1255+
12321256
/**
12331257
* dfs_cache_get_tgt_share - parse a DFS target
12341258
*
@@ -1242,56 +1266,46 @@ void dfs_cache_put_refsrv_sessions(const uuid_t *mount_id)
12421266
int dfs_cache_get_tgt_share(char *path, const struct dfs_cache_tgt_iterator *it, char **share,
12431267
char **prefix)
12441268
{
1245-
char *s, sep, *p;
1246-
size_t len;
1247-
size_t plen1, plen2;
1269+
char sep;
1270+
char *target_share;
1271+
char *ppath = NULL;
1272+
const char *target_ppath, *dfsref_ppath;
1273+
size_t target_pplen, dfsref_pplen;
1274+
size_t len, c;
12481275

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

1252-
*share = NULL;
1253-
*prefix = NULL;
1254-
12551279
sep = it->it_name[0];
12561280
if (sep != '\\' && sep != '/')
12571281
return -EINVAL;
12581282

1259-
s = strchr(it->it_name + 1, sep);
1260-
if (!s)
1261-
return -EINVAL;
1283+
target_ppath = parse_target_share(it->it_name, &target_share);
1284+
if (IS_ERR(target_ppath))
1285+
return PTR_ERR(target_ppath);
12621286

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

1266-
/* extract target share */
1267-
*share = kstrndup(it->it_name, s - it->it_name, GFP_KERNEL);
1268-
if (!*share)
1269-
return -ENOMEM;
1291+
target_pplen = strlen(target_ppath);
1292+
dfsref_pplen = strlen(dfsref_ppath);
12701293

1271-
/* skip separator */
1272-
if (*s)
1273-
s++;
1274-
/* point to prefix in DFS path */
1275-
p = path + it->it_path_consumed;
1276-
if (*p == sep)
1277-
p++;
1278-
1279-
/* merge prefix paths from DFS path and target node */
1280-
plen1 = it->it_name + strlen(it->it_name) - s;
1281-
plen2 = path + strlen(path) - p;
1282-
if (plen1 || plen2) {
1283-
len = plen1 + plen2 + 2;
1284-
*prefix = kmalloc(len, GFP_KERNEL);
1285-
if (!*prefix) {
1286-
kfree(*share);
1287-
*share = NULL;
1294+
/* merge prefix paths from DFS referral path and target node */
1295+
if (target_pplen || dfsref_pplen) {
1296+
len = target_pplen + dfsref_pplen + 2;
1297+
ppath = kzalloc(len, GFP_KERNEL);
1298+
if (!ppath) {
1299+
kfree(target_share);
12881300
return -ENOMEM;
12891301
}
1290-
if (plen1)
1291-
scnprintf(*prefix, len, "%.*s%c%.*s", (int)plen1, s, sep, (int)plen2, p);
1292-
else
1293-
strscpy(*prefix, p, len);
1302+
c = strscpy(ppath, target_ppath, len);
1303+
if (c && dfsref_pplen)
1304+
ppath[c] = sep;
1305+
strlcat(ppath, dfsref_ppath, len);
12941306
}
1307+
*share = target_share;
1308+
*prefix = ppath;
12951309
return 0;
12961310
}
12971311

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

13351349
kfree(ip);

0 commit comments

Comments
 (0)