Merge branch 'master' into next
[pandora-kernel.git] / security / integrity / ima / ima_policy.c
index 8643a93..aef8c0a 100644 (file)
@@ -246,6 +246,9 @@ static int ima_lsm_rule_init(struct ima_measure_rule_entry *entry,
 {
        int result;
 
+       if (entry->lsm[lsm_rule].rule)
+               return -EINVAL;
+
        entry->lsm[lsm_rule].type = audit_type;
        result = security_filter_rule_init(entry->lsm[lsm_rule].type,
                                           Audit_equal, args,
@@ -253,6 +256,13 @@ static int ima_lsm_rule_init(struct ima_measure_rule_entry *entry,
        return result;
 }
 
+static void ima_log_string(struct audit_buffer *ab, char *key, char *value)
+{
+       audit_log_format(ab, "%s=", key);
+       audit_log_untrustedstring(ab, value);
+       audit_log_format(ab, " ");
+}
+
 static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry)
 {
        struct audit_buffer *ab;
@@ -261,28 +271,41 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry)
 
        ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_INTEGRITY_RULE);
 
-       entry->action = -1;
-       while ((p = strsep(&rule, " \n")) != NULL) {
+       entry->uid = -1;
+       entry->action = UNKNOWN;
+       while ((p = strsep(&rule, " \t")) != NULL) {
                substring_t args[MAX_OPT_ARGS];
                int token;
                unsigned long lnum;
 
                if (result < 0)
                        break;
-               if (!*p)
+               if ((*p == '\0') || (*p == ' ') || (*p == '\t'))
                        continue;
                token = match_token(p, policy_tokens, args);
                switch (token) {
                case Opt_measure:
-                       audit_log_format(ab, "%s ", "measure");
+                       ima_log_string(ab, "action", "measure");
+
+                       if (entry->action != UNKNOWN)
+                               result = -EINVAL;
+
                        entry->action = MEASURE;
                        break;
                case Opt_dont_measure:
-                       audit_log_format(ab, "%s ", "dont_measure");
+                       ima_log_string(ab, "action", "dont_measure");
+
+                       if (entry->action != UNKNOWN)
+                               result = -EINVAL;
+
                        entry->action = DONT_MEASURE;
                        break;
                case Opt_func:
-                       audit_log_format(ab, "func=%s ", args[0].from);
+                       ima_log_string(ab, "func", args[0].from);
+
+                       if (entry->func)
+                               result  = -EINVAL;
+
                        if (strcmp(args[0].from, "FILE_CHECK") == 0)
                                entry->func = FILE_CHECK;
                        /* PATH_CHECK is for backwards compat */
@@ -298,7 +321,11 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry)
                                entry->flags |= IMA_FUNC;
                        break;
                case Opt_mask:
-                       audit_log_format(ab, "mask=%s ", args[0].from);
+                       ima_log_string(ab, "mask", args[0].from);
+
+                       if (entry->mask)
+                               result = -EINVAL;
+
                        if ((strcmp(args[0].from, "MAY_EXEC")) == 0)
                                entry->mask = MAY_EXEC;
                        else if (strcmp(args[0].from, "MAY_WRITE") == 0)
@@ -313,14 +340,26 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry)
                                entry->flags |= IMA_MASK;
                        break;
                case Opt_fsmagic:
-                       audit_log_format(ab, "fsmagic=%s ", args[0].from);
+                       ima_log_string(ab, "fsmagic", args[0].from);
+
+                       if (entry->fsmagic) {
+                               result = -EINVAL;
+                               break;
+                       }
+
                        result = strict_strtoul(args[0].from, 16,
                                                &entry->fsmagic);
                        if (!result)
                                entry->flags |= IMA_FSMAGIC;
                        break;
                case Opt_uid:
-                       audit_log_format(ab, "uid=%s ", args[0].from);
+                       ima_log_string(ab, "uid", args[0].from);
+
+                       if (entry->uid != -1) {
+                               result = -EINVAL;
+                               break;
+                       }
+
                        result = strict_strtoul(args[0].from, 10, &lnum);
                        if (!result) {
                                entry->uid = (uid_t) lnum;
@@ -331,50 +370,51 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry)
                        }
                        break;
                case Opt_obj_user:
-                       audit_log_format(ab, "obj_user=%s ", args[0].from);
+                       ima_log_string(ab, "obj_user", args[0].from);
                        result = ima_lsm_rule_init(entry, args[0].from,
                                                   LSM_OBJ_USER,
                                                   AUDIT_OBJ_USER);
                        break;
                case Opt_obj_role:
-                       audit_log_format(ab, "obj_role=%s ", args[0].from);
+                       ima_log_string(ab, "obj_role", args[0].from);
                        result = ima_lsm_rule_init(entry, args[0].from,
                                                   LSM_OBJ_ROLE,
                                                   AUDIT_OBJ_ROLE);
                        break;
                case Opt_obj_type:
-                       audit_log_format(ab, "obj_type=%s ", args[0].from);
+                       ima_log_string(ab, "obj_type", args[0].from);
                        result = ima_lsm_rule_init(entry, args[0].from,
                                                   LSM_OBJ_TYPE,
                                                   AUDIT_OBJ_TYPE);
                        break;
                case Opt_subj_user:
-                       audit_log_format(ab, "subj_user=%s ", args[0].from);
+                       ima_log_string(ab, "subj_user", args[0].from);
                        result = ima_lsm_rule_init(entry, args[0].from,
                                                   LSM_SUBJ_USER,
                                                   AUDIT_SUBJ_USER);
                        break;
                case Opt_subj_role:
-                       audit_log_format(ab, "subj_role=%s ", args[0].from);
+                       ima_log_string(ab, "subj_role", args[0].from);
                        result = ima_lsm_rule_init(entry, args[0].from,
                                                   LSM_SUBJ_ROLE,
                                                   AUDIT_SUBJ_ROLE);
                        break;
                case Opt_subj_type:
-                       audit_log_format(ab, "subj_type=%s ", args[0].from);
+                       ima_log_string(ab, "subj_type", args[0].from);
                        result = ima_lsm_rule_init(entry, args[0].from,
                                                   LSM_SUBJ_TYPE,
                                                   AUDIT_SUBJ_TYPE);
                        break;
                case Opt_err:
-                       audit_log_format(ab, "UNKNOWN=%s ", p);
+                       ima_log_string(ab, "UNKNOWN", p);
+                       result = -EINVAL;
                        break;
                }
        }
-       if (entry->action == UNKNOWN)
+       if (!result && (entry->action == UNKNOWN))
                result = -EINVAL;
 
-       audit_log_format(ab, "res=%d", !result ? 0 : 1);
+       audit_log_format(ab, "res=%d", !!result);
        audit_log_end(ab);
        return result;
 }
@@ -384,13 +424,14 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry)
  * @rule - ima measurement policy rule
  *
  * Uses a mutex to protect the policy list from multiple concurrent writers.
- * Returns 0 on success, an error code on failure.
+ * Returns the length of the rule parsed, an error code on failure
  */
-int ima_parse_add_rule(char *rule)
+ssize_t ima_parse_add_rule(char *rule)
 {
        const char *op = "update_policy";
+       char *p;
        struct ima_measure_rule_entry *entry;
-       int result = 0;
+       ssize_t result, len;
        int audit_info = 0;
 
        /* Prevent installed policy from changing */
@@ -410,18 +451,28 @@ int ima_parse_add_rule(char *rule)
 
        INIT_LIST_HEAD(&entry->list);
 
-       result = ima_parse_rule(rule, entry);
-       if (!result) {
-               mutex_lock(&ima_measure_mutex);
-               list_add_tail(&entry->list, &measure_policy_rules);
-               mutex_unlock(&ima_measure_mutex);
-       } else {
+       p = strsep(&rule, "\n");
+       len = strlen(p) + 1;
+
+       if (*p == '#') {
+               kfree(entry);
+               return len;
+       }
+
+       result = ima_parse_rule(p, entry);
+       if (result) {
                kfree(entry);
                integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
                                    NULL, op, "invalid policy", result,
                                    audit_info);
+               return result;
        }
-       return result;
+
+       mutex_lock(&ima_measure_mutex);
+       list_add_tail(&entry->list, &measure_policy_rules);
+       mutex_unlock(&ima_measure_mutex);
+
+       return len;
 }
 
 /* ima_delete_rules called to cleanup invalid policy */