diff options
author | Pavel Shilovsky <pshilov@microsoft.com> | 2017-02-28 19:05:19 -0500 |
---|---|---|
committer | Steve French <smfrench@gmail.com> | 2017-03-01 17:42:40 -0500 |
commit | 61cfac6f267dabcf2740a7ec8a0295833b28b5f5 (patch) | |
tree | 308037a3f6b3b5fb7a851a01a53e0c36fbaeb28f /fs | |
parent | 6053dc981449718d90a429933e99b441e1adaea6 (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.c | 32 |
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 | ||
1612 | static int | ||
1613 | smb2_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; |