Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux...
authorJames Morris <james.l.morris@oracle.com>
Thu, 2 Oct 2014 09:47:23 +0000 (19:47 +1000)
committerJames Morris <james.l.morris@oracle.com>
Thu, 2 Oct 2014 09:47:23 +0000 (19:47 +1000)
Documentation/kernel-parameters.txt
security/integrity/ima/ima.h
security/integrity/ima/ima_api.c
security/integrity/ima/ima_appraise.c
security/integrity/ima/ima_init.c
security/integrity/ima/ima_main.c
security/integrity/ima/ima_policy.c

index 0cd5049..802a3fd 100644 (file)
@@ -1292,7 +1292,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        Set number of hash buckets for inode cache.
 
        ima_appraise=   [IMA] appraise integrity measurements
-                       Format: { "off" | "enforce" | "fix" }
+                       Format: { "off" | "enforce" | "fix" | "log" }
                        default: "enforce"
 
        ima_appraise_tcb [IMA]
index 8e4bb88..8ee997d 100644 (file)
@@ -43,6 +43,9 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 };
 #define IMA_TEMPLATE_IMA_NAME "ima"
 #define IMA_TEMPLATE_IMA_FMT "d|n"
 
+/* current content of the policy */
+extern int ima_policy_flag;
+
 /* set during initialization */
 extern int ima_initialized;
 extern int ima_used_chip;
@@ -153,14 +156,16 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
                     int flags);
 void ima_init_policy(void);
 void ima_update_policy(void);
+void ima_update_policy_flag(void);
 ssize_t ima_parse_add_rule(char *);
 void ima_delete_rules(void);
 
 /* Appraise integrity measurements */
 #define IMA_APPRAISE_ENFORCE   0x01
 #define IMA_APPRAISE_FIX       0x02
-#define IMA_APPRAISE_MODULES   0x04
-#define IMA_APPRAISE_FIRMWARE  0x08
+#define IMA_APPRAISE_LOG       0x04
+#define IMA_APPRAISE_MODULES   0x08
+#define IMA_APPRAISE_FIRMWARE  0x10
 
 #ifdef CONFIG_IMA_APPRAISE
 int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
index 65c41a9..8688597 100644 (file)
@@ -179,11 +179,6 @@ int ima_get_action(struct inode *inode, int mask, int function)
        return ima_match_policy(inode, function, mask, flags);
 }
 
-int ima_must_measure(struct inode *inode, int mask, int function)
-{
-       return ima_match_policy(inode, function, mask, IMA_MEASURE);
-}
-
 /*
  * ima_collect_measurement - collect file measurement
  *
index 013ec3f..9226854 100644 (file)
@@ -23,6 +23,8 @@ static int __init default_appraise_setup(char *str)
 {
        if (strncmp(str, "off", 3) == 0)
                ima_appraise = 0;
+       else if (strncmp(str, "log", 3) == 0)
+               ima_appraise = IMA_APPRAISE_LOG;
        else if (strncmp(str, "fix", 3) == 0)
                ima_appraise = IMA_APPRAISE_FIX;
        return 1;
@@ -316,7 +318,7 @@ void ima_inode_post_setattr(struct dentry *dentry)
        struct integrity_iint_cache *iint;
        int must_appraise, rc;
 
-       if (!ima_initialized || !ima_appraise || !S_ISREG(inode->i_mode)
+       if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode)
            || !inode->i_op->removexattr)
                return;
 
@@ -354,7 +356,7 @@ static void ima_reset_appraise_flags(struct inode *inode, int digsig)
 {
        struct integrity_iint_cache *iint;
 
-       if (!ima_initialized || !ima_appraise || !S_ISREG(inode->i_mode))
+       if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode))
                return;
 
        iint = integrity_iint_find(inode);
index e8f9d70..9164fc8 100644 (file)
@@ -43,7 +43,7 @@ int ima_used_chip;
  * a different value.) Violations add a zero entry to the measurement
  * list and extend the aggregate PCR value with ff...ff's.
  */
