[RFC][PATCH 3/3] evm: Return -EAGAIN to ignore verification failures

Roberto Sassu roberto.sassu at huawei.com
Wed Apr 29 07:39:35 UTC 2020


By default, EVM maintains the same behavior as before hooks were moved
outside the LSM infrastructure. When EVM returns -EPERM, callers stop their
execution and return the error to user space.

This patch introduces a new mode, called ignore, that changes the return
value of the pre hooks from -EPERM to -EAGAIN. It also modifies the callers
of pre and post hooks to continue the execution if -EAGAIN is returned. The
error is then handled by the post hooks.

The only error that is not ignored is when user space is trying to modify a
portable signature. Once that signature has been validated with the current
values of metadata, there is no valid reason to change them.

>From user space perspective, operations on corrupted metadata are
successfully performed but post hooks didn't update the HMAC. At the next
IMA verification, when evm_verifyxattr() is called, corruption will be
detected and access will be denied.

Signed-off-by: Roberto Sassu <roberto.sassu at huawei.com>
---
 fs/attr.c                         |  2 +-
 fs/xattr.c                        |  4 ++--
 security/integrity/evm/evm_main.c | 23 +++++++++++++++++------
 3 files changed, 20 insertions(+), 9 deletions(-)

diff --git a/fs/attr.c b/fs/attr.c
index 6ce60e1eba34..6370e2f3704d 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -329,7 +329,7 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de
 	if (error)
 		return error;
 	evm_error = evm_inode_setattr(dentry, attr);
-	if (evm_error)
+	if (evm_error && evm_error != -EAGAIN)
 		return evm_error;
 	error = try_break_deleg(inode, delegated_inode);
 	if (error)
diff --git a/fs/xattr.c b/fs/xattr.c
index b1fd2aa481a8..73f0f3cd6c45 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -229,7 +229,7 @@ vfs_setxattr(struct dentry *dentry, const char *name, const void *value,
 		goto out;
 
 	evm_error = evm_inode_setxattr(dentry, name, value, size);
-	if (evm_error) {
+	if (evm_error && evm_error != -EAGAIN) {
 		error = evm_error;
 		goto out;
 	}
@@ -408,7 +408,7 @@ vfs_removexattr(struct dentry *dentry, const char *name)
 		goto out;
 
 	evm_error = evm_inode_removexattr(dentry, name);
-	if (evm_error) {
+	if (evm_error && evm_error != -EAGAIN) {
 		error = evm_error;
 		goto out;
 	}
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index ca9eaef7058b..ef09caa3bbcf 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -54,11 +54,13 @@ static struct xattr_list evm_config_default_xattrnames[] = {
 
 LIST_HEAD(evm_config_xattrnames);
 
-static int evm_fixmode;
+static int evm_fixmode, evm_ignoremode __ro_after_init;
 static int __init evm_set_fixmode(char *str)
 {
 	if (strncmp(str, "fix", 3) == 0)
 		evm_fixmode = 1;
+	if (strncmp(str, "ignore", 6) == 0)
+		evm_ignoremode = 1;
 	return 0;
 }
 __setup("evm=", evm_set_fixmode);
@@ -311,6 +313,7 @@ static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name,
 			     const void *xattr_value, size_t xattr_value_len)
 {
 	enum integrity_status evm_status;
+	int rc = -EPERM;
 
 	if (strcmp(xattr_name, XATTR_NAME_EVM) == 0) {
 		if (!capable(CAP_SYS_ADMIN))
@@ -345,12 +348,17 @@ static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name,
 				    -EPERM, 0);
 	}
 out:
-	if (evm_status != INTEGRITY_PASS)
+	if (evm_status != INTEGRITY_PASS) {
+		if (evm_ignoremode && evm_status != INTEGRITY_PASS_IMMUTABLE)
+			rc = -EAGAIN;
+
 		integrity_audit_msg(AUDIT_INTEGRITY_METADATA, d_backing_inode(dentry),
 				    dentry->d_name.name, "appraise_metadata",
 				    integrity_status_msg[evm_status],
-				    -EPERM, 0);
-	return evm_status == INTEGRITY_PASS ? 0 : -EPERM;
+				    rc, 0);
+	}
+
+	return evm_status == INTEGRITY_PASS ? 0 : rc;
 }
 
 /**
@@ -482,6 +490,7 @@ int evm_inode_setattr(struct dentry *dentry, struct iattr *attr)
 {
 	unsigned int ia_valid = attr->ia_valid;
 	enum integrity_status evm_status;
+	int rc = -EPERM;
 
 	/* Policy permits modification of the protected attrs even though
 	 * there's no HMAC key loaded
@@ -495,10 +504,12 @@ int evm_inode_setattr(struct dentry *dentry, struct iattr *attr)
 	if ((evm_status == INTEGRITY_PASS) ||
 	    (evm_status == INTEGRITY_NOXATTRS))
 		return 0;
+	if (evm_ignoremode && evm_status != INTEGRITY_PASS_IMMUTABLE)
+		rc = -EAGAIN;
 	integrity_audit_msg(AUDIT_INTEGRITY_METADATA, d_backing_inode(dentry),
 			    dentry->d_name.name, "appraise_metadata",
-			    integrity_status_msg[evm_status], -EPERM, 0);
-	return -EPERM;
+			    integrity_status_msg[evm_status], rc, 0);
+	return rc;
 }
 
 /**
-- 
2.17.1



More information about the Linux-security-module-archive mailing list