mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 04:38:03 +00:00
five smb3 client fixes, and an immportant netfs fix for cifs write regression
-----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAmb3FfgACgkQiiy9cAdy T1HLMQv/ZXkiNPvMmCHJE3rWdSBZQdGLDV1qOhxuW9y4CvenIhukwDmwOq7wjWOn 3dQHDaqFkVTVurosozFOJK9Aw94iz2Ad9dlryMcNN+Gb4vY3d9l3AvsbqmgbZSsg DmdqOg1SA9NgDaHl6RFsFQQY9O5BsjkEeHBX71gZZUYMw1d6CTpFUT+wTD43L0LQ g8r0Ksil7edw9f5WGvu8YzB4rclR45QiTVG1OMgXmr43cvoJz3GrIPXeHNm7j5D7 hzx6ELNviY77DPKnxSd55UGPngVms6c1qqWCOJMefsJRY5bhh3lEc+TQyX11HGft Kta1TQI2gI1xgueqpR2Dh/bUuprWcc6vCbNjxezXpFOiSMt6qNfGzQDE9gZAALAj 568lRpwcMPgS9laqK4Sh9v5+Vw6E8T+FUAJKvtLRidv5iBoqI0+50mhHTBlBgiy6 XdyiAdUGSzejcu/OiOGc9C4PvVRgf0qw9+hqqZeZAsRydKgw3QwPtJ6yW+RYu86p xQ5CE6zs =mpUs -----END PGP SIGNATURE----- Merge tag '6.12rc-more-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6 Pull xmb client fixes from Steve French: - Noisy log message cleanup - Important netfs fix for cifs crash in generic/074 - Three minor improvements to use of hashing (multichannel and mount improvements) - Fix decryption crash for large read with small esize * tag '6.12rc-more-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6: smb: client: make SHA-512 TFM ephemeral smb: client: make HMAC-MD5 TFM ephemeral smb: client: stop flooding dmesg in smb2_calc_signature() smb: client: allocate crypto only for primary server smb: client: fix UAF in async decryption netfs: Fix write oops in generic/346 (9p) and generic/074 (cifs)
This commit is contained in:
commit
f04ff5a02b
@ -58,6 +58,7 @@ static inline void netfs_proc_del_rreq(struct netfs_io_request *rreq) {}
|
||||
/*
|
||||
* misc.c
|
||||
*/
|
||||
struct folio_queue *netfs_buffer_make_space(struct netfs_io_request *rreq);
|
||||
int netfs_buffer_append_folio(struct netfs_io_request *rreq, struct folio *folio,
|
||||
bool needs_put);
|
||||
struct folio_queue *netfs_delete_buffer_head(struct netfs_io_request *wreq);
|
||||
|
@ -8,35 +8,67 @@
|
||||
#include <linux/swap.h>
|
||||
#include "internal.h"
|
||||
|
||||
/*
|
||||
* Make sure there's space in the rolling queue.
|
||||
*/
|
||||
struct folio_queue *netfs_buffer_make_space(struct netfs_io_request *rreq)
|
||||
{
|
||||
struct folio_queue *tail = rreq->buffer_tail, *prev;
|
||||
unsigned int prev_nr_slots = 0;
|
||||
|
||||
if (WARN_ON_ONCE(!rreq->buffer && tail) ||
|
||||
WARN_ON_ONCE(rreq->buffer && !tail))
|
||||
return ERR_PTR(-EIO);
|
||||
|
||||
prev = tail;
|
||||
if (prev) {
|
||||
if (!folioq_full(tail))
|
||||
return tail;
|
||||
prev_nr_slots = folioq_nr_slots(tail);
|
||||
}
|
||||
|
||||
tail = kmalloc(sizeof(*tail), GFP_NOFS);
|
||||
if (!tail)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
netfs_stat(&netfs_n_folioq);
|
||||
folioq_init(tail);
|
||||
tail->prev = prev;
|
||||
if (prev)
|
||||
/* [!] NOTE: After we set prev->next, the consumer is entirely
|
||||
* at liberty to delete prev.
|
||||
*/
|
||||
WRITE_ONCE(prev->next, tail);
|
||||
|
||||
rreq->buffer_tail = tail;
|
||||
if (!rreq->buffer) {
|
||||
rreq->buffer = tail;
|
||||
iov_iter_folio_queue(&rreq->io_iter, ITER_SOURCE, tail, 0, 0, 0);
|
||||
} else {
|
||||
/* Make sure we don't leave the master iterator pointing to a
|
||||
* block that might get immediately consumed.
|
||||
*/
|
||||
if (rreq->io_iter.folioq == prev &&
|
||||
rreq->io_iter.folioq_slot == prev_nr_slots) {
|
||||
rreq->io_iter.folioq = tail;
|
||||
rreq->io_iter.folioq_slot = 0;
|
||||
}
|
||||
}
|
||||
rreq->buffer_tail_slot = 0;
|
||||
return tail;
|
||||
}
|
||||
|
||||
/*
|
||||
* Append a folio to the rolling queue.
|
||||
*/
|
||||
int netfs_buffer_append_folio(struct netfs_io_request *rreq, struct folio *folio,
|
||||
bool needs_put)
|
||||
{
|
||||
struct folio_queue *tail = rreq->buffer_tail;
|
||||
struct folio_queue *tail;
|
||||
unsigned int slot, order = folio_order(folio);
|
||||
|
||||
if (WARN_ON_ONCE(!rreq->buffer && tail) ||
|
||||
WARN_ON_ONCE(rreq->buffer && !tail))
|
||||
return -EIO;
|
||||
|
||||
if (!tail || folioq_full(tail)) {
|
||||
tail = kmalloc(sizeof(*tail), GFP_NOFS);
|
||||
if (!tail)
|
||||
return -ENOMEM;
|
||||
netfs_stat(&netfs_n_folioq);
|
||||
folioq_init(tail);
|
||||
tail->prev = rreq->buffer_tail;
|
||||
if (tail->prev)
|
||||
tail->prev->next = tail;
|
||||
rreq->buffer_tail = tail;
|
||||
if (!rreq->buffer) {
|
||||
rreq->buffer = tail;
|
||||
iov_iter_folio_queue(&rreq->io_iter, ITER_SOURCE, tail, 0, 0, 0);
|
||||
}
|
||||
rreq->buffer_tail_slot = 0;
|
||||
}
|
||||
tail = netfs_buffer_make_space(rreq);
|
||||
if (IS_ERR(tail))
|
||||
return PTR_ERR(tail);
|
||||
|
||||
rreq->io_iter.count += PAGE_SIZE << order;
|
||||
|
||||
|
@ -153,12 +153,22 @@ static void netfs_prepare_write(struct netfs_io_request *wreq,
|
||||
loff_t start)
|
||||
{
|
||||
struct netfs_io_subrequest *subreq;
|
||||
struct iov_iter *wreq_iter = &wreq->io_iter;
|
||||
|
||||
/* Make sure we don't point the iterator at a used-up folio_queue
|
||||
* struct being used as a placeholder to prevent the queue from
|
||||
* collapsing. In such a case, extend the queue.
|
||||
*/
|
||||
if (iov_iter_is_folioq(wreq_iter) &&
|
||||
wreq_iter->folioq_slot >= folioq_nr_slots(wreq_iter->folioq)) {
|
||||
netfs_buffer_make_space(wreq);
|
||||
}
|
||||
|
||||
subreq = netfs_alloc_subrequest(wreq);
|
||||
subreq->source = stream->source;
|
||||
subreq->start = start;
|
||||
subreq->stream_nr = stream->stream_nr;
|
||||
subreq->io_iter = wreq->io_iter;
|
||||
subreq->io_iter = *wreq_iter;
|
||||
|
||||
_enter("R=%x[%x]", wreq->debug_id, subreq->debug_index);
|
||||
|
||||
|
@ -416,7 +416,7 @@ find_timestamp(struct cifs_ses *ses)
|
||||
}
|
||||
|
||||
static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
|
||||
const struct nls_table *nls_cp)
|
||||
const struct nls_table *nls_cp, struct shash_desc *hmacmd5)
|
||||
{
|
||||
int rc = 0;
|
||||
int len;
|
||||
@ -425,34 +425,26 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
|
||||
wchar_t *domain;
|
||||
wchar_t *server;
|
||||
|
||||
if (!ses->server->secmech.hmacmd5) {
|
||||
cifs_dbg(VFS, "%s: can't generate ntlmv2 hash\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* calculate md4 hash of password */
|
||||
E_md4hash(ses->password, nt_hash, nls_cp);
|
||||
|
||||
rc = crypto_shash_setkey(ses->server->secmech.hmacmd5->tfm, nt_hash,
|
||||
CIFS_NTHASH_SIZE);
|
||||
rc = crypto_shash_setkey(hmacmd5->tfm, nt_hash, CIFS_NTHASH_SIZE);
|
||||
if (rc) {
|
||||
cifs_dbg(VFS, "%s: Could not set NT Hash as a key\n", __func__);
|
||||
cifs_dbg(VFS, "%s: Could not set NT hash as a key, rc=%d\n", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = crypto_shash_init(ses->server->secmech.hmacmd5);
|
||||
rc = crypto_shash_init(hmacmd5);
|
||||
if (rc) {
|
||||
cifs_dbg(VFS, "%s: Could not init hmacmd5\n", __func__);
|
||||
cifs_dbg(VFS, "%s: Could not init HMAC-MD5, rc=%d\n", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* convert ses->user_name to unicode */
|
||||
len = ses->user_name ? strlen(ses->user_name) : 0;
|
||||
user = kmalloc(2 + (len * 2), GFP_KERNEL);
|
||||
if (user == NULL) {
|
||||
rc = -ENOMEM;
|
||||
return rc;
|
||||
}
|
||||
if (user == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
if (len) {
|
||||
len = cifs_strtoUTF16(user, ses->user_name, len, nls_cp);
|
||||
@ -461,11 +453,10 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
|
||||
*(u16 *)user = 0;
|
||||
}
|
||||
|
||||
rc = crypto_shash_update(ses->server->secmech.hmacmd5,
|
||||
(char *)user, 2 * len);
|
||||
rc = crypto_shash_update(hmacmd5, (char *)user, 2 * len);
|
||||
kfree(user);
|
||||
if (rc) {
|
||||
cifs_dbg(VFS, "%s: Could not update with user\n", __func__);
|
||||
cifs_dbg(VFS, "%s: Could not update with user, rc=%d\n", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -474,19 +465,15 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
|
||||
len = strlen(ses->domainName);
|
||||
|
||||
domain = kmalloc(2 + (len * 2), GFP_KERNEL);
|
||||
if (domain == NULL) {
|
||||
rc = -ENOMEM;
|
||||
return rc;
|
||||
}
|
||||
if (domain == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
len = cifs_strtoUTF16((__le16 *)domain, ses->domainName, len,
|
||||
nls_cp);
|
||||
rc =
|
||||
crypto_shash_update(ses->server->secmech.hmacmd5,
|
||||
(char *)domain, 2 * len);
|
||||
rc = crypto_shash_update(hmacmd5, (char *)domain, 2 * len);
|
||||
kfree(domain);
|
||||
if (rc) {
|
||||
cifs_dbg(VFS, "%s: Could not update with domain\n",
|
||||
__func__);
|
||||
cifs_dbg(VFS, "%s: Could not update with domain, rc=%d\n", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
} else {
|
||||
@ -494,33 +481,27 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
|
||||
len = strlen(ses->ip_addr);
|
||||
|
||||
server = kmalloc(2 + (len * 2), GFP_KERNEL);
|
||||
if (server == NULL) {
|
||||
rc = -ENOMEM;
|
||||
return rc;
|
||||
}
|
||||
len = cifs_strtoUTF16((__le16 *)server, ses->ip_addr, len,
|
||||
nls_cp);
|
||||
rc =
|
||||
crypto_shash_update(ses->server->secmech.hmacmd5,
|
||||
(char *)server, 2 * len);
|
||||
if (server == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
len = cifs_strtoUTF16((__le16 *)server, ses->ip_addr, len, nls_cp);
|
||||
rc = crypto_shash_update(hmacmd5, (char *)server, 2 * len);
|
||||
kfree(server);
|
||||
if (rc) {
|
||||
cifs_dbg(VFS, "%s: Could not update with server\n",
|
||||
__func__);
|
||||
cifs_dbg(VFS, "%s: Could not update with server, rc=%d\n", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
rc = crypto_shash_final(ses->server->secmech.hmacmd5,
|
||||
ntlmv2_hash);
|
||||
rc = crypto_shash_final(hmacmd5, ntlmv2_hash);
|
||||
if (rc)
|
||||
cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__);
|
||||
cifs_dbg(VFS, "%s: Could not generate MD5 hash, rc=%d\n", __func__, rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash)
|
||||
CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash, struct shash_desc *hmacmd5)
|
||||
{
|
||||
int rc;
|
||||
struct ntlmv2_resp *ntlmv2 = (struct ntlmv2_resp *)
|
||||
@ -531,43 +512,33 @@ CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash)
|
||||
hash_len = ses->auth_key.len - (CIFS_SESS_KEY_SIZE +
|
||||
offsetof(struct ntlmv2_resp, challenge.key[0]));
|
||||
|
||||
if (!ses->server->secmech.hmacmd5) {
|
||||
cifs_dbg(VFS, "%s: can't generate ntlmv2 hash\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = crypto_shash_setkey(ses->server->secmech.hmacmd5->tfm,
|
||||
ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE);
|
||||
rc = crypto_shash_setkey(hmacmd5->tfm, ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE);
|
||||
if (rc) {
|
||||
cifs_dbg(VFS, "%s: Could not set NTLMV2 Hash as a key\n",
|
||||
__func__);
|
||||
cifs_dbg(VFS, "%s: Could not set NTLMv2 hash as a key, rc=%d\n", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = crypto_shash_init(ses->server->secmech.hmacmd5);
|
||||
rc = crypto_shash_init(hmacmd5);
|
||||
if (rc) {
|
||||
cifs_dbg(VFS, "%s: Could not init hmacmd5\n", __func__);
|
||||
cifs_dbg(VFS, "%s: Could not init HMAC-MD5, rc=%d\n", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (ses->server->negflavor == CIFS_NEGFLAVOR_EXTENDED)
|
||||
memcpy(ntlmv2->challenge.key,
|
||||
ses->ntlmssp->cryptkey, CIFS_SERVER_CHALLENGE_SIZE);
|
||||
memcpy(ntlmv2->challenge.key, ses->ntlmssp->cryptkey, CIFS_SERVER_CHALLENGE_SIZE);
|
||||
else
|
||||
memcpy(ntlmv2->challenge.key,
|
||||
ses->server->cryptkey, CIFS_SERVER_CHALLENGE_SIZE);
|
||||
rc = crypto_shash_update(ses->server->secmech.hmacmd5,
|
||||
ntlmv2->challenge.key, hash_len);
|
||||
memcpy(ntlmv2->challenge.key, ses->server->cryptkey, CIFS_SERVER_CHALLENGE_SIZE);
|
||||
|
||||
rc = crypto_shash_update(hmacmd5, ntlmv2->challenge.key, hash_len);
|
||||
if (rc) {
|
||||
cifs_dbg(VFS, "%s: Could not update with response\n", __func__);
|
||||
cifs_dbg(VFS, "%s: Could not update with response, rc=%d\n", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Note that the MD5 digest over writes anon.challenge_key.key */
|
||||
rc = crypto_shash_final(ses->server->secmech.hmacmd5,
|
||||
ntlmv2->ntlmv2_hash);
|
||||
rc = crypto_shash_final(hmacmd5, ntlmv2->ntlmv2_hash);
|
||||
if (rc)
|
||||
cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__);
|
||||
cifs_dbg(VFS, "%s: Could not generate MD5 hash, rc=%d\n", __func__, rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@ -575,6 +546,7 @@ CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash)
|
||||
int
|
||||
setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
|
||||
{
|
||||
struct shash_desc *hmacmd5 = NULL;
|
||||
int rc;
|
||||
int baselen;
|
||||
unsigned int tilen;
|
||||
@ -640,55 +612,51 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
|
||||
|
||||
cifs_server_lock(ses->server);
|
||||
|
||||
rc = cifs_alloc_hash("hmac(md5)", &ses->server->secmech.hmacmd5);
|
||||
rc = cifs_alloc_hash("hmac(md5)", &hmacmd5);
|
||||
if (rc) {
|
||||
cifs_dbg(VFS, "Could not allocate HMAC-MD5, rc=%d\n", rc);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
/* calculate ntlmv2_hash */
|
||||
rc = calc_ntlmv2_hash(ses, ntlmv2_hash, nls_cp);
|
||||
rc = calc_ntlmv2_hash(ses, ntlmv2_hash, nls_cp, hmacmd5);
|
||||
if (rc) {
|
||||
cifs_dbg(VFS, "Could not get v2 hash rc %d\n", rc);
|
||||
cifs_dbg(VFS, "Could not get NTLMv2 hash, rc=%d\n", rc);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
/* calculate first part of the client response (CR1) */
|
||||
rc = CalcNTLMv2_response(ses, ntlmv2_hash);
|
||||
rc = CalcNTLMv2_response(ses, ntlmv2_hash, hmacmd5);
|
||||
if (rc) {
|
||||
cifs_dbg(VFS, "Could not calculate CR1 rc: %d\n", rc);
|
||||
cifs_dbg(VFS, "Could not calculate CR1, rc=%d\n", rc);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
/* now calculate the session key for NTLMv2 */
|
||||
rc = crypto_shash_setkey(ses->server->secmech.hmacmd5->tfm,
|
||||
ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE);
|
||||
rc = crypto_shash_setkey(hmacmd5->tfm, ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE);
|
||||
if (rc) {
|
||||
cifs_dbg(VFS, "%s: Could not set NTLMV2 Hash as a key\n",
|
||||
__func__);
|
||||
cifs_dbg(VFS, "%s: Could not set NTLMv2 hash as a key, rc=%d\n", __func__, rc);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
rc = crypto_shash_init(ses->server->secmech.hmacmd5);
|
||||
rc = crypto_shash_init(hmacmd5);
|
||||
if (rc) {
|
||||
cifs_dbg(VFS, "%s: Could not init hmacmd5\n", __func__);
|
||||
cifs_dbg(VFS, "%s: Could not init HMAC-MD5, rc=%d\n", __func__, rc);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
rc = crypto_shash_update(ses->server->secmech.hmacmd5,
|
||||
ntlmv2->ntlmv2_hash,
|
||||
CIFS_HMAC_MD5_HASH_SIZE);
|
||||
rc = crypto_shash_update(hmacmd5, ntlmv2->ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE);
|
||||
if (rc) {
|
||||
cifs_dbg(VFS, "%s: Could not update with response\n", __func__);
|
||||
cifs_dbg(VFS, "%s: Could not update with response, rc=%d\n", __func__, rc);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
rc = crypto_shash_final(ses->server->secmech.hmacmd5,
|
||||
ses->auth_key.response);
|
||||
rc = crypto_shash_final(hmacmd5, ses->auth_key.response);
|
||||
if (rc)
|
||||
cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__);
|
||||
|
||||
cifs_dbg(VFS, "%s: Could not generate MD5 hash, rc=%d\n", __func__, rc);
|
||||
unlock:
|
||||
cifs_server_unlock(ses->server);
|
||||
cifs_free_hash(&hmacmd5);
|
||||
setup_ntlmv2_rsp_ret:
|
||||
kfree_sensitive(tiblob);
|
||||
|
||||
@ -732,16 +700,19 @@ cifs_crypto_secmech_release(struct TCP_Server_Info *server)
|
||||
cifs_free_hash(&server->secmech.aes_cmac);
|
||||
cifs_free_hash(&server->secmech.hmacsha256);
|
||||
cifs_free_hash(&server->secmech.md5);
|
||||
cifs_free_hash(&server->secmech.sha512);
|
||||
cifs_free_hash(&server->secmech.hmacmd5);
|
||||
|
||||
if (server->secmech.enc) {
|
||||
crypto_free_aead(server->secmech.enc);
|
||||
if (!SERVER_IS_CHAN(server)) {
|
||||
if (server->secmech.enc) {
|
||||
crypto_free_aead(server->secmech.enc);
|
||||
server->secmech.enc = NULL;
|
||||
}
|
||||
|
||||
if (server->secmech.dec) {
|
||||
crypto_free_aead(server->secmech.dec);
|
||||
server->secmech.dec = NULL;
|
||||
}
|
||||
} else {
|
||||
server->secmech.enc = NULL;
|
||||
}
|
||||
|
||||
if (server->secmech.dec) {
|
||||
crypto_free_aead(server->secmech.dec);
|
||||
server->secmech.dec = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -178,10 +178,8 @@ struct session_key {
|
||||
|
||||
/* crypto hashing related structure/fields, not specific to a sec mech */
|
||||
struct cifs_secmech {
|
||||
struct shash_desc *hmacmd5; /* hmacmd5 hash function, for NTLMv2/CR1 hashes */
|
||||
struct shash_desc *md5; /* md5 hash function, for CIFS/SMB1 signatures */
|
||||
struct shash_desc *hmacsha256; /* hmac-sha256 hash function, for SMB2 signatures */
|
||||
struct shash_desc *sha512; /* sha512 hash function, for SMB3.1.1 preauth hash */
|
||||
struct shash_desc *aes_cmac; /* block-cipher based MAC function, for SMB3 signatures */
|
||||
|
||||
struct crypto_aead *enc; /* smb3 encryption AEAD TFM (AES-CCM and AES-GCM) */
|
||||
|
@ -624,7 +624,7 @@ cifs_ses_add_channel(struct cifs_ses *ses,
|
||||
* to sign packets before we generate the channel signing key
|
||||
* (we sign with the session key)
|
||||
*/
|
||||
rc = smb311_crypto_shash_allocate(chan->server);
|
||||
rc = smb3_crypto_shash_allocate(chan->server);
|
||||
if (rc) {
|
||||
cifs_dbg(VFS, "%s: crypto alloc failed\n", __func__);
|
||||
mutex_unlock(&ses->session_mutex);
|
||||
|
@ -906,41 +906,41 @@ smb311_update_preauth_hash(struct cifs_ses *ses, struct TCP_Server_Info *server,
|
||||
|| (hdr->Status !=
|
||||
cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))))
|
||||
return 0;
|
||||
|
||||
ok:
|
||||
rc = smb311_crypto_shash_allocate(server);
|
||||
if (rc)
|
||||
rc = cifs_alloc_hash("sha512", &sha512);
|
||||
if (rc) {
|
||||
cifs_dbg(VFS, "%s: Could not allocate SHA512 shash, rc=%d\n", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
sha512 = server->secmech.sha512;
|
||||
rc = crypto_shash_init(sha512);
|
||||
if (rc) {
|
||||
cifs_dbg(VFS, "%s: Could not init sha512 shash\n", __func__);
|
||||
return rc;
|
||||
cifs_dbg(VFS, "%s: Could not init SHA512 shash, rc=%d\n", __func__, rc);
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
rc = crypto_shash_update(sha512, ses->preauth_sha_hash,
|
||||
SMB2_PREAUTH_HASH_SIZE);
|
||||
if (rc) {
|
||||
cifs_dbg(VFS, "%s: Could not update sha512 shash\n", __func__);
|
||||
return rc;
|
||||
cifs_dbg(VFS, "%s: Could not update SHA512 shash, rc=%d\n", __func__, rc);
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
for (i = 0; i < nvec; i++) {
|
||||
rc = crypto_shash_update(sha512, iov[i].iov_base, iov[i].iov_len);
|
||||
if (rc) {
|
||||
cifs_dbg(VFS, "%s: Could not update sha512 shash\n",
|
||||
__func__);
|
||||
return rc;
|
||||
cifs_dbg(VFS, "%s: Could not update SHA512 shash, rc=%d\n", __func__, rc);
|
||||
goto err_free;
|
||||
}
|
||||
}
|
||||
|
||||
rc = crypto_shash_final(sha512, ses->preauth_sha_hash);
|
||||
if (rc) {
|
||||
cifs_dbg(VFS, "%s: Could not finalize sha512 shash\n",
|
||||
__func__);
|
||||
return rc;
|
||||
cifs_dbg(VFS, "%s: Could not finalize SHA12 shash, rc=%d\n", __func__, rc);
|
||||
goto err_free;
|
||||
}
|
||||
err_free:
|
||||
cifs_free_hash(&sha512);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -4309,7 +4309,7 @@ smb2_get_enc_key(struct TCP_Server_Info *server, __u64 ses_id, int enc, u8 *key)
|
||||
*/
|
||||
static int
|
||||
crypt_message(struct TCP_Server_Info *server, int num_rqst,
|
||||
struct smb_rqst *rqst, int enc)
|
||||
struct smb_rqst *rqst, int enc, struct crypto_aead *tfm)
|
||||
{
|
||||
struct smb2_transform_hdr *tr_hdr =
|
||||
(struct smb2_transform_hdr *)rqst[0].rq_iov[0].iov_base;
|
||||
@ -4320,8 +4320,6 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst,
|
||||
u8 key[SMB3_ENC_DEC_KEY_SIZE];
|
||||
struct aead_request *req;
|
||||
u8 *iv;
|
||||
DECLARE_CRYPTO_WAIT(wait);
|
||||
struct crypto_aead *tfm;
|
||||
unsigned int crypt_len = le32_to_cpu(tr_hdr->OriginalMessageSize);
|
||||
void *creq;
|
||||
size_t sensitive_size;
|
||||
@ -4333,14 +4331,6 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst,
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = smb3_crypto_aead_allocate(server);
|
||||
if (rc) {
|
||||
cifs_server_dbg(VFS, "%s: crypto alloc failed\n", __func__);
|
||||
return rc;
|
||||
}
|
||||
|
||||
tfm = enc ? server->secmech.enc : server->secmech.dec;
|
||||
|
||||
if ((server->cipher_type == SMB2_ENCRYPTION_AES256_CCM) ||
|
||||
(server->cipher_type == SMB2_ENCRYPTION_AES256_GCM))
|
||||
rc = crypto_aead_setkey(tfm, key, SMB3_GCM256_CRYPTKEY_SIZE);
|
||||
@ -4380,11 +4370,7 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst,
|
||||
aead_request_set_crypt(req, sg, sg, crypt_len, iv);
|
||||
aead_request_set_ad(req, assoc_data_len);
|
||||
|
||||
aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
|
||||
crypto_req_done, &wait);
|
||||
|
||||
rc = crypto_wait_req(enc ? crypto_aead_encrypt(req)
|
||||
: crypto_aead_decrypt(req), &wait);
|
||||
rc = enc ? crypto_aead_encrypt(req) : crypto_aead_decrypt(req);
|
||||
|
||||
if (!rc && enc)
|
||||
memcpy(&tr_hdr->Signature, sign, SMB2_SIGNATURE_SIZE);
|
||||
@ -4526,7 +4512,7 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, int num_rqst,
|
||||
/* fill the 1st iov with a transform header */
|
||||
fill_transform_hdr(tr_hdr, orig_len, old_rq, server->cipher_type);
|
||||
|
||||
rc = crypt_message(server, num_rqst, new_rq, 1);
|
||||
rc = crypt_message(server, num_rqst, new_rq, 1, server->secmech.enc);
|
||||
cifs_dbg(FYI, "Encrypt message returned %d\n", rc);
|
||||
if (rc)
|
||||
goto err_free;
|
||||
@ -4551,8 +4537,9 @@ decrypt_raw_data(struct TCP_Server_Info *server, char *buf,
|
||||
unsigned int buf_data_size, struct iov_iter *iter,
|
||||
bool is_offloaded)
|
||||
{
|
||||
struct kvec iov[2];
|
||||
struct crypto_aead *tfm;
|
||||
struct smb_rqst rqst = {NULL};
|
||||
struct kvec iov[2];
|
||||
size_t iter_size = 0;
|
||||
int rc;
|
||||
|
||||
@ -4568,9 +4555,31 @@ decrypt_raw_data(struct TCP_Server_Info *server, char *buf,
|
||||
iter_size = iov_iter_count(iter);
|
||||
}
|
||||
|
||||
rc = crypt_message(server, 1, &rqst, 0);
|
||||
if (is_offloaded) {
|
||||
if ((server->cipher_type == SMB2_ENCRYPTION_AES128_GCM) ||
|
||||
(server->cipher_type == SMB2_ENCRYPTION_AES256_GCM))
|
||||
tfm = crypto_alloc_aead("gcm(aes)", 0, 0);
|
||||
else
|
||||
tfm = crypto_alloc_aead("ccm(aes)", 0, 0);
|
||||
if (IS_ERR(tfm)) {
|
||||
rc = PTR_ERR(tfm);
|
||||
cifs_server_dbg(VFS, "%s: Failed alloc decrypt TFM, rc=%d\n", __func__, rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
} else {
|
||||
if (unlikely(!server->secmech.dec))
|
||||
return -EIO;
|
||||
|
||||
tfm = server->secmech.dec;
|
||||
}
|
||||
|
||||
rc = crypt_message(server, 1, &rqst, 0, tfm);
|
||||
cifs_dbg(FYI, "Decrypt message returned %d\n", rc);
|
||||
|
||||
if (is_offloaded)
|
||||
crypto_free_aead(tfm);
|
||||
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
@ -1266,6 +1266,16 @@ SMB2_negotiate(const unsigned int xid,
|
||||
else
|
||||
cifs_server_dbg(VFS, "Missing expected negotiate contexts\n");
|
||||
}
|
||||
|
||||
if (server->cipher_type && !rc) {
|
||||
if (!SERVER_IS_CHAN(server)) {
|
||||
rc = smb3_crypto_aead_allocate(server);
|
||||
} else {
|
||||
/* For channels, just reuse the primary server crypto secmech. */
|
||||
server->secmech.enc = server->primary_server->secmech.enc;
|
||||
server->secmech.dec = server->primary_server->secmech.dec;
|
||||
}
|
||||
}
|
||||
neg_exit:
|
||||
free_rsp_buf(resp_buftype, rsp);
|
||||
return rc;
|
||||
|
@ -291,7 +291,7 @@ extern int smb2_validate_and_copy_iov(unsigned int offset,
|
||||
extern void smb2_copy_fs_info_to_kstatfs(
|
||||
struct smb2_fs_full_size_info *pfs_inf,
|
||||
struct kstatfs *kst);
|
||||
extern int smb311_crypto_shash_allocate(struct TCP_Server_Info *server);
|
||||
extern int smb3_crypto_shash_allocate(struct TCP_Server_Info *server);
|
||||
extern int smb311_update_preauth_hash(struct cifs_ses *ses,
|
||||
struct TCP_Server_Info *server,
|
||||
struct kvec *iov, int nvec);
|
||||
|
@ -26,8 +26,7 @@
|
||||
#include "../common/smb2status.h"
|
||||
#include "smb2glob.h"
|
||||
|
||||
static int
|
||||
smb3_crypto_shash_allocate(struct TCP_Server_Info *server)
|
||||
int smb3_crypto_shash_allocate(struct TCP_Server_Info *server)
|
||||
{
|
||||
struct cifs_secmech *p = &server->secmech;
|
||||
int rc;
|
||||
@ -46,33 +45,6 @@ smb3_crypto_shash_allocate(struct TCP_Server_Info *server)
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
smb311_crypto_shash_allocate(struct TCP_Server_Info *server)
|
||||
{
|
||||
struct cifs_secmech *p = &server->secmech;
|
||||
int rc = 0;
|
||||
|
||||
rc = cifs_alloc_hash("hmac(sha256)", &p->hmacsha256);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = cifs_alloc_hash("cmac(aes)", &p->aes_cmac);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
rc = cifs_alloc_hash("sha512", &p->sha512);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
cifs_free_hash(&p->aes_cmac);
|
||||
cifs_free_hash(&p->hmacsha256);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int smb2_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key)
|
||||
{
|
||||
@ -242,7 +214,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
|
||||
|
||||
ses = smb2_find_smb_ses(server, le64_to_cpu(shdr->SessionId));
|
||||
if (unlikely(!ses)) {
|
||||
cifs_server_dbg(VFS, "%s: Could not find session\n", __func__);
|
||||
cifs_server_dbg(FYI, "%s: Could not find session\n", __func__);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user