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

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
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -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,
+4 −2
Original line number Diff line number Diff line
@@ -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,
+54 −33
Original line number Diff line number Diff line
@@ -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 (allocate_crypto) {
		rc = cifs_alloc_hash("hmac(sha256)", &hash, &sdesc);
		if (rc) {
		cifs_server_dbg(VFS, "%s: sha256 alloc failed\n", __func__);
			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,
				 ses->auth_key.response, SMB2_NTLMV2_SESSKEY_SIZE);
	rc = crypto_shash_setkey(hash, ses->auth_key.response,
			SMB2_NTLMV2_SESSKEY_SIZE);
	if (rc) {
		cifs_server_dbg(VFS, "%s: Could not update with response\n", __func__);
		return rc;
		cifs_server_dbg(VFS,
				"%s: Could not update with response\n",
				__func__);
		goto out;
	}

	shash = &server->secmech.sdeschmacsha256->shash;
	rc = crypto_shash_init(shash);
	if (rc) {
		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,
					 iov[0].iov_len);
		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__);
			return rc;
			goto out;
		}
		drqst.rq_iov++;
		drqst.rq_nvec--;
@@ -283,6 +287,9 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
	if (!rc)
		memcpy(shdr->Signature, sigptr, SMB2_SIGNATURE_SIZE);

out:
	if (allocate_crypto)
		cifs_free_hash(&hash, &sdesc);
	return rc;
}

@@ -504,14 +511,17 @@ generate_smb311signingkey(struct cifs_ses *ses)
}

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;
	unsigned char smb3_signature[SMB2_CMACAES_SIZE];
	unsigned char *sigptr = smb3_signature;
	struct kvec *iov = rqst->rq_iov;
	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;
	u8 key[SMB3_SIGN_KEY_SIZE];

@@ -519,14 +529,24 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
	if (rc)
		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(shdr->Signature, 0x0, SMB2_SIGNATURE_SIZE);

	rc = crypto_shash_setkey(server->secmech.cmacaes,
				 key, SMB2_CMACAES_SIZE);
	rc = crypto_shash_setkey(hash, key, SMB2_CMACAES_SIZE);
	if (rc) {
		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);
	if (rc) {
		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) {
			cifs_server_dbg(VFS, "%s: Could not update with payload\n",
				 __func__);
			return rc;
			goto out;
		}
		drqst.rq_iov++;
		drqst.rq_nvec--;
@@ -564,6 +584,9 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
	if (!rc)
		memcpy(shdr->Signature, sigptr, SMB2_SIGNATURE_SIZE);

out:
	if (allocate_crypto)
		cifs_free_hash(&hash, &sdesc);
	return rc;
}

@@ -593,7 +616,7 @@ smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server)
		return 0;
	}

	rc = server->ops->calc_signature(rqst, server);
	rc = server->ops->calc_signature(rqst, server, false);

	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);

	mutex_lock(&server->srv_mutex);
	rc = server->ops->calc_signature(rqst, server);
	mutex_unlock(&server->srv_mutex);
	rc = server->ops->calc_signature(rqst, server, true);

	if (rc)
		return rc;