ima: re-initialize IMA policy LSM info
Mimi Zohar [Thu, 3 Jan 2013 19:19:09 +0000 (14:19 -0500)]
Although the IMA policy does not change, the LSM policy can be
reloaded, leaving the IMA LSM based rules referring to the old,
stale LSM policy.  This patch updates the IMA LSM based rules
to reflect the reloaded LSM policy.

Reported-by: Sven Vermeulen <sven.vermeulen@siphos.be>
tested-by: Sven Vermeulen <sven.vermeulen@siphos.be>
Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
Cc: Eric Paris <eparis@parisplace.org>
Cc: Casey Schaufler <casey@schaufler-ca.com>

security/integrity/ima/ima_policy.c

index af7d182..70f888d 100644 (file)
@@ -49,6 +49,7 @@ struct ima_rule_entry {
        kuid_t fowner;
        struct {
                void *rule;     /* LSM file metadata specific */
+               void *args_p;   /* audit value */
                int type;       /* audit type */
        } lsm[MAX_LSM_RULES];
 };
@@ -119,6 +120,35 @@ static int __init default_appraise_policy_setup(char *str)
 }
 __setup("ima_appraise_tcb", default_appraise_policy_setup);
 
+/* 
+ * Although the IMA policy does not change, the LSM policy can be
+ * reloaded, leaving the IMA LSM based rules referring to the old,
+ * stale LSM policy.
+ *
+ * Update the IMA LSM based rules to reflect the reloaded LSM policy. 
+ * We assume the rules still exist; and BUG_ON() if they don't.
+ */
+static void ima_lsm_update_rules(void)
+{
+       struct ima_rule_entry *entry, *tmp;
+       int result;
+       int i;
+
+       mutex_lock(&ima_rules_mutex);
+       list_for_each_entry_safe(entry, tmp, &ima_policy_rules, list) {
+               for (i = 0; i < MAX_LSM_RULES; i++) {
+                       if (!entry->lsm[i].rule)
+                               continue;
+                       result = security_filter_rule_init(entry->lsm[i].type,
+                                                          Audit_equal,
+                                                          entry->lsm[i].args_p,
+                                                          &entry->lsm[i].rule);
+                       BUG_ON(!entry->lsm[i].rule);
+               }
+       }
+       mutex_unlock(&ima_rules_mutex);
+}
+
 /**
  * ima_match_rules - determine whether an inode matches the measure rule.
  * @rule: a pointer to a rule
@@ -149,10 +179,11 @@ static bool ima_match_rules(struct ima_rule_entry *rule,
        for (i = 0; i < MAX_LSM_RULES; i++) {
                int rc = 0;
                u32 osid, sid;
+               int retried = 0;
 
                if (!rule->lsm[i].rule)
                        continue;
-
+retry:
                switch (i) {
                case LSM_OBJ_USER:
                case LSM_OBJ_ROLE:
@@ -176,6 +207,11 @@ static bool ima_match_rules(struct ima_rule_entry *rule,
                default:
                        break;
                }
+               if ((rc < 0) && (!retried)) {
+                       retried = 1;
+                       ima_lsm_update_rules();
+                       goto retry;
+               } 
                if (!rc)
                        return false;
        }
@@ -306,19 +342,27 @@ static match_table_t policy_tokens = {
 };
 
 static int ima_lsm_rule_init(struct ima_rule_entry *entry,
-                            char *args, int lsm_rule, int audit_type)
+                            substring_t *args, int lsm_rule, int audit_type)
 {
        int result;
 
        if (entry->lsm[lsm_rule].rule)
                return -EINVAL;
 
+       entry->lsm[lsm_rule].args_p = match_strdup(args);
+       if (!entry->lsm[lsm_rule].args_p)
+               return -ENOMEM;
+
        entry->lsm[lsm_rule].type = audit_type;
        result = security_filter_rule_init(entry->lsm[lsm_rule].type,
-                                          Audit_equal, args,
+                                          Audit_equal,
+                                          entry->lsm[lsm_rule].args_p,
                                           &entry->lsm[lsm_rule].rule);
-       if (!entry->lsm[lsm_rule].rule)
+       if (!entry->lsm[lsm_rule].rule) {
+               kfree(entry->lsm[lsm_rule].args_p);
                return -EINVAL;
+       }
+
        return result;
 }
 
@@ -481,37 +525,37 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
                        break;
                case Opt_obj_user:
                        ima_log_string(ab, "obj_user", args[0].from);
-                       result = ima_lsm_rule_init(entry, args[0].from,
+                       result = ima_lsm_rule_init(entry, args,
                                                   LSM_OBJ_USER,
                                                   AUDIT_OBJ_USER);
                        break;
                case Opt_obj_role:
                        ima_log_string(ab, "obj_role", args[0].from);
-                       result = ima_lsm_rule_init(entry, args[0].from,
+                       result = ima_lsm_rule_init(entry, args,
                                                   LSM_OBJ_ROLE,
                                                   AUDIT_OBJ_ROLE);
                        break;
                case Opt_obj_type:
                        ima_log_string(ab, "obj_type", args[0].from);
-                       result = ima_lsm_rule_init(entry, args[0].from,
+                       result = ima_lsm_rule_init(entry, args,
                                                   LSM_OBJ_TYPE,
                                                   AUDIT_OBJ_TYPE);
                        break;
                case Opt_subj_user:
                        ima_log_string(ab, "subj_user", args[0].from);
-                       result = ima_lsm_rule_init(entry, args[0].from,
+                       result = ima_lsm_rule_init(entry, args,
                                                   LSM_SUBJ_USER,
                                                   AUDIT_SUBJ_USER);
                        break;
                case Opt_subj_role:
                        ima_log_string(ab, "subj_role", args[0].from);
-                       result = ima_lsm_rule_init(entry, args[0].from,
+                       result = ima_lsm_rule_init(entry, args,
                                                   LSM_SUBJ_ROLE,
                                                   AUDIT_SUBJ_ROLE);
                        break;
                case Opt_subj_type:
                        ima_log_string(ab, "subj_type", args[0].from);
-                       result = ima_lsm_rule_init(entry, args[0].from,
+                       result = ima_lsm_rule_init(entry, args,
                                                   LSM_SUBJ_TYPE,
                                                   AUDIT_SUBJ_TYPE);
                        break;
@@ -589,9 +633,13 @@ ssize_t ima_parse_add_rule(char *rule)
 void ima_delete_rules(void)
 {
        struct ima_rule_entry *entry, *tmp;
+       int i;
 
        mutex_lock(&ima_rules_mutex);
        list_for_each_entry_safe(entry, tmp, &ima_policy_rules, list) {
+               for (i = 0; i < MAX_LSM_RULES; i++)
+                       kfree(entry->lsm[i].args_p);
+
                list_del(&entry->list);
                kfree(entry);
        }