mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-16 08:44:21 +08:00
Security fixes for SMB3 for 4.17-rc3
-----BEGIN PGP SIGNATURE----- iQGwBAABCAAaBQJa4LQCExxzbWZyZW5jaEBnbWFpbC5jb20ACgkQiiy9cAdyT1GQ OAv+KPrprp+2jkoEZRgy/cJBZGmMCfyfjxM9eAZUr35FfkuMF8ir4cJ0AbbSpQOY E+WDdeRhS9FjueIVGKGi74C9yhJpEEDPtvFCFqhGJ5/AIDBBDpC4KyCQEfJDTlGo b+USbBcu+6bzqASN/L4fwhz1E+Q45RUb98E/IHPOKzV7qASyjYpB9CUcFaANt03k GK+VKNJF5ppa9YRgXwoPFbD4M2B/Wfe5ZP5+9ZYnYmZnpIUFCuY1rrASuJdcwFN2 z97sGmqacR+a12FkdfZCoeK+dpsQ+ZeyKiB5sOpj+gr7apKAEmESjRlC1xpNRJ4B TOvkOSyYaNUr94HJo8FXzs1a/j8I59Cn2ER2o8Z0f1s7QvgFxvF09AnDUPQt1OBK 197KNO6a/E1Rd+umPzKvgTIbrm7fcPYZgEWNHdbd3Hf8eBvFs8372GZXGLSkupmJ jnBkwYbukz6KsVNEx8m/9fGhKhyJCZ34yTEKrT+aNDQ0aA4vVuP/WUa+GtNSkDuL WX0u =U4ba -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
cac264288a
@ -455,6 +455,9 @@ cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required)
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
* SetFS as we do on SessSetup and reconnect?
|
||||
@ -3007,22 +3023,6 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
|
||||
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
|
||||
* 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)
|
||||
wsize = volume_info->wsize ? volume_info->wsize : CIFS_DEFAULT_IOSIZE;
|
||||
wsize = min_t(unsigned int, wsize, server->max_write);
|
||||
#ifdef CONFIG_CIFS_SMB_DIRECT
|
||||
if (server->rdma)
|
||||
wsize = min_t(unsigned int,
|
||||
if (server->rdma) {
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
|
||||
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)
|
||||
rsize = volume_info->rsize ? volume_info->rsize : CIFS_DEFAULT_IOSIZE;
|
||||
rsize = min_t(unsigned int, rsize, server->max_read);
|
||||
#ifdef CONFIG_CIFS_SMB_DIRECT
|
||||
if (server->rdma)
|
||||
rsize = min_t(unsigned int,
|
||||
if (server->rdma) {
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
|
||||
|
@ -383,10 +383,10 @@ static void
|
||||
build_encrypt_ctxt(struct smb2_encryption_neg_context *pneg_ctxt)
|
||||
{
|
||||
pneg_ctxt->ContextType = SMB2_ENCRYPTION_CAPABILITIES;
|
||||
pneg_ctxt->DataLength = cpu_to_le16(6);
|
||||
pneg_ctxt->CipherCount = cpu_to_le16(2);
|
||||
pneg_ctxt->Ciphers[0] = SMB2_ENCRYPTION_AES128_GCM;
|
||||
pneg_ctxt->Ciphers[1] = SMB2_ENCRYPTION_AES128_CCM;
|
||||
pneg_ctxt->DataLength = cpu_to_le16(4); /* Cipher Count + le16 cipher */
|
||||
pneg_ctxt->CipherCount = cpu_to_le16(1);
|
||||
/* pneg_ctxt->Ciphers[0] = SMB2_ENCRYPTION_AES128_GCM;*/ /* not supported yet */
|
||||
pneg_ctxt->Ciphers[0] = SMB2_ENCRYPTION_AES128_CCM;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -444,6 +444,7 @@ static int decode_encrypt_ctx(struct TCP_Server_Info *server,
|
||||
return -EINVAL;
|
||||
}
|
||||
server->cipher_type = ctxt->Ciphers[0];
|
||||
server->capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -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
|
||||
* 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) {
|
||||
|
||||
struct smbd_buffer_descriptor_v1 *v1;
|
||||
@ -2968,7 +2969,7 @@ smb2_async_writev(struct cifs_writedata *wdata,
|
||||
* If we want to do a server RDMA read, fill in and append
|
||||
* 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) {
|
||||
|
||||
struct smbd_buffer_descriptor_v1 *v1;
|
||||
|
@ -297,7 +297,7 @@ struct smb2_encryption_neg_context {
|
||||
__le16 DataLength;
|
||||
__le32 Reserved;
|
||||
__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;
|
||||
|
||||
struct smb2_negotiate_rsp {
|
||||
|
@ -2086,7 +2086,7 @@ int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst)
|
||||
int start, i, j;
|
||||
int max_iov_size =
|
||||
info->max_send_size - sizeof(struct smbd_data_transfer);
|
||||
struct kvec iov[SMBDIRECT_MAX_SGE];
|
||||
struct kvec *iov;
|
||||
int rc;
|
||||
|
||||
info->smbd_send_pending++;
|
||||
@ -2096,32 +2096,20 @@ int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst)
|
||||
}
|
||||
|
||||
/*
|
||||
* This usually means a configuration error
|
||||
* We use RDMA read/write for packet size > rdma_readwrite_threshold
|
||||
* 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
|
||||
* Skip the RFC1002 length defined in MS-SMB2 section 2.1
|
||||
* It is used only for TCP transport in the iov[0]
|
||||
* In future we may want to add a transport layer under protocol
|
||||
* 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;
|
||||
buflen += iov[0].iov_len;
|
||||
|
||||
if (rqst->rq_iov[0].iov_len != 4) {
|
||||
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 */
|
||||
for (i = 1; i < rqst->rq_nvec; i++) {
|
||||
iov[i].iov_base = rqst->rq_iov[i].iov_base;
|
||||
iov[i].iov_len = rqst->rq_iov[i].iov_len;
|
||||
for (i = 0; i < rqst->rq_nvec-1; i++) {
|
||||
buflen += iov[i].iov_len;
|
||||
}
|
||||
|
||||
@ -2198,14 +2186,14 @@ int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst)
|
||||
goto done;
|
||||
}
|
||||
i++;
|
||||
if (i == rqst->rq_nvec)
|
||||
if (i == rqst->rq_nvec-1)
|
||||
break;
|
||||
}
|
||||
start = i;
|
||||
buflen = 0;
|
||||
} else {
|
||||
i++;
|
||||
if (i == rqst->rq_nvec) {
|
||||
if (i == rqst->rq_nvec-1) {
|
||||
/* send out all remaining vecs */
|
||||
remaining_data_length -= buflen;
|
||||
log_write(INFO,
|
||||
|
@ -753,7 +753,7 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
|
||||
goto out;
|
||||
|
||||
#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,
|
||||
rqst->rq_nvec-1);
|
||||
#endif
|
||||
@ -798,7 +798,7 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
|
||||
*resp_buf_type = CIFS_SMALL_BUFFER;
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
if (ses->status == CifsNew) {
|
||||
if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP)) {
|
||||
struct kvec iov = {
|
||||
.iov_base = buf + 4,
|
||||
.iov_len = get_rfc1002_length(buf)
|
||||
@ -834,8 +834,11 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
|
||||
if (n_vec + 1 > CIFS_MAX_IOV_SIZE) {
|
||||
new_iov = kmalloc(sizeof(struct kvec) * (n_vec + 1),
|
||||
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;
|
||||
}
|
||||
} else
|
||||
new_iov = s_iov;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user