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: Long Li <longli@microsoft.com> Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
Родитель
d4e5160d1a
Коммит
eda1c54f14
|
@ -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,
|
||||||
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 @@
|
||||||
#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)
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
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) {
|
||||||
if (rc) {
|
rc = cifs_alloc_hash("hmac(sha256)", &hash, &sdesc);
|
||||||
cifs_server_dbg(VFS, "%s: sha256 alloc failed\n", __func__);
|
if (rc) {
|
||||||
return rc;
|
cifs_server_dbg(VFS,
|
||||||
|
"%s: sha256 alloc failed\n", __func__);
|
||||||
|
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)
|
||||||
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,
|
||||||
__func__);
|
"%s: Could not update with payload\n",
|
||||||
return rc;
|
__func__);
|
||||||
|
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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
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;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче