summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorPavel Shilovsky <pshilov@microsoft.com>2017-02-28 19:05:19 -0500
committerSteve French <smfrench@gmail.com>2017-03-01 17:42:40 -0500
commit61cfac6f267dabcf2740a7ec8a0295833b28b5f5 (patch)
tree308037a3f6b3b5fb7a851a01a53e0c36fbaeb28f /fs
parent6053dc981449718d90a429933e99b441e1adaea6 (diff)
CIFS: Fix possible use after free in demultiplex thread
The recent changes that added SMB3 encryption support introduced a possible use after free in the demultiplex thread. When we process an encrypted packed we obtain a pointer to SMB session but do not obtain a reference. This can possibly lead to a situation when this session was freed before we copy a decryption key from there. Fix this by obtaining a copy of the key rather than a pointer to the session under a spinlock. Signed-off-by: Pavel Shilovsky <pshilov@microsoft.com> Signed-off-by: Steve French <smfrench@gmail.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/cifs/smb2ops.c32
1 files changed, 26 insertions, 6 deletions
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index a44b4dbe4aae..d2cdd9c19d17 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -1609,6 +1609,26 @@ static void cifs_crypt_complete(struct crypto_async_request *req, int err)
1609 complete(&res->completion); 1609 complete(&res->completion);
1610} 1610}
1611 1611
1612static int
1613smb2_get_enc_key(struct TCP_Server_Info *server, __u64 ses_id, int enc, u8 *key)
1614{
1615 struct cifs_ses *ses;
1616 u8 *ses_enc_key;
1617
1618 spin_lock(&cifs_tcp_ses_lock);
1619 list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
1620 if (ses->Suid != ses_id)
1621 continue;
1622 ses_enc_key = enc ? ses->smb3encryptionkey :
1623 ses->smb3decryptionkey;
1624 memcpy(key, ses_enc_key, SMB3_SIGN_KEY_SIZE);
1625 spin_unlock(&cifs_tcp_ses_lock);
1626 return 0;
1627 }
1628 spin_unlock(&cifs_tcp_ses_lock);
1629
1630 return 1;
1631}
1612/* 1632/*
1613 * Encrypt or decrypt @rqst message. @rqst has the following format: 1633 * Encrypt or decrypt @rqst message. @rqst has the following format:
1614 * iov[0] - transform header (associate data), 1634 * iov[0] - transform header (associate data),
@@ -1622,10 +1642,10 @@ crypt_message(struct TCP_Server_Info *server, struct smb_rqst *rqst, int enc)
1622 struct smb2_transform_hdr *tr_hdr = 1642 struct smb2_transform_hdr *tr_hdr =
1623 (struct smb2_transform_hdr *)rqst->rq_iov[0].iov_base; 1643 (struct smb2_transform_hdr *)rqst->rq_iov[0].iov_base;
1624 unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 24; 1644 unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 24;
1625 struct cifs_ses *ses;
1626 int rc = 0; 1645 int rc = 0;
1627 struct scatterlist *sg; 1646 struct scatterlist *sg;
1628 u8 sign[SMB2_SIGNATURE_SIZE] = {}; 1647 u8 sign[SMB2_SIGNATURE_SIZE] = {};
1648 u8 key[SMB3_SIGN_KEY_SIZE];
1629 struct aead_request *req; 1649 struct aead_request *req;
1630 char *iv; 1650 char *iv;
1631 unsigned int iv_len; 1651 unsigned int iv_len;
@@ -1635,9 +1655,10 @@ crypt_message(struct TCP_Server_Info *server, struct smb_rqst *rqst, int enc)
1635 1655
1636 init_completion(&result.completion); 1656 init_completion(&result.completion);
1637 1657
1638 ses = smb2_find_smb_ses(server, tr_hdr->SessionId); 1658 rc = smb2_get_enc_key(server, tr_hdr->SessionId, enc, key);
1639 if (!ses) { 1659 if (rc) {
1640 cifs_dbg(VFS, "%s: Could not find session\n", __func__); 1660 cifs_dbg(VFS, "%s: Could not get %scryption key\n", __func__,
1661 enc ? "en" : "de");
1641 return 0; 1662 return 0;
1642 } 1663 }
1643 1664
@@ -1649,8 +1670,7 @@ crypt_message(struct TCP_Server_Info *server, struct smb_rqst *rqst, int enc)
1649 1670
1650 tfm = enc ? server->secmech.ccmaesencrypt : 1671 tfm = enc ? server->secmech.ccmaesencrypt :
1651 server->secmech.ccmaesdecrypt; 1672 server->secmech.ccmaesdecrypt;
1652 rc = crypto_aead_setkey(tfm, enc ? ses->smb3encryptionkey : 1673 rc = crypto_aead_setkey(tfm, key, SMB3_SIGN_KEY_SIZE);
1653 ses->smb3decryptionkey, SMB3_SIGN_KEY_SIZE);
1654 if (rc) { 1674 if (rc) {
1655 cifs_dbg(VFS, "%s: Failed to set aead key %d\n", __func__, rc); 1675 cifs_dbg(VFS, "%s: Failed to set aead key %d\n", __func__, rc);
1656 return rc; 1676 return rc;