-static void __init ima_add_boot_aggregate(void)
+static int __init ima_add_boot_aggregate(void)
 {
        static const char op[] = "add_boot_aggregate";
        const char *audit_cause = "ENOMEM";
@@ -72,17 +72,23 @@ static void __init ima_add_boot_aggregate(void)
 
        result = ima_alloc_init_template(iint, NULL, boot_aggregate_name,
                                         NULL, 0, &entry);
-       if (result < 0)
-               return;
+       if (result < 0) {
+               audit_cause = "alloc_entry";
+               goto err_out;
+       }
 
        result = ima_store_template(entry, violation, NULL,
                                    boot_aggregate_name);
-       if (result < 0)
+       if (result < 0) {
                ima_free_template_entry(entry);
-       return;
+               audit_cause = "store_entry";
+               goto err_out;
+       }
+       return 0;
 err_out:
        integrity_audit_msg(AUDIT_INTEGRITY_PCR, NULL, boot_aggregate_name, op,
                            audit_cause, result, 0);
+       return result;
 }
 
 int __init ima_init(void)
@@ -98,6 +104,10 @@ int __init ima_init(void)
        if (!ima_used_chip)
                pr_info("No TPM chip found, activating TPM-bypass!\n");
 
+       rc = ima_init_keyring(INTEGRITY_KEYRING_IMA);
+       if (rc)
+               return rc;
+
        rc = ima_init_crypto();
        if (rc)
                return rc;
@@ -105,7 +115,10 @@ int __init ima_init(void)
        if (rc != 0)
                return rc;
 
-       ima_add_boot_aggregate();       /* boot aggregate must be first entry */
+       rc = ima_add_boot_aggregate();  /* boot aggregate must be first entry */
+       if (rc != 0)
+               return rc;
+
        ima_init_policy();
 
        return ima_fs_init();
index 673a37e..62f59ec 100644 (file)
@@ -77,42 +77,39 @@ __setup("ima_hash=", hash_setup);
  *       could result in a file measurement error.
  *
  */
