TPM2 chips supports algorithms other than SHA1. However, the original IMA design hardcode template hash to be SHA1. This patch added CONFIG_IMA_TEMPLATE_HASH as well as ima_tpm_hash= cmdline argument for configurating template hash. The usage is simuliar to CONFIG_IMA_DEFAULT_HASH and ima_hash=. The configured hash is checked against TPM and make sure that the hash algorithm is supported by ima_tpm_chip. To accommodate the change, we must put a digest length into binary measurement list items. The binary measurement list item format is changed to this: 16bit-le=pcr# 16bit-le=template digest size char[n]=template digest 32bit-le=template name size char[n]=template name [eventdata length] eventdata[n]=template specific data The first element is now a 16bit pcr number and a 16bit template digest size, instead of the original 32bit pcr number. The format of ascii_measurement_list is also changed. For sha1 template hash, the format is the same as before. For other hash algorithms, a hash name is prepended as such: "sha256:30ee3e25620478759600be00e06fda7b4fe23bbf575621d480400d536cf54f5b" Signed-off-by: GUO Zihua <guozihua@xxxxxxxxxx> --- .../admin-guide/kernel-parameters.txt | 7 +++ security/integrity/ima/Kconfig | 36 ++++++++++++- security/integrity/ima/ima.h | 2 + security/integrity/ima/ima_crypto.c | 51 ++++++++++--------- security/integrity/ima/ima_fs.c | 43 +++++++++++----- security/integrity/ima/ima_init.c | 44 +++++++++++++++- security/integrity/ima/ima_main.c | 1 + 7 files changed, 144 insertions(+), 40 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 647a55fcba27..33ab98d52062 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -1987,6 +1987,13 @@ The list of supported hash algorithms is defined in crypto/hash_info.h. + ima_tpm_hash= [IMA] + Format: { sha1 | sha256 | sha512 | ... } + default: "sha1" + + The algorithm configured will be checked against the + supported algorithm of the TPM chip should it exists. + ima_policy= [IMA] The builtin policies to load during IMA setup. Format: "tcb | appraise_tcb | secure_boot | diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index c17660bf5f34..b0e6da3ee257 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig @@ -121,9 +121,43 @@ config IMA_DEFAULT_HASH default "sha1" if IMA_DEFAULT_HASH_SHA1 default "sha256" if IMA_DEFAULT_HASH_SHA256 default "sha512" if IMA_DEFAULT_HASH_SHA512 - default "wp512" if IMA_DEFAULT_HASH_WP512 default "sm3" if IMA_DEFAULT_HASH_SM3 +choice + prompt "Default template hash algorithm" + default IMA_TEMPLATE_HASH_SHA1 + depends on IMA + help + Select the hash algorithm used for the template hash, + and PCR extension. The compiled default hash algorithm + can be overwritten using the kernel command line + 'ima_tpm_hash=' option. The configured algorithm is + checked against the TPM chip used. + + config IMA_TEMPLATE_HASH_SHA1 + bool "SHA1 (default)" + depends on CRYPTO_SHA1=y + + config IMA_TEMPLATE_HASH_SHA256 + bool "SHA256" + depends on CRYPTO_SHA256=y + + config IMA_TEMPLATE_HASH_SHA512 + bool "SHA512" + depends on CRYPTO_SHA512=y + + config IMA_TEMPLATE_HASH_SM3 + bool "SM3" + depends on CRYPTO_SM3_GENERIC=y +endchoice + +config IMA_TEMPLATE_HASH + string + depends on IMA + default "sha1" if IMA_TEMPLATE_HASH_SHA1 + default "sha256" if IMA_TEMPLATE_HASH_SHA256 + default "sha512" if IMA_TEMPLATE_HASH_SHA512 + config IMA_WRITE_POLICY bool "Enable multiple writes to the IMA policy" depends on IMA diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index c29db699c996..a280062abbf8 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -51,8 +51,10 @@ extern atomic_t ima_setxattr_allowed_hash_algorithms; /* set during initialization */ extern int ima_hash_algo __ro_after_init; +extern int ima_tpm_algo __ro_after_init; extern int ima_sha1_idx __ro_after_init; extern int ima_hash_algo_idx __ro_after_init; +extern int ima_tpm_algo_idx __ro_after_init; extern int ima_extra_slots __ro_after_init; extern int ima_appraise; extern struct tpm_chip *ima_tpm_chip; diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index 51ad29940f05..0c748646d000 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c @@ -64,6 +64,7 @@ struct ima_algo_desc { int ima_sha1_idx __ro_after_init; int ima_hash_algo_idx __ro_after_init; +int ima_tpm_algo_idx __ro_after_init; /* * Additional number of slots reserved, as needed, for SHA1 * and IMA default algo. @@ -122,22 +123,22 @@ int __init ima_init_crypto(void) if (rc) return rc; - ima_sha1_idx = -1; ima_hash_algo_idx = -1; + ima_tpm_algo_idx = -1; for (i = 0; i < NR_BANKS(ima_tpm_chip); i++) { algo = ima_tpm_chip->allocated_banks[i].crypto_id; - if (algo == HASH_ALGO_SHA1) - ima_sha1_idx = i; - if (algo == ima_hash_algo) ima_hash_algo_idx = i; + + if (algo == ima_tpm_algo) + ima_tpm_algo_idx = i; } - if (ima_sha1_idx < 0) { - ima_sha1_idx = NR_BANKS(ima_tpm_chip) + ima_extra_slots++; + if (ima_tpm_algo_idx < 0) { + ima_tpm_algo_idx = NR_BANKS(ima_tpm_chip) + ima_extra_slots++; if (ima_hash_algo == HASH_ALGO_SHA1) - ima_hash_algo_idx = ima_sha1_idx; + ima_hash_algo_idx = ima_tpm_algo_idx; } if (ima_hash_algo_idx < 0) @@ -160,6 +161,8 @@ int __init ima_init_crypto(void) if (algo == ima_hash_algo) { ima_algo_array[i].tfm = ima_shash_tfm; + if (ima_tpm_algo == ima_hash_algo) + ima_algo_array[i].tfm = ima_shash_tfm; continue; } @@ -175,23 +178,24 @@ int __init ima_init_crypto(void) } } - if (ima_sha1_idx >= NR_BANKS(ima_tpm_chip)) { - if (ima_hash_algo == HASH_ALGO_SHA1) { - ima_algo_array[ima_sha1_idx].tfm = ima_shash_tfm; + if (ima_tpm_algo_idx >= NR_BANKS(ima_tpm_chip)) { + if (ima_tpm_algo == ima_hash_algo) { + ima_algo_array[ima_tpm_algo_idx].tfm = ima_shash_tfm; } else { - ima_algo_array[ima_sha1_idx].tfm = - ima_alloc_tfm(HASH_ALGO_SHA1); - if (IS_ERR(ima_algo_array[ima_sha1_idx].tfm)) { - rc = PTR_ERR(ima_algo_array[ima_sha1_idx].tfm); + ima_algo_array[ima_tpm_algo_idx].tfm = + ima_alloc_tfm(ima_tpm_algo); + if (IS_ERR(ima_algo_array[ima_tpm_algo_idx].tfm)) { + rc = PTR_ERR( + ima_algo_array[ima_tpm_algo_idx].tfm); goto out_array; } } - ima_algo_array[ima_sha1_idx].algo = HASH_ALGO_SHA1; + ima_algo_array[ima_tpm_algo_idx].algo = ima_tpm_algo; } if (ima_hash_algo_idx >= NR_BANKS(ima_tpm_chip) && - ima_hash_algo_idx != ima_sha1_idx) { + ima_hash_algo_idx != ima_tpm_algo_idx) { ima_algo_array[ima_hash_algo_idx].tfm = ima_shash_tfm; ima_algo_array[ima_hash_algo_idx].algo = ima_hash_algo; } @@ -630,26 +634,25 @@ int ima_calc_field_array_hash(struct ima_field_data *field_data, u16 alg_id; int rc, i; - rc = ima_calc_field_array_hash_tfm(field_data, entry, ima_sha1_idx); + rc = ima_calc_field_array_hash_tfm(field_data, entry, ima_tpm_algo_idx); if (rc) return rc; - entry->digests[ima_sha1_idx].alg_id = TPM_ALG_SHA1; - for (i = 0; i < NR_BANKS(ima_tpm_chip) + ima_extra_slots; i++) { - if (i == ima_sha1_idx) - continue; if (i < NR_BANKS(ima_tpm_chip)) { alg_id = ima_tpm_chip->allocated_banks[i].alg_id; entry->digests[i].alg_id = alg_id; } - /* for unmapped TPM algorithms digest is still a padded SHA1 */ + if (i == ima_tpm_algo_idx) + continue; + + /* for unmapped TPM algorithms digest full length digest */ if (!ima_algo_array[i].tfm) { memcpy(entry->digests[i].digest, - entry->digests[ima_sha1_idx].digest, - TPM_DIGEST_SIZE); + entry->digests[ima_tpm_algo_idx].digest, + TPM_MAX_DIGEST_SIZE); continue; } diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index cd1683dad3bf..036eb80c338b 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -117,8 +117,9 @@ void ima_putc(struct seq_file *m, void *data, int datalen) } /* print format: - * 32bit-le=pcr# - * char[20]=template digest + * 16bit-le=pcr# + * 16bit-le=template digest size + * char[n]=template digest * 32bit-le=template name size * char[n]=template name * [eventdata length] @@ -130,7 +131,8 @@ int ima_measurements_show(struct seq_file *m, void *v) struct ima_queue_entry *qe = v; struct ima_template_entry *e; char *template_name; - u32 pcr, namelen, template_data_len; /* temporary fields */ + u32 namelen, template_data_len; /* temporary fields */ + u16 pcr, template_hash_len; bool is_ima_template = false; int i; @@ -147,21 +149,30 @@ int ima_measurements_show(struct seq_file *m, void *v) * PCR used defaults to the same (config option) in * little-endian format, unless set in policy */ - pcr = !ima_canonical_fmt ? e->pcr : (__force u32)cpu_to_le32(e->pcr); - ima_putc(m, &pcr, sizeof(e->pcr)); - - /* 2nd: template digest */ - ima_putc(m, e->digests[ima_sha1_idx].digest, TPM_DIGEST_SIZE); - - /* 3rd: template name size */ + pcr = !ima_canonical_fmt ? (u16)e->pcr : + (__force u16)cpu_to_le16(e->pcr); + ima_putc(m, &pcr, sizeof(pcr)); + + /* 2nd: template digest size */ + template_hash_len = (u16)hash_digest_size[ima_tpm_algo]; + if (ima_canonical_fmt) + template_hash_len = + (__force u16)cpu_to_le16(template_hash_len); + ima_putc(m, &template_hash_len, sizeof(template_hash_len)); + + /* 3rd: template digest */ + ima_putc(m, e->digests[ima_tpm_algo_idx].digest, + hash_digest_size[ima_tpm_algo]); + + /* 4th: template name size */ namelen = !ima_canonical_fmt ? strlen(template_name) : (__force u32)cpu_to_le32(strlen(template_name)); ima_putc(m, &namelen, sizeof(namelen)); - /* 4th: template name */ + /* 5th: template name */ ima_putc(m, template_name, strlen(template_name)); - /* 5th: template length (except for 'ima' template) */ + /* 6th: template length (except for 'ima' template) */ if (strcmp(template_name, IMA_TEMPLATE_IMA_NAME) == 0) is_ima_template = true; @@ -171,7 +182,7 @@ int ima_measurements_show(struct seq_file *m, void *v) ima_putc(m, &template_data_len, sizeof(e->template_data_len)); } - /* 6th: template specific data */ + /* 7th: template specific data */ for (i = 0; i < e->template_desc->num_fields; i++) { enum ima_show_type show = IMA_SHOW_BINARY; const struct ima_template_field *field = @@ -233,8 +244,12 @@ static int ima_ascii_measurements_show(struct seq_file *m, void *v) /* 1st: PCR used (config option) */ seq_printf(m, "%2d ", e->pcr); + if (ima_tpm_algo != HASH_ALGO_SHA1) + seq_printf(m, "%s:", hash_algo_name[ima_tpm_algo]); + /* 2nd: SHA1 template hash */ - ima_print_digest(m, e->digests[ima_sha1_idx].digest, TPM_DIGEST_SIZE); + ima_print_digest(m, e->digests[ima_tpm_algo_idx].digest, + hash_digest_size[ima_tpm_algo]); /* 3th: template name */ seq_printf(m, " %s", template_name); diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c index 63979aefc95f..cc54229cb5ae 100644 --- a/security/integrity/ima/ima_init.c +++ b/security/integrity/ima/ima_init.c @@ -23,6 +23,40 @@ /* name for boot aggregate entry */ const char boot_aggregate_name[] = "boot_aggregate"; struct tpm_chip *ima_tpm_chip; +static int ima_tpm_algo_tmp = -1; + +static bool __init ima_tpm_support_algo(int algo) +{ + int j; + + if (algo < 0 || algo > HASH_ALGO__LAST) + return false; + + for (j = 0; j < NR_BANKS(ima_tpm_chip); j++) { + if (ima_tpm_chip->allocated_banks[j].crypto_id == algo) + return true; + } + return false; +} + +/* + * This funciton setup hash algorithm used by TPM extension. + * The hash algorithm is checked against supported algorithms + * of the chip. + * + * This function would be called by cmdline handling and ima_init. + * A possible situation is when the first time this is called, + * ima_tpm_chip has not been initialized yet. + */ +static int __init tpm_hash_setup(char *str) +{ + ima_tpm_algo_tmp = match_string(hash_algo_name, HASH_ALGO__LAST, str); + if (ima_tpm_algo_tmp < 0) + pr_err("invalid template hash algorithm \"%s\"", str); + + return 1; +} +__setup("ima_tpm_hash=", tpm_hash_setup); /* Add the boot aggregate to the IMA measurement list and extend * the PCR register. @@ -117,9 +151,17 @@ int __init ima_init(void) { int rc; + if (ima_tpm_algo_tmp < 0) + tpm_hash_setup(CONFIG_IMA_TEMPLATE_HASH); + ima_tpm_chip = tpm_default_chip(); - if (!ima_tpm_chip) + if (!ima_tpm_chip) { pr_info("No TPM chip found, activating TPM-bypass!\n"); + ima_tpm_algo = ima_tpm_algo_tmp; + } else if (ima_tpm_support_algo(ima_tpm_algo_tmp)) + ima_tpm_algo = ima_tpm_algo_tmp; + else + ima_tpm_algo = HASH_ALGO_SHA1; rc = integrity_init_keyring(INTEGRITY_KEYRING_IMA); if (rc) diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 365db0e43d7c..fa4f6c261cd7 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -35,6 +35,7 @@ int ima_appraise; #endif int __ro_after_init ima_hash_algo = HASH_ALGO_SHA1; +int __ro_after_init ima_tpm_algo = HASH_ALGO_SHA1; static int hash_setup_done; static struct notifier_block ima_lsm_policy_notifier = { -- 2.17.1