Commit eda1c54f authored by Long Li's avatar Long Li Committed by Steve French

cifs: Allocate crypto structures on the fly for calculating signatures of incoming packets

CIFS uses pre-allocated crypto structures to calculate signatures for both
incoming and outgoing packets. In this way it doesn't need to allocate crypto
structures for every packet, but it requires a lock to prevent concurrent
access to crypto structures.

Remove the lock by allocating crypto structures on the fly for
incoming packets. At the same time, we can still use pre-allocated crypto
structures for outgoing packets, as they are already protected by transport
lock srv_mutex.
Signed-off-by: default avatarLong Li <longli@microsoft.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent d4e5160d
...@@ -426,7 +426,8 @@ struct smb_version_operations { ...@@ -426,7 +426,8 @@ struct smb_version_operations {
/* generate new lease key */ /* generate new lease key */
void (*new_lease_key)(struct cifs_fid *); void (*new_lease_key)(struct cifs_fid *);
int (*generate_signingkey)(struct cifs_ses *); int (*generate_signingkey)(struct cifs_ses *);
int (*calc_signature)(struct smb_rqst *, struct TCP_Server_Info *); int (*calc_signature)(struct smb_rqst *, struct TCP_Server_Info *,
bool allocate_crypto);
int (*set_integrity)(const unsigned int, struct cifs_tcon *tcon, int (*set_integrity)(const unsigned int, struct cifs_tcon *tcon,
struct cifsFileInfo *src_file); struct cifsFileInfo *src_file);
int (*enum_snapshots)(const unsigned int xid, struct cifs_tcon *tcon, int (*enum_snapshots)(const unsigned int xid, struct cifs_tcon *tcon,
......
...@@ -55,9 +55,11 @@ extern struct cifs_ses *smb2_find_smb_ses(struct TCP_Server_Info *server, ...@@ -55,9 +55,11 @@ extern struct cifs_ses *smb2_find_smb_ses(struct TCP_Server_Info *server,
extern struct cifs_tcon *smb2_find_smb_tcon(struct TCP_Server_Info *server, extern struct cifs_tcon *smb2_find_smb_tcon(struct TCP_Server_Info *server,
__u64 ses_id, __u32 tid); __u64 ses_id, __u32 tid);
extern int smb2_calc_signature(struct smb_rqst *rqst, extern int smb2_calc_signature(struct smb_rqst *rqst,
struct TCP_Server_Info *server); struct TCP_Server_Info *server,
bool allocate_crypto);
extern int smb3_calc_signature(struct smb_rqst *rqst, extern int smb3_calc_signature(struct smb_rqst *rqst,
struct TCP_Server_Info *server); struct TCP_Server_Info *server,
bool allocate_crypto);
extern void smb2_echo_request(struct work_struct *work); extern void smb2_echo_request(struct work_struct *work);
extern __le32 smb2_get_lease_state(struct cifsInodeInfo *cinode); extern __le32 smb2_get_lease_state(struct cifsInodeInfo *cinode);
extern bool smb2_is_valid_oplock_break(char *buffer, extern bool smb2_is_valid_oplock_break(char *buffer,
......
...@@ -40,14 +40,6 @@ ...@@ -40,14 +40,6 @@
#include "smb2status.h" #include "smb2status.h"
#include "smb2glob.h" #include "smb2glob.h"
static int
smb2_crypto_shash_allocate(struct TCP_Server_Info *server)
{
return cifs_alloc_hash("hmac(sha256)",
&server->secmech.hmacsha256,
&server->secmech.sdeschmacsha256);
}
static int static int
smb3_crypto_shash_allocate(struct TCP_Server_Info *server) smb3_crypto_shash_allocate(struct TCP_Server_Info *server)
{ {
...@@ -219,7 +211,8 @@ smb2_find_smb_tcon(struct TCP_Server_Info *server, __u64 ses_id, __u32 tid) ...@@ -219,7 +211,8 @@ smb2_find_smb_tcon(struct TCP_Server_Info *server, __u64 ses_id, __u32 tid)
} }
int int
smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
bool allocate_crypto)
{ {
int rc; int rc;
unsigned char smb2_signature[SMB2_HMACSHA256_SIZE]; unsigned char smb2_signature[SMB2_HMACSHA256_SIZE];
...@@ -228,6 +221,8 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) ...@@ -228,6 +221,8 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[0].iov_base; struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[0].iov_base;
struct cifs_ses *ses; struct cifs_ses *ses;
struct shash_desc *shash; struct shash_desc *shash;
struct crypto_shash *hash;
struct sdesc *sdesc = NULL;
struct smb_rqst drqst; struct smb_rqst drqst;
ses = smb2_find_smb_ses(server, shdr->SessionId); ses = smb2_find_smb_ses(server, shdr->SessionId);
...@@ -239,24 +234,32 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) ...@@ -239,24 +234,32 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
memset(smb2_signature, 0x0, SMB2_HMACSHA256_SIZE); memset(smb2_signature, 0x0, SMB2_HMACSHA256_SIZE);
memset(shdr->Signature, 0x0, SMB2_SIGNATURE_SIZE); memset(shdr->Signature, 0x0, SMB2_SIGNATURE_SIZE);
rc = smb2_crypto_shash_allocate(server); if (allocate_crypto) {
rc = cifs_alloc_hash("hmac(sha256)", &hash, &sdesc);
if (rc) { if (rc) {
cifs_server_dbg(VFS, "%s: sha256 alloc failed\n", __func__); cifs_server_dbg(VFS,
"%s: sha256 alloc failed\n", __func__);
return rc; return rc;
} }
shash = &sdesc->shash;
} else {
hash = server->secmech.hmacsha256;
shash = &server->secmech.sdeschmacsha256->shash;
}
rc = crypto_shash_setkey(server->secmech.hmacsha256, rc = crypto_shash_setkey(hash, ses->auth_key.response,
ses->auth_key.response, SMB2_NTLMV2_SESSKEY_SIZE); SMB2_NTLMV2_SESSKEY_SIZE);
if (rc) { if (rc) {
cifs_server_dbg(VFS, "%s: Could not update with response\n", __func__); cifs_server_dbg(VFS,
return rc; "%s: Could not update with response\n",
__func__);
goto out;
} }
shash = &server->secmech.sdeschmacsha256->shash;
rc = crypto_shash_init(shash); rc = crypto_shash_init(shash);
if (rc) { if (rc) {
cifs_server_dbg(VFS, "%s: Could not init sha256", __func__); cifs_server_dbg(VFS, "%s: Could not init sha256", __func__);
return rc; goto out;
} }
/* /*
...@@ -271,9 +274,10 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) ...@@ -271,9 +274,10 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
rc = crypto_shash_update(shash, iov[0].iov_base, rc = crypto_shash_update(shash, iov[0].iov_base,
iov[0].iov_len); iov[0].iov_len);
if (rc) { if (rc) {
cifs_server_dbg(VFS, "%s: Could not update with payload\n", cifs_server_dbg(VFS,
"%s: Could not update with payload\n",
__func__); __func__);
return rc; goto out;
} }
drqst.rq_iov++; drqst.rq_iov++;
drqst.rq_nvec--; drqst.rq_nvec--;
...@@ -283,6 +287,9 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) ...@@ -283,6 +287,9 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
if (!rc) if (!rc)
memcpy(shdr->Signature, sigptr, SMB2_SIGNATURE_SIZE); memcpy(shdr->Signature, sigptr, SMB2_SIGNATURE_SIZE);
out:
if (allocate_crypto)
cifs_free_hash(&hash, &sdesc);
return rc; return rc;
} }
...@@ -504,14 +511,17 @@ generate_smb311signingkey(struct cifs_ses *ses) ...@@ -504,14 +511,17 @@ generate_smb311signingkey(struct cifs_ses *ses)
} }
int int
smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
bool allocate_crypto)
{ {
int rc; int rc;
unsigned char smb3_signature[SMB2_CMACAES_SIZE]; unsigned char smb3_signature[SMB2_CMACAES_SIZE];
unsigned char *sigptr = smb3_signature; unsigned char *sigptr = smb3_signature;
struct kvec *iov = rqst->rq_iov; struct kvec *iov = rqst->rq_iov;
struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[0].iov_base; struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[0].iov_base;
struct shash_desc *shash = &server->secmech.sdesccmacaes->shash; struct shash_desc *shash;
struct crypto_shash *hash;
struct sdesc *sdesc = NULL;
struct smb_rqst drqst; struct smb_rqst drqst;
u8 key[SMB3_SIGN_KEY_SIZE]; u8 key[SMB3_SIGN_KEY_SIZE];
...@@ -519,14 +529,24 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) ...@@ -519,14 +529,24 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
if (rc) if (rc)
return 0; return 0;
if (allocate_crypto) {
rc = cifs_alloc_hash("cmac(aes)", &hash, &sdesc);
if (rc)
return rc;
shash = &sdesc->shash;
} else {
hash = server->secmech.cmacaes;
shash = &server->secmech.sdesccmacaes->shash;
}
memset(smb3_signature, 0x0, SMB2_CMACAES_SIZE); memset(smb3_signature, 0x0, SMB2_CMACAES_SIZE);
memset(shdr->Signature, 0x0, SMB2_SIGNATURE_SIZE); memset(shdr->Signature, 0x0, SMB2_SIGNATURE_SIZE);
rc = crypto_shash_setkey(server->secmech.cmacaes, rc = crypto_shash_setkey(hash, key, SMB2_CMACAES_SIZE);
key, SMB2_CMACAES_SIZE);
if (rc) { if (rc) {
cifs_server_dbg(VFS, "%s: Could not set key for cmac aes\n", __func__); cifs_server_dbg(VFS, "%s: Could not set key for cmac aes\n", __func__);
return rc; goto out;
} }
/* /*
...@@ -537,7 +557,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) ...@@ -537,7 +557,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
rc = crypto_shash_init(shash); rc = crypto_shash_init(shash);
if (rc) { if (rc) {
cifs_server_dbg(VFS, "%s: Could not init cmac aes\n", __func__); cifs_server_dbg(VFS, "%s: Could not init cmac aes\n", __func__);
return rc; goto out;
} }
/* /*
...@@ -554,7 +574,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) ...@@ -554,7 +574,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
if (rc) { if (rc) {
cifs_server_dbg(VFS, "%s: Could not update with payload\n", cifs_server_dbg(VFS, "%s: Could not update with payload\n",
__func__); __func__);
return rc; goto out;
} }
drqst.rq_iov++; drqst.rq_iov++;
drqst.rq_nvec--; drqst.rq_nvec--;
...@@ -564,6 +584,9 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) ...@@ -564,6 +584,9 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
if (!rc) if (!rc)
memcpy(shdr->Signature, sigptr, SMB2_SIGNATURE_SIZE); memcpy(shdr->Signature, sigptr, SMB2_SIGNATURE_SIZE);
out:
if (allocate_crypto)
cifs_free_hash(&hash, &sdesc);
return rc; return rc;
} }
...@@ -593,7 +616,7 @@ smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server) ...@@ -593,7 +616,7 @@ smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server)
return 0; return 0;
} }
rc = server->ops->calc_signature(rqst, server); rc = server->ops->calc_signature(rqst, server, false);
return rc; return rc;
} }
...@@ -631,9 +654,7 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) ...@@ -631,9 +654,7 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
memset(shdr->Signature, 0, SMB2_SIGNATURE_SIZE); memset(shdr->Signature, 0, SMB2_SIGNATURE_SIZE);
mutex_lock(&server->srv_mutex); rc = server->ops->calc_signature(rqst, server, true);
rc = server->ops->calc_signature(rqst, server);
mutex_unlock(&server->srv_mutex);
if (rc) if (rc)
return rc; return rc;
......
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