diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-28 12:51:56 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-28 12:51:56 -0400 |
commit | cac264288abe0f54b91e51d97c949b706c9435c7 (patch) | |
tree | bec86258708d5f7a9bce34de14fcaed58bc46e34 | |
parent | 0d95cfa922c24bcc20b5ccf7496b6ac7c8e29efb (diff) | |
parent | 8bcda1d2a79da4ab84162574eee2c9f6e1a12a03 (diff) |
Merge tag '4.17-rc2-smb3' of git://git.samba.org/sfrench/cifs-2.6
Pull cifs fixes from Steve French:
"A few security related fixes for SMB3, most importantly for SMB3.11
encryption"
* tag '4.17-rc2-smb3' of git://git.samba.org/sfrench/cifs-2.6:
cifs: smbd: Avoid allocating iov on the stack
cifs: smbd: Don't use RDMA read/write when signing is used
SMB311: Fix reconnect
SMB3: Fix 3.11 encryption to Windows and handle encrypted smb3 tcon
CIFS: set *resp_buf_type to NO_BUFFER on error
-rw-r--r-- | fs/cifs/cifssmb.c | 3 | ||||
-rw-r--r-- | fs/cifs/connect.c | 32 | ||||
-rw-r--r-- | fs/cifs/smb2ops.c | 18 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.c | 13 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.h | 2 | ||||
-rw-r--r-- | fs/cifs/smbdirect.c | 36 | ||||
-rw-r--r-- | fs/cifs/transport.c | 9 |
7 files changed, 59 insertions, 54 deletions
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 6d3e40d7029c..1529a088383d 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -455,6 +455,9 @@ cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required) | |||
455 | server->sign = true; | 455 | server->sign = true; |
456 | } | 456 | } |
457 | 457 | ||
458 | if (cifs_rdma_enabled(server) && server->sign) | ||
459 | cifs_dbg(VFS, "Signing is enabled, and RDMA read/write will be disabled"); | ||
460 | |||
458 | return 0; | 461 | return 0; |
459 | } | 462 | } |
460 | 463 | ||
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index e8830f076a7f..a5aa158d535a 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -2959,6 +2959,22 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info) | |||
2959 | } | 2959 | } |
2960 | } | 2960 | } |
2961 | 2961 | ||
2962 | if (volume_info->seal) { | ||
2963 | if (ses->server->vals->protocol_id == 0) { | ||
2964 | cifs_dbg(VFS, | ||
2965 | "SMB3 or later required for encryption\n"); | ||
2966 | rc = -EOPNOTSUPP; | ||
2967 | goto out_fail; | ||
2968 | } else if (tcon->ses->server->capabilities & | ||
2969 | SMB2_GLOBAL_CAP_ENCRYPTION) | ||
2970 | tcon->seal = true; | ||
2971 | else { | ||
2972 | cifs_dbg(VFS, "Encryption is not supported on share\n"); | ||
2973 | rc = -EOPNOTSUPP; | ||
2974 | goto out_fail; | ||
2975 | } | ||
2976 | } | ||
2977 | |||
2962 | /* | 2978 | /* |
2963 | * BB Do we need to wrap session_mutex around this TCon call and Unix | 2979 | * BB Do we need to wrap session_mutex around this TCon call and Unix |
2964 | * SetFS as we do on SessSetup and reconnect? | 2980 | * SetFS as we do on SessSetup and reconnect? |
@@ -3007,22 +3023,6 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info) | |||
3007 | tcon->use_resilient = true; | 3023 | tcon->use_resilient = true; |
3008 | } | 3024 | } |
3009 | 3025 | ||
3010 | if (volume_info->seal) { | ||
3011 | if (ses->server->vals->protocol_id == 0) { | ||
3012 | cifs_dbg(VFS, | ||
3013 | "SMB3 or later required for encryption\n"); | ||
3014 | rc = -EOPNOTSUPP; | ||
3015 | goto out_fail; | ||
3016 | } else if (tcon->ses->server->capabilities & | ||
3017 | SMB2_GLOBAL_CAP_ENCRYPTION) | ||
3018 | tcon->seal = true; | ||
3019 | else { | ||
3020 | cifs_dbg(VFS, "Encryption is not supported on share\n"); | ||
3021 | rc = -EOPNOTSUPP; | ||
3022 | goto out_fail; | ||
3023 | } | ||
3024 | } | ||
3025 | |||
3026 | /* | 3026 | /* |
3027 | * We can have only one retry value for a connection to a share so for | 3027 | * We can have only one retry value for a connection to a share so for |
3028 | * resources mounted more than once to the same server share the last | 3028 | * resources mounted more than once to the same server share the last |
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 38ebf3f357d2..b76b85881dcc 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c | |||
@@ -252,9 +252,14 @@ smb2_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info) | |||
252 | wsize = volume_info->wsize ? volume_info->wsize : CIFS_DEFAULT_IOSIZE; | 252 | wsize = volume_info->wsize ? volume_info->wsize : CIFS_DEFAULT_IOSIZE; |
253 | wsize = min_t(unsigned int, wsize, server->max_write); | 253 | wsize = min_t(unsigned int, wsize, server->max_write); |
254 | #ifdef CONFIG_CIFS_SMB_DIRECT | 254 | #ifdef CONFIG_CIFS_SMB_DIRECT |
255 | if (server->rdma) | 255 | if (server->rdma) { |
256 | wsize = min_t(unsigned int, | 256 | if (server->sign) |
257 | wsize = min_t(unsigned int, | ||
258 | wsize, server->smbd_conn->max_fragmented_send_size); | ||
259 | else | ||
260 | wsize = min_t(unsigned int, | ||
257 | wsize, server->smbd_conn->max_readwrite_size); | 261 | wsize, server->smbd_conn->max_readwrite_size); |
262 | } | ||
258 | #endif | 263 | #endif |
259 | if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU)) | 264 | if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU)) |
260 | wsize = min_t(unsigned int, wsize, SMB2_MAX_BUFFER_SIZE); | 265 | wsize = min_t(unsigned int, wsize, SMB2_MAX_BUFFER_SIZE); |
@@ -272,9 +277,14 @@ smb2_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info) | |||
272 | rsize = volume_info->rsize ? volume_info->rsize : CIFS_DEFAULT_IOSIZE; | 277 | rsize = volume_info->rsize ? volume_info->rsize : CIFS_DEFAULT_IOSIZE; |
273 | rsize = min_t(unsigned int, rsize, server->max_read); | 278 | rsize = min_t(unsigned int, rsize, server->max_read); |
274 | #ifdef CONFIG_CIFS_SMB_DIRECT | 279 | #ifdef CONFIG_CIFS_SMB_DIRECT |
275 | if (server->rdma) | 280 | if (server->rdma) { |
276 | rsize = min_t(unsigned int, | 281 | if (server->sign) |
282 | rsize = min_t(unsigned int, | ||
283 | rsize, server->smbd_conn->max_fragmented_recv_size); | ||
284 | else | ||
285 | rsize = min_t(unsigned int, | ||
277 | rsize, server->smbd_conn->max_readwrite_size); | 286 | rsize, server->smbd_conn->max_readwrite_size); |
287 | } | ||
278 | #endif | 288 | #endif |
279 | 289 | ||
280 | if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU)) | 290 | if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU)) |
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 0f044c4a2dc9..60db51bae0e3 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c | |||
@@ -383,10 +383,10 @@ static void | |||
383 | build_encrypt_ctxt(struct smb2_encryption_neg_context *pneg_ctxt) | 383 | build_encrypt_ctxt(struct smb2_encryption_neg_context *pneg_ctxt) |
384 | { | 384 | { |
385 | pneg_ctxt->ContextType = SMB2_ENCRYPTION_CAPABILITIES; | 385 | pneg_ctxt->ContextType = SMB2_ENCRYPTION_CAPABILITIES; |
386 | pneg_ctxt->DataLength = cpu_to_le16(6); | 386 | pneg_ctxt->DataLength = cpu_to_le16(4); /* Cipher Count + le16 cipher */ |
387 | pneg_ctxt->CipherCount = cpu_to_le16(2); | 387 | pneg_ctxt->CipherCount = cpu_to_le16(1); |
388 | pneg_ctxt->Ciphers[0] = SMB2_ENCRYPTION_AES128_GCM; | 388 | /* pneg_ctxt->Ciphers[0] = SMB2_ENCRYPTION_AES128_GCM;*/ /* not supported yet */ |
389 | pneg_ctxt->Ciphers[1] = SMB2_ENCRYPTION_AES128_CCM; | 389 | pneg_ctxt->Ciphers[0] = SMB2_ENCRYPTION_AES128_CCM; |
390 | } | 390 | } |
391 | 391 | ||
392 | static void | 392 | static void |
@@ -444,6 +444,7 @@ static int decode_encrypt_ctx(struct TCP_Server_Info *server, | |||
444 | return -EINVAL; | 444 | return -EINVAL; |
445 | } | 445 | } |
446 | server->cipher_type = ctxt->Ciphers[0]; | 446 | server->cipher_type = ctxt->Ciphers[0]; |
447 | server->capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION; | ||
447 | return 0; | 448 | return 0; |
448 | } | 449 | } |
449 | 450 | ||
@@ -2590,7 +2591,7 @@ smb2_new_read_req(void **buf, unsigned int *total_len, | |||
2590 | * If we want to do a RDMA write, fill in and append | 2591 | * If we want to do a RDMA write, fill in and append |
2591 | * smbd_buffer_descriptor_v1 to the end of read request | 2592 | * smbd_buffer_descriptor_v1 to the end of read request |
2592 | */ | 2593 | */ |
2593 | if (server->rdma && rdata && | 2594 | if (server->rdma && rdata && !server->sign && |
2594 | rdata->bytes >= server->smbd_conn->rdma_readwrite_threshold) { | 2595 | rdata->bytes >= server->smbd_conn->rdma_readwrite_threshold) { |
2595 | 2596 | ||
2596 | struct smbd_buffer_descriptor_v1 *v1; | 2597 | struct smbd_buffer_descriptor_v1 *v1; |
@@ -2968,7 +2969,7 @@ smb2_async_writev(struct cifs_writedata *wdata, | |||
2968 | * If we want to do a server RDMA read, fill in and append | 2969 | * If we want to do a server RDMA read, fill in and append |
2969 | * smbd_buffer_descriptor_v1 to the end of write request | 2970 | * smbd_buffer_descriptor_v1 to the end of write request |
2970 | */ | 2971 | */ |
2971 | if (server->rdma && wdata->bytes >= | 2972 | if (server->rdma && !server->sign && wdata->bytes >= |
2972 | server->smbd_conn->rdma_readwrite_threshold) { | 2973 | server->smbd_conn->rdma_readwrite_threshold) { |
2973 | 2974 | ||
2974 | struct smbd_buffer_descriptor_v1 *v1; | 2975 | struct smbd_buffer_descriptor_v1 *v1; |
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h index 6093e5142b2b..d28f358022c5 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h | |||
@@ -297,7 +297,7 @@ struct smb2_encryption_neg_context { | |||
297 | __le16 DataLength; | 297 | __le16 DataLength; |
298 | __le32 Reserved; | 298 | __le32 Reserved; |
299 | __le16 CipherCount; /* AES-128-GCM and AES-128-CCM */ | 299 | __le16 CipherCount; /* AES-128-GCM and AES-128-CCM */ |
300 | __le16 Ciphers[2]; /* Ciphers[0] since only one used now */ | 300 | __le16 Ciphers[1]; /* Ciphers[0] since only one used now */ |
301 | } __packed; | 301 | } __packed; |
302 | 302 | ||
303 | struct smb2_negotiate_rsp { | 303 | struct smb2_negotiate_rsp { |
diff --git a/fs/cifs/smbdirect.c b/fs/cifs/smbdirect.c index 87817ddcc096..c62f7c95683c 100644 --- a/fs/cifs/smbdirect.c +++ b/fs/cifs/smbdirect.c | |||
@@ -2086,7 +2086,7 @@ int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst) | |||
2086 | int start, i, j; | 2086 | int start, i, j; |
2087 | int max_iov_size = | 2087 | int max_iov_size = |
2088 | info->max_send_size - sizeof(struct smbd_data_transfer); | 2088 | info->max_send_size - sizeof(struct smbd_data_transfer); |
2089 | struct kvec iov[SMBDIRECT_MAX_SGE]; | 2089 | struct kvec *iov; |
2090 | int rc; | 2090 | int rc; |
2091 | 2091 | ||
2092 | info->smbd_send_pending++; | 2092 | info->smbd_send_pending++; |
@@ -2096,32 +2096,20 @@ int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst) | |||
2096 | } | 2096 | } |
2097 | 2097 | ||
2098 | /* | 2098 | /* |
2099 | * This usually means a configuration error | 2099 | * Skip the RFC1002 length defined in MS-SMB2 section 2.1 |
2100 | * We use RDMA read/write for packet size > rdma_readwrite_threshold | 2100 | * It is used only for TCP transport in the iov[0] |
2101 | * as long as it's properly configured we should never get into this | ||
2102 | * situation | ||
2103 | */ | ||
2104 | if (rqst->rq_nvec + rqst->rq_npages > SMBDIRECT_MAX_SGE) { | ||
2105 | log_write(ERR, "maximum send segment %x exceeding %x\n", | ||
2106 | rqst->rq_nvec + rqst->rq_npages, SMBDIRECT_MAX_SGE); | ||
2107 | rc = -EINVAL; | ||
2108 | goto done; | ||
2109 | } | ||
2110 | |||
2111 | /* | ||
2112 | * Remove the RFC1002 length defined in MS-SMB2 section 2.1 | ||
2113 | * It is used only for TCP transport | ||
2114 | * In future we may want to add a transport layer under protocol | 2101 | * In future we may want to add a transport layer under protocol |
2115 | * layer so this will only be issued to TCP transport | 2102 | * layer so this will only be issued to TCP transport |
2116 | */ | 2103 | */ |
2117 | iov[0].iov_base = (char *)rqst->rq_iov[0].iov_base + 4; | 2104 | |
2118 | iov[0].iov_len = rqst->rq_iov[0].iov_len - 4; | 2105 | if (rqst->rq_iov[0].iov_len != 4) { |
2119 | buflen += iov[0].iov_len; | 2106 | log_write(ERR, "expected the pdu length in 1st iov, but got %zu\n", rqst->rq_iov[0].iov_len); |
2107 | return -EINVAL; | ||
2108 | } | ||
2109 | iov = &rqst->rq_iov[1]; | ||
2120 | 2110 | ||
2121 | /* total up iov array first */ | 2111 | /* total up iov array first */ |
2122 | for (i = 1; i < rqst->rq_nvec; i++) { | 2112 | for (i = 0; i < rqst->rq_nvec-1; i++) { |
2123 | iov[i].iov_base = rqst->rq_iov[i].iov_base; | ||
2124 | iov[i].iov_len = rqst->rq_iov[i].iov_len; | ||
2125 | buflen += iov[i].iov_len; | 2113 | buflen += iov[i].iov_len; |
2126 | } | 2114 | } |
2127 | 2115 | ||
@@ -2198,14 +2186,14 @@ int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst) | |||
2198 | goto done; | 2186 | goto done; |
2199 | } | 2187 | } |
2200 | i++; | 2188 | i++; |
2201 | if (i == rqst->rq_nvec) | 2189 | if (i == rqst->rq_nvec-1) |
2202 | break; | 2190 | break; |
2203 | } | 2191 | } |
2204 | start = i; | 2192 | start = i; |
2205 | buflen = 0; | 2193 | buflen = 0; |
2206 | } else { | 2194 | } else { |
2207 | i++; | 2195 | i++; |
2208 | if (i == rqst->rq_nvec) { | 2196 | if (i == rqst->rq_nvec-1) { |
2209 | /* send out all remaining vecs */ | 2197 | /* send out all remaining vecs */ |
2210 | remaining_data_length -= buflen; | 2198 | remaining_data_length -= buflen; |
2211 | log_write(INFO, | 2199 | log_write(INFO, |
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 8f6f25918229..927226a2122f 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
@@ -753,7 +753,7 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses, | |||
753 | goto out; | 753 | goto out; |
754 | 754 | ||
755 | #ifdef CONFIG_CIFS_SMB311 | 755 | #ifdef CONFIG_CIFS_SMB311 |
756 | if (ses->status == CifsNew) | 756 | if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP)) |
757 | smb311_update_preauth_hash(ses, rqst->rq_iov+1, | 757 | smb311_update_preauth_hash(ses, rqst->rq_iov+1, |
758 | rqst->rq_nvec-1); | 758 | rqst->rq_nvec-1); |
759 | #endif | 759 | #endif |
@@ -798,7 +798,7 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses, | |||
798 | *resp_buf_type = CIFS_SMALL_BUFFER; | 798 | *resp_buf_type = CIFS_SMALL_BUFFER; |
799 | 799 | ||
800 | #ifdef CONFIG_CIFS_SMB311 | 800 | #ifdef CONFIG_CIFS_SMB311 |
801 | if (ses->status == CifsNew) { | 801 | if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP)) { |
802 | struct kvec iov = { | 802 | struct kvec iov = { |
803 | .iov_base = buf + 4, | 803 | .iov_base = buf + 4, |
804 | .iov_len = get_rfc1002_length(buf) | 804 | .iov_len = get_rfc1002_length(buf) |
@@ -834,8 +834,11 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, | |||
834 | if (n_vec + 1 > CIFS_MAX_IOV_SIZE) { | 834 | if (n_vec + 1 > CIFS_MAX_IOV_SIZE) { |
835 | new_iov = kmalloc(sizeof(struct kvec) * (n_vec + 1), | 835 | new_iov = kmalloc(sizeof(struct kvec) * (n_vec + 1), |
836 | GFP_KERNEL); | 836 | GFP_KERNEL); |
837 | if (!new_iov) | 837 | if (!new_iov) { |
838 | /* otherwise cifs_send_recv below sets resp_buf_type */ | ||
839 | *resp_buf_type = CIFS_NO_BUFFER; | ||
838 | return -ENOMEM; | 840 | return -ENOMEM; |
841 | } | ||
839 | } else | 842 | } else |
840 | new_iov = s_iov; | 843 | new_iov = s_iov; |
841 | 844 | ||