Re: [PATCH] cifs: Allocate crypto structures on the fly for calculating signatures of incoming packets

From: Pavel Shilovsky
Date: Fri Apr 03 2020 - 13:45:52 EST


ÐÑ, 31 ÐÐÑ. 2020 Ð. Ð 16:22, <longli@xxxxxxxxxxxxxxxxx>:
>
> From: Long Li <longli@xxxxxxxxxxxxx>
>
> 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@xxxxxxxxxxxxx>
> ---
> fs/cifs/cifsglob.h | 3 +-
> fs/cifs/smb2proto.h | 6 ++-
> fs/cifs/smb2transport.c | 87 +++++++++++++++++++++++++----------------
> 3 files changed, 60 insertions(+), 36 deletions(-)
>
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index 0d956360e984..7448e7202e7a 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -426,7 +426,8 @@ struct smb_version_operations {
> /* generate new lease key */
> void (*new_lease_key)(struct cifs_fid *);
> 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,
> struct cifsFileInfo *src_file);
> int (*enum_snapshots)(const unsigned int xid, struct cifs_tcon *tcon,
> diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
> index 4d1ff7b66fdc..087d5f14320b 100644
> --- a/fs/cifs/smb2proto.h
> +++ b/fs/cifs/smb2proto.h
> @@ -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,
> __u64 ses_id, __u32 tid);
> 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,
> - struct TCP_Server_Info *server);
> + struct TCP_Server_Info *server,
> + bool allocate_crypto);
> extern void smb2_echo_request(struct work_struct *work);
> extern __le32 smb2_get_lease_state(struct cifsInodeInfo *cinode);
> extern bool smb2_is_valid_oplock_break(char *buffer,
> diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c
> index 08b703b7a15e..c01e19a3b112 100644
> --- a/fs/cifs/smb2transport.c
> +++ b/fs/cifs/smb2transport.c
> @@ -40,14 +40,6 @@
> #include "smb2status.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
> 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
> -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;
> 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 cifs_ses *ses;
> struct shash_desc *shash;
> + struct crypto_shash *hash;
> + struct sdesc *sdesc = NULL;
> struct smb_rqst drqst;
>
> 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(shdr->Signature, 0x0, SMB2_SIGNATURE_SIZE);
>
> - rc = smb2_crypto_shash_allocate(server);
> - if (rc) {
> - cifs_server_dbg(VFS, "%s: sha256 alloc failed\n", __func__);
> - return rc;
> + if (allocate_crypto) {
> + rc = cifs_alloc_hash("hmac(sha256)", &hash, &sdesc);
> + if (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;
> }

smb2_crypto_shash_allocate() unconditionally allocated
server->secmech.hmacsha256 and server->secmech.sdeschmacsha256->shash.
Now the code doesn't allocate those variables at all. Unlike SMB3
where structures are allocated in during key generation, for SMB2 we
do it on demand in smb2_calc_signature(). So, the code above should be
changed to call smb2_crypto_shash_allocate() in "else" block.

--
Best regards,
Pavel Shilovsky