Merge tag 'integrity-v6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/zohar...
[platform/kernel/linux-rpi.git] / security / integrity / ima / ima_policy.c
index 54c475f..20cffd3 100644 (file)
@@ -398,12 +398,6 @@ static struct ima_rule_entry *ima_lsm_copy_rule(struct ima_rule_entry *entry)
 
                nentry->lsm[i].type = entry->lsm[i].type;
                nentry->lsm[i].args_p = entry->lsm[i].args_p;
-               /*
-                * Remove the reference from entry so that the associated
-                * memory will not be freed during a later call to
-                * ima_lsm_free_rule(entry).
-                */
-               entry->lsm[i].args_p = NULL;
 
                ima_filter_rule_init(nentry->lsm[i].type, Audit_equal,
                                     nentry->lsm[i].args_p,
@@ -417,6 +411,7 @@ static struct ima_rule_entry *ima_lsm_copy_rule(struct ima_rule_entry *entry)
 
 static int ima_lsm_update_rule(struct ima_rule_entry *entry)
 {
+       int i;
        struct ima_rule_entry *nentry;
 
        nentry = ima_lsm_copy_rule(entry);
@@ -431,7 +426,8 @@ static int ima_lsm_update_rule(struct ima_rule_entry *entry)
         * references and the entry itself. All other memory references will now
         * be owned by nentry.
         */
-       ima_lsm_free_rule(entry);
+       for (i = 0; i < MAX_LSM_RULES; i++)
+               ima_filter_rule_free(entry->lsm[i].rule);
        kfree(entry);
 
        return 0;
@@ -549,6 +545,9 @@ static bool ima_match_rules(struct ima_rule_entry *rule,
                            const char *func_data)
 {
        int i;
+       bool result = false;
+       struct ima_rule_entry *lsm_rule = rule;
+       bool rule_reinitialized = false;
 
        if ((rule->flags & IMA_FUNC) &&
            (rule->func != func && func != POST_SETATTR))
@@ -612,35 +611,55 @@ static bool ima_match_rules(struct ima_rule_entry *rule,
                int rc = 0;
                u32 osid;
 
-               if (!rule->lsm[i].rule) {
-                       if (!rule->lsm[i].args_p)
+               if (!lsm_rule->lsm[i].rule) {
+                       if (!lsm_rule->lsm[i].args_p)
                                continue;
                        else
                                return false;
                }
+
+retry:
                switch (i) {
                case LSM_OBJ_USER:
                case LSM_OBJ_ROLE:
                case LSM_OBJ_TYPE:
                        security_inode_getsecid(inode, &osid);
-                       rc = ima_filter_rule_match(osid, rule->lsm[i].type,
+                       rc = ima_filter_rule_match(osid, lsm_rule->lsm[i].type,
                                                   Audit_equal,
-                                                  rule->lsm[i].rule);
+                                                  lsm_rule->lsm[i].rule);
                        break;
                case LSM_SUBJ_USER:
                case LSM_SUBJ_ROLE:
                case LSM_SUBJ_TYPE:
-                       rc = ima_filter_rule_match(secid, rule->lsm[i].type,
+                       rc = ima_filter_rule_match(secid, lsm_rule->lsm[i].type,
                                                   Audit_equal,
-                                                  rule->lsm[i].rule);
+                                                  lsm_rule->lsm[i].rule);
                        break;
                default:
                        break;
                }
-               if (!rc)
-                       return false;
+
+               if (rc == -ESTALE && !rule_reinitialized) {
+                       lsm_rule = ima_lsm_copy_rule(rule);
+                       if (lsm_rule) {
+                               rule_reinitialized = true;
+                               goto retry;
+                       }
+               }
+               if (!rc) {
+                       result = false;
+                       goto out;
+               }
        }
-       return true;
+       result = true;
+
+out:
+       if (rule_reinitialized) {
+               for (i = 0; i < MAX_LSM_RULES; i++)
+                       ima_filter_rule_free(lsm_rule->lsm[i].rule);
+               kfree(lsm_rule);
+       }
+       return result;
 }
 
 /*