Commit cac26428 authored by Linus Torvalds's avatar Linus Torvalds

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
parents 0d95cfa9 8bcda1d2
...@@ -455,6 +455,9 @@ cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required) ...@@ -455,6 +455,9 @@ cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required)
server->sign = true; server->sign = true;
} }
if (cifs_rdma_enabled(server) && server->sign)
cifs_dbg(VFS, "Signing is enabled, and RDMA read/write will be disabled");
return 0; return 0;
} }
......
...@@ -2959,6 +2959,22 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info) ...@@ -2959,6 +2959,22 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
} }
} }
if (volume_info->seal) {
if (ses->server->vals->protocol_id == 0) {
cifs_dbg(VFS,
"SMB3 or later required for encryption\n");
rc = -EOPNOTSUPP;
goto out_fail;
} else if (tcon->ses->server->capabilities &
SMB2_GLOBAL_CAP_ENCRYPTION)
tcon->seal = true;
else {
cifs_dbg(VFS, "Encryption is not supported on share\n");
rc = -EOPNOTSUPP;
goto out_fail;
}
}
/* /*
* BB Do we need to wrap session_mutex around this TCon call and Unix * BB Do we need to wrap session_mutex around this TCon call and Unix
* SetFS as we do on SessSetup and reconnect? * 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,22 +3023,6 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
tcon->use_resilient = true; tcon->use_resilient = true;
} }
if (volume_info->seal) {
if (ses->server->vals->protocol_id == 0) {
cifs_dbg(VFS,
"SMB3 or later required for encryption\n");
rc = -EOPNOTSUPP;
goto out_fail;
} else if (tcon->ses->server->capabilities &
SMB2_GLOBAL_CAP_ENCRYPTION)
tcon->seal = true;
else {
cifs_dbg(VFS, "Encryption is not supported on share\n");
rc = -EOPNOTSUPP;
goto out_fail;
}
}
/* /*
* We can have only one retry value for a connection to a share so for * We can have only one retry value for a connection to a share so for
* resources mounted more than once to the same server share the last * resources mounted more than once to the same server share the last
......
...@@ -252,9 +252,14 @@ smb2_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info) ...@@ -252,9 +252,14 @@ smb2_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
wsize = volume_info->wsize ? volume_info->wsize : CIFS_DEFAULT_IOSIZE; wsize = volume_info->wsize ? volume_info->wsize : CIFS_DEFAULT_IOSIZE;
wsize = min_t(unsigned int, wsize, server->max_write); wsize = min_t(unsigned int, wsize, server->max_write);
#ifdef CONFIG_CIFS_SMB_DIRECT #ifdef CONFIG_CIFS_SMB_DIRECT
if (server->rdma) if (server->rdma) {
wsize = min_t(unsigned int, if (server->sign)
wsize = min_t(unsigned int,
wsize, server->smbd_conn->max_fragmented_send_size);
else
wsize = min_t(unsigned int,
wsize, server->smbd_conn->max_readwrite_size); wsize, server->smbd_conn->max_readwrite_size);
}
#endif #endif
if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU)) if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
wsize = min_t(unsigned int, wsize, SMB2_MAX_BUFFER_SIZE); 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,9 +277,14 @@ smb2_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
rsize = volume_info->rsize ? volume_info->rsize : CIFS_DEFAULT_IOSIZE; rsize = volume_info->rsize ? volume_info->rsize : CIFS_DEFAULT_IOSIZE;
rsize = min_t(unsigned int, rsize, server->max_read); rsize = min_t(unsigned int, rsize, server->max_read);
#ifdef CONFIG_CIFS_SMB_DIRECT #ifdef CONFIG_CIFS_SMB_DIRECT
if (server->rdma) if (server->rdma) {
rsize = min_t(unsigned int, if (server->sign)
rsize = min_t(unsigned int,
rsize, server->smbd_conn->max_fragmented_recv_size);
else
rsize = min_t(unsigned int,
rsize, server->smbd_conn->max_readwrite_size); rsize, server->smbd_conn->max_readwrite_size);
}
#endif #endif
if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU)) if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
......
...@@ -383,10 +383,10 @@ static void ...@@ -383,10 +383,10 @@ static void
build_encrypt_ctxt(struct smb2_encryption_neg_context *pneg_ctxt) build_encrypt_ctxt(struct smb2_encryption_neg_context *pneg_ctxt)
{ {
pneg_ctxt->ContextType = SMB2_ENCRYPTION_CAPABILITIES; pneg_ctxt->ContextType = SMB2_ENCRYPTION_CAPABILITIES;
pneg_ctxt->DataLength = cpu_to_le16(6); pneg_ctxt->DataLength = cpu_to_le16(4); /* Cipher Count + le16 cipher */
pneg_ctxt->CipherCount = cpu_to_le16(2); pneg_ctxt->CipherCount = cpu_to_le16(1);
pneg_ctxt->Ciphers[0] = SMB2_ENCRYPTION_AES128_GCM; /* pneg_ctxt->Ciphers[0] = SMB2_ENCRYPTION_AES128_GCM;*/ /* not supported yet */
pneg_ctxt->Ciphers[1] = SMB2_ENCRYPTION_AES128_CCM; pneg_ctxt->Ciphers[0] = SMB2_ENCRYPTION_AES128_CCM;
} }
static void static void
...@@ -444,6 +444,7 @@ static int decode_encrypt_ctx(struct TCP_Server_Info *server, ...@@ -444,6 +444,7 @@ static int decode_encrypt_ctx(struct TCP_Server_Info *server,
return -EINVAL; return -EINVAL;
} }
server->cipher_type = ctxt->Ciphers[0]; server->cipher_type = ctxt->Ciphers[0];
server->capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION;
return 0; return 0;
} }
...@@ -2590,7 +2591,7 @@ smb2_new_read_req(void **buf, unsigned int *total_len, ...@@ -2590,7 +2591,7 @@ smb2_new_read_req(void **buf, unsigned int *total_len,
* If we want to do a RDMA write, fill in and append * If we want to do a RDMA write, fill in and append
* smbd_buffer_descriptor_v1 to the end of read request * smbd_buffer_descriptor_v1 to the end of read request
*/ */
if (server->rdma && rdata && if (server->rdma && rdata && !server->sign &&
rdata->bytes >= server->smbd_conn->rdma_readwrite_threshold) { rdata->bytes >= server->smbd_conn->rdma_readwrite_threshold) {
struct smbd_buffer_descriptor_v1 *v1; struct smbd_buffer_descriptor_v1 *v1;
...@@ -2968,7 +2969,7 @@ smb2_async_writev(struct cifs_writedata *wdata, ...@@ -2968,7 +2969,7 @@ smb2_async_writev(struct cifs_writedata *wdata,
* If we want to do a server RDMA read, fill in and append * If we want to do a server RDMA read, fill in and append
* smbd_buffer_descriptor_v1 to the end of write request * smbd_buffer_descriptor_v1 to the end of write request
*/ */
if (server->rdma && wdata->bytes >= if (server->rdma && !server->sign && wdata->bytes >=
server->smbd_conn->rdma_readwrite_threshold) { server->smbd_conn->rdma_readwrite_threshold) {
struct smbd_buffer_descriptor_v1 *v1; struct smbd_buffer_descriptor_v1 *v1;
......
...@@ -297,7 +297,7 @@ struct smb2_encryption_neg_context { ...@@ -297,7 +297,7 @@ struct smb2_encryption_neg_context {
__le16 DataLength; __le16 DataLength;
__le32 Reserved; __le32 Reserved;
__le16 CipherCount; /* AES-128-GCM and AES-128-CCM */ __le16 CipherCount; /* AES-128-GCM and AES-128-CCM */
__le16 Ciphers[2]; /* Ciphers[0] since only one used now */ __le16 Ciphers[1]; /* Ciphers[0] since only one used now */
} __packed; } __packed;
struct smb2_negotiate_rsp { struct smb2_negotiate_rsp {
......
...@@ -2086,7 +2086,7 @@ int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst) ...@@ -2086,7 +2086,7 @@ int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst)
int start, i, j; int start, i, j;
int max_iov_size = int max_iov_size =
info->max_send_size - sizeof(struct smbd_data_transfer); info->max_send_size - sizeof(struct smbd_data_transfer);
struct kvec iov[SMBDIRECT_MAX_SGE]; struct kvec *iov;
int rc; int rc;
info->smbd_send_pending++; info->smbd_send_pending++;
...@@ -2096,32 +2096,20 @@ int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst) ...@@ -2096,32 +2096,20 @@ int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst)
} }
/* /*
* This usually means a configuration error * Skip the RFC1002 length defined in MS-SMB2 section 2.1
* We use RDMA read/write for packet size > rdma_readwrite_threshold * It is used only for TCP transport in the iov[0]
* as long as it's properly configured we should never get into this
* situation
*/
if (rqst->rq_nvec + rqst->rq_npages > SMBDIRECT_MAX_SGE) {
log_write(ERR, "maximum send segment %x exceeding %x\n",
rqst->rq_nvec + rqst->rq_npages, SMBDIRECT_MAX_SGE);
rc = -EINVAL;
goto done;
}
/*
* Remove the RFC1002 length defined in MS-SMB2 section 2.1
* It is used only for TCP transport
* In future we may want to add a transport layer under protocol * In future we may want to add a transport layer under protocol
* layer so this will only be issued to TCP transport * layer so this will only be issued to TCP transport
*/ */
iov[0].iov_base = (char *)rqst->rq_iov[0].iov_base + 4;
iov[0].iov_len = rqst->rq_iov[0].iov_len - 4; if (rqst->rq_iov[0].iov_len != 4) {
buflen += iov[0].iov_len; log_write(ERR, "expected the pdu length in 1st iov, but got %zu\n", rqst->rq_iov[0].iov_len);
return -EINVAL;
}
iov = &rqst->rq_iov[1];
/* total up iov array first */ /* total up iov array first */
for (i = 1; i < rqst->rq_nvec; i++) { for (i = 0; i < rqst->rq_nvec-1; i++) {
iov[i].iov_base = rqst->rq_iov[i].iov_base;
iov[i].iov_len = rqst->rq_iov[i].iov_len;
buflen += iov[i].iov_len; buflen += iov[i].iov_len;
} }
...@@ -2198,14 +2186,14 @@ int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst) ...@@ -2198,14 +2186,14 @@ int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst)
goto done; goto done;
} }
i++; i++;
if (i == rqst->rq_nvec) if (i == rqst->rq_nvec-1)
break; break;
} }
start = i; start = i;
buflen = 0; buflen = 0;
} else { } else {
i++; i++;
if (i == rqst->rq_nvec) { if (i == rqst->rq_nvec-1) {
/* send out all remaining vecs */ /* send out all remaining vecs */
remaining_data_length -= buflen; remaining_data_length -= buflen;
log_write(INFO, log_write(INFO,
......
...@@ -753,7 +753,7 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses, ...@@ -753,7 +753,7 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
goto out; goto out;
#ifdef CONFIG_CIFS_SMB311 #ifdef CONFIG_CIFS_SMB311
if (ses->status == CifsNew) if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP))
smb311_update_preauth_hash(ses, rqst->rq_iov+1, smb311_update_preauth_hash(ses, rqst->rq_iov+1,
rqst->rq_nvec-1); rqst->rq_nvec-1);
#endif #endif
...@@ -798,7 +798,7 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses, ...@@ -798,7 +798,7 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
*resp_buf_type = CIFS_SMALL_BUFFER; *resp_buf_type = CIFS_SMALL_BUFFER;
#ifdef CONFIG_CIFS_SMB311 #ifdef CONFIG_CIFS_SMB311
if (ses->status == CifsNew) { if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP)) {
struct kvec iov = { struct kvec iov = {
.iov_base = buf + 4, .iov_base = buf + 4,
.iov_len = get_rfc1002_length(buf) .iov_len = get_rfc1002_length(buf)
...@@ -834,8 +834,11 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, ...@@ -834,8 +834,11 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
if (n_vec + 1 > CIFS_MAX_IOV_SIZE) { if (n_vec + 1 > CIFS_MAX_IOV_SIZE) {
new_iov = kmalloc(sizeof(struct kvec) * (n_vec + 1), new_iov = kmalloc(sizeof(struct kvec) * (n_vec + 1),
GFP_KERNEL); GFP_KERNEL);
if (!new_iov) if (!new_iov) {
/* otherwise cifs_send_recv below sets resp_buf_type */
*resp_buf_type = CIFS_NO_BUFFER;
return -ENOMEM; return -ENOMEM;
}
} else } else
new_iov = s_iov; new_iov = s_iov;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment