evm: permit mode bits to be updated

Before permitting 'security.evm' to be updated, 'security.evm' must
exist and be valid.  In the case that there are no existing EVM protected
xattrs, it is safe for posix acls to update the mode bits.

To differentiate between no 'security.evm' xattr and no xattrs used to
calculate 'security.evm', this patch defines INTEGRITY_NOXATTR.

Signed-off-by: Mimi Zohar <zohar@us.ibm.com>
diff --git a/include/linux/integrity.h b/include/linux/integrity.h
index 9684433..a0c4125 100644
--- a/include/linux/integrity.h
+++ b/include/linux/integrity.h
@@ -16,6 +16,7 @@
 	INTEGRITY_PASS = 0,
 	INTEGRITY_FAIL,
 	INTEGRITY_NOLABEL,
+	INTEGRITY_NOXATTRS,
 	INTEGRITY_UNKNOWN,
 };
 
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index 73c008d..92d3d99 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -66,7 +66,7 @@
 					     struct integrity_iint_cache *iint)
 {
 	struct evm_ima_xattr_data xattr_data;
-	enum integrity_status evm_status;
+	enum integrity_status evm_status = INTEGRITY_PASS;
 	int rc;
 
 	if (iint && iint->evm_status == INTEGRITY_PASS)
@@ -76,25 +76,18 @@
 
 	rc = evm_calc_hmac(dentry, xattr_name, xattr_value,
 			   xattr_value_len, xattr_data.digest);
-	if (rc < 0)
-		goto err_out;
+	if (rc < 0) {
+		evm_status = (rc == -ENODATA)
+		    ? INTEGRITY_NOXATTRS : INTEGRITY_FAIL;
+		goto out;
+	}
 
 	xattr_data.type = EVM_XATTR_HMAC;
 	rc = vfs_xattr_cmp(dentry, XATTR_NAME_EVM, (u8 *)&xattr_data,
 			   sizeof xattr_data, GFP_NOFS);
 	if (rc < 0)
-		goto err_out;
-	evm_status = INTEGRITY_PASS;
-	goto out;
-
-err_out:
-	switch (rc) {
-	case -ENODATA:		/* file not labelled */
-		evm_status = INTEGRITY_NOLABEL;
-		break;
-	default:
-		evm_status = INTEGRITY_FAIL;
-	}
+		evm_status = (rc == -ENODATA)
+		    ? INTEGRITY_NOLABEL : INTEGRITY_FAIL;
 out:
 	if (iint)
 		iint->evm_status = evm_status;
@@ -199,7 +192,7 @@
 			return 0;
 		evm_status = evm_verify_current_integrity(dentry);
 		if ((evm_status == INTEGRITY_PASS) ||
-			(evm_status == INTEGRITY_NOLABEL))
+		    (evm_status == INTEGRITY_NOXATTRS))
 			return 0;
 		return -EPERM;
 	}
@@ -293,7 +286,10 @@
 	if (!(ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID)))
 		return 0;
 	evm_status = evm_verify_current_integrity(dentry);
-	return evm_status == INTEGRITY_PASS ? 0 : -EPERM;
+	if ((evm_status == INTEGRITY_PASS) ||
+	    (evm_status == INTEGRITY_NOXATTRS))
+		return 0;
+	return -EPERM;
 }
 
 /**