From: Roberto Sassu Date: Fri, 5 Jun 2026 17:22:34 +0000 (+0200) Subject: ima: Add support for flushing the hash table when staging measurements X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c26d9d9246cc66e3472a2bbd186152d0572d7aab;p=thirdparty%2Fkernel%2Flinux.git ima: Add support for flushing the hash table when staging measurements During staging and delete, measurements are not completely deallocated. Their entry digest portion is kept and is still reachable with the hash table to detect duplicate records. If the number of records is significant, this reduces the memory saving benefit of staging. Some users might be interested in achieving the best memory saving (the measurements are completely deallocated) at the cost of having duplicate records across the staged measurement lists. Duplicate records are still avoided within the current measurement list. Introduce the new kernel option ima_flush_htable to decide whether or not the digests of staged measurement records are flushed from the hash table, when they are deleted, to achieve the maximum memory saving. When the option is enabled, replace the old hash table with a new one, by calling ima_alloc_replace_htable(), and completely delete the measurements records. Note: This code derives from the Alt-IMA Huawei project, whose license is GPL-2.0 OR MIT. Link: https://github.com/linux-integrity/linux/issues/1 Signed-off-by: Roberto Sassu Signed-off-by: Mimi Zohar --- diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 4d0f545fb3ec..aad318803f82 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -2343,6 +2343,12 @@ Kernel parameters Use the canonical format for the binary runtime measurements, instead of host native format. + ima_flush_htable [IMA] + Flush the IMA hash table when deleting all the + staged measurement records, to achieve maximum + memory saving at the cost of having duplicate + records across the staged measurement lists. + ima_hash= [IMA] Format: { md5 | sha1 | rmd160 | sha256 | sha384 | sha512 | ... } diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c index cdc21e1b929b..df1e81ea7a36 100644 --- a/security/integrity/ima/ima_queue.c +++ b/security/integrity/ima/ima_queue.c @@ -22,6 +22,20 @@ #define AUDIT_CAUSE_LEN_MAX 32 +static bool ima_flush_htable; + +static int __init ima_flush_htable_setup(char *str) +{ + if (IS_ENABLED(CONFIG_IMA_DISABLE_HTABLE)) { + pr_warn("Hash table not enabled, ignoring request to flush\n"); + return 1; + } + + ima_flush_htable = true; + return 1; +} +__setup("ima_flush_htable", ima_flush_htable_setup); + /* pre-allocated array of tpm_digest structures to extend a PCR */ static struct tpm_digest *digests; @@ -332,7 +346,7 @@ out_unlock: return ret; } -static void ima_queue_delete(struct list_head *head); +static void ima_queue_delete(struct list_head *head, bool flush_htable); /** * ima_queue_staged_delete_all - Delete staged measurements @@ -350,6 +364,7 @@ static void ima_queue_delete(struct list_head *head); */ int ima_queue_staged_delete_all(void) { + struct hlist_head *old_queue = NULL; LIST_HEAD(ima_measurements_trim); mutex_lock(&ima_extend_list_mutex); @@ -371,21 +386,35 @@ int ima_queue_staged_delete_all(void) if (IS_ENABLED(CONFIG_IMA_KEXEC)) binary_runtime_size[BINARY_STAGED] = 0; + if (ima_flush_htable) { + old_queue = ima_alloc_replace_htable(); + if (IS_ERR(old_queue)) { + mutex_unlock(&ima_extend_list_mutex); + return PTR_ERR(old_queue); + } + } + mutex_unlock(&ima_extend_list_mutex); - ima_queue_delete(&ima_measurements_trim); + if (ima_flush_htable) { + synchronize_rcu(); + kfree(old_queue); + } + + ima_queue_delete(&ima_measurements_trim, ima_flush_htable); return 0; } /** * ima_queue_delete - Delete measurements * @head: List head measurements are deleted from + * @flush_htable: Whether or not the hash table is being flushed * * Delete the measurements from the passed list head completely if the - * hash table is not enabled, or partially (only the template data), if the - * hash table is used. + * hash table is not enabled or is being flushed, or partially (only the + * template data), if the hash table is used. */ -static void ima_queue_delete(struct list_head *head) +static void ima_queue_delete(struct list_head *head, bool flush_htable) { struct ima_queue_entry *qe, *qe_tmp; unsigned int i; @@ -407,7 +436,7 @@ static void ima_queue_delete(struct list_head *head) list_del(&qe->later); /* No leak if condition is false, referenced by ima_htable. */ - if (IS_ENABLED(CONFIG_IMA_DISABLE_HTABLE)) { + if (IS_ENABLED(CONFIG_IMA_DISABLE_HTABLE) || flush_htable) { kfree(qe->entry->digests); kfree(qe->entry); kfree(qe);