Hi Enrico,
On Mon, 2024-04-08 at 23:28 +0200, Enrico Bravi wrote:
> The template hash showed by the ascii_runtime_measurements and
> binary_runtime_measurements is the one calculated using sha1 and there is
> no possibility to change this value, despite the fact that the template
> hash is calculated using the hash algorithms corresponding to all the PCR
> banks configured in the TPM.
>
> Add the support to retrieve the ima log with the template data hash
> calculated with a specific hash algorithm.
> Add a new file in the securityfs ima directory for each hash algo
> configured in a PCR bank of the TPM. Each new file has the name with
> the following structure:
>
> {binary, ascii}_runtime_measurements_<hash_algo_name>
>
> Legacy files are kept, to avoid breaking existing applications, but as
> symbolic links which point to {binary, ascii}_runtime_measurements_sha1
> files. These two files are created even if a TPM chip is not detected or
> the sha1 bank is not configured in the TPM.
>
> As example, in the case a TPM chip is present and sha256 is the only
> configured PCR bank, the listing of the securityfs ima directory is the
> following:
>
> lr--r--r-- [...] ascii_runtime_measurements -> ascii_runtime_measurements_sha1
> -r--r----- [...] ascii_runtime_measurements_sha1
> -r--r----- [...] ascii_runtime_measurements_sha256
> lr--r--r-- [...] binary_runtime_measurements ->
> binary_runtime_measurements_sha1
> -r--r----- [...] binary_runtime_measurements_sha1
> -r--r----- [...] binary_runtime_measurements_sha256
> --w------- [...] policy
> -r--r----- [...] runtime_measurements_count
> -r--r----- [...] violations
>
> Signed-off-by: Enrico Bravi <[email protected]>
> Signed-off-by: Silvia Sisinni <[email protected]>
> Reviewed-by: Roberto Sassu <[email protected]>
Much better. Just a few comments inline.
>
> ---
>
> v6:
> - Fixed format error when applying the patch.
>
> v5:
> - Added lookup_algo_by_dentry() function to select the hash algo during
> measurements dump. (suggested by Roberto)
> - Renamed remove_measurements_list_files() to
> remove_securityfs_measurement_lists() and create_measurements_list_files()
> to create_securityfs_measurement_lists(), and marked both as __init.
> (suggested by Mimi)
> - Renamed ima_ascii_measurements_files to ascii_securityfs_measurement_lists,
> ima_binary_measurements_files to binary_securityfs_measurement_lists and
> ima_measurements_files_count to securityfs_measurement_list_count, and
> marked them as __ro_after_init. (suggested by Mimi)
> - Added missing NULL assignment for file.file in ima_dump_measurement_list()
> during kexec.
>
> v4:
> - Added NULL check on m->file for measurements list dump called by
> ima_dump_measurement_list() on kexec.
> - Exported ima_algo_array and struct ima_algo_desc declaration from
> ima_crypto.c to access this information in ima_fs.c.
> - Added ima_measurements_files_count global variable to avoid extra
> logic each time the number of measurements file is needed.
>
> v3:
> - Added create_measurements_list_files function for measurements files
> creation.
> - Parameterized the remove_measurements_list_files function and add NULL
> check before freeing files' list.
> - Removed algorithm selection based on file name during ima_measurements_show
> and ima_ascii_measurements_show, and selecting it comparing dentry address.
> - Allocate also sha1 file following the schema
> {binary, ascii}_runtime_measurements_<hash_algo_name> and keep legacy
> files as symbolic links to those files.
> - Allocate measurements files lists even if a TPM chip is not detected,
> adding only sha1 files.
>
> v2:
> - Changed the behavior of configuring at boot time the template data hash
> algorithm.
> - Removed template data hash algo name prefix.
> - Removed ima_template_hash command line option.
> - Introducing a new file in the securityfs ima subdir for each PCR banks
> algorithm configured in the TPM.
> (suggested by Roberto)
>
> security/integrity/ima/ima.h | 10 +++
> security/integrity/ima/ima_crypto.c | 7 +-
> security/integrity/ima/ima_fs.c | 131 +++++++++++++++++++++++++---
> security/integrity/ima/ima_kexec.c | 1 +
> 4 files changed, 131 insertions(+), 18 deletions(-)
>
> diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
> index 11d7c0332207..72ac73ebc83e 100644
> --- a/security/integrity/ima/ima.h
> +++ b/security/integrity/ima/ima.h
> @@ -54,6 +54,16 @@ extern int ima_hash_algo __ro_after_init;
> 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;
> +
> +/* IMA hash algorithm description */
> +struct ima_algo_desc {
> + struct crypto_shash *tfm;
> + enum hash_algo algo;
> +};
> +
> +/* hash algorithms configured in IMA */
> +extern struct ima_algo_desc *ima_algo_array;
> +
> extern int ima_appraise;
> 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 f3738b2c8bcd..3606931fc525 100644
> --- a/security/integrity/ima/ima_crypto.c
> +++ b/security/integrity/ima/ima_crypto.c
> @@ -57,11 +57,6 @@ MODULE_PARM_DESC(ahash_bufsize, "Maximum ahash buffer
> size");
> static struct crypto_shash *ima_shash_tfm;
> static struct crypto_ahash *ima_ahash_tfm;
>
> -struct ima_algo_desc {
> - struct crypto_shash *tfm;
> - enum hash_algo algo;
> -};
> -
> int ima_sha1_idx __ro_after_init;
> int ima_hash_algo_idx __ro_after_init;
> /*
> @@ -70,7 +65,7 @@ int ima_hash_algo_idx __ro_after_init;
> */
> int ima_extra_slots __ro_after_init;
>
> -static struct ima_algo_desc *ima_algo_array;
> +struct ima_algo_desc *ima_algo_array;
ima_algo_array should probably be defined as __ro_after_init, especially now
that the scope is changing.
>
> static int __init ima_init_ima_crypto(void)
> {
> diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
> index cd1683dad3bf..7d9c2ef5b86c 100644
> --- a/security/integrity/ima/ima_fs.c
> +++ b/security/integrity/ima/ima_fs.c
> @@ -116,9 +116,30 @@ void ima_putc(struct seq_file *m, void *data, int
> datalen)
> seq_putc(m, *(char *)data++);
> }
>
> +static struct dentry **ascii_securityfs_measurement_lists __ro_after_init;
> +static struct dentry **binary_securityfs_measurement_lists __ro_after_init;
> +static int securityfs_measurement_list_count __ro_after_init;
> +
> +static void lookup_algo_by_dentry(int *algo_idx, enum hash_algo *algo,
> + struct seq_file *m, struct dentry
> **dentry_list)
Please rename the function without "_by_dentry". Consider naming the function
lookup_measurement_list_algo(). Instead of dentry_list, consider naming the
variable measurement_lists or just lists.
> +{
> + struct dentry *dentry;
> + int i;
> +
> + dentry = file_dentry(m->file);
> +
> + for (i = 0; i < securityfs_measurement_list_count; i++) {
> + if (dentry == dentry_list[i]) {
> + *algo_idx = i;
> + *algo = ima_algo_array[i].algo;
> + break;
> + }
> + }
> +}
> +
> /* print format:
> * 32bit-le=pcr#
> - * char[20]=template digest
> + * char[n]=template digest
> * 32bit-le=template name size
> * char[n]=template name
> * [eventdata length]
> @@ -132,7 +153,15 @@ int ima_measurements_show(struct seq_file *m, void *v)
> char *template_name;
> u32 pcr, namelen, template_data_len; /* temporary fields */
> bool is_ima_template = false;
> - int i;
> + int i, algo_idx;
> + enum hash_algo algo;
> +
> + algo_idx = ima_sha1_idx;
> + algo = HASH_ALGO_SHA1;
> +
> + if (m->file != NULL)
> + lookup_algo_by_dentry(&algo_idx, &algo, m,
> + binary_securityfs_measurement_lists);
>
> /* get entry */
> e = qe->entry;
> @@ -151,7 +180,7 @@ int ima_measurements_show(struct seq_file *m, void *v)
> ima_putc(m, &pcr, sizeof(e->pcr));
>
> /* 2nd: template digest */
> - ima_putc(m, e->digests[ima_sha1_idx].digest, TPM_DIGEST_SIZE);
> + ima_putc(m, e->digests[algo_idx].digest, hash_digest_size[algo]);
>
> /* 3rd: template name size */
> namelen = !ima_canonical_fmt ? strlen(template_name) :
> @@ -220,7 +249,15 @@ static int ima_ascii_measurements_show(struct seq_file
> *m, void *v)
> struct ima_queue_entry *qe = v;
> struct ima_template_entry *e;
> char *template_name;
> - int i;
> + int i, algo_idx;
> + enum hash_algo algo;
The preferred variable definition ordering is reverse fir tree. Reverse the two
lines.
> + algo_idx = ima_sha1_idx;
> + algo = HASH_ALGO_SHA1;
> +
> + if (m->file != NULL)
> + lookup_algo_by_dentry(&algo_idx, &algo, m,
> + ascii_securityfs_measurement_lists);
>
> /* get entry */
> e = qe->entry;
> @@ -233,8 +270,8 @@ 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 */
> + ima_print_digest(m, e->digests[algo_idx].digest,
> hash_digest_size[algo]);
>
> /* 3th: template name */
> seq_printf(m, " %s", template_name);
> @@ -379,6 +416,69 @@ static const struct seq_operations ima_policy_seqops = {
> };
> #endif
>
> +static void __init remove_securityfs_measurement_lists(struct dentry
> **dentry_list)
> +{
> + int i;
> +
> + if (dentry_list) {
> + for (i = 0; i < securityfs_measurement_list_count; i++)
> + securityfs_remove(dentry_list[i]);
> +
> + kfree(dentry_list);
> + }
> +
> + securityfs_measurement_list_count = 0;
> +}
> +
> +static int __init create_securityfs_measurement_lists(void)
> +{
> + int i;
> + u16 algo;
> + char file_name[NAME_MAX + 1];
> + struct dentry *dentry;
> +
> + securityfs_measurement_list_count = NR_BANKS(ima_tpm_chip);
> +
> + if (ima_sha1_idx >= NR_BANKS(ima_tpm_chip))
> + securityfs_measurement_list_count++;
> +
> + ascii_securityfs_measurement_lists =
> kcalloc(securityfs_measurement_list_count,
> + sizeof(struct dentry *),
> GFP_KERNEL);
Although lines > 80 characters are permitted, it isn't needed here. Like the
original ascii_runtime_measurements initialization, split the line after the
ascii_securityfs_measurement_lists variable name.
> + if (!ascii_securityfs_measurement_lists)
> + return -ENOMEM;
> +
> + binary_securityfs_measurement_lists =
> kcalloc(securityfs_measurement_list_count,
> + sizeof(struct dentry *),
> GFP_KERNEL);
Same here.
> + if (!binary_securityfs_measurement_lists)
> + return -ENOMEM;
> +
> + for (i = 0; i < securityfs_measurement_list_count; i++) {
> + algo = ima_algo_array[i].algo;
> +
> + sprintf(file_name, "ascii_runtime_measurements_%s",
> + hash_algo_name[algo]);
> + dentry = securityfs_create_file(file_name, S_IRUSR | S_IRGRP,
> + ima_dir, NULL,
> + &ima_ascii_measurements_ops);
> + if (IS_ERR(dentry))
> + return PTR_ERR(dentry);
> +
> + ascii_securityfs_measurement_lists[i] = dentry;
> +
> + sprintf(file_name, "binary_runtime_measurements_%s",
> + hash_algo_name[algo]);
> + dentry = securityfs_create_file(file_name, S_IRUSR | S_IRGRP,
> + ima_dir, NULL,
> + &ima_measurements_ops);
> + if (IS_ERR(dentry))
> + return PTR_ERR(dentry);
> +
> + binary_securityfs_measurement_lists[i] = dentry;
> + }
> +
> + return 0;
> +}
> +
> /*
> * ima_open_policy: sequentialize access to the policy file
> */
> @@ -454,6 +554,9 @@ int __init ima_fs_init(void)
> {
> int ret;
>
> + ascii_securityfs_measurement_lists = NULL;
> + binary_securityfs_measurement_lists = NULL;
> +
> ima_dir = securityfs_create_dir("ima", integrity_dir);
> if (IS_ERR(ima_dir))
> return PTR_ERR(ima_dir);
> @@ -465,19 +568,21 @@ int __init ima_fs_init(void)
> goto out;
> }
>
> + ret = create_securityfs_measurement_lists();
> + if (ret != 0)
> + goto out;
> +
> binary_runtime_measurements =
> - securityfs_create_file("binary_runtime_measurements",
> - S_IRUSR | S_IRGRP, ima_dir, NULL,
> - &ima_measurements_ops);
> + securityfs_create_symlink("binary_runtime_measurements",
> ima_dir,
> + "binary_runtime_measurements_sha1",
> NULL);
> 80 characters here and in a few other places.
thanks,
Mimi
> if (IS_ERR(binary_runtime_measurements)) {
> ret = PTR_ERR(binary_runtime_measurements);
> goto out;
> }
>
> ascii_runtime_measurements =
> - securityfs_create_file("ascii_runtime_measurements",
> - S_IRUSR | S_IRGRP, ima_dir, NULL,
> - &ima_ascii_measurements_ops);
> + securityfs_create_symlink("ascii_runtime_measurements", ima_dir,
> + "ascii_runtime_measurements_sha1",
> NULL);
> if (IS_ERR(ascii_runtime_measurements)) {
> ret = PTR_ERR(ascii_runtime_measurements);
> goto out;
> @@ -515,6 +620,8 @@ int __init ima_fs_init(void)
> securityfs_remove(runtime_measurements_count);
> securityfs_remove(ascii_runtime_measurements);
> securityfs_remove(binary_runtime_measurements);
> + remove_securityfs_measurement_lists(ascii_securityfs_measurement_lists);
> + remove_securityfs_measurement_lists(binary_securityfs_measurement_lists)
> ;
> securityfs_remove(ima_symlink);
> securityfs_remove(ima_dir);
>
> diff --git a/security/integrity/ima/ima_kexec.c
> b/security/integrity/ima/ima_kexec.c
> index dadc1d138118..52e00332defe 100644
> --- a/security/integrity/ima/ima_kexec.c
> +++ b/security/integrity/ima/ima_kexec.c
> @@ -30,6 +30,7 @@ static int ima_dump_measurement_list(unsigned long
> *buffer_size, void **buffer,
> goto out;
> }
>
> + file.file = NULL;
> file.size = segment_size;
> file.read_pos = 0;
> file.count = sizeof(khdr); /* reserved space */
>
> base-commit: 38aa3f5ac6d2de6b471ecb6e1cd878957ae7e8de