summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/linux/ima.h5
-rw-r--r--security/integrity/ima/ima_policy.c72
2 files changed, 75 insertions, 2 deletions
diff --git a/include/linux/ima.h b/include/linux/ima.h
index 948135fb60f1..62c5241b0899 100644
--- a/include/linux/ima.h
+++ b/include/linux/ima.h
@@ -39,6 +39,11 @@ static inline bool arch_ima_get_secureboot(void)
}
#endif
+static inline const char * const *arch_get_ima_policy(void)
+{
+ return NULL;
+}
+
#else
static inline int ima_bprm_check(struct linux_binprm *bprm)
{
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index 1e30d09a56db..b20770704b6c 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -20,6 +20,7 @@
#include <linux/rculist.h>
#include <linux/genhd.h>
#include <linux/seq_file.h>
+#include <linux/ima.h>
#include "ima.h"
@@ -195,6 +196,9 @@ static struct ima_rule_entry secure_boot_rules[] __ro_after_init = {
.flags = IMA_FUNC | IMA_DIGSIG_REQUIRED},
};
+/* An array of architecture specific rules */
+struct ima_rule_entry *arch_policy_entry __ro_after_init;
+
static LIST_HEAD(ima_default_rules);
static LIST_HEAD(ima_policy_rules);
static LIST_HEAD(ima_temp_rules);
@@ -501,6 +505,49 @@ static void add_rules(struct ima_rule_entry *entries, int count,
}
}
+static int ima_parse_rule(char *rule, struct ima_rule_entry *entry);
+
+static int __init ima_init_arch_policy(void)
+{
+ const char * const *arch_rules;
+ const char * const *rules;
+ int arch_entries = 0;
+ int i = 0;
+
+ arch_rules = arch_get_ima_policy();
+ if (!arch_rules)
+ return arch_entries;
+
+ /* Get number of rules */
+ for (rules = arch_rules; *rules != NULL; rules++)
+ arch_entries++;
+
+ arch_policy_entry = kcalloc(arch_entries + 1,
+ sizeof(*arch_policy_entry), GFP_KERNEL);
+ if (!arch_policy_entry)
+ return 0;
+
+ /* Convert each policy string rules to struct ima_rule_entry format */
+ for (rules = arch_rules, i = 0; *rules != NULL; rules++) {
+ char rule[255];
+ int result;
+
+ result = strlcpy(rule, *rules, sizeof(rule));
+
+ INIT_LIST_HEAD(&arch_policy_entry[i].list);
+ result = ima_parse_rule(rule, &arch_policy_entry[i]);
+ if (result) {
+ pr_warn("Skipping unknown architecture policy rule: %s\n",
+ rule);
+ memset(&arch_policy_entry[i], 0,
+ sizeof(*arch_policy_entry));
+ continue;
+ }
+ i++;
+ }
+ return i;
+}
+
/**
* ima_init_policy - initialize the default measure rules.
*
@@ -509,7 +556,7 @@ static void add_rules(struct ima_rule_entry *entries, int count,
*/
void __init ima_init_policy(void)
{
- int build_appraise_entries;
+ int build_appraise_entries, arch_entries;
/* if !ima_policy, we load NO default rules */
if (ima_policy)
@@ -531,8 +578,21 @@ void __init ima_init_policy(void)
}
/*
+ * Based on runtime secure boot flags, insert arch specific measurement
+ * and appraise rules requiring file signatures for both the initial
+ * and custom policies, prior to other appraise rules.
+ * (Highest priority)
+ */
+ arch_entries = ima_init_arch_policy();
+ if (!arch_entries)
+ pr_info("No architecture policies found\n");
+ else
+ add_rules(arch_policy_entry, arch_entries,
+ IMA_DEFAULT_POLICY | IMA_CUSTOM_POLICY);
+
+ /*
* Insert the builtin "secure_boot" policy rules requiring file
- * signatures, prior to any other appraise rules.
+ * signatures, prior to other appraise rules.
*/
if (ima_use_secure_boot)
add_rules(secure_boot_rules, ARRAY_SIZE(secure_boot_rules),
@@ -591,6 +651,14 @@ void ima_update_policy(void)
if (ima_rules != policy) {
ima_policy_flag = 0;
ima_rules = policy;
+
+ /*
+ * IMA architecture specific policy rules are specified
+ * as strings and converted to an array of ima_entry_rules
+ * on boot. After loading a custom policy, free the
+ * architecture specific rules stored as an array.
+ */
+ kfree(arch_policy_entry);
}
ima_update_policy_flag();
}