[RFC][PATCH 4/8] ima: Add digest_cache_measure and digest_cache_appraise boot-time policies

From: Roberto Sassu
Date: Wed Feb 14 2024 - 09:38:05 EST


From: Roberto Sassu <roberto.sassu@xxxxxxxxxx>

Specify the 'digest_cache_measure' boot-time policy with 'ima_policy=' in
the kernel command line to add the following rule at the beginning of the
IMA policy, before other rules:

measure func=DIGEST_LIST_CHECK pcr=12

which will measure digest lists into PCR 12 (or the value in
CONFIG_IMA_DIGEST_CACHE_MEASURE_PCR_IDX).

'digest_cache_measure' also adds 'digest_cache=content pcr=12' to the other
measure rules, if they have a compatible IMA hook. The PCR value still
comes from CONFIG_IMA_DIGEST_CACHE_MEASURE_PCR_IDX.

Specify 'digest_cache_appraise' to add the following rule at the beginning,
before other rules:

appraise func=DIGEST_LIST_CHECK appraise_type=imasig|modsig

which will appraise digest lists with IMA signatures or module-style
appended signatures.

'digest_cache_appraise' also adds 'digest_cache=content' to the other
appraise rules, if they have a compatible IMA hook.

Signed-off-by: Roberto Sassu <roberto.sassu@xxxxxxxxxx>
---
.../admin-guide/kernel-parameters.txt | 15 ++++++-
security/integrity/ima/Kconfig | 10 +++++
security/integrity/ima/ima_policy.c | 45 +++++++++++++++++++
3 files changed, 69 insertions(+), 1 deletion(-)

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 31b3a25680d0..a79967fcba7d 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -2011,7 +2011,8 @@
ima_policy= [IMA]
The builtin policies to load during IMA setup.
Format: "tcb | appraise_tcb | secure_boot |
- fail_securely | critical_data"
+ fail_securely | critical_data |
+ digest_cache_measure | digest_cache_appraise"

The "tcb" policy measures all programs exec'd, files
mmap'd for exec, and all files opened with the read
@@ -2033,6 +2034,18 @@
The "critical_data" policy measures kernel integrity
critical data.

+ The "digest_cache_measure" policy measures digest lists
+ into PCR 12 (can be changed with kernel config), enables
+ the digest cache to be used for the other selected
+ measure rules (if compatible), and measures the files
+ with digest not found in the digest list into PCR 12
+ (changeable).
+
+ The "digest_cache_appraise" policy appraises digest
+ lists with IMA signatures or module-style appended
+ signatures, and enables the digest cache to be used for
+ the other selected appraise rules (if compatible).
+
ima_tcb [IMA] Deprecated. Use ima_policy= instead.
Load a policy which meets the needs of the Trusted
Computing Base. This means IMA will measure all
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
index 475c32615006..6a481019fb6e 100644
--- a/security/integrity/ima/Kconfig
+++ b/security/integrity/ima/Kconfig
@@ -321,4 +321,14 @@ config IMA_DISABLE_HTABLE
help
This option disables htable to allow measurement of duplicate records.

+config IMA_DIGEST_CACHE_MEASURE_PCR_IDX
+ int
+ range 8 14
+ default 12
+ help
+ This option determines the TPM PCR register index that IMA uses to
+ maintain the integrity aggregate of the measurement list, when the
+ digest_cache LSM is used (different measurement style). If unsure,
+ use the default 12.
+
endif
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index 4ac83df8d255..04127f962ef4 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -254,6 +254,21 @@ static struct ima_rule_entry critical_data_rules[] __ro_after_init = {
{.action = MEASURE, .func = CRITICAL_DATA, .flags = IMA_FUNC},
};

+static struct ima_rule_entry measure_digest_cache_rule __ro_after_init = {
+#ifdef CONFIG_SECURITY_DIGEST_CACHE
+ .action = MEASURE, .func = DIGEST_LIST_CHECK,
+ .pcr = CONFIG_IMA_DIGEST_CACHE_MEASURE_PCR_IDX,
+ .flags = IMA_FUNC | IMA_PCR
+#endif
+};
+
+static struct ima_rule_entry appraise_digest_cache_rule __ro_after_init = {
+#ifdef CONFIG_SECURITY_DIGEST_CACHE
+ .action = APPRAISE, .func = DIGEST_LIST_CHECK,
+ .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED | IMA_MODSIG_ALLOWED,
+#endif
+};
+
/* An array of architecture specific rules */
static struct ima_rule_entry *arch_policy_entry __ro_after_init;

@@ -278,6 +293,8 @@ static bool ima_use_appraise_tcb __initdata;
static bool ima_use_secure_boot __initdata;
static bool ima_use_critical_data __initdata;
static bool ima_fail_unverifiable_sigs __ro_after_init;
+static bool ima_digest_cache_measure __ro_after_init;
+static bool ima_digest_cache_appraise __ro_after_init;
static int __init policy_setup(char *str)
{
char *p;
@@ -295,6 +312,10 @@ static int __init policy_setup(char *str)
ima_use_critical_data = true;
else if (strcmp(p, "fail_securely") == 0)
ima_fail_unverifiable_sigs = true;
+ else if (strcmp(p, "digest_cache_measure") == 0)
+ ima_digest_cache_measure = true;
+ else if (strcmp(p, "digest_cache_appraise") == 0)
+ ima_digest_cache_appraise = true;
else
pr_err("policy \"%s\" not found", p);
}
@@ -897,6 +918,20 @@ static void add_rules(struct ima_rule_entry *entries, int count,
for (i = 0; i < count; i++) {
struct ima_rule_entry *entry;

+ if (IS_ENABLED(CONFIG_SECURITY_DIGEST_CACHE) &&
+ entries[i].action == MEASURE && ima_digest_cache_measure &&
+ ima_digest_cache_func_allowed(&entries[i])) {
+ entries[i].digest_cache_mask |= IMA_DIGEST_CACHE_MEASURE_CONTENT;
+ entries[i].pcr = CONFIG_IMA_DIGEST_CACHE_MEASURE_PCR_IDX;
+ entries[i].flags |= IMA_PCR;
+ }
+
+ if (IS_ENABLED(CONFIG_SECURITY_DIGEST_CACHE) &&
+ entries[i].action == APPRAISE &&
+ ima_digest_cache_appraise &&
+ ima_digest_cache_func_allowed(&entries[i]))
+ entries[i].digest_cache_mask |= IMA_DIGEST_CACHE_APPRAISE_CONTENT;
+
if (policy_rule & IMA_DEFAULT_POLICY)
list_add_tail(&entries[i].list, &ima_default_rules);

@@ -971,6 +1006,16 @@ void __init ima_init_policy(void)
{
int build_appraise_entries, arch_entries;

+ /*
+ * We need to load digest cache rules at the beginning, to avoid dont_
+ * rules causing ours to not be reached.
+ */
+ if (ima_digest_cache_measure)
+ add_rules(&measure_digest_cache_rule, 1, IMA_DEFAULT_POLICY);
+
+ if (ima_digest_cache_appraise)
+ add_rules(&appraise_digest_cache_rule, 1, IMA_DEFAULT_POLICY);
+
/* if !ima_policy, we load NO default rules */
if (ima_policy)
add_rules(dont_measure_rules, ARRAY_SIZE(dont_measure_rules),
--
2.34.1