Merge branch 'next-integrity' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorri...
[sfrench/cifs-2.6.git] / security / integrity / ima / ima_policy.c
index fcf5b27290630f5b7d981915e9ee226ee0071817..8bc8a1c8cb3f8cc3cf03fc3255d568438baa580f 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/rculist.h>
 #include <linux/genhd.h>
 #include <linux/seq_file.h>
+#include <linux/ima.h>
 
 #include "ima.h"
 
@@ -58,6 +59,8 @@ enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE,
 
 enum policy_types { ORIGINAL_TCB = 1, DEFAULT_TCB };
 
+enum policy_rule_list { IMA_DEFAULT_POLICY = 1, IMA_CUSTOM_POLICY };
+
 struct ima_rule_entry {
        struct list_head list;
        int action;
@@ -104,7 +107,8 @@ static struct ima_rule_entry dont_measure_rules[] __ro_after_init = {
         .flags = IMA_FSMAGIC},
        {.action = DONT_MEASURE, .fsmagic = CGROUP2_SUPER_MAGIC,
         .flags = IMA_FSMAGIC},
-       {.action = DONT_MEASURE, .fsmagic = NSFS_MAGIC, .flags = IMA_FSMAGIC}
+       {.action = DONT_MEASURE, .fsmagic = NSFS_MAGIC, .flags = IMA_FSMAGIC},
+       {.action = DONT_MEASURE, .fsmagic = EFIVARFS_MAGIC, .flags = IMA_FSMAGIC}
 };
 
 static struct ima_rule_entry original_measurement_rules[] __ro_after_init = {
@@ -147,6 +151,7 @@ static struct ima_rule_entry default_appraise_rules[] __ro_after_init = {
        {.action = DONT_APPRAISE, .fsmagic = SELINUX_MAGIC, .flags = IMA_FSMAGIC},
        {.action = DONT_APPRAISE, .fsmagic = SMACK_MAGIC, .flags = IMA_FSMAGIC},
        {.action = DONT_APPRAISE, .fsmagic = NSFS_MAGIC, .flags = IMA_FSMAGIC},
+       {.action = DONT_APPRAISE, .fsmagic = EFIVARFS_MAGIC, .flags = IMA_FSMAGIC},
        {.action = DONT_APPRAISE, .fsmagic = CGROUP_SUPER_MAGIC, .flags = IMA_FSMAGIC},
        {.action = DONT_APPRAISE, .fsmagic = CGROUP2_SUPER_MAGIC, .flags = IMA_FSMAGIC},
 #ifdef CONFIG_IMA_WRITE_POLICY
@@ -193,6 +198,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);
@@ -473,6 +481,75 @@ static int ima_appraise_flag(enum ima_hooks func)
        return 0;
 }
 
+static void add_rules(struct ima_rule_entry *entries, int count,
+                     enum policy_rule_list policy_rule)
+{
+       int i = 0;
+
+       for (i = 0; i < count; i++) {
+               struct ima_rule_entry *entry;
+
+               if (policy_rule & IMA_DEFAULT_POLICY)
+                       list_add_tail(&entries[i].list, &ima_default_rules);
+
+               if (policy_rule & IMA_CUSTOM_POLICY) {
+                       entry = kmemdup(&entries[i], sizeof(*entry),
+                                       GFP_KERNEL);
+                       if (!entry)
+                               continue;
+
+                       list_add_tail(&entry->list, &ima_policy_rules);
+               }
+               if (entries[i].action == APPRAISE)
+                       temp_ima_appraise |= ima_appraise_flag(entries[i].func);
+               if (entries[i].func == POLICY_CHECK)
+                       temp_ima_appraise |= IMA_APPRAISE_POLICY;
+       }
+}
+
+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.
  *
