aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPavel Shilovsky <pshilov@microsoft.com>2016-11-03 19:47:37 -0400
committerSteve French <smfrench@gmail.com>2017-02-01 17:46:36 -0500
commit026e93dc0a3eefb0be060bcb9ecd8d7a7fd5c398 (patch)
tree1816fb41fc8a99d0d967a3ebb324f341b5eaee3e
parentcabfb3680f78981d26c078a26e5c748531257ebb (diff)
CIFS: Encrypt SMB3 requests before sending
This change allows to encrypt packets if it is required by a server for SMB sessions or tree connections. Signed-off-by: Pavel Shilovsky <pshilov@microsoft.com>
-rw-r--r--fs/cifs/Kconfig2
-rw-r--r--fs/cifs/cifsencrypt.c13
-rw-r--r--fs/cifs/cifsfs.c2
-rw-r--r--fs/cifs/cifsglob.h2
-rw-r--r--fs/cifs/cifsproto.h2
-rw-r--r--fs/cifs/connect.c4
-rw-r--r--fs/cifs/smb2ops.c256
-rw-r--r--fs/cifs/smb2pdu.h5
-rw-r--r--fs/cifs/smb2proto.h3
-rw-r--r--fs/cifs/smb2transport.c41
10 files changed, 320 insertions, 10 deletions
diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig
index ff0d1fe542f7..034f00f21390 100644
--- a/fs/cifs/Kconfig
+++ b/fs/cifs/Kconfig
@@ -174,6 +174,8 @@ config CIFS_SMB2
174 select CRYPTO_AES 174 select CRYPTO_AES
175 select CRYPTO_SHA256 175 select CRYPTO_SHA256
176 select CRYPTO_CMAC 176 select CRYPTO_CMAC
177 select CRYPTO_AEAD2
178 select CRYPTO_CCM
177 179
178 help 180 help
179 This enables support for the Server Message Block version 2 181 This enables support for the Server Message Block version 2
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index d8af15f19dd8..058ac9b36f04 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -34,6 +34,7 @@
34#include <linux/random.h> 34#include <linux/random.h>
35#include <linux/highmem.h> 35#include <linux/highmem.h>
36#include <crypto/skcipher.h> 36#include <crypto/skcipher.h>
37#include <crypto/aead.h>
37 38
38static int 39static int
39cifs_crypto_shash_md5_allocate(struct TCP_Server_Info *server) 40cifs_crypto_shash_md5_allocate(struct TCP_Server_Info *server)
@@ -874,7 +875,7 @@ out:
874} 875}
875 876
876void 877void
877cifs_crypto_shash_release(struct TCP_Server_Info *server) 878cifs_crypto_secmech_release(struct TCP_Server_Info *server)
878{ 879{
879 if (server->secmech.cmacaes) { 880 if (server->secmech.cmacaes) {
880 crypto_free_shash(server->secmech.cmacaes); 881 crypto_free_shash(server->secmech.cmacaes);
@@ -896,6 +897,16 @@ cifs_crypto_shash_release(struct TCP_Server_Info *server)
896 server->secmech.hmacmd5 = NULL; 897 server->secmech.hmacmd5 = NULL;
897 } 898 }
898 899
900 if (server->secmech.ccmaesencrypt) {
901 crypto_free_aead(server->secmech.ccmaesencrypt);
902 server->secmech.ccmaesencrypt = NULL;
903 }
904
905 if (server->secmech.ccmaesdecrypt) {
906 crypto_free_aead(server->secmech.ccmaesdecrypt);
907 server->secmech.ccmaesdecrypt = NULL;
908 }
909
899 kfree(server->secmech.sdesccmacaes); 910 kfree(server->secmech.sdesccmacaes);
900 server->secmech.sdesccmacaes = NULL; 911 server->secmech.sdesccmacaes = NULL;
901 kfree(server->secmech.sdeschmacsha256); 912 kfree(server->secmech.sdeschmacsha256);
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 956dd85d7aef..15e1db8738ae 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -1376,6 +1376,8 @@ MODULE_SOFTDEP("pre: nls");
1376MODULE_SOFTDEP("pre: aes"); 1376MODULE_SOFTDEP("pre: aes");
1377MODULE_SOFTDEP("pre: cmac"); 1377MODULE_SOFTDEP("pre: cmac");
1378MODULE_SOFTDEP("pre: sha256"); 1378MODULE_SOFTDEP("pre: sha256");
1379MODULE_SOFTDEP("pre: aead2");
1380MODULE_SOFTDEP("pre: ccm");
1379#endif /* CONFIG_CIFS_SMB2 */ 1381#endif /* CONFIG_CIFS_SMB2 */
1380module_init(init_cifs) 1382module_init(init_cifs)
1381module_exit(exit_cifs) 1383module_exit(exit_cifs)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index ff7114d27a69..14196e00f79e 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -136,6 +136,8 @@ struct cifs_secmech {
136 struct sdesc *sdescmd5; /* ctxt to generate cifs/smb signature */ 136 struct sdesc *sdescmd5; /* ctxt to generate cifs/smb signature */
137 struct sdesc *sdeschmacsha256; /* ctxt to generate smb2 signature */ 137 struct sdesc *sdeschmacsha256; /* ctxt to generate smb2 signature */
138 struct sdesc *sdesccmacaes; /* ctxt to generate smb3 signature */ 138 struct sdesc *sdesccmacaes; /* ctxt to generate smb3 signature */
139 struct crypto_aead *ccmaesencrypt; /* smb3 encryption aead */
140 struct crypto_aead *ccmaesdecrypt; /* smb3 decryption aead */
139}; 141};
140 142
141/* per smb session structure/fields */ 143/* per smb session structure/fields */
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 711718cd73dd..26872f54ca3f 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -445,7 +445,7 @@ extern int SMBNTencrypt(unsigned char *, unsigned char *, unsigned char *,
445 const struct nls_table *); 445 const struct nls_table *);
446extern int setup_ntlm_response(struct cifs_ses *, const struct nls_table *); 446extern int setup_ntlm_response(struct cifs_ses *, const struct nls_table *);
447extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *); 447extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *);
448extern void cifs_crypto_shash_release(struct TCP_Server_Info *); 448extern void cifs_crypto_secmech_release(struct TCP_Server_Info *server);
449extern int calc_seckey(struct cifs_ses *); 449extern int calc_seckey(struct cifs_ses *);
450extern int generate_smb30signingkey(struct cifs_ses *); 450extern int generate_smb30signingkey(struct cifs_ses *);
451extern int generate_smb311signingkey(struct cifs_ses *); 451extern int generate_smb311signingkey(struct cifs_ses *);
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 35ae49ed1f76..b84febf960e9 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -2154,7 +2154,7 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)
2154 server->tcpStatus = CifsExiting; 2154 server->tcpStatus = CifsExiting;
2155 spin_unlock(&GlobalMid_Lock); 2155 spin_unlock(&GlobalMid_Lock);
2156 2156
2157 cifs_crypto_shash_release(server); 2157 cifs_crypto_secmech_release(server);
2158 cifs_fscache_release_client_cookie(server); 2158 cifs_fscache_release_client_cookie(server);
2159 2159
2160 kfree(server->session_key.response); 2160 kfree(server->session_key.response);
@@ -2273,7 +2273,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
2273 return tcp_ses; 2273 return tcp_ses;
2274 2274
2275out_err_crypto_release: 2275out_err_crypto_release:
2276 cifs_crypto_shash_release(tcp_ses); 2276 cifs_crypto_secmech_release(tcp_ses);
2277 2277
2278 put_net(cifs_net_ns(tcp_ses)); 2278 put_net(cifs_net_ns(tcp_ses));
2279 2279
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index ef8b2a8363b3..54b49358eaaf 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -20,6 +20,8 @@
20#include <linux/pagemap.h> 20#include <linux/pagemap.h>
21#include <linux/vfs.h> 21#include <linux/vfs.h>
22#include <linux/falloc.h> 22#include <linux/falloc.h>
23#include <linux/scatterlist.h>
24#include <crypto/aead.h>
23#include "cifsglob.h" 25#include "cifsglob.h"
24#include "smb2pdu.h" 26#include "smb2pdu.h"
25#include "smb2proto.h" 27#include "smb2proto.h"
@@ -1547,6 +1549,256 @@ smb2_dir_needs_close(struct cifsFileInfo *cfile)
1547 return !cfile->invalidHandle; 1549 return !cfile->invalidHandle;
1548} 1550}
1549 1551
1552static void
1553fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, struct smb_rqst *old_rq)
1554{
1555 struct smb2_sync_hdr *shdr =
1556 (struct smb2_sync_hdr *)old_rq->rq_iov[1].iov_base;
1557 unsigned int orig_len = get_rfc1002_length(old_rq->rq_iov[0].iov_base);
1558
1559 memset(tr_hdr, 0, sizeof(struct smb2_transform_hdr));
1560 tr_hdr->ProtocolId = SMB2_TRANSFORM_PROTO_NUM;
1561 tr_hdr->OriginalMessageSize = cpu_to_le32(orig_len);
1562 tr_hdr->Flags = cpu_to_le16(0x01);
1563 get_random_bytes(&tr_hdr->Nonce, SMB3_AES128CMM_NONCE);
1564 memcpy(&tr_hdr->SessionId, &shdr->SessionId, 8);
1565 inc_rfc1001_len(tr_hdr, sizeof(struct smb2_transform_hdr) - 4);
1566 inc_rfc1001_len(tr_hdr, orig_len);
1567}
1568
1569static struct scatterlist *
1570init_sg(struct smb_rqst *rqst, u8 *sign)
1571{
1572 unsigned int sg_len = rqst->rq_nvec + rqst->rq_npages + 1;
1573 unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 24;
1574 struct scatterlist *sg;
1575 unsigned int i;
1576 unsigned int j;
1577
1578 sg = kmalloc_array(sg_len, sizeof(struct scatterlist), GFP_KERNEL);
1579 if (!sg)
1580 return NULL;
1581
1582 sg_init_table(sg, sg_len);
1583 sg_set_buf(&sg[0], rqst->rq_iov[0].iov_base + 24, assoc_data_len);
1584 for (i = 1; i < rqst->rq_nvec; i++)
1585 sg_set_buf(&sg[i], rqst->rq_iov[i].iov_base,
1586 rqst->rq_iov[i].iov_len);
1587 for (j = 0; i < sg_len - 1; i++, j++) {
1588 unsigned int len = (j < rqst->rq_npages - 1) ? rqst->rq_pagesz
1589 : rqst->rq_tailsz;
1590 sg_set_page(&sg[i], rqst->rq_pages[j], len, 0);
1591 }
1592 sg_set_buf(&sg[sg_len - 1], sign, SMB2_SIGNATURE_SIZE);
1593 return sg;
1594}
1595
1596struct cifs_crypt_result {
1597 int err;
1598 struct completion completion;
1599};
1600
1601static void cifs_crypt_complete(struct crypto_async_request *req, int err)
1602{
1603 struct cifs_crypt_result *res = req->data;
1604
1605 if (err == -EINPROGRESS)
1606 return;
1607
1608 res->err = err;
1609 complete(&res->completion);
1610}
1611
1612/*
1613 * Encrypt or decrypt @rqst message. @rqst has the following format:
1614 * iov[0] - transform header (associate data),
1615 * iov[1-N] and pages - data to encrypt.
1616 * On success return encrypted data in iov[1-N] and pages, leave iov[0]
1617 * untouched.
1618 */
1619static int
1620crypt_message(struct TCP_Server_Info *server, struct smb_rqst *rqst, int enc)
1621{
1622 struct smb2_transform_hdr *tr_hdr =
1623 (struct smb2_transform_hdr *)rqst->rq_iov[0].iov_base;
1624 unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 24;
1625 struct cifs_ses *ses;
1626 int rc = 0;
1627 struct scatterlist *sg;
1628 u8 sign[SMB2_SIGNATURE_SIZE] = {};
1629 struct aead_request *req;
1630 char *iv;
1631 unsigned int iv_len;
1632 struct cifs_crypt_result result = {0, };
1633 struct crypto_aead *tfm;
1634 unsigned int crypt_len = le32_to_cpu(tr_hdr->OriginalMessageSize);
1635
1636 init_completion(&result.completion);
1637
1638 ses = smb2_find_smb_ses(server, tr_hdr->SessionId);
1639 if (!ses) {
1640 cifs_dbg(VFS, "%s: Could not find session\n", __func__);
1641 return 0;
1642 }
1643
1644 rc = smb3_crypto_aead_allocate(server);
1645 if (rc) {
1646 cifs_dbg(VFS, "%s: crypto alloc failed\n", __func__);
1647 return rc;
1648 }
1649
1650 tfm = enc ? server->secmech.ccmaesencrypt :
1651 server->secmech.ccmaesdecrypt;
1652 rc = crypto_aead_setkey(tfm, enc ? ses->smb3encryptionkey :
1653 ses->smb3decryptionkey, SMB3_SIGN_KEY_SIZE);
1654 if (rc) {
1655 cifs_dbg(VFS, "%s: Failed to set aead key %d\n", __func__, rc);
1656 return rc;
1657 }
1658
1659 rc = crypto_aead_setauthsize(tfm, SMB2_SIGNATURE_SIZE);
1660 if (rc) {
1661 cifs_dbg(VFS, "%s: Failed to set authsize %d\n", __func__, rc);
1662 return rc;
1663 }
1664
1665 req = aead_request_alloc(tfm, GFP_KERNEL);
1666 if (!req) {
1667 cifs_dbg(VFS, "%s: Failed to alloc aead request", __func__);
1668 return -ENOMEM;
1669 }
1670
1671 if (!enc) {
1672 memcpy(sign, &tr_hdr->Signature, SMB2_SIGNATURE_SIZE);
1673 crypt_len += SMB2_SIGNATURE_SIZE;
1674 }
1675
1676 sg = init_sg(rqst, sign);
1677 if (!sg) {
1678 cifs_dbg(VFS, "%s: Failed to init sg %d", __func__, rc);
1679 goto free_req;
1680 }
1681
1682 iv_len = crypto_aead_ivsize(tfm);
1683 iv = kzalloc(iv_len, GFP_KERNEL);
1684 if (!iv) {
1685 cifs_dbg(VFS, "%s: Failed to alloc IV", __func__);
1686 goto free_sg;
1687 }
1688 iv[0] = 3;
1689 memcpy(iv + 1, (char *)tr_hdr->Nonce, SMB3_AES128CMM_NONCE);
1690
1691 aead_request_set_crypt(req, sg, sg, crypt_len, iv);
1692 aead_request_set_ad(req, assoc_data_len);
1693
1694 aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
1695 cifs_crypt_complete, &result);
1696
1697 rc = enc ? crypto_aead_encrypt(req) : crypto_aead_decrypt(req);
1698
1699 if (rc == -EINPROGRESS || rc == -EBUSY) {
1700 wait_for_completion(&result.completion);
1701 rc = result.err;
1702 }
1703
1704 if (!rc && enc)
1705 memcpy(&tr_hdr->Signature, sign, SMB2_SIGNATURE_SIZE);
1706
1707 kfree(iv);
1708free_sg:
1709 kfree(sg);
1710free_req:
1711 kfree(req);
1712 return rc;
1713}
1714
1715static int
1716smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq,
1717 struct smb_rqst *old_rq)
1718{
1719 struct kvec *iov;
1720 struct page **pages;
1721 struct smb2_transform_hdr *tr_hdr;
1722 unsigned int npages = old_rq->rq_npages;
1723 int i;
1724 int rc = -ENOMEM;
1725
1726 pages = kmalloc_array(npages, sizeof(struct page *), GFP_KERNEL);
1727 if (!pages)
1728 return rc;
1729
1730 new_rq->rq_pages = pages;
1731 new_rq->rq_npages = old_rq->rq_npages;
1732 new_rq->rq_pagesz = old_rq->rq_pagesz;
1733 new_rq->rq_tailsz = old_rq->rq_tailsz;
1734
1735 for (i = 0; i < npages; i++) {
1736 pages[i] = alloc_page(GFP_KERNEL|__GFP_HIGHMEM);
1737 if (!pages[i])
1738 goto err_free_pages;
1739 }
1740
1741 iov = kmalloc_array(old_rq->rq_nvec, sizeof(struct kvec), GFP_KERNEL);
1742 if (!iov)
1743 goto err_free_pages;
1744
1745 /* copy all iovs from the old except the 1st one (rfc1002 length) */
1746 memcpy(&iov[1], &old_rq->rq_iov[1],
1747 sizeof(struct kvec) * (old_rq->rq_nvec - 1));
1748 new_rq->rq_iov = iov;
1749 new_rq->rq_nvec = old_rq->rq_nvec;
1750
1751 tr_hdr = kmalloc(sizeof(struct smb2_transform_hdr), GFP_KERNEL);
1752 if (!tr_hdr)
1753 goto err_free_iov;
1754
1755 /* fill the 1st iov with a transform header */
1756 fill_transform_hdr(tr_hdr, old_rq);
1757 new_rq->rq_iov[0].iov_base = tr_hdr;
1758 new_rq->rq_iov[0].iov_len = sizeof(struct smb2_transform_hdr);
1759
1760 /* copy pages form the old */
1761 for (i = 0; i < npages; i++) {
1762 char *dst = kmap(new_rq->rq_pages[i]);
1763 char *src = kmap(old_rq->rq_pages[i]);
1764 unsigned int len = (i < npages - 1) ? new_rq->rq_pagesz :
1765 new_rq->rq_tailsz;
1766 memcpy(dst, src, len);
1767 kunmap(new_rq->rq_pages[i]);
1768 kunmap(old_rq->rq_pages[i]);
1769 }
1770
1771 rc = crypt_message(server, new_rq, 1);
1772 cifs_dbg(FYI, "encrypt message returned %d", rc);
1773 if (rc)
1774 goto err_free_tr_hdr;
1775
1776 return rc;
1777
1778err_free_tr_hdr:
1779 kfree(tr_hdr);
1780err_free_iov:
1781 kfree(iov);
1782err_free_pages:
1783 for (i = i - 1; i >= 0; i--)
1784 put_page(pages[i]);
1785 kfree(pages);
1786 return rc;
1787}
1788
1789static void
1790smb3_free_transform_rq(struct smb_rqst *rqst)
1791{
1792 int i = rqst->rq_npages - 1;
1793
1794 for (; i >= 0; i--)
1795 put_page(rqst->rq_pages[i]);
1796 kfree(rqst->rq_pages);
1797 /* free transform header */
1798 kfree(rqst->rq_iov[0].iov_base);
1799 kfree(rqst->rq_iov);
1800}
1801
1550struct smb_version_operations smb20_operations = { 1802struct smb_version_operations smb20_operations = {
1551 .compare_fids = smb2_compare_fids, 1803 .compare_fids = smb2_compare_fids,
1552 .setup_request = smb2_setup_request, 1804 .setup_request = smb2_setup_request,
@@ -1793,6 +2045,8 @@ struct smb_version_operations smb30_operations = {
1793 .dir_needs_close = smb2_dir_needs_close, 2045 .dir_needs_close = smb2_dir_needs_close,
1794 .fallocate = smb3_fallocate, 2046 .fallocate = smb3_fallocate,
1795 .enum_snapshots = smb3_enum_snapshots, 2047 .enum_snapshots = smb3_enum_snapshots,
2048 .init_transform_rq = smb3_init_transform_rq,
2049 .free_transform_rq = smb3_free_transform_rq,
1796}; 2050};
1797 2051
1798#ifdef CONFIG_CIFS_SMB311 2052#ifdef CONFIG_CIFS_SMB311
@@ -1881,6 +2135,8 @@ struct smb_version_operations smb311_operations = {
1881 .dir_needs_close = smb2_dir_needs_close, 2135 .dir_needs_close = smb2_dir_needs_close,
1882 .fallocate = smb3_fallocate, 2136 .fallocate = smb3_fallocate,
1883 .enum_snapshots = smb3_enum_snapshots, 2137 .enum_snapshots = smb3_enum_snapshots,
2138 .init_transform_rq = smb3_init_transform_rq,
2139 .free_transform_rq = smb3_free_transform_rq,
1884}; 2140};
1885#endif /* CIFS_SMB311 */ 2141#endif /* CIFS_SMB311 */
1886 2142
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index 35ff9fae1c27..c03b252501a1 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -134,11 +134,14 @@ struct smb2_pdu {
134 __le16 StructureSize2; /* size of wct area (varies, request specific) */ 134 __le16 StructureSize2; /* size of wct area (varies, request specific) */
135} __packed; 135} __packed;
136 136
137#define SMB3_AES128CMM_NONCE 11
138#define SMB3_AES128GCM_NONCE 12
139
137struct smb2_transform_hdr { 140struct smb2_transform_hdr {
138 __be32 smb2_buf_length; /* big endian on wire */ 141 __be32 smb2_buf_length; /* big endian on wire */
139 /* length is only two or three bytes - with 142 /* length is only two or three bytes - with
140 one or two byte type preceding it that MBZ */ 143 one or two byte type preceding it that MBZ */
141 __u8 ProtocolId[4]; /* 0xFD 'S' 'M' 'B' */ 144 __le32 ProtocolId; /* 0xFD 'S' 'M' 'B' */
142 __u8 Signature[16]; 145 __u8 Signature[16];
143 __u8 Nonce[16]; 146 __u8 Nonce[16];
144 __le32 OriginalMessageSize; 147 __le32 OriginalMessageSize;
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index f2d511a6971b..7d30b754e132 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -56,6 +56,8 @@ extern void smb2_echo_request(struct work_struct *work);
56extern __le32 smb2_get_lease_state(struct cifsInodeInfo *cinode); 56extern __le32 smb2_get_lease_state(struct cifsInodeInfo *cinode);
57extern bool smb2_is_valid_oplock_break(char *buffer, 57extern bool smb2_is_valid_oplock_break(char *buffer,
58 struct TCP_Server_Info *srv); 58 struct TCP_Server_Info *srv);
59extern struct cifs_ses *smb2_find_smb_ses(struct TCP_Server_Info *server,
60 __u64 ses_id);
59 61
60extern void move_smb2_info_to_cifs(FILE_ALL_INFO *dst, 62extern void move_smb2_info_to_cifs(FILE_ALL_INFO *dst,
61 struct smb2_file_all_info *src); 63 struct smb2_file_all_info *src);
@@ -97,6 +99,7 @@ extern int smb2_unlock_range(struct cifsFileInfo *cfile,
97 struct file_lock *flock, const unsigned int xid); 99 struct file_lock *flock, const unsigned int xid);
98extern int smb2_push_mandatory_locks(struct cifsFileInfo *cfile); 100extern int smb2_push_mandatory_locks(struct cifsFileInfo *cfile);
99extern void smb2_reconnect_server(struct work_struct *work); 101extern void smb2_reconnect_server(struct work_struct *work);
102extern int smb3_crypto_aead_allocate(struct TCP_Server_Info *server);
100 103
101/* 104/*
102 * SMB2 Worker functions - most of protocol specific implementation details 105 * SMB2 Worker functions - most of protocol specific implementation details
diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c
index 93b27752b634..3caa11dd957a 100644
--- a/fs/cifs/smb2transport.c
+++ b/fs/cifs/smb2transport.c
@@ -31,6 +31,7 @@
31#include <asm/processor.h> 31#include <asm/processor.h>
32#include <linux/mempool.h> 32#include <linux/mempool.h>
33#include <linux/highmem.h> 33#include <linux/highmem.h>
34#include <crypto/aead.h>
34#include "smb2pdu.h" 35#include "smb2pdu.h"
35#include "cifsglob.h" 36#include "cifsglob.h"
36#include "cifsproto.h" 37#include "cifsproto.h"
@@ -114,14 +115,14 @@ smb3_crypto_shash_allocate(struct TCP_Server_Info *server)
114 return 0; 115 return 0;
115} 116}
116 117
117static struct cifs_ses * 118struct cifs_ses *
118smb2_find_smb_ses(struct smb2_sync_hdr *shdr, struct TCP_Server_Info *server) 119smb2_find_smb_ses(struct TCP_Server_Info *server, __u64 ses_id)
119{ 120{
120 struct cifs_ses *ses; 121 struct cifs_ses *ses;
121 122
122 spin_lock(&cifs_tcp_ses_lock); 123 spin_lock(&cifs_tcp_ses_lock);
123 list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { 124 list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
124 if (ses->Suid != shdr->SessionId) 125 if (ses->Suid != ses_id)
125 continue; 126 continue;
126 spin_unlock(&cifs_tcp_ses_lock); 127 spin_unlock(&cifs_tcp_ses_lock);
127 return ses; 128 return ses;
@@ -141,7 +142,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
141 struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[1].iov_base; 142 struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[1].iov_base;
142 struct cifs_ses *ses; 143 struct cifs_ses *ses;
143 144
144 ses = smb2_find_smb_ses(shdr, server); 145 ses = smb2_find_smb_ses(server, shdr->SessionId);
145 if (!ses) { 146 if (!ses) {
146 cifs_dbg(VFS, "%s: Could not find session\n", __func__); 147 cifs_dbg(VFS, "%s: Could not find session\n", __func__);
147 return 0; 148 return 0;
@@ -358,7 +359,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
358 struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[1].iov_base; 359 struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[1].iov_base;
359 struct cifs_ses *ses; 360 struct cifs_ses *ses;
360 361
361 ses = smb2_find_smb_ses(shdr, server); 362 ses = smb2_find_smb_ses(server, shdr->SessionId);
362 if (!ses) { 363 if (!ses) {
363 cifs_dbg(VFS, "%s: Could not find session\n", __func__); 364 cifs_dbg(VFS, "%s: Could not find session\n", __func__);
364 return 0; 365 return 0;
@@ -618,3 +619,33 @@ smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
618 619
619 return mid; 620 return mid;
620} 621}
622
623int
624smb3_crypto_aead_allocate(struct TCP_Server_Info *server)
625{
626 struct crypto_aead *tfm;
627
628 if (!server->secmech.ccmaesencrypt) {
629 tfm = crypto_alloc_aead("ccm(aes)", 0, 0);
630 if (IS_ERR(tfm)) {
631 cifs_dbg(VFS, "%s: Failed to alloc encrypt aead\n",
632 __func__);
633 return PTR_ERR(tfm);
634 }
635 server->secmech.ccmaesencrypt = tfm;
636 }
637
638 if (!server->secmech.ccmaesdecrypt) {
639 tfm = crypto_alloc_aead("ccm(aes)", 0, 0);
640 if (IS_ERR(tfm)) {
641 crypto_free_aead(server->secmech.ccmaesencrypt);
642 server->secmech.ccmaesencrypt = NULL;
643 cifs_dbg(VFS, "%s: Failed to alloc decrypt aead\n",
644 __func__);
645 return PTR_ERR(tfm);
646 }
647 server->secmech.ccmaesdecrypt = tfm;
648 }
649
650 return 0;
651}