Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity into next
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 0cd50491..802a3fd 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1292,7 +1292,7 @@
 			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]
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 8e4bb88..8ee997d 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -43,6 +43,9 @@
 #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 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,
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index 65c41a9..8688597 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -179,11 +179,6 @@
 	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
  *
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index 013ec3f..9226854 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -23,6 +23,8 @@
 {
 	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 @@
 	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 @@
 {
 	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);
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
index e8f9d70..9164fc8 100644
--- a/security/integrity/ima/ima_init.c
+++ b/security/integrity/ima/ima_init.c
@@ -43,7 +43,7 @@
  * 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 @@
 
 	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 @@
 	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 @@
 	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();
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 673a37e..62f59ec 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -77,42 +77,39 @@
  *	  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 @@
 			       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 @@
 	 * 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 @@
 
 	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 @@
 		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 @@
 					      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_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 @@
 
 	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;
 }
 
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index 07099a8..cdc620b 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -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 @@
 	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 @@
 
 	if (ima_rules == &ima_default_rules) {
 		ima_rules = &ima_policy_rules;
+		ima_update_policy_flag();
 		cause = "complete";
 		result = 0;
 	}