[PATCH 09/23] TPMLIB: Do some source cleanups

David Howells <[email protected]>
Newsgroups net.sourceforge.lists.tpmdd-devel,org.kernel.vger.keyrings,org.kernel.vger.linux-integrity,org.kernel.vger.linux-security-module
Message-ID <153486707011.13066.14435967283392358361.stgit@warthog.procyon.org.uk>
Clean up the TPM library file that was split out of trusted keys.

Signed-off-by: David Howells <[email protected]>
---

 drivers/char/tpm/tpm-library.c |  187 +++++++++++++++++++++++-----------------
 drivers/char/tpm/tpm-library.h |   14 +--
 include/linux/tpm.h            |    4 -
 security/keys/trusted.c        |    6 +
 4 files changed, 121 insertions(+), 90 deletions(-)

diff --git a/drivers/char/tpm/tpm-library.c b/drivers/char/tpm/tpm-library.c
index 1be4f71cabcb..e4cfc1f090e1 100644
--- a/drivers/char/tpm/tpm-library.c
+++ b/drivers/char/tpm/tpm-library.c
@@ -8,44 +8,36 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation, version 2 of the License.
- *
- * See Documentation/security/keys-trusted-encrypted.txt
  */
 
-#include <linux/uaccess.h>
-#include <linux/module.h>
-#include <linux/init.h>
+#define pr_fmt(fmt) "TPMLIB: "fmt
 #include <linux/slab.h>
-#include <linux/parser.h>
-#include <linux/string.h>
 #include <linux/err.h>
-#include <keys/user-type.h>
-#include <keys/trusted-type.h>
-#include <linux/key-type.h>
-#include <linux/rcupdate.h>
+#include <linux/mutex.h>
 #include <linux/crypto.h>
 #include <crypto/hash.h>
 #include <crypto/sha.h>
-#include <linux/capability.h>
 #include <linux/tpm.h>
 #include <linux/tpm_command.h>
 
 #include "tpm-library.h"
 
-static const char hmac_alg[] = "hmac(sha1)";
-static const char hash_alg[] = "sha1";
+static const char tpm_hmac_alg[] = "hmac(sha1)";
+static const char tpm_hash_alg[] = "sha1";
 
