diff mbox series

[RFC,7/8] ima: Use digest cache for appraisal

Message ID 20240214143525.2205481-8-roberto.sassu@huaweicloud.com (mailing list archive)
State New
Headers show
Series ima: Integrate with digest_cache LSM | expand

Commit Message

Roberto Sassu Feb. 14, 2024, 2:35 p.m. UTC
From: Roberto Sassu <roberto.sassu@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).

As for measurement, pass the AND of the policy mask and the digest list
verification mask 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), the
other appraisal methods (xattr and modsig) are not available, and the AND
of the masks has the IMA_DIGEST_CACHE_APPRAISE_CONTENT flag set, mark the
file as successfully appraised (i.e. set the integrity status to
INTEGRITY_PASS and return zero).

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

Patch

diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index cf04f5a22234..36faf2bc81b0 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -433,7 +433,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 digest_cache_mask);
 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);
@@ -458,7 +459,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,
+					   u8 digest_cache_mask)
 {
 	return INTEGRITY_UNKNOWN;
 }
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index 27ccc9a2c09f..dcea88d502a9 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 digest_cache_mask)
 {
 	static const char op[] = "appraise_data";
 	const char *cause = "unknown";
@@ -488,12 +489,19 @@  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 &&
+	    !digest_cache_mask)
 		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 && !digest_cache_mask) {
 		if (rc && rc != -ENODATA)
 			goto out;
 
@@ -524,8 +532,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 || digest_cache_mask)
 			break;
 		fallthrough;
 	case INTEGRITY_NOLABEL:		/* No security.evm xattr. */
@@ -555,6 +566,12 @@  int ima_appraise_measurement(enum ima_hooks func, struct ima_iint_cache *iint,
 	     rc == -ENOKEY))
 		rc = modsig_verify(func, modsig, &status, &cause);
 
+	if (!xattr_value && !try_modsig &&
+	    (digest_cache_mask & IMA_DIGEST_CACHE_APPRAISE_CONTENT)) {
+		status = INTEGRITY_PASS;
+		rc = 0;
+	}
+
 out:
 	/*
 	 * File signatures on some filesystems can not be properly verified.
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 48a09747ae7a..a66522a22cbc 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -400,7 +400,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,
+						      allow_mask);
 			inode_unlock(inode);
 		}
 		if (!rc)