hc
2024-05-10 9999e48639b3cecb08ffb37358bcba3b48161b29
kernel/fs/cifs/sess.c
....@@ -31,6 +31,284 @@
3131 #include <linux/utsname.h>
3232 #include <linux/slab.h>
3333 #include "cifs_spnego.h"
34
+#include "smb2proto.h"
35
+
36
+bool
37
+is_server_using_iface(struct TCP_Server_Info *server,
38
+ struct cifs_server_iface *iface)
39
+{
40
+ struct sockaddr_in *i4 = (struct sockaddr_in *)&iface->sockaddr;
41
+ struct sockaddr_in6 *i6 = (struct sockaddr_in6 *)&iface->sockaddr;
42
+ struct sockaddr_in *s4 = (struct sockaddr_in *)&server->dstaddr;
43
+ struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)&server->dstaddr;
44
+
45
+ if (server->dstaddr.ss_family != iface->sockaddr.ss_family)
46
+ return false;
47
+ if (server->dstaddr.ss_family == AF_INET) {
48
+ if (s4->sin_addr.s_addr != i4->sin_addr.s_addr)
49
+ return false;
50
+ } else if (server->dstaddr.ss_family == AF_INET6) {
51
+ if (memcmp(&s6->sin6_addr, &i6->sin6_addr,
52
+ sizeof(i6->sin6_addr)) != 0)
53
+ return false;
54
+ } else {
55
+ /* unknown family.. */
56
+ return false;
57
+ }
58
+ return true;
59
+}
60
+
61
+bool is_ses_using_iface(struct cifs_ses *ses, struct cifs_server_iface *iface)
62
+{
63
+ int i;
64
+
65
+ for (i = 0; i < ses->chan_count; i++) {
66
+ if (is_server_using_iface(ses->chans[i].server, iface))
67
+ return true;
68
+ }
69
+ return false;
70
+}
71
+
72
+/* returns number of channels added */
73
+int cifs_try_adding_channels(struct cifs_ses *ses)
74
+{
75
+ int old_chan_count = ses->chan_count;
76
+ int left = ses->chan_max - ses->chan_count;
77
+ int i = 0;
78
+ int rc = 0;
79
+ int tries = 0;
80
+ struct cifs_server_iface *ifaces = NULL;
81
+ size_t iface_count;
82
+
83
+ if (left <= 0) {
84
+ cifs_dbg(FYI,
85
+ "ses already at max_channels (%zu), nothing to open\n",
86
+ ses->chan_max);
87
+ return 0;
88
+ }
89
+
90
+ if (ses->server->dialect < SMB30_PROT_ID) {
91
+ cifs_dbg(VFS, "multichannel is not supported on this protocol version, use 3.0 or above\n");
92
+ return 0;
93
+ }
94
+
95
+ if (!(ses->server->capabilities & SMB2_GLOBAL_CAP_MULTI_CHANNEL)) {
96
+ cifs_dbg(VFS, "server %s does not support multichannel\n", ses->server->hostname);
97
+ ses->chan_max = 1;
98
+ return 0;
99
+ }
100
+
101
+ /*
102
+ * Make a copy of the iface list at the time and use that
103
+ * instead so as to not hold the iface spinlock for opening
104
+ * channels
105
+ */
106
+ spin_lock(&ses->iface_lock);
107
+ iface_count = ses->iface_count;
108
+ if (iface_count <= 0) {
109
+ spin_unlock(&ses->iface_lock);
110
+ cifs_dbg(VFS, "no iface list available to open channels\n");
111
+ return 0;
112
+ }
113
+ ifaces = kmemdup(ses->iface_list, iface_count*sizeof(*ifaces),
114
+ GFP_ATOMIC);
115
+ if (!ifaces) {
116
+ spin_unlock(&ses->iface_lock);
117
+ return 0;
118
+ }
119
+ spin_unlock(&ses->iface_lock);
120
+
121
+ /*
122
+ * Keep connecting to same, fastest, iface for all channels as
123
+ * long as its RSS. Try next fastest one if not RSS or channel
124
+ * creation fails.
125
+ */
126
+ while (left > 0) {
127
+ struct cifs_server_iface *iface;
128
+
129
+ tries++;
130
+ if (tries > 3*ses->chan_max) {
131
+ cifs_dbg(FYI, "too many channel open attempts (%d channels left to open)\n",
132
+ left);
133
+ break;
134
+ }
135
+
136
+ iface = &ifaces[i];
137
+ if (is_ses_using_iface(ses, iface) && !iface->rss_capable) {
138
+ i = (i+1) % iface_count;
139
+ continue;
140
+ }
141
+
142
+ rc = cifs_ses_add_channel(ses, iface);
143
+ if (rc) {
144
+ cifs_dbg(FYI, "failed to open extra channel on iface#%d rc=%d\n",
145
+ i, rc);
146
+ i = (i+1) % iface_count;
147
+ continue;
148
+ }
149
+
150
+ cifs_dbg(FYI, "successfully opened new channel on iface#%d\n",
151
+ i);
152
+ left--;
153
+ }
154
+
155
+ kfree(ifaces);
156
+ return ses->chan_count - old_chan_count;
157
+}
158
+
159
+/*
160
+ * If server is a channel of ses, return the corresponding enclosing
161
+ * cifs_chan otherwise return NULL.
162
+ */
163
+struct cifs_chan *
164
+cifs_ses_find_chan(struct cifs_ses *ses, struct TCP_Server_Info *server)
165
+{
166
+ int i;
167
+
168
+ for (i = 0; i < ses->chan_count; i++) {
169
+ if (ses->chans[i].server == server)
170
+ return &ses->chans[i];
171
+ }
172
+ return NULL;
173
+}
174
+
175
+int
176
+cifs_ses_add_channel(struct cifs_ses *ses, struct cifs_server_iface *iface)
177
+{
178
+ struct cifs_chan *chan;
179
+ struct smb_vol vol = {NULL};
180
+ static const char unc_fmt[] = "\\%s\\foo";
181
+ char unc[sizeof(unc_fmt)+SERVER_NAME_LEN_WITH_NULL] = {0};
182
+ struct sockaddr_in *ipv4 = (struct sockaddr_in *)&iface->sockaddr;
183
+ struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)&iface->sockaddr;
184
+ int rc;
185
+ unsigned int xid = get_xid();
186
+
187
+ if (iface->sockaddr.ss_family == AF_INET)
188
+ cifs_dbg(FYI, "adding channel to ses %p (speed:%zu bps rdma:%s ip:%pI4)\n",
189
+ ses, iface->speed, iface->rdma_capable ? "yes" : "no",
190
+ &ipv4->sin_addr);
191
+ else
192
+ cifs_dbg(FYI, "adding channel to ses %p (speed:%zu bps rdma:%s ip:%pI4)\n",
193
+ ses, iface->speed, iface->rdma_capable ? "yes" : "no",
194
+ &ipv6->sin6_addr);
195
+
196
+ /*
197
+ * Setup a smb_vol with mostly the same info as the existing
198
+ * session and overwrite it with the requested iface data.
199
+ *
200
+ * We need to setup at least the fields used for negprot and
201
+ * sesssetup.
202
+ *
203
+ * We only need the volume here, so we can reuse memory from
204
+ * the session and server without caring about memory
205
+ * management.
206
+ */
207
+
208
+ /* Always make new connection for now (TODO?) */
209
+ vol.nosharesock = true;
210
+
211
+ /* Auth */
212
+ vol.domainauto = ses->domainAuto;
213
+ vol.domainname = ses->domainName;
214
+ vol.username = ses->user_name;
215
+ vol.password = ses->password;
216
+ vol.sectype = ses->sectype;
217
+ vol.sign = ses->sign;
218
+
219
+ /* UNC and paths */
220
+ /* XXX: Use ses->server->hostname? */
221
+ sprintf(unc, unc_fmt, ses->serverName);
222
+ vol.UNC = unc;
223
+ vol.prepath = "";
224
+
225
+ /* Reuse same version as master connection */
226
+ vol.vals = ses->server->vals;
227
+ vol.ops = ses->server->ops;
228
+
229
+ vol.noblocksnd = ses->server->noblocksnd;
230
+ vol.noautotune = ses->server->noautotune;
231
+ vol.sockopt_tcp_nodelay = ses->server->tcp_nodelay;
232
+ vol.echo_interval = ses->server->echo_interval / HZ;
233
+ vol.max_credits = ses->server->max_credits;
234
+
235
+ /*
236
+ * This will be used for encoding/decoding user/domain/pw
237
+ * during sess setup auth.
238
+ *
239
+ * XXX: We use the default for simplicity but the proper way
240
+ * would be to use the one that ses used, which is not
241
+ * stored. This might break when dealing with non-ascii
242
+ * strings.
243
+ */
244
+ vol.local_nls = load_nls_default();
245
+
246
+ /* Use RDMA if possible */
247
+ vol.rdma = iface->rdma_capable;
248
+ memcpy(&vol.dstaddr, &iface->sockaddr, sizeof(struct sockaddr_storage));
249
+
250
+ /* reuse master con client guid */
251
+ memcpy(&vol.client_guid, ses->server->client_guid,
252
+ SMB2_CLIENT_GUID_SIZE);
253
+ vol.use_client_guid = true;
254
+
255
+ mutex_lock(&ses->session_mutex);
256
+
257
+ chan = ses->binding_chan = &ses->chans[ses->chan_count];
258
+ chan->server = cifs_get_tcp_session(&vol);
259
+ if (IS_ERR(chan->server)) {
260
+ rc = PTR_ERR(chan->server);
261
+ chan->server = NULL;
262
+ goto out;
263
+ }
264
+ spin_lock(&cifs_tcp_ses_lock);
265
+ chan->server->is_channel = true;
266
+ spin_unlock(&cifs_tcp_ses_lock);
267
+
268
+ /*
269
+ * We need to allocate the server crypto now as we will need
270
+ * to sign packets before we generate the channel signing key
271
+ * (we sign with the session key)
272
+ */
273
+ rc = smb311_crypto_shash_allocate(chan->server);
274
+ if (rc) {
275
+ cifs_dbg(VFS, "%s: crypto alloc failed\n", __func__);
276
+ goto out;
277
+ }
278
+
279
+ ses->binding = true;
280
+ rc = cifs_negotiate_protocol(xid, ses);
281
+ if (rc)
282
+ goto out;
283
+
284
+ rc = cifs_setup_session(xid, ses, vol.local_nls);
285
+ if (rc)
286
+ goto out;
287
+
288
+ /* success, put it on the list
289
+ * XXX: sharing ses between 2 tcp servers is not possible, the
290
+ * way "internal" linked lists works in linux makes element
291
+ * only able to belong to one list
292
+ *
293
+ * the binding session is already established so the rest of
294
+ * the code should be able to look it up, no need to add the
295
+ * ses to the new server.
296
+ */
297
+
298
+ ses->chan_count++;
299
+ atomic_set(&ses->chan_seq, 0);
300
+out:
301
+ ses->binding = false;
302
+ ses->binding_chan = NULL;
303
+ mutex_unlock(&ses->session_mutex);
304
+
305
+ if (rc && chan->server)
306
+ cifs_put_tcp_session(chan->server, 0);
307
+ unload_nls(vol.local_nls);
308
+
309
+ free_xid(xid);
310
+ return rc;
311
+}
34312
35313 static __u32 cifs_ssetup_hdr(struct cifs_ses *ses, SESSION_SETUP_ANDX *pSMB)
36314 {
....@@ -159,13 +437,16 @@
159437 const struct nls_table *nls_cp)
160438 {
161439 char *bcc_ptr = *pbcc_area;
440
+ int len;
162441
163442 /* copy user */
164443 /* BB what about null user mounts - check that we do this BB */
165444 /* copy user */
166445 if (ses->user_name != NULL) {
167
- strncpy(bcc_ptr, ses->user_name, CIFS_MAX_USERNAME_LEN);
168
- bcc_ptr += strnlen(ses->user_name, CIFS_MAX_USERNAME_LEN);
446
+ len = strscpy(bcc_ptr, ses->user_name, CIFS_MAX_USERNAME_LEN);
447
+ if (WARN_ON_ONCE(len < 0))
448
+ len = CIFS_MAX_USERNAME_LEN - 1;
449
+ bcc_ptr += len;
169450 }
170451 /* else null user mount */
171452 *bcc_ptr = 0;
....@@ -173,8 +454,10 @@
173454
174455 /* copy domain */
175456 if (ses->domainName != NULL) {
176
- strncpy(bcc_ptr, ses->domainName, CIFS_MAX_DOMAINNAME_LEN);
177
- bcc_ptr += strnlen(ses->domainName, CIFS_MAX_DOMAINNAME_LEN);
457
+ len = strscpy(bcc_ptr, ses->domainName, CIFS_MAX_DOMAINNAME_LEN);
458
+ if (WARN_ON_ONCE(len < 0))
459
+ len = CIFS_MAX_DOMAINNAME_LEN - 1;
460
+ bcc_ptr += len;
178461 } /* else we will send a null domain name
179462 so the server will default to its own domain */
180463 *bcc_ptr = 0;
....@@ -242,9 +525,10 @@
242525
243526 kfree(ses->serverOS);
244527
245
- ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
528
+ ses->serverOS = kmalloc(len + 1, GFP_KERNEL);
246529 if (ses->serverOS) {
247
- strncpy(ses->serverOS, bcc_ptr, len);
530
+ memcpy(ses->serverOS, bcc_ptr, len);
531
+ ses->serverOS[len] = 0;
248532 if (strncmp(ses->serverOS, "OS/2", 4) == 0)
249533 cifs_dbg(FYI, "OS/2 server\n");
250534 }
....@@ -258,9 +542,11 @@
258542
259543 kfree(ses->serverNOS);
260544
261
- ses->serverNOS = kzalloc(len + 1, GFP_KERNEL);
262
- if (ses->serverNOS)
263
- strncpy(ses->serverNOS, bcc_ptr, len);
545
+ ses->serverNOS = kmalloc(len + 1, GFP_KERNEL);
546
+ if (ses->serverNOS) {
547
+ memcpy(ses->serverNOS, bcc_ptr, len);
548
+ ses->serverNOS[len] = 0;
549
+ }
264550
265551 bcc_ptr += len + 1;
266552 bleft -= len + 1;
....@@ -310,15 +596,15 @@
310596 tioffset = le32_to_cpu(pblob->TargetInfoArray.BufferOffset);
311597 tilen = le16_to_cpu(pblob->TargetInfoArray.Length);
312598 if (tioffset > blob_len || tioffset + tilen > blob_len) {
313
- cifs_dbg(VFS, "tioffset + tilen too high %u + %u",
314
- tioffset, tilen);
599
+ cifs_dbg(VFS, "tioffset + tilen too high %u + %u\n",
600
+ tioffset, tilen);
315601 return -EINVAL;
316602 }
317603 if (tilen) {
318604 ses->auth_key.response = kmemdup(bcc_ptr + tioffset, tilen,
319605 GFP_KERNEL);
320606 if (!ses->auth_key.response) {
321
- cifs_dbg(VFS, "Challenge target info alloc failure");
607
+ cifs_dbg(VFS, "Challenge target info alloc failure\n");
322608 return -ENOMEM;
323609 }
324610 ses->auth_key.len = tilen;
....@@ -334,6 +620,7 @@
334620 void build_ntlmssp_negotiate_blob(unsigned char *pbuffer,
335621 struct cifs_ses *ses)
336622 {
623
+ struct TCP_Server_Info *server = cifs_ses_server(ses);
337624 NEGOTIATE_MESSAGE *sec_blob = (NEGOTIATE_MESSAGE *)pbuffer;
338625 __u32 flags;
339626
....@@ -346,9 +633,9 @@
346633 NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
347634 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC |
348635 NTLMSSP_NEGOTIATE_SEAL;
349
- if (ses->server->sign)
636
+ if (server->sign)
350637 flags |= NTLMSSP_NEGOTIATE_SIGN;
351
- if (!ses->server->session_estab || ses->ntlmssp->sesskey_per_smbsess)
638
+ if (!server->session_estab || ses->ntlmssp->sesskey_per_smbsess)
352639 flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
353640
354641 sec_blob->NegotiateFlags = cpu_to_le32(flags);
....@@ -519,7 +806,7 @@
519806 if ((server->sec_kerberos || server->sec_mskerberos) &&
520807 (global_secflags & CIFSSEC_MAY_KRB5))
521808 return Kerberos;
522
- /* Fallthrough */
809
+ fallthrough;
523810 default:
524811 return Unspecified;
525812 }
....@@ -534,9 +821,9 @@
534821 if (global_secflags & CIFSSEC_MAY_NTLM)
535822 return NTLM;
536823 default:
537
- /* Fallthrough to attempt LANMAN authentication next */
538824 break;
539825 }
826
+ fallthrough; /* to attempt LANMAN authentication next */
540827 case CIFS_NEGFLAVOR_LANMAN:
541828 switch (requested) {
542829 case LANMAN:
....@@ -544,7 +831,7 @@
544831 case Unspecified:
545832 if (global_secflags & CIFSSEC_MAY_LANMAN)
546833 return LANMAN;
547
- /* Fallthrough */
834
+ fallthrough;
548835 default:
549836 return Unspecified;
550837 }
....@@ -659,8 +946,7 @@
659946 struct kvec rsp_iov = { NULL, 0 };
660947
661948 count = sess_data->iov[1].iov_len + sess_data->iov[2].iov_len;
662
- smb_buf->smb_buf_length =
663
- cpu_to_be32(be32_to_cpu(smb_buf->smb_buf_length) + count);
949
+ be32_add_cpu(&smb_buf->smb_buf_length, count);
664950 put_bcc(count, smb_buf);
665951
666952 rc = SendReceive2(sess_data->xid, sess_data->ses,
....@@ -690,7 +976,6 @@
690976 char *bcc_ptr;
691977 struct cifs_ses *ses = sess_data->ses;
692978 char lnm_session_key[CIFS_AUTH_RESP_SIZE];
693
- __u32 capabilities;
694979 __u16 bytes_remaining;
695980
696981 /* lanman 2 style sessionsetup */
....@@ -701,7 +986,7 @@
701986
702987 pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
703988 bcc_ptr = sess_data->iov[2].iov_base;
704
- capabilities = cifs_ssetup_hdr(ses, pSMB);
989
+ (void)cifs_ssetup_hdr(ses, pSMB);
705990
706991 pSMB->req.hdr.Flags2 &= ~SMBFLG2_UNICODE;
707992
....@@ -711,7 +996,7 @@
711996
712997 /* Calculate hash with password and copy into bcc_ptr.
713998 * Encryption Key (stored as in cryptkey) gets used if the
714
- * security mode bit in Negottiate Protocol response states
999
+ * security mode bit in Negotiate Protocol response states
7151000 * to use challenge/response method (i.e. Password bit is 1).
7161001 */
7171002 rc = calc_lanman_hash(ses->password, ses->server->cryptkey,
....@@ -1044,9 +1329,8 @@
10441329 * sending us a response in an expected form
10451330 */
10461331 if (msg->version != CIFS_SPNEGO_UPCALL_VERSION) {
1047
- cifs_dbg(VFS,
1048
- "incorrect version of cifs.upcall (expected %d but got %d)",
1049
- CIFS_SPNEGO_UPCALL_VERSION, msg->version);
1332
+ cifs_dbg(VFS, "incorrect version of cifs.upcall (expected %d but got %d)\n",
1333
+ CIFS_SPNEGO_UPCALL_VERSION, msg->version);
10501334 rc = -EKEYREJECTED;
10511335 goto out_put_spnego_key;
10521336 }
....@@ -1054,8 +1338,8 @@
10541338 ses->auth_key.response = kmemdup(msg->data, msg->sesskey_len,
10551339 GFP_KERNEL);
10561340 if (!ses->auth_key.response) {
1057
- cifs_dbg(VFS, "Kerberos can't allocate (%u bytes) memory",
1058
- msg->sesskey_len);
1341
+ cifs_dbg(VFS, "Kerberos can't allocate (%u bytes) memory\n",
1342
+ msg->sesskey_len);
10591343 rc = -ENOMEM;
10601344 goto out_put_spnego_key;
10611345 }
....@@ -1154,14 +1438,12 @@
11541438 static int
11551439 _sess_auth_rawntlmssp_assemble_req(struct sess_data *sess_data)
11561440 {
1157
- struct smb_hdr *smb_buf;
11581441 SESSION_SETUP_ANDX *pSMB;
11591442 struct cifs_ses *ses = sess_data->ses;
11601443 __u32 capabilities;
11611444 char *bcc_ptr;
11621445
11631446 pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
1164
- smb_buf = (struct smb_hdr *)pSMB;
11651447
11661448 capabilities = cifs_ssetup_hdr(ses, pSMB);
11671449 if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) {
....@@ -1400,8 +1682,7 @@
14001682 type = cifs_select_sectype(ses->server, ses->sectype);
14011683 cifs_dbg(FYI, "sess setup type %d\n", type);
14021684 if (type == Unspecified) {
1403
- cifs_dbg(VFS,
1404
- "Unable to select appropriate authentication method!");
1685
+ cifs_dbg(VFS, "Unable to select appropriate authentication method!\n");
14051686 return -EINVAL;
14061687 }
14071688
....@@ -1431,7 +1712,6 @@
14311712 #else
14321713 cifs_dbg(VFS, "Kerberos negotiated but upcall support disabled!\n");
14331714 return -ENOSYS;
1434
- break;
14351715 #endif /* CONFIG_CIFS_UPCALL */
14361716 case RawNTLMSSP:
14371717 sess_data->func = sess_auth_rawntlmssp_negotiate;