[RFC][PATCH] ima: add crypto agility support for template-hash algorithm

Enrico Bravi
2023-12-14T14:54:09Z

The purpose of this patch is to add the possibility to configure the hash
algorithm to use when calculating the template-hash.
The ima_template_hash command line parameter has been introduced to enable
this configuration.
The entry will contain the hash_algo_name before the actual template-hash,
separated by a colon (:).
An example of the resulting ima log is the following:

10 sha256:64326[...]25313 ima-ng sha1:5fc9b[...]974e6 boot_aggregate
10 sha256:afd64[...]e3123 ima-ng sha1:5a493[...]f9566 /init
10 sha256:99329[...]a6353 ima-ng sha1:8c87d[...]3d8c7 /usr/bin/sh
10 sha256:a16ad[...]2ac0e ima-ng sha1:59d4b[...]330b0 /etc/ld.so.cache

This patch has been created starting from the master branch of the main tree:
<git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git>

Signed-off-by: Silvia Sisinni <silvia.sisinni@polito.it>
Signed-off-by: Enrico Bravi <enrico.bravi@polito.it>
---
security/integrity/ima/Kconfig | 30 +++++++++++++++++++++++++++
security/integrity/ima/ima.h | 2 ++
security/integrity/ima/ima_crypto.c | 26 ++++++++++++++++++++++-
security/integrity/ima/ima_fs.c | 25 ++++++++++++++--------
security/integrity/ima/ima_main.c | 32 +++++++++++++++++++++++++++++
5 files changed, 105 insertions(+), 10 deletions(-)

diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
index a6bd817efc1a..9cdeedb2be53 100644
--- a/security/integrity/ima/Kconfig
+++ b/security/integrity/ima/Kconfig
@@ -121,6 +121,36 @@ config IMA_DEFAULT_HASH
default "wp512" if IMA_DEFAULT_HASH_WP512
default "sm3" if IMA_DEFAULT_HASH_SM3

+choice
+ prompt "Default template-hash algorithm"
+ default IMA_DEFAULT_TEMPLATE_HASH_SHA1
+ depends on IMA
+ help
+ Select the default template-hash algorithm written in Measurement
+ Log entries. The compiled default template-hash algorithm can
+ be overwritten using the kernel command line 'ima_template_hash='
+ option.
+
+ config IMA_DEFAULT_TEMPLATE_HASH_SHA1
+ bool "SHA1 (default)"
+ depends on CRYPTO_SHA1=y
+
+ config IMA_DEFAULT_TEMPLATE_HASH_SHA256
+ bool "SHA256"
+ depends on CRYPTO_SHA256=y
+
+ config IMA_DEFAULT_TEMPLATE_HASH_SHA512
+ bool "SHA512"
+ depends on CRYPTO_SHA512=y
+endchoice
+
+config IMA_DEFAULT_TEMPLATE_HASH
+ string
+ depends on IMA
+ default "sha1" if IMA_DEFAULT_TEMPLATE_HASH_SHA1
+ default "sha256" if IMA_DEFAULT_TEMPLATE_HASH_SHA256
+ default "sha512" if IMA_DEFAULT_TEMPLATE_HASH_SHA512
+
config IMA_WRITE_POLICY
bool "Enable multiple writes to the IMA policy"
default n
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index c29db699c996..a19375b9a6e4 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -55,6 +55,8 @@ extern int ima_sha1_idx __ro_after_init;
extern int ima_hash_algo_idx __ro_after_init;
extern int ima_extra_slots __ro_after_init;
extern int ima_appraise;
+extern int ima_template_hash_algo __ro_after_init;
+extern int ima_template_hash_algo_idx __ro_after_init;
extern struct tpm_chip *ima_tpm_chip;
extern const char boot_aggregate_name[];

diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c
index 51ad29940f05..448b55ed5033 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_template_hash_algo_idx __ro_after_init;
/*
* Additional number of slots reserved, as needed, for SHA1
* and IMA default algo.
@@ -124,6 +125,7 @@ int __init ima_init_crypto(void)

ima_sha1_idx = -1;
ima_hash_algo_idx = -1;
+ ima_template_hash_algo_idx = -1;

for (i = 0; i < NR_BANKS(ima_tpm_chip); i++) {
algo = ima_tpm_chip->allocated_banks[i].crypto_id;
@@ -132,16 +134,28 @@ int __init ima_init_crypto(void)

if (algo == ima_hash_algo)
ima_hash_algo_idx = i;
+
+ if (algo == ima_template_hash_algo)
+ ima_template_hash_algo_idx = i;
}

if (ima_sha1_idx < 0) {
ima_sha1_idx = NR_BANKS(ima_tpm_chip) + ima_extra_slots++;
if (ima_hash_algo == HASH_ALGO_SHA1)
ima_hash_algo_idx = ima_sha1_idx;
+
+ if (ima_template_hash_algo == HASH_ALGO_SHA1)
+ ima_template_hash_algo_idx = ima_sha1_idx;
}

- if (ima_hash_algo_idx < 0)
+ if (ima_hash_algo_idx < 0) {
ima_hash_algo_idx = NR_BANKS(ima_tpm_chip) + ima_extra_slots++;
+ if (ima_template_hash_algo == ima_hash_algo)
+ ima_template_hash_algo_idx = ima_hash_algo_idx;
+ }
+
+ if (ima_template_hash_algo_idx < 0)
+ ima_template_hash_algo_idx = NR_BANKS(ima_tpm_chip) + ima_extra_slots++;

ima_algo_array = kcalloc(NR_BANKS(ima_tpm_chip) + ima_extra_slots,
sizeof(*ima_algo_array), GFP_KERNEL);
@@ -196,6 +210,16 @@ int __init ima_init_crypto(void)
ima_algo_array[ima_hash_algo_idx].algo = ima_hash_algo;
}

+ if (ima_template_hash_algo_idx >= NR_BANKS(ima_tpm_chip) &&
+ ima_template_hash_algo_idx != ima_sha1_idx &&
+ ima_template_hash_algo_idx != ima_hash_algo_idx) {
+ ima_algo_array[ima_template_hash_algo_idx].tfm = ima_alloc_tfm(ima_template_hash_algo);
+ if (IS_ERR(ima_algo_array[ima_template_hash_algo_idx].tfm)) {
+ rc = PTR_ERR(ima_algo_array[ima_template_hash_algo_idx].tfm);
+ goto out_array;
+ }
+ }
+
return 0;
out_array:
for (i = 0; i < NR_BANKS(ima_tpm_chip) + ima_extra_slots; i++) {
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index cd1683dad3bf..5545602a6144 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -21,6 +21,7 @@
#include <linux/rcupdate.h>
#include <linux/parser.h>
#include <linux/vmalloc.h>
+#include <crypto/hash_info.h>

#include "ima.h"

@@ -130,7 +131,7 @@ 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 pcr, namelen, template_hash_len, template_data_len; /* temporary fields */
bool is_ima_template = false;
int i;

@@ -150,18 +151,23 @@ int ima_measurements_show(struct seq_file *m, void *v)
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);
+ /* 2nd: template digest size */
+ template_hash_len = !ima_canonical_fmt ? hash_digest_size[ima_template_hash_algo] :
+ (__force u32)cpu_to_le32(hash_digest_size[ima_template_hash_algo]);
+ ima_putc(m, &template_hash_len, sizeof(template_hash_len));

- /* 3rd: template name size */
+ /* 3rd: template digest */
+ ima_putc(m, e->digests[ima_template_hash_algo_idx].digest, hash_digest_size[ima_template_hash_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 +177,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 +239,9 @@ static int ima_ascii_measurements_show(struct seq_file *m, void *v)
/* 1st: PCR used (config option) */
seq_printf(m, "%2d ", e->pcr);

- /* 2nd: SHA1 template hash */
- ima_print_digest(m, e->digests[ima_sha1_idx].digest, TPM_DIGEST_SIZE);
+ /* 2nd: template hash (hash_algo_name:digest)*/
+ seq_printf(m, "%s:", hash_algo_name[ima_template_hash_algo]);
+ ima_print_digest(m, e->digests[ima_template_hash_algo_idx].digest, hash_digest_size[ima_template_hash_algo]);

/* 3th: template name */
seq_printf(m, " %s", template_name);
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index cc1217ac2c6f..fa31ecb66606 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -36,7 +36,9 @@ int ima_appraise;
#endif

int __ro_after_init ima_hash_algo = HASH_ALGO_SHA1;
+int __ro_after_init ima_template_hash_algo = HASH_ALGO_SHA1;
static int hash_setup_done;
+static int template_hash_setup_done;

static struct notifier_block ima_lsm_policy_notifier = {
.notifier_call = ima_lsm_policy_change,
@@ -76,6 +78,26 @@ static int __init hash_setup(char *str)
}
__setup("ima_hash=", hash_setup);

+static int __init template_hash_setup(char *str)
+{
+ int i;
+
+ if (template_hash_setup_done)
+ return 1;
+
+ i = match_string(hash_algo_name, HASH_ALGO__LAST, str);
+ if (i < 0) {
+ pr_err("invalid template-hash algorithm \"%s\"", str);
+ return 1;
+ }
+
+ ima_template_hash_algo = i;
+
+ template_hash_setup_done = 1;
+ return 1;
+}
+__setup("ima_template_hash=", template_hash_setup);
+
enum hash_algo ima_get_current_hash_algo(void)
{
return ima_hash_algo;
@@ -1096,6 +1118,7 @@ static int __init init_ima(void)
ima_appraise_parse_cmdline();
ima_init_template_list();
hash_setup(CONFIG_IMA_DEFAULT_HASH);
+ template_hash_setup(CONFIG_IMA_DEFAULT_TEMPLATE_HASH);
error = ima_init();

if (error && strcmp(hash_algo_name[ima_hash_algo],
@@ -1107,6 +1130,15 @@ static int __init init_ima(void)
error = ima_init();
}

+ if (error && strcmp(hash_algo_name[ima_template_hash_algo],
+ CONFIG_IMA_DEFAULT_TEMPLATE_HASH) != 0) {
+ pr_info("Allocating %s failed, going to use default template-hash algorithm %s\n",
+ hash_algo_name[ima_template_hash_algo], CONFIG_IMA_DEFAULT_TEMPLATE_HASH);
+ template_hash_setup_done = 0;
+ template_hash_setup(CONFIG_IMA_DEFAULT_TEMPLATE_HASH);
+ error = ima_init();
+ }
+
if (error)
return error;

base-commit: 88035e5694a86a7167d490bb95e9df97a9bb162b
--
2.34.1