diff options
author | James Morris <james.morris@microsoft.com> | 2019-02-13 12:01:00 -0800 |
---|---|---|
committer | James Morris <james.morris@microsoft.com> | 2019-02-13 12:01:00 -0800 |
commit | 5da10728037afea6743b76afddfdc9950cd711b3 (patch) | |
tree | efc57d8e14bebb64e7401b37d29d4d1fe4220c2d /security | |
parent | e7a44cfd639945a0dec749f896adc1d340c2a6aa (diff) | |
parent | 50a81b60bfe075a0023670ff86558abd02536799 (diff) | |
download | lwn-5da10728037afea6743b76afddfdc9950cd711b3.tar.gz lwn-5da10728037afea6743b76afddfdc9950cd711b3.zip |
Merge tag 'tpmdd-next-20190213' of git://git.infradead.org/users/jjs/linux-tpmdd into next-tpm
tpmdd updates for Linux v5.1
From: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Clean up the transmission flow
==============================
Cleaned up the whole transmission flow. Locking of the chip is now done in
the level of tpm_try_get_ops() and tpm_put_ops() instead taking the chip
lock inside tpm_transmit(). The nested calls inside tpm_transmit(), used
with the resource manager, have been refactored out.
Should make easier to perform more complex transactions with the TPM
without making the subsystem a bigger mess (e.g. encrypted channel patches
by James Bottomley).
PPI 1.3 support
===============
TPM PPI 1.3 introduces an additional optional command parameter that may be
needed for some commands. Display the parameter if the command requires
such a parameter. Only command 23 (SetPCRBanks) needs one.
The PPI request file will show output like this then:
# echo "23 16" > request
# cat request
23 16
# echo "5" > request
# cat request
5
Extend all PCR banks in IMA
===========================
Instead of static PCR banks array, the array of available PCR banks is now
allocated dynamically. The digests sizes are determined dynamically using a
probe PCR read without relying crypto's static list of hash algorithms.
This should finally make sealing of measurements in IMA safe and secure.
TPM 2.0 selftests
=================
Added a test suite to tools/testing/selftests/tpm2 previously outside of
the kernel tree: https://github.com/jsakkine-intel/tpm2-scripts.
Diffstat (limited to 'security')
-rw-r--r-- | security/integrity/ima/ima.h | 1 | ||||
-rw-r--r-- | security/integrity/ima/ima_crypto.c | 10 | ||||
-rw-r--r-- | security/integrity/ima/ima_init.c | 4 | ||||
-rw-r--r-- | security/integrity/ima/ima_queue.c | 27 | ||||
-rw-r--r-- | security/keys/trusted.c | 73 |
5 files changed, 90 insertions, 25 deletions
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index cc12f3449a72..89d65cf8053d 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -153,6 +153,7 @@ int ima_measurements_show(struct seq_file *m, void *v); unsigned long ima_get_binary_runtime_size(void); int ima_init_template(void); void ima_init_template_list(void); +int __init ima_init_digests(void); /* * used to protect h_table and sha_table diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index acf2c7df7145..16a4f45863b1 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c @@ -643,12 +643,12 @@ int ima_calc_buffer_hash(const void *buf, loff_t len, return calc_buffer_shash(buf, len, hash); } -static void __init ima_pcrread(u32 idx, u8 *pcr) +static void __init ima_pcrread(u32 idx, struct tpm_digest *d) { if (!ima_tpm_chip) return; - if (tpm_pcr_read(ima_tpm_chip, idx, pcr) != 0) + if (tpm_pcr_read(ima_tpm_chip, idx, d) != 0) pr_err("Error Communicating to TPM chip\n"); } @@ -658,7 +658,7 @@ static void __init ima_pcrread(u32 idx, u8 *pcr) static int __init ima_calc_boot_aggregate_tfm(char *digest, struct crypto_shash *tfm) { - u8 pcr_i[TPM_DIGEST_SIZE]; + struct tpm_digest d = { .alg_id = TPM_ALG_SHA1, .digest = {0} }; int rc; u32 i; SHASH_DESC_ON_STACK(shash, tfm); @@ -672,9 +672,9 @@ static int __init ima_calc_boot_aggregate_tfm(char *digest, /* cumulative sha1 over tpm registers 0-7 */ for (i = TPM_PCR0; i < TPM_PCR8; i++) { - ima_pcrread(i, pcr_i); + ima_pcrread(i, &d); /* now accumulate with current aggregate */ - rc = crypto_shash_update(shash, pcr_i, TPM_DIGEST_SIZE); + rc = crypto_shash_update(shash, d.digest, TPM_DIGEST_SIZE); } if (!rc) crypto_shash_final(shash, digest); diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c index 6bb42a9c5e47..6c9295449751 100644 --- a/security/integrity/ima/ima_init.c +++ b/security/integrity/ima/ima_init.c @@ -123,8 +123,12 @@ int __init ima_init(void) if (rc != 0) return rc; + /* It can be called before ima_init_digests(), it does not use TPM. */ ima_load_kexec_buffer(); + rc = ima_init_digests(); + if (rc != 0) + return rc; rc = ima_add_boot_aggregate(); /* boot aggregate must be first entry */ if (rc != 0) return rc; diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c index 0e41dc1df1d4..6b6d044e0440 100644 --- a/security/integrity/ima/ima_queue.c +++ b/security/integrity/ima/ima_queue.c @@ -27,6 +27,9 @@ #define AUDIT_CAUSE_LEN_MAX 32 +/* pre-allocated array of tpm_digest structures to extend a PCR */ +static struct tpm_digest *digests; + LIST_HEAD(ima_measurements); /* list of all measurements */ #ifdef CONFIG_IMA_KEXEC static unsigned long binary_runtime_size; @@ -140,11 +143,15 @@ unsigned long ima_get_binary_runtime_size(void) static int ima_pcr_extend(const u8 *hash, int pcr) { int result = 0; + int i; if (!ima_tpm_chip) return result; - result = tpm_pcr_extend(ima_tpm_chip, pcr, hash); + for (i = 0; i < ima_tpm_chip->nr_allocated_banks; i++) + memcpy(digests[i].digest, hash, TPM_DIGEST_SIZE); + + result = tpm_pcr_extend(ima_tpm_chip, pcr, digests); if (result != 0) pr_err("Error Communicating to TPM chip, result: %d\n", result); return result; @@ -211,3 +218,21 @@ int ima_restore_measurement_entry(struct ima_template_entry *entry) mutex_unlock(&ima_extend_list_mutex); return result; } + +int __init ima_init_digests(void) +{ + int i; + + if (!ima_tpm_chip) + return 0; + + digests = kcalloc(ima_tpm_chip->nr_allocated_banks, sizeof(*digests), + GFP_NOFS); + if (!digests) + return -ENOMEM; + + for (i = 0; i < ima_tpm_chip->nr_allocated_banks; i++) + digests[i].alg_id = ima_tpm_chip->allocated_banks[i].alg_id; + + return 0; +} diff --git a/security/keys/trusted.c b/security/keys/trusted.c index 4d98f4f87236..bcc9c6ead7fd 100644 --- a/security/keys/trusted.c +++ b/security/keys/trusted.c @@ -34,6 +34,8 @@ static const char hmac_alg[] = "hmac(sha1)"; static const char hash_alg[] = "sha1"; +static struct tpm_chip *chip; +static struct tpm_digest *digests; struct sdesc { struct shash_desc shash; @@ -362,7 +364,7 @@ int trusted_tpm_send(unsigned char *cmd, size_t buflen) int rc; dump_tpm_buf(cmd); - rc = tpm_send(NULL, cmd, buflen); + rc = tpm_send(chip, cmd, buflen); dump_tpm_buf(cmd); if (rc > 0) /* Can't return positive return codes values to keyctl */ @@ -379,15 +381,10 @@ EXPORT_SYMBOL_GPL(trusted_tpm_send); */ static int pcrlock(const int pcrnum) { - unsigned char hash[SHA1_DIGEST_SIZE]; - int ret; - if (!capable(CAP_SYS_ADMIN)) return -EPERM; - ret = tpm_get_random(NULL, hash, SHA1_DIGEST_SIZE); - if (ret != SHA1_DIGEST_SIZE) - return ret; - return tpm_pcr_extend(NULL, pcrnum, hash) ? -EINVAL : 0; + + return tpm_pcr_extend(chip, pcrnum, digests) ? -EINVAL : 0; } /* @@ -400,7 +397,7 @@ static int osap(struct tpm_buf *tb, struct osapsess *s, unsigned char ononce[TPM_NONCE_SIZE]; int ret; - ret = tpm_get_random(NULL, ononce, TPM_NONCE_SIZE); + ret = tpm_get_random(chip, ononce, TPM_NONCE_SIZE); if (ret != TPM_NONCE_SIZE) return ret; @@ -496,7 +493,7 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype, if (ret < 0) goto out; - ret = tpm_get_random(NULL, td->nonceodd, TPM_NONCE_SIZE); + ret = tpm_get_random(chip, td->nonceodd, TPM_NONCE_SIZE); if (ret != TPM_NONCE_SIZE) goto out; ordinal = htonl(TPM_ORD_SEAL); @@ -606,7 +603,7 @@ static int tpm_unseal(struct tpm_buf *tb, ordinal = htonl(TPM_ORD_UNSEAL); keyhndl = htonl(SRKHANDLE); - ret = tpm_get_random(NULL, nonceodd, TPM_NONCE_SIZE); + 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); return ret; @@ -751,7 +748,7 @@ static int getoptions(char *c, struct trusted_key_payload *pay, int i; int tpm2; - tpm2 = tpm_is_tpm2(NULL); + tpm2 = tpm_is_tpm2(chip); if (tpm2 < 0) return tpm2; @@ -920,7 +917,7 @@ static struct trusted_key_options *trusted_options_alloc(void) struct trusted_key_options *options; int tpm2; - tpm2 = tpm_is_tpm2(NULL); + tpm2 = tpm_is_tpm2(chip); if (tpm2 < 0) return NULL; @@ -970,7 +967,7 @@ static int trusted_instantiate(struct key *key, size_t key_len; int tpm2; - tpm2 = tpm_is_tpm2(NULL); + tpm2 = tpm_is_tpm2(chip); if (tpm2 < 0) return tpm2; @@ -1011,7 +1008,7 @@ static int trusted_instantiate(struct key *key, switch (key_cmd) { case Opt_load: if (tpm2) - ret = tpm_unseal_trusted(NULL, payload, options); + ret = tpm_unseal_trusted(chip, payload, options); else ret = key_unseal(payload, options); dump_payload(payload); @@ -1021,13 +1018,13 @@ static int trusted_instantiate(struct key *key, break; case Opt_new: key_len = payload->key_len; - ret = tpm_get_random(NULL, payload->key, key_len); + ret = tpm_get_random(chip, payload->key, key_len); if (ret != key_len) { pr_info("trusted_key: key_create failed (%d)\n", ret); goto out; } if (tpm2) - ret = tpm_seal_trusted(NULL, payload, options); + ret = tpm_seal_trusted(chip, payload, options); else ret = key_seal(payload, options); if (ret < 0) @@ -1221,21 +1218,59 @@ hashalg_fail: return ret; } +static int __init init_digests(void) +{ + u8 digest[TPM_MAX_DIGEST_SIZE]; + int ret; + int i; + + ret = tpm_get_random(chip, digest, TPM_MAX_DIGEST_SIZE); + if (ret < 0) + return ret; + if (ret < TPM_MAX_DIGEST_SIZE) + return -EFAULT; + + digests = kcalloc(chip->nr_allocated_banks, sizeof(*digests), + GFP_KERNEL); + if (!digests) + return -ENOMEM; + + for (i = 0; i < chip->nr_allocated_banks; i++) + memcpy(digests[i].digest, digest, TPM_MAX_DIGEST_SIZE); + + return 0; +} + static int __init init_trusted(void) { int ret; + chip = tpm_default_chip(); + if (!chip) + return -ENOENT; + ret = init_digests(); + if (ret < 0) + goto err_put; ret = trusted_shash_alloc(); if (ret < 0) - return ret; + goto err_free; ret = register_key_type(&key_type_trusted); if (ret < 0) - trusted_shash_release(); + goto err_release; + return 0; +err_release: + trusted_shash_release(); +err_free: + kfree(digests); +err_put: + put_device(&chip->dev); return ret; } static void __exit cleanup_trusted(void) { + put_device(&chip->dev); + kfree(digests); trusted_shash_release(); unregister_key_type(&key_type_trusted); } |