-static void ima_rdwr_violation_check(struct file *file)
+static void ima_rdwr_violation_check(struct file *file,
+                                    struct integrity_iint_cache *iint,
+                                    int must_measure,
+                                    char **pathbuf,
+                                    const char **pathname)
 {
        struct inode *inode = file_inode(file);
        fmode_t mode = file->f_mode;
        bool send_tomtou = false, send_writers = false;
-       char *pathbuf = NULL;
-       const char *pathname;
-
-       if (!S_ISREG(inode->i_mode) || !ima_initialized)
-               return;
 
        if (mode & FMODE_WRITE) {
                if (atomic_read(&inode->i_readcount) && IS_IMA(inode)) {
-                       struct integrity_iint_cache *iint;
-                       iint = integrity_iint_find(inode);
+                       if (!iint)
+                               iint = integrity_iint_find(inode);
                        /* IMA_MEASURE is set from reader side */
                        if (iint && (iint->flags & IMA_MEASURE))
                                send_tomtou = true;
                }
        } else {
-               if ((atomic_read(&inode->i_writecount) > 0) &&
-                   ima_must_measure(inode, MAY_READ, FILE_CHECK))
+               if ((atomic_read(&inode->i_writecount) > 0) && must_measure)
                        send_writers = true;
        }
 
        if (!send_tomtou && !send_writers)
                return;
 
-       pathname = ima_d_path(&file->f_path, &pathbuf);
+       *pathname = ima_d_path(&file->f_path, pathbuf);
 
        if (send_tomtou)
-               ima_add_violation(file, pathname, "invalid_pcr", "ToMToU");
+               ima_add_violation(file, *pathname, "invalid_pcr", "ToMToU");
        if (send_writers)
-               ima_add_violation(file, pathname,
+               ima_add_violation(file, *pathname,
                                  "invalid_pcr", "open_writers");
-       kfree(pathbuf);
 }
 
 static void ima_check_last_writer(struct integrity_iint_cache *iint,
@@ -160,15 +157,16 @@ static int process_measurement(struct file *file, int mask, int function,
                               int opened)
 {
        struct inode *inode = file_inode(file);
-       struct integrity_iint_cache *iint;
+       struct integrity_iint_cache *iint = NULL;
        struct ima_template_desc *template_desc;
        char *pathbuf = NULL;
        const char *pathname = NULL;
        int rc = -ENOMEM, action, must_appraise;
        struct evm_ima_xattr_data *xattr_value = NULL, **xattr_ptr = NULL;
        int xattr_len = 0;
+       bool violation_check;
 
-       if (!ima_initialized || !S_ISREG(inode->i_mode))
+       if (!ima_policy_flag || !S_ISREG(inode->i_mode))
                return 0;
 
        /* Return an IMA_MEASURE, IMA_APPRAISE, IMA_AUDIT action
@@ -176,7 +174,9 @@ static int process_measurement(struct file *file, int mask, int function,
         * Included is the appraise submask.
         */
        action = ima_get_action(inode, mask, function);
-       if (!action)
+       violation_check = ((function == FILE_CHECK || function == MMAP_CHECK) &&
+                          (ima_policy_flag & IMA_MEASURE));
+       if (!action && !violation_check)
                return 0;
 
        must_appraise = action & IMA_APPRAISE;
@@ -187,9 +187,20 @@ static int process_measurement(struct file *file, int mask, int function,
 
        mutex_lock(&inode->i_mutex);
 
-       iint = integrity_inode_get(inode);
-       if (!iint)
-               goto out;
+       if (action) {
+               iint = integrity_inode_get(inode);
+               if (!iint)
+                       goto out;
+       }
+
+       if (violation_check) {
+               ima_rdwr_violation_check(file, iint, action & IMA_MEASURE,
+                                        &pathbuf, &pathname);
+               if (!action) {
+                       rc = 0;
+                       goto out_free;
+               }
+       }
 
        /* Determine if already appraised/measured based on bitmask
         * (IMA_MEASURE, IMA_MEASURED, IMA_XXXX_APPRAISE, IMA_XXXX_APPRAISED,
@@ -218,7 +229,8 @@ static int process_measurement(struct file *file, int mask, int function,
                goto out_digsig;
        }
 
-       pathname = ima_d_path(&file->f_path, &pathbuf);
+       if (!pathname)  /* ima_rdwr_violation possibly pre-fetched */
+               pathname = ima_d_path(&file->f_path, &pathbuf);
 
        if (action & IMA_MEASURE)
                ima_store_measurement(iint, file, pathname,
@@ -228,13 +240,15 @@ static int process_measurement(struct file *file, int mask, int function,
                                              xattr_value, xattr_len, opened);
        if (action & IMA_AUDIT)
                ima_audit_measurement(iint, pathname);
-       kfree(pathbuf);
+
 out_digsig:
        if ((mask & MAY_WRITE) && (iint->flags & IMA_DIGSIG))
                rc = -EACCES;
+       kfree(xattr_value);
+out_free:
+       kfree(pathbuf);
 out:
        mutex_unlock(&inode->i_mutex);
-       kfree(xattr_value);
        if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE))
                return -EACCES;
        return 0;
@@ -288,7 +302,6 @@ int ima_bprm_check(struct linux_binprm *bprm)
  */
 int ima_file_check(struct file *file, int mask, int opened)
 {
-       ima_rdwr_violation_check(file);
        return process_measurement(file,
                                   mask & (MAY_READ | MAY_WRITE | MAY_EXEC),
                                   FILE_CHECK, opened);
@@ -334,14 +347,10 @@ static int __init init_ima(void)
 
        hash_setup(CONFIG_IMA_DEFAULT_HASH);
        error = ima_init();
-       if (error)
-               goto out;
-
-       error = ima_init_keyring(INTEGRITY_KEYRING_IMA);
-       if (error)
-               goto out;
-       ima_initialized = 1;
-out:
+       if (!error) {
+               ima_initialized = 1;
+               ima_update_policy_flag();
+       }
        return error;
 }
 
index 07099a8..cdc620b 100644 (file)
@@ -35,6 +35,8 @@
 #define DONT_APPRAISE  0x0008
 #define AUDIT          0x0040
 
+int ima_policy_flag;
+
 #define MAX_LSM_RULES 6
 enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE,
        LSM_SUBJ_USER, LSM_SUBJ_ROLE, LSM_SUBJ_TYPE
@@ -295,6 +297,26 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
        return action;
 }
 
+/*
+ * Initialize the ima_policy_flag variable based on the currently
+ * loaded policy.  Based on this flag, the decision to short circuit
+ * out of a function or not call the function in the first place
+ * can be made earlier.
+ */
+void ima_update_policy_flag(void)
+{
+       struct ima_rule_entry *entry;
+
+       ima_policy_flag = 0;
+       list_for_each_entry(entry, ima_rules, list) {
+               if (entry->action & IMA_DO_MASK)
+                       ima_policy_flag |= entry->action;
+       }
+
+       if (!ima_appraise)
+               ima_policy_flag &= ~IMA_APPRAISE;
+}
+
 /**
  * ima_init_policy - initialize the default measure rules.
  *
@@ -341,6 +363,7 @@ void ima_update_policy(void)
 
        if (ima_rules == &ima_default_rules) {
                ima_rules = &ima_policy_rules;
+               ima_update_policy_flag();
                cause = "complete";
                result = 0;
        }