Clean up the TPM library file that was split out of trusted keys. Signed-off-by: David Howells <dhowells@xxxxxxxxxx> --- 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);