@@ -481,68 +558,68 @@ static int ima_appraise_flag(enum ima_hooks func)
  */
 void __init ima_init_policy(void)
 {
-       int i, measure_entries, appraise_entries, secure_boot_entries;
+       int build_appraise_entries, arch_entries;
 
-       /* if !ima_policy set entries = 0 so we load NO default rules */
-       measure_entries = ima_policy ? ARRAY_SIZE(dont_measure_rules) : 0;
-       appraise_entries = ima_use_appraise_tcb ?
-                        ARRAY_SIZE(default_appraise_rules) : 0;
-       secure_boot_entries = ima_use_secure_boot ?
-                       ARRAY_SIZE(secure_boot_rules) : 0;
-
-       for (i = 0; i < measure_entries; i++)
-               list_add_tail(&dont_measure_rules[i].list, &ima_default_rules);
+       /* if !ima_policy, we load NO default rules */
+       if (ima_policy)
+               add_rules(dont_measure_rules, ARRAY_SIZE(dont_measure_rules),
+                         IMA_DEFAULT_POLICY);
 
        switch (ima_policy) {
        case ORIGINAL_TCB:
-               for (i = 0; i < ARRAY_SIZE(original_measurement_rules); i++)
-                       list_add_tail(&original_measurement_rules[i].list,
-                                     &ima_default_rules);
+               add_rules(original_measurement_rules,
+                         ARRAY_SIZE(original_measurement_rules),
+                         IMA_DEFAULT_POLICY);
                break;
        case DEFAULT_TCB:
-               for (i = 0; i < ARRAY_SIZE(default_measurement_rules); i++)
-                       list_add_tail(&default_measurement_rules[i].list,
-                                     &ima_default_rules);
+               add_rules(default_measurement_rules,
+                         ARRAY_SIZE(default_measurement_rules),
+                         IMA_DEFAULT_POLICY);
        default:
                break;
        }
 
+       /*
+        * 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.
         */
-       for (i = 0; i < secure_boot_entries; i++) {
-               list_add_tail(&secure_boot_rules[i].list, &ima_default_rules);
-               temp_ima_appraise |=
-                   ima_appraise_flag(secure_boot_rules[i].func);
-       }
+       if (ima_use_secure_boot)
+               add_rules(secure_boot_rules, ARRAY_SIZE(secure_boot_rules),
+                         IMA_DEFAULT_POLICY);
 
        /*
         * Insert the build time appraise rules requiring file signatures
         * for both the initial and custom policies, prior to other appraise
-        * rules.
+        * rules. As the secure boot rules includes all of the build time
+        * rules, include either one or the other set of rules, but not both.
         */
-       for (i = 0; i < ARRAY_SIZE(build_appraise_rules); i++) {
-               struct ima_rule_entry *entry;
-
-               if (!secure_boot_entries)
-                       list_add_tail(&build_appraise_rules[i].list,
-                                     &ima_default_rules);
-
-               entry = kmemdup(&build_appraise_rules[i], sizeof(*entry),
-                               GFP_KERNEL);
-               if (entry)
-                       list_add_tail(&entry->list, &ima_policy_rules);
-               build_ima_appraise |=
-                       ima_appraise_flag(build_appraise_rules[i].func);
+       build_appraise_entries = ARRAY_SIZE(build_appraise_rules);
+       if (build_appraise_entries) {
+               if (ima_use_secure_boot)
+                       add_rules(build_appraise_rules, build_appraise_entries,
+                                 IMA_CUSTOM_POLICY);
+               else
+                       add_rules(build_appraise_rules, build_appraise_entries,
+                                 IMA_DEFAULT_POLICY | IMA_CUSTOM_POLICY);
        }
 
-       for (i = 0; i < appraise_entries; i++) {
-               list_add_tail(&default_appraise_rules[i].list,
-                             &ima_default_rules);
-               if (default_appraise_rules[i].func == POLICY_CHECK)
-                       temp_ima_appraise |= IMA_APPRAISE_POLICY;
-       }
+       if (ima_use_appraise_tcb)
+               add_rules(default_appraise_rules,
+                         ARRAY_SIZE(default_appraise_rules),
+                         IMA_DEFAULT_POLICY);
 
        ima_rules = &ima_default_rules;
        ima_update_policy_flag();
@@ -576,6 +653,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();
 }