Commit f04ff5a0 authored by Linus Torvalds's avatar Linus Torvalds

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)
parents ad46e8f9 220d83b5
...@@ -58,6 +58,7 @@ static inline void netfs_proc_del_rreq(struct netfs_io_request *rreq) {} ...@@ -58,6 +58,7 @@ static inline void netfs_proc_del_rreq(struct netfs_io_request *rreq) {}
/* /*
* misc.c * 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, int netfs_buffer_append_folio(struct netfs_io_request *rreq, struct folio *folio,
bool needs_put); bool needs_put);
struct folio_queue *netfs_delete_buffer_head(struct netfs_io_request *wreq); struct folio_queue *netfs_delete_buffer_head(struct netfs_io_request *wreq);
......
...@@ -9,34 +9,66 @@ ...@@ -9,34 +9,66 @@
#include "internal.h" #include "internal.h"
/* /*
* Append a folio to the rolling queue. * Make sure there's space in the rolling queue.
*/ */
int netfs_buffer_append_folio(struct netfs_io_request *rreq, struct folio *folio, struct folio_queue *netfs_buffer_make_space(struct netfs_io_request *rreq)
bool needs_put)
{ {
struct folio_queue *tail = rreq->buffer_tail; struct folio_queue *tail = rreq->buffer_tail, *prev;
unsigned int slot, order = folio_order(folio); unsigned int prev_nr_slots = 0;
if (WARN_ON_ONCE(!rreq->buffer && tail) || if (WARN_ON_ONCE(!rreq->buffer && tail) ||
WARN_ON_ONCE(rreq->buffer && !tail)) WARN_ON_ONCE(rreq->buffer && !tail))
return -EIO; return ERR_PTR(-EIO);
if (!tail || folioq_full(tail)) { prev = tail;
tail = kmalloc(sizeof(*tail), GFP_NOFS); if (prev) {
if (!tail) if (!folioq_full(tail))
return -ENOMEM; return tail;
netfs_stat(&netfs_n_folioq); prev_nr_slots = folioq_nr_slots(tail);
folioq_init(tail); }
tail->prev = rreq->buffer_tail;
if (tail->prev) tail = kmalloc(sizeof(*tail), GFP_NOFS);
tail->prev->next = tail; if (!tail)
rreq->buffer_tail = tail; return ERR_PTR(-ENOMEM);
if (!rreq->buffer) { netfs_stat(&netfs_n_folioq);
rreq->buffer = tail; folioq_init(tail);
iov_iter_folio_queue(&rreq->io_iter, ITER_SOURCE, tail, 0, 0, 0); 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;
} }
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;
unsigned int slot, order = folio_order(folio);
tail = netfs_buffer_make_space(rreq);
if (IS_ERR(tail))
return PTR_ERR(tail);
rreq->io_iter.count += PAGE_SIZE << order; rreq->io_iter.count += PAGE_SIZE << order;
......
...@@ -153,12 +153,22 @@ static void netfs_prepare_write(struct netfs_io_request *wreq, ...@@ -153,12 +153,22 @@ static void netfs_prepare_write(struct netfs_io_request *wreq,
loff_t start) loff_t start)
{ {
struct netfs_io_subrequest *subreq; 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 = netfs_alloc_subrequest(wreq);
subreq->source = stream->source; subreq->source = stream->source;
subreq->start = start; subreq->start = start;
subreq->stream_nr = stream->stream_nr; 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); _enter("R=%x[%x]", wreq->debug_id, subreq->debug_index);
......
...@@ -416,7 +416,7 @@ find_timestamp(struct cifs_ses *ses) ...@@ -416,7 +416,7 @@ find_timestamp(struct cifs_ses *ses)
} }
static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, 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 rc = 0;
int len; int len;
...@@ -425,34 +425,26 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, ...@@ -425,34 +425,26 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
wchar_t *domain; wchar_t *domain;
wchar_t *server; 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 */ /* calculate md4 hash of password */
E_md4hash(ses->password, nt_hash, nls_cp); E_md4hash(ses->password, nt_hash, nls_cp);
rc = crypto_shash_setkey(ses->server->secmech.hmacmd5->tfm, nt_hash, rc = crypto_shash_setkey(hmacmd5->tfm, nt_hash, CIFS_NTHASH_SIZE);
CIFS_NTHASH_SIZE);
if (rc) { 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; return rc;
} }
rc = crypto_shash_init(ses->server->secmech.hmacmd5); rc = crypto_shash_init(hmacmd5);
if (rc) { 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; return rc;
} }
/* convert ses->user_name to unicode */ /* convert ses->user_name to unicode */
len = ses->user_name ? strlen(ses->user_name) : 0; len = ses->user_name ? strlen(ses->user_name) : 0;
user = kmalloc(2 + (len * 2), GFP_KERNEL); user = kmalloc(2 + (len * 2), GFP_KERNEL);
if (user == NULL) { if (user == NULL)
rc = -ENOMEM; return -ENOMEM;
return rc;
}
if (len) { if (len) {
len = cifs_strtoUTF16(user, ses->user_name, len, nls_cp); 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, ...@@ -461,11 +453,10 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
*(u16 *)user = 0; *(u16 *)user = 0;
} }
rc = crypto_shash_update(ses->server->secmech.hmacmd5, rc = crypto_shash_update(hmacmd5, (char *)user, 2 * len);
(char *)user, 2 * len);
kfree(user); kfree(user);
if (rc) { 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; return rc;
} }
...@@ -474,19 +465,15 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, ...@@ -474,19 +465,15 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
len = strlen(ses->domainName); len = strlen(ses->domainName);
domain = kmalloc(2 + (len * 2), GFP_KERNEL); domain = kmalloc(2 + (len * 2), GFP_KERNEL);
if (domain == NULL) { if (domain == NULL)
rc = -ENOMEM; return -ENOMEM;
return rc;
}
len = cifs_strtoUTF16((__le16 *)domain, ses->domainName, len, len = cifs_strtoUTF16((__le16 *)domain, ses->domainName, len,
nls_cp); nls_cp);
rc = rc = crypto_shash_update(hmacmd5, (char *)domain, 2 * len);
crypto_shash_update(ses->server->secmech.hmacmd5,
(char *)domain, 2 * len);
kfree(domain); kfree(domain);
if (rc) { if (rc) {
cifs_dbg(VFS, "%s: Could not update with domain\n", cifs_dbg(VFS, "%s: Could not update with domain, rc=%d\n", __func__, rc);
__func__);
return rc; return rc;
} }
} else { } else {
...@@ -494,33 +481,27 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, ...@@ -494,33 +481,27 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
len = strlen(ses->ip_addr); len = strlen(ses->ip_addr);
server = kmalloc(2 + (len * 2), GFP_KERNEL); server = kmalloc(2 + (len * 2), GFP_KERNEL);
if (server == NULL) { if (server == NULL)
rc = -ENOMEM; return -ENOMEM;
return rc;
} len = cifs_strtoUTF16((__le16 *)server, ses->ip_addr, len, nls_cp);
len = cifs_strtoUTF16((__le16 *)server, ses->ip_addr, len, rc = crypto_shash_update(hmacmd5, (char *)server, 2 * len);
nls_cp);
rc =
crypto_shash_update(ses->server->secmech.hmacmd5,
(char *)server, 2 * len);
kfree(server); kfree(server);
if (rc) { if (rc) {
cifs_dbg(VFS, "%s: Could not update with server\n", cifs_dbg(VFS, "%s: Could not update with server, rc=%d\n", __func__, rc);
__func__);
return rc; return rc;
} }
} }
rc = crypto_shash_final(ses->server->secmech.hmacmd5, rc = crypto_shash_final(hmacmd5, ntlmv2_hash);
ntlmv2_hash);
if (rc) 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; return rc;
} }
static int 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; int rc;
struct ntlmv2_resp *ntlmv2 = (struct ntlmv2_resp *) struct ntlmv2_resp *ntlmv2 = (struct ntlmv2_resp *)
...@@ -531,43 +512,33 @@ CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash) ...@@ -531,43 +512,33 @@ CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash)
hash_len = ses->auth_key.len - (CIFS_SESS_KEY_SIZE + hash_len = ses->auth_key.len - (CIFS_SESS_KEY_SIZE +
offsetof(struct ntlmv2_resp, challenge.key[0])); offsetof(struct ntlmv2_resp, challenge.key[0]));
if (!ses->server->secmech.hmacmd5) { rc = crypto_shash_setkey(hmacmd5->tfm, ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE);
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);
if (rc) { if (rc) {
cifs_dbg(VFS, "%s: Could not set NTLMV2 Hash as a key\n", cifs_dbg(VFS, "%s: Could not set NTLMv2 hash as a key, rc=%d\n", __func__, rc);
__func__);
return rc; return rc;
} }
rc = crypto_shash_init(ses->server->secmech.hmacmd5); rc = crypto_shash_init(hmacmd5);
if (rc) { 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; return rc;
} }
if (ses->server->negflavor == CIFS_NEGFLAVOR_EXTENDED) if (ses->server->negflavor == CIFS_NEGFLAVOR_EXTENDED)
memcpy(ntlmv2->challenge.key, memcpy(ntlmv2->challenge.key, ses->ntlmssp->cryptkey, CIFS_SERVER_CHALLENGE_SIZE);
ses->ntlmssp->cryptkey, CIFS_SERVER_CHALLENGE_SIZE);
else else
memcpy(ntlmv2->challenge.key, memcpy(ntlmv2->challenge.key, ses->server->cryptkey, CIFS_SERVER_CHALLENGE_SIZE);
ses->server->cryptkey, CIFS_SERVER_CHALLENGE_SIZE);
rc = crypto_shash_update(ses->server->secmech.hmacmd5, rc = crypto_shash_update(hmacmd5, ntlmv2->challenge.key, hash_len);
ntlmv2->challenge.key, hash_len);
if (rc) { 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; return rc;
} }
/* Note that the MD5 digest over writes anon.challenge_key.key */ /* Note that the MD5 digest over writes anon.challenge_key.key */
rc = crypto_shash_final(ses->server->secmech.hmacmd5, rc = crypto_shash_final(hmacmd5, ntlmv2->ntlmv2_hash);
ntlmv2->ntlmv2_hash);
if (rc) 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; return rc;
} }
...@@ -575,6 +546,7 @@ CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash) ...@@ -575,6 +546,7 @@ CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash)
int int
setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
{ {
struct shash_desc *hmacmd5 = NULL;
int rc; int rc;
int baselen; int baselen;
unsigned int tilen; unsigned int tilen;
...@@ -640,55 +612,51 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) ...@@ -640,55 +612,51 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
cifs_server_lock(ses->server); cifs_server_lock(ses->server);
rc = cifs_alloc_hash("hmac(md5)", &ses->server->secmech.hmacmd5); rc = cifs_alloc_hash("hmac(md5)", &hmacmd5);
if (rc) { if (rc) {
cifs_dbg(VFS, "Could not allocate HMAC-MD5, rc=%d\n", rc);
goto unlock; goto unlock;
} }
/* calculate ntlmv2_hash */ /* calculate ntlmv2_hash */
rc = calc_ntlmv2_hash(ses, ntlmv2_hash, nls_cp); rc = calc_ntlmv2_hash(ses, ntlmv2_hash, nls_cp, hmacmd5);
if (rc) { 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; goto unlock;
} }
/* calculate first part of the client response (CR1) */ /* calculate first part of the client response (CR1) */
rc = CalcNTLMv2_response(ses, ntlmv2_hash); rc = CalcNTLMv2_response(ses, ntlmv2_hash, hmacmd5);
if (rc) { 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; goto unlock;
} }
/* now calculate the session key for NTLMv2 */ /* now calculate the session key for NTLMv2 */
rc = crypto_shash_setkey(ses->server->secmech.hmacmd5->tfm, rc = crypto_shash_setkey(hmacmd5->tfm, ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE);
ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE);
if (rc) { if (rc) {
cifs_dbg(VFS, "%s: Could not set NTLMV2 Hash as a key\n", cifs_dbg(VFS, "%s: Could not set NTLMv2 hash as a key, rc=%d\n", __func__, rc);
__func__);
goto unlock; goto unlock;
} }
rc = crypto_shash_init(ses->server->secmech.hmacmd5); rc = crypto_shash_init(hmacmd5);
if (rc) { 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; goto unlock;
} }
rc = crypto_shash_update(ses->server->secmech.hmacmd5, rc = crypto_shash_update(hmacmd5, ntlmv2->ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE);
ntlmv2->ntlmv2_hash,
CIFS_HMAC_MD5_HASH_SIZE);
if (rc) { 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; goto unlock;
} }
rc = crypto_shash_final(ses->server->secmech.hmacmd5, rc = crypto_shash_final(hmacmd5, ses->auth_key.response);
ses->auth_key.response);
if (rc) 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: unlock:
cifs_server_unlock(ses->server); cifs_server_unlock(ses->server);
cifs_free_hash(&hmacmd5);
setup_ntlmv2_rsp_ret: setup_ntlmv2_rsp_ret:
kfree_sensitive(tiblob); kfree_sensitive(tiblob);
...@@ -732,16 +700,19 @@ cifs_crypto_secmech_release(struct TCP_Server_Info *server) ...@@ -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.aes_cmac);
cifs_free_hash(&server->secmech.hmacsha256); cifs_free_hash(&server->secmech.hmacsha256);
cifs_free_hash(&server->secmech.md5); cifs_free_hash(&server->secmech.md5);
cifs_free_hash(&server->secmech.sha512);
cifs_free_hash(&server->secmech.hmacmd5);
if (server->secmech.enc) { if (!SERVER_IS_CHAN(server)) {
crypto_free_aead(server->secmech.enc); if (server->secmech.enc) {
server->secmech.enc = NULL; crypto_free_aead(server->secmech.enc);
} server->secmech.enc = NULL;
}
if (server->secmech.dec) { if (server->secmech.dec) {
crypto_free_aead(server->secmech.dec); crypto_free_aead(server->secmech.dec);
server->secmech.dec = NULL;
}
} else {
server->secmech.enc = NULL;
server->secmech.dec = NULL; server->secmech.dec = NULL;
} }
} }
...@@ -178,10 +178,8 @@ struct session_key { ...@@ -178,10 +178,8 @@ struct session_key {
/* crypto hashing related structure/fields, not specific to a sec mech */ /* crypto hashing related structure/fields, not specific to a sec mech */
struct cifs_secmech { 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 *md5; /* md5 hash function, for CIFS/SMB1 signatures */
struct shash_desc *hmacsha256; /* hmac-sha256 hash function, for SMB2 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 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) */ 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, ...@@ -624,7 +624,7 @@ cifs_ses_add_channel(struct cifs_ses *ses,
* to sign packets before we generate the channel signing key * to sign packets before we generate the channel signing key
* (we sign with the session key) * (we sign with the session key)
*/ */
rc = smb311_crypto_shash_allocate(chan->server); rc = smb3_crypto_shash_allocate(chan->server);
if (rc) { if (rc) {
cifs_dbg(VFS, "%s: crypto alloc failed\n", __func__); cifs_dbg(VFS, "%s: crypto alloc failed\n", __func__);
mutex_unlock(&ses->session_mutex); mutex_unlock(&ses->session_mutex);
......
...@@ -906,41 +906,41 @@ smb311_update_preauth_hash(struct cifs_ses *ses, struct TCP_Server_Info *server, ...@@ -906,41 +906,41 @@ smb311_update_preauth_hash(struct cifs_ses *ses, struct TCP_Server_Info *server,
|| (hdr->Status != || (hdr->Status !=
cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED)))) cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))))
return 0; return 0;
ok: ok:
rc = smb311_crypto_shash_allocate(server); rc = cifs_alloc_hash("sha512", &sha512);
if (rc) if (rc) {
cifs_dbg(VFS, "%s: Could not allocate SHA512 shash, rc=%d\n", __func__, rc);
return rc; return rc;
}
sha512 = server->secmech.sha512;
rc = crypto_shash_init(sha512); rc = crypto_shash_init(sha512);
if (rc) { if (rc) {
cifs_dbg(VFS, "%s: Could not init sha512 shash\n", __func__); cifs_dbg(VFS, "%s: Could not init SHA512 shash, rc=%d\n", __func__, rc);
return rc; goto err_free;
} }
rc = crypto_shash_update(sha512, ses->preauth_sha_hash, rc = crypto_shash_update(sha512, ses->preauth_sha_hash,
SMB2_PREAUTH_HASH_SIZE); SMB2_PREAUTH_HASH_SIZE);
if (rc) { if (rc) {
cifs_dbg(VFS, "%s: Could not update sha512 shash\n", __func__); cifs_dbg(VFS, "%s: Could not update SHA512 shash, rc=%d\n", __func__, rc);
return rc; goto err_free;
} }
for (i = 0; i < nvec; i++) { for (i = 0; i < nvec; i++) {
rc = crypto_shash_update(sha512, iov[i].iov_base, iov[i].iov_len); rc = crypto_shash_update(sha512, iov[i].iov_base, iov[i].iov_len);
if (rc) { if (rc) {
cifs_dbg(VFS, "%s: Could not update sha512 shash\n", cifs_dbg(VFS, "%s: Could not update SHA512 shash, rc=%d\n", __func__, rc);
__func__); goto err_free;
return rc;
} }
} }
rc = crypto_shash_final(sha512, ses->preauth_sha_hash); rc = crypto_shash_final(sha512, ses->preauth_sha_hash);
if (rc) { if (rc) {
cifs_dbg(VFS, "%s: Could not finalize sha512 shash\n", cifs_dbg(VFS, "%s: Could not finalize SHA12 shash, rc=%d\n", __func__, rc);
__func__); goto err_free;
return rc;
} }
err_free:
cifs_free_hash(&sha512);
return 0; return 0;
} }
...@@ -4309,7 +4309,7 @@ smb2_get_enc_key(struct TCP_Server_Info *server, __u64 ses_id, int enc, u8 *key) ...@@ -4309,7 +4309,7 @@ smb2_get_enc_key(struct TCP_Server_Info *server, __u64 ses_id, int enc, u8 *key)
*/ */
static int static int
crypt_message(struct TCP_Server_Info *server, int num_rqst, 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 *tr_hdr =
(struct smb2_transform_hdr *)rqst[0].rq_iov[0].iov_base; (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, ...@@ -4320,8 +4320,6 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst,
u8 key[SMB3_ENC_DEC_KEY_SIZE]; u8 key[SMB3_ENC_DEC_KEY_SIZE];
struct aead_request *req; struct aead_request *req;
u8 *iv; u8 *iv;
DECLARE_CRYPTO_WAIT(wait);
struct crypto_aead *tfm;
unsigned int crypt_len = le32_to_cpu(tr_hdr->OriginalMessageSize); unsigned int crypt_len = le32_to_cpu(tr_hdr->OriginalMessageSize);
void *creq; void *creq;
size_t sensitive_size; size_t sensitive_size;
...@@ -4333,14 +4331,6 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst, ...@@ -4333,14 +4331,6 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst,
return rc; 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) || if ((server->cipher_type == SMB2_ENCRYPTION_AES256_CCM) ||
(server->cipher_type == SMB2_ENCRYPTION_AES256_GCM)) (server->cipher_type == SMB2_ENCRYPTION_AES256_GCM))
rc = crypto_aead_setkey(tfm, key, SMB3_GCM256_CRYPTKEY_SIZE); rc = crypto_aead_setkey(tfm, key, SMB3_GCM256_CRYPTKEY_SIZE);
...@@ -4380,11 +4370,7 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst, ...@@ -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_crypt(req, sg, sg, crypt_len, iv);
aead_request_set_ad(req, assoc_data_len); aead_request_set_ad(req, assoc_data_len);
aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, rc = enc ? crypto_aead_encrypt(req) : crypto_aead_decrypt(req);
crypto_req_done, &wait);
rc = crypto_wait_req(enc ? crypto_aead_encrypt(req)
: crypto_aead_decrypt(req), &wait);
if (!rc && enc) if (!rc && enc)
memcpy(&tr_hdr->Signature, sign, SMB2_SIGNATURE_SIZE); memcpy(&tr_hdr->Signature, sign, SMB2_SIGNATURE_SIZE);
...@@ -4526,7 +4512,7 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, int num_rqst, ...@@ -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 the 1st iov with a transform header */
fill_transform_hdr(tr_hdr, orig_len, old_rq, server->cipher_type); 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); cifs_dbg(FYI, "Encrypt message returned %d\n", rc);
if (rc) if (rc)
goto err_free; goto err_free;
...@@ -4551,8 +4537,9 @@ decrypt_raw_data(struct TCP_Server_Info *server, char *buf, ...@@ -4551,8 +4537,9 @@ decrypt_raw_data(struct TCP_Server_Info *server, char *buf,
unsigned int buf_data_size, struct iov_iter *iter, unsigned int buf_data_size, struct iov_iter *iter,
bool is_offloaded) bool is_offloaded)
{ {
struct kvec iov[2]; struct crypto_aead *tfm;
struct smb_rqst rqst = {NULL}; struct smb_rqst rqst = {NULL};
struct kvec iov[2];
size_t iter_size = 0; size_t iter_size = 0;
int rc; int rc;
...@@ -4568,9 +4555,31 @@ decrypt_raw_data(struct TCP_Server_Info *server, char *buf, ...@@ -4568,9 +4555,31 @@ decrypt_raw_data(struct TCP_Server_Info *server, char *buf,
iter_size = iov_iter_count(iter); 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); cifs_dbg(FYI, "Decrypt message returned %d\n", rc);
if (is_offloaded)
crypto_free_aead(tfm);
if (rc) if (rc)
return rc; return rc;
......
...@@ -1266,6 +1266,16 @@ SMB2_negotiate(const unsigned int xid, ...@@ -1266,6 +1266,16 @@ SMB2_negotiate(const unsigned int xid,
else else
cifs_server_dbg(VFS, "Missing expected negotiate contexts\n"); 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: neg_exit:
free_rsp_buf(resp_buftype, rsp); free_rsp_buf(resp_buftype, rsp);
return rc; return rc;
......
...@@ -291,7 +291,7 @@ extern int smb2_validate_and_copy_iov(unsigned int offset, ...@@ -291,7 +291,7 @@ extern int smb2_validate_and_copy_iov(unsigned int offset,
extern void smb2_copy_fs_info_to_kstatfs( extern void smb2_copy_fs_info_to_kstatfs(
struct smb2_fs_full_size_info *pfs_inf, struct smb2_fs_full_size_info *pfs_inf,
struct kstatfs *kst); 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, extern int smb311_update_preauth_hash(struct cifs_ses *ses,
struct TCP_Server_Info *server, struct TCP_Server_Info *server,
struct kvec *iov, int nvec); struct kvec *iov, int nvec);
......
...@@ -26,8 +26,7 @@ ...@@ -26,8 +26,7 @@
#include "../common/smb2status.h" #include "../common/smb2status.h"
#include "smb2glob.h" #include "smb2glob.h"
static int int smb3_crypto_shash_allocate(struct TCP_Server_Info *server)
smb3_crypto_shash_allocate(struct TCP_Server_Info *server)
{ {
struct cifs_secmech *p = &server->secmech; struct cifs_secmech *p = &server->secmech;
int rc; int rc;
...@@ -46,33 +45,6 @@ smb3_crypto_shash_allocate(struct TCP_Server_Info *server) ...@@ -46,33 +45,6 @@ smb3_crypto_shash_allocate(struct TCP_Server_Info *server)
return rc; 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 static
int smb2_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key) 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, ...@@ -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)); ses = smb2_find_smb_ses(server, le64_to_cpu(shdr->SessionId));
if (unlikely(!ses)) { 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; return -ENOENT;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment