[RFC][PATCH v2 8/9] ima: Use digest caches for appraisal

Roberto Sassu roberto.sassu at huaweicloud.com
Mon Apr 15 16:10:43 UTC 2024


From: Roberto Sassu <roberto.sassu at huawei.com>

Similarly to measurement, enable the new appraisal style too using digest
caches.

Instead of verifying individual file signatures, verify the signature of
lists of digests and search calculated file digests in those lists.

The benefits are that signed lists of digests already exist (e.g. RPM
package headers), although their format needs to be supported by the
digest_cache LSM, and appraisal with digest lists is computationally much
less expensive than with individual file signatures (see the performance
evaluation of the digest_cache LSM).

Take the allowed usage after the call to
ima_digest_cache_update_allowed_usage(), and pass it to
ima_appraise_measurement().

If EVM is disabled or the file does not have any protected xattr
(evm_verifyxattr() returns INTEGRITY_UNKNOWN or INTEGRITY_NOXATTRS) and the
allowed usage has the IMA_DIGEST_CACHE_APPRAISE_DATA flag set, mark the
file as successfully appraised (i.e. set the integrity status to
INTEGRITY_PASS and return zero).

The digest cache method is tried first, for performance reasons, in the
event there are for example IMA signatures in the system (which are
computationally more expensive to verify). The usage of the digest_cache
LSM has anyway to be authorized in the IMA policy.

Signed-off-by: Roberto Sassu <roberto.sassu at huawei.com>
---
 security/integrity/ima/ima.h          |  6 ++++--
 security/integrity/ima/ima_appraise.c | 30 ++++++++++++++++++++-------
 security/integrity/ima/ima_main.c     |  3 ++-
 3 files changed, 29 insertions(+), 10 deletions(-)

diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 865137dfcf22..1f0810be9f8a 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -432,7 +432,8 @@ int ima_check_blacklist(struct ima_iint_cache *iint,
 int ima_appraise_measurement(enum ima_hooks func, struct ima_iint_cache *iint,
 			     struct file *file, const unsigned char *filename,
 			     struct evm_ima_xattr_data *xattr_value,
-			     int xattr_len, const struct modsig *modsig);
+			     int xattr_len, const struct modsig *modsig,
+			     u64 allowed_usage);
 int ima_must_appraise(struct mnt_idmap *idmap, struct inode *inode,
 		      int mask, enum ima_hooks func);
 void ima_update_xattr(struct ima_iint_cache *iint, struct file *file);
@@ -457,7 +458,8 @@ static inline int ima_appraise_measurement(enum ima_hooks func,
 					   const unsigned char *filename,
 					   struct evm_ima_xattr_data *xattr_value,
 					   int xattr_len,
-					   const struct modsig *modsig)
+					   const struct modsig *modsig,
+					   u64 allowed_usage)
 {
 	return INTEGRITY_UNKNOWN;
 }
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index 27ccc9a2c09f..3b4d6491e69e 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -478,7 +478,8 @@ int ima_check_blacklist(struct ima_iint_cache *iint,
 int ima_appraise_measurement(enum ima_hooks func, struct ima_iint_cache *iint,
 			     struct file *file, const unsigned char *filename,
 			     struct evm_ima_xattr_data *xattr_value,
-			     int xattr_len, const struct modsig *modsig)
+			     int xattr_len, const struct modsig *modsig,
+			     u64 allowed_usage)
 {
 	static const char op[] = "appraise_data";
 	const char *cause = "unknown";
@@ -488,12 +489,18 @@ int ima_appraise_measurement(enum ima_hooks func, struct ima_iint_cache *iint,
 	int rc = xattr_len;
 	bool try_modsig = iint->flags & IMA_MODSIG_ALLOWED && modsig;
 
-	/* If not appraising a modsig, we need an xattr. */
-	if (!(inode->i_opflags & IOP_XATTR) && !try_modsig)
+	/*
+	 * If not appraising a modsig/there is no digest cache match, we need
+	 * an xattr.
+	 */
+	if (!(inode->i_opflags & IOP_XATTR) && !try_modsig && !allowed_usage)
 		return INTEGRITY_UNKNOWN;
 
-	/* If reading the xattr failed and there's no modsig, error out. */
-	if (rc <= 0 && !try_modsig) {
+	/*
+	 * If reading the xattr failed and there's no modsig/digest cache match,
+	 * error out.
+	 */
+	if (rc <= 0 && !try_modsig && !allowed_usage) {
 		if (rc && rc != -ENODATA)
 			goto out;
 
@@ -524,8 +531,11 @@ int ima_appraise_measurement(enum ima_hooks func, struct ima_iint_cache *iint,
 	case INTEGRITY_UNKNOWN:
 		break;
 	case INTEGRITY_NOXATTRS:	/* No EVM protected xattrs. */
-		/* It's fine not to have xattrs when using a modsig. */
-		if (try_modsig)
+		/*
+		 * It's fine not to have xattrs when using a modsig or the
+		 * digest cache.
+		 */
+		if (try_modsig || allowed_usage)
 			break;
 		fallthrough;
 	case INTEGRITY_NOLABEL:		/* No security.evm xattr. */
@@ -542,6 +552,12 @@ int ima_appraise_measurement(enum ima_hooks func, struct ima_iint_cache *iint,
 		WARN_ONCE(true, "Unexpected integrity status %d\n", status);
 	}
 
+	if (allowed_usage & IMA_DIGEST_CACHE_APPRAISE_DATA) {
+		status = INTEGRITY_PASS;
+		rc = 0;
+		goto out;
+	}
+
 	if (xattr_value)
 		rc = xattr_verify(func, iint, xattr_value, xattr_len, &status,
 				  &cause);
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 0ff5de9bef70..7ae2bd888d41 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -384,7 +384,8 @@ static int process_measurement(struct file *file, const struct cred *cred,
 			inode_lock(inode);
 			rc = ima_appraise_measurement(func, iint, file,
 						      pathname, xattr_value,
-						      xattr_len, modsig);
+						      xattr_len, modsig,
+						      digest_cache_usage);
 			inode_unlock(inode);
 		}
 		if (!rc)
-- 
2.34.1




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