-struct sdesc {
+struct tpm_sdesc {
 	struct shash_desc shash;
 	char ctx[];
 };
 
-static struct crypto_shash *hashalg;
-static struct crypto_shash *hmacalg;
+static DEFINE_MUTEX(tpm_library_init_mutex);
+static atomic_t tpm_library_usage;
+static struct crypto_shash *tpm_hashalg;
+static struct crypto_shash *tpm_hmacalg;
 
-static struct sdesc *init_sdesc(struct crypto_shash *alg)
+static struct tpm_sdesc *tpm_init_sdesc(struct crypto_shash *alg)
 {
-	struct sdesc *sdesc;
+	struct tpm_sdesc *sdesc;
 	int size;
 
 	size = sizeof(struct shash_desc) + crypto_shash_descsize(alg);
@@ -60,12 +52,12 @@ static struct sdesc *init_sdesc(struct crypto_shash *alg)
 static int TSS_sha1(const unsigned char *data, unsigned int datalen,
 		    unsigned char *digest)
 {
-	struct sdesc *sdesc;
+	struct tpm_sdesc *sdesc;
 	int ret;
 
-	sdesc = init_sdesc(hashalg);
+	sdesc = tpm_init_sdesc(tpm_hashalg);
 	if (IS_ERR(sdesc)) {
-		pr_info("trusted_key: can't alloc %s\n", hash_alg);
+		pr_info("Can't alloc %s\n", tpm_hash_alg);
 		return PTR_ERR(sdesc);
 	}
 
@@ -77,19 +69,19 @@ static int TSS_sha1(const unsigned char *data, unsigned int datalen,
 static int TSS_rawhmac(unsigned char *digest, const unsigned char *key,
 		       unsigned int keylen, ...)
 {
-	struct sdesc *sdesc;
+	struct tpm_sdesc *sdesc;
 	va_list argp;
 	unsigned int dlen;
 	unsigned char *data;
 	int ret;
 
-	sdesc = init_sdesc(hmacalg);
+	sdesc = tpm_init_sdesc(tpm_hmacalg);
 	if (IS_ERR(sdesc)) {
-		pr_info("trusted_key: can't alloc %s\n", hmac_alg);
+		pr_info("Can't alloc %s\n", tpm_hmac_alg);
 		return PTR_ERR(sdesc);
 	}
 
-	ret = crypto_shash_setkey(hmacalg, key, keylen);
+	ret = crypto_shash_setkey(tpm_hmacalg, key, keylen);
 	if (ret < 0)
 		goto out;
 	ret = crypto_shash_init(&sdesc->shash);
@@ -126,16 +118,16 @@ static int TSS_authhmac(unsigned char *digest, const unsigned char *key,
 			unsigned char *h2, unsigned char h3, ...)
 {
 	unsigned char paramdigest[SHA1_DIGEST_SIZE];
-	struct sdesc *sdesc;
+	struct tpm_sdesc *sdesc;
 	unsigned int dlen;
 	unsigned char *data;
 	unsigned char c;
 	int ret;
 	va_list argp;
 
-	sdesc = init_sdesc(hashalg);
+	sdesc = tpm_init_sdesc(tpm_hashalg);
 	if (IS_ERR(sdesc)) {
-		pr_info("trusted_key: can't alloc %s\n", hash_alg);
+		pr_info("Can't alloc %s\n", tpm_hash_alg);
 		return PTR_ERR(sdesc);
 	}
 
@@ -187,7 +179,7 @@ static int TSS_checkhmac1(unsigned char *buffer,
 	unsigned char *authdata;
 	unsigned char testhmac[SHA1_DIGEST_SIZE];
 	unsigned char paramdigest[SHA1_DIGEST_SIZE];
-	struct sdesc *sdesc;
+	struct tpm_sdesc *sdesc;
 	unsigned int dlen;
 	unsigned int dpos;
 	va_list argp;
@@ -205,9 +197,9 @@ static int TSS_checkhmac1(unsigned char *buffer,
 	continueflag = authdata - 1;
 	enonce = continueflag - TPM_NONCE_SIZE;
 
-	sdesc = init_sdesc(hashalg);
+	sdesc = tpm_init_sdesc(tpm_hashalg);
 	if (IS_ERR(sdesc)) {
-		pr_info("trusted_key: can't alloc %s\n", hash_alg);
+		pr_info("Can't alloc %s\n", tpm_hash_alg);
 		return PTR_ERR(sdesc);
 	}
 	ret = crypto_shash_init(&sdesc->shash);
@@ -274,7 +266,7 @@ static int TSS_checkhmac2(unsigned char *buffer,
 	unsigned char testhmac1[SHA1_DIGEST_SIZE];
 	unsigned char testhmac2[SHA1_DIGEST_SIZE];
 	unsigned char paramdigest[SHA1_DIGEST_SIZE];
-	struct sdesc *sdesc;
+	struct tpm_sdesc *sdesc;
 	unsigned int dlen;
 	unsigned int dpos;
 	va_list argp;
@@ -297,9 +289,9 @@ static int TSS_checkhmac2(unsigned char *buffer,
 	enonce1 = continueflag1 - TPM_NONCE_SIZE;
 	enonce2 = continueflag2 - TPM_NONCE_SIZE;
 
-	sdesc = init_sdesc(hashalg);
+	sdesc = tpm_init_sdesc(tpm_hashalg);
 	if (IS_ERR(sdesc)) {
-		pr_info("trusted_key: can't alloc %s\n", hash_alg);
+		pr_info("Can't alloc %s\n", tpm_hash_alg);
 		return PTR_ERR(sdesc);
 	}
 	ret = crypto_shash_init(&sdesc->shash);
@@ -355,8 +347,8 @@ out:
  * For key specific tpm requests, we will generate and send our
  * own TPM command packets using the drivers send function.
  */
-static int trusted_tpm_send(struct tpm_chip *chip, unsigned char *cmd,
-			    size_t buflen, const char *desc)
+static int tpm_send_dump(struct tpm_chip *chip,
+			 unsigned char *cmd, size_t buflen, const char *desc)
 {
 	int rc;
 
@@ -372,9 +364,10 @@ static int trusted_tpm_send(struct tpm_chip *chip, unsigned char *cmd,
 /*
  * Create an object specific authorisation protocol (OSAP) session
  */
-static int osap(struct tpm_chip *chip,
-		struct tpm_buf *tb, struct osapsess *s,
-		const unsigned char *key, uint16_t type, uint32_t handle)
+static int tpm_create_osap(struct tpm_chip *chip,
+			   struct tpm_buf *tb, struct tpm_osapsess *s,
+			   const unsigned char *key, uint16_t type,
+			   uint32_t handle)
 {
 	unsigned char enonce[TPM_NONCE_SIZE];
 	unsigned char ononce[TPM_NONCE_SIZE];
@@ -392,8 +385,8 @@ static int osap(struct tpm_chip *chip,
 	store32(tb, handle);
 	storebytes(tb, ononce, TPM_NONCE_SIZE);
 
-	ret = trusted_tpm_send(chip, tb->data, MAX_BUF_SIZE,
-			       "creating OSAP session");
+	ret = tpm_send_dump(chip, tb->data, MAX_BUF_SIZE,
+			    "creating OSAP session");
 	if (ret < 0)
 		return ret;
 
@@ -409,8 +402,8 @@ static int osap(struct tpm_chip *chip,
 /*
  * Create an object independent authorisation protocol (oiap) session
  */
-static int oiap(struct tpm_chip *chip, struct tpm_buf *tb, uint32_t *handle,
-		unsigned char *nonce)
+static int tpm_create_oiap(struct tpm_chip *chip, struct tpm_buf *tb,
+			   uint32_t *handle, unsigned char *nonce)
 {
 	int ret;
 
@@ -418,8 +411,8 @@ static int oiap(struct tpm_chip *chip, struct tpm_buf *tb, uint32_t *handle,
 	store16(tb, TPM_TAG_RQU_COMMAND);
 	store32(tb, TPM_OIAP_SIZE);
 	store32(tb, TPM_ORD_OIAP);
-	ret = trusted_tpm_send(chip, tb->data, MAX_BUF_SIZE,
-			       "creating OIAP session");
+	ret = tpm_send_dump(chip, tb->data, MAX_BUF_SIZE,
+			    "creating OIAP session");
 	if (ret < 0)
 		return ret;
 
@@ -448,7 +441,7 @@ int tpm_seal(struct tpm_chip *chip, struct tpm_buf *tb, uint16_t keytype,
 	     const unsigned char *blobauth,
 	     const unsigned char *pcrinfo, uint32_t pcrinfosize)
 {
-	struct osapsess sess;
+	struct tpm_osapsess sess;
 	struct tpm_digests *td;
 	unsigned char cont;
 	uint32_t ordinal;
@@ -466,7 +459,7 @@ int tpm_seal(struct tpm_chip *chip, struct tpm_buf *tb, uint16_t keytype,
 		return -ENOMEM;
 
 	/* get session for sealing key */
-	ret = osap(chip, tb, &sess, keyauth, keytype, keyhandle);
+	ret = tpm_create_osap(chip, tb, &sess, keyauth, keytype, keyhandle);
 	if (ret < 0)
 		goto out;
 	dump_sess(&sess);
@@ -527,8 +520,8 @@ int tpm_seal(struct tpm_chip *chip, struct tpm_buf *tb, uint16_t keytype,
 	store8(tb, cont);
 	storebytes(tb, td->pubauth, SHA1_DIGEST_SIZE);
 
-	ret = trusted_tpm_send(chip, tb->data, MAX_BUF_SIZE,
-			       "sealing data");
+	ret = tpm_send_dump(chip, tb->data, MAX_BUF_SIZE,
+			    "sealing data");
 	if (ret < 0)
 		goto out;
 
@@ -577,14 +570,14 @@ int tpm_unseal(struct tpm_chip *chip, struct tpm_buf *tb,
 	int ret;
 
 	/* sessions for unsealing key and data */
-	ret = oiap(chip, tb, &authhandle1, enonce1);
+	ret = tpm_create_oiap(chip, tb, &authhandle1, enonce1);
 	if (ret < 0) {
-		pr_info("trusted_key: oiap failed (%d)\n", ret);
+		pr_info("Failed to create OIAP 1 (%d)\n", ret);
 		return ret;
 	}
-	ret = oiap(chip, tb, &authhandle2, enonce2);
+	ret = tpm_create_oiap(chip, tb, &authhandle2, enonce2);
 	if (ret < 0) {
-		pr_info("trusted_key: oiap failed (%d)\n", ret);
+		pr_info("Failed to create OIAP 2 (%d)\n", ret);
 		return ret;
 	}
 
@@ -592,7 +585,7 @@ int tpm_unseal(struct tpm_chip *chip, struct tpm_buf *tb,
 	keyhndl = htonl(SRKHANDLE);
 	ret = tpm_get_random(chip, nonceodd, TPM_NONCE_SIZE);
 	if (ret != TPM_NONCE_SIZE) {
-		pr_info("trusted_key: tpm_get_random failed (%d)\n", ret);
+		pr_info("tpm_get_random failed (%d)\n", ret);
 		return ret;
 	}
 	ret = TSS_authhmac(authdata1, keyauth, TPM_NONCE_SIZE,
@@ -622,10 +615,10 @@ int tpm_unseal(struct tpm_chip *chip, struct tpm_buf *tb,
 	store8(tb, cont);
 	storebytes(tb, authdata2, SHA1_DIGEST_SIZE);
 
-	ret = trusted_tpm_send(chip, tb->data, MAX_BUF_SIZE,
-			       "unsealing data");
+	ret = tpm_send_dump(chip, tb->data, MAX_BUF_SIZE,
+			    "unsealing data");
 	if (ret < 0) {
-		pr_info("trusted_key: authhmac failed (%d)\n", ret);
+		pr_info("authhmac failed (%d)\n", ret);
 		return ret;
 	}
 
@@ -637,7 +630,7 @@ int tpm_unseal(struct tpm_chip *chip, struct tpm_buf *tb,
 			     *datalen, TPM_DATA_OFFSET + sizeof(uint32_t), 0,
 			     0);
 	if (ret < 0) {
-		pr_info("trusted_key: TSS_checkhmac2 failed (%d)\n", ret);
+		pr_info("TSS_checkhmac2 failed (%d)\n", ret);
 		return ret;
 	}
 	memcpy(data, tb->data + TPM_DATA_OFFSET + sizeof(uint32_t), *datalen);
@@ -645,38 +638,76 @@ int tpm_unseal(struct tpm_chip *chip, struct tpm_buf *tb,
 }
 EXPORT_SYMBOL_GPL(tpm_unseal);
 
-void trusted_shash_release(void)
-{
-	if (hashalg)
-		crypto_free_shash(hashalg);
-	if (hmacalg)
-		crypto_free_shash(hmacalg);
-}
-EXPORT_SYMBOL_GPL(trusted_shash_release);
-
-int trusted_shash_alloc(void)
+/**
+ * tpm_library_use - Tell the TPM library we want to make use of it
+ *
+ * Tell the TPM library that we want to make use of it, allowing it to
+ * allocate the resources it needs.
+ */
+int tpm_library_use(void)
 {
+	struct crypto_shash *hashalg = NULL;
+	struct crypto_shash *hmacalg = NULL;
 	int ret;
 
-	hmacalg = crypto_alloc_shash(hmac_alg, 0, CRYPTO_ALG_ASYNC);
+	if (atomic_inc_not_zero(&tpm_library_usage))
+		return 0;
+
+	/* We don't want to hold a mutex whilst allocating a crypto
+	 * object as it may have to call up to userspace.
+	 */
+	hmacalg = crypto_alloc_shash(tpm_hmac_alg, 0, CRYPTO_ALG_ASYNC);
 	if (IS_ERR(hmacalg)) {
-		pr_info("trusted_key: could not allocate crypto %s\n",
-			hmac_alg);
-		return PTR_ERR(hmacalg);
+		pr_info("Could not allocate crypto %s\n", tpm_hmac_alg);
+		ret = PTR_ERR(hmacalg);
+		goto hmacalg_fail;
 	}
 
-	hashalg = crypto_alloc_shash(hash_alg, 0, CRYPTO_ALG_ASYNC);
+	hashalg = crypto_alloc_shash(tpm_hash_alg, 0, CRYPTO_ALG_ASYNC);
 	if (IS_ERR(hashalg)) {
-		pr_info("trusted_key: could not allocate crypto %s\n",
-			hash_alg);
+		pr_info("Could not allocate crypto %s\n", tpm_hash_alg);
 		ret = PTR_ERR(hashalg);
 		goto hashalg_fail;
 	}
 
+	mutex_lock(&tpm_library_init_mutex);
+
+	if (atomic_inc_return(&tpm_library_usage) == 1) {
+		tpm_hmacalg = hmacalg;
+		tpm_hashalg = hashalg;
+	} else {
+		crypto_free_shash(hashalg);
+		crypto_free_shash(hmacalg);
+	}
+
+	mutex_unlock(&tpm_library_init_mutex);
 	return 0;
 
 hashalg_fail:
-	crypto_free_shash(hmacalg);
+	crypto_free_shash(tpm_hmacalg);
+hmacalg_fail:
 	return ret;
 }
-EXPORT_SYMBOL_GPL(trusted_shash_alloc);
+EXPORT_SYMBOL_GPL(tpm_library_use);
+
+/**
+ * tpm_library_unuse - Tell the TPM library we've finished with it
+ *
+ * Tell the TPM library we've finished with it, allowing it to free the
+ * resources it had allocated.
+ */
+void tpm_library_unuse(void)
+{
+	if (atomic_add_unless(&tpm_library_usage, -1, 1))
+		return;
+
+	mutex_lock(&tpm_library_init_mutex);
+
+	if (atomic_dec_and_test(&tpm_library_usage)) {
+		crypto_free_shash(tpm_hashalg);
+		crypto_free_shash(tpm_hmacalg);
+	}
+
+	mutex_unlock(&tpm_library_init_mutex);
+}
+EXPORT_SYMBOL_GPL(tpm_library_unuse);
diff --git a/drivers/char/tpm/tpm-library.h b/drivers/char/tpm/tpm-library.h
index eec1dfe26c2a..6f7571cc6d6c 100644
--- a/drivers/char/tpm/tpm-library.h
+++ b/drivers/char/tpm/tpm-library.h
@@ -15,7 +15,7 @@
 #define LOAD32N(buffer, offset)	(*(uint32_t *)&buffer[offset])
 #define LOAD16(buffer, offset)	(ntohs(*(uint16_t *)&buffer[offset]))
 
-struct osapsess {
+struct tpm_osapsess {
 	uint32_t handle;
 	unsigned char secret[SHA1_DIGEST_SIZE];
 	unsigned char enonce[TPM_NONCE_SIZE];
@@ -51,14 +51,14 @@ static inline void storebytes(struct tpm_buf *buf, const unsigned char *in,
 #define TPM_DEBUG 0
 
 #ifdef TPM_DEBUG
-static inline void dump_sess(struct osapsess *s)
+static inline void dump_sess(struct tpm_osapsess *s)
 {
-	print_hex_dump(KERN_INFO, "trusted-key: handle ", DUMP_PREFIX_NONE,
+	print_hex_dump(KERN_INFO, "handle ", DUMP_PREFIX_NONE,
 		       16, 1, &s->handle, 4, 0);
-	pr_info("trusted-key: secret:\n");
+	pr_info("secret:\n");
 	print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE,
 		       16, 1, &s->secret, SHA1_DIGEST_SIZE, 0);
-	pr_info("trusted-key: enonce:\n");
+	pr_info("enonce:\n");
 	print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE,
 		       16, 1, &s->enonce, SHA1_DIGEST_SIZE, 0);
 }
@@ -67,13 +67,13 @@ static inline void dump_tpm_buf(unsigned char *buf)
 {
 	int len;
 
-	pr_info("\ntrusted-key: tpm buffer\n");
+	pr_info("\ntpm buffer\n");
 	len = LOAD32(buf, TPM_SIZE_OFFSET);
 	print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, buf, len, 0);
 }
 
 #else
-static inline void dump_sess(struct osapsess *s)
+static inline void dump_sess(struct tpm_osapsess *s)
 {
 }
 
diff --git a/include/linux/tpm.h b/include/linux/tpm.h
index 5d8caf56c272..b08539920f76 100644
--- a/include/linux/tpm.h
+++ b/include/linux/tpm.h
@@ -100,8 +100,8 @@ struct tpm_buf {
 
 #define INIT_BUF(tb) (tb->len = 0)
 
-extern void trusted_shash_release(void);
-extern int trusted_shash_alloc(void);
+extern int tpm_library_use(void);
+extern void tpm_library_unuse(void);
 
 extern int tpm_seal(struct tpm_chip *chip, struct tpm_buf *tb, uint16_t keytype,
 		    uint32_t keyhandle, const unsigned char *keyauth,
diff --git a/security/keys/trusted.c b/security/keys/trusted.c
index 83c6a485e62a..3afb152a6ae2 100644
--- a/security/keys/trusted.c
+++ b/security/keys/trusted.c
@@ -521,19 +521,19 @@ static int __init init_trusted(void)
 {
 	int ret;
 
-	ret = trusted_shash_alloc();
+	ret = tpm_library_use();
 	if (ret < 0)
 		return ret;
 	ret = register_key_type(&key_type_trusted);
 	if (ret < 0)
-		trusted_shash_release();
+		tpm_library_unuse();
 	return ret;
 }
 
 static void __exit cleanup_trusted(void)
 {
-	trusted_shash_release();
 	unregister_key_type(&key_type_trusted);
+	tpm_library_unuse();
 }
 
 late_initcall(init_trusted);


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.