[RFC][PATCH v2 09/13] ima: Use digest cache for appraisal

From: Roberto Sassu
Date: Sat Aug 12 2023 - 06:50:05 EST


From: Roberto Sassu <roberto.sassu@xxxxxxxxxx>

If the digest of the accessed file is found in the digest cache, pass the
ANDed masks from the IMA policy and from the digest cache to
ima_appraise_measurement().

If the DIGEST_CACHE_APPRAISE_CONTENT flag is set in the mask, security.ima
is not available, and the modsig method is disabled, grant access in
read-only mode (except for new files).

Since xattrs were not verified with EVM, writes need to be prevented to
avoid the HMAC to be updated from an unverified one.

Signed-off-by: Roberto Sassu <roberto.sassu@xxxxxxxxxx>
---
security/integrity/ima/ima.h | 6 ++++--
security/integrity/ima/ima_appraise.c | 14 +++++++++++++-
security/integrity/ima/ima_main.c | 3 ++-
3 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index bb75cc3d2fd..06887f8f1bc 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -322,7 +322,8 @@ int ima_appraise_measurement(enum ima_hooks func,
struct integrity_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 integrity_iint_cache *iint, struct file *file);
@@ -346,7 +347,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 10dbafdae3d..969a02802b9 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -479,7 +479,8 @@ int ima_appraise_measurement(enum ima_hooks func,
struct integrity_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";
@@ -514,6 +515,17 @@ int ima_appraise_measurement(enum ima_hooks func,
(!(iint->flags & IMA_DIGSIG_REQUIRED) ||
(inode->i_size == 0)))
status = INTEGRITY_PASS;
+ /*
+ * Except for new files, use the digest cache to appraise the
+ * file content and, at the same time, mark the file as
+ * immutable to prevent file updates and transitioning from an
+ * unverified HMAC to a valid HMAC.
+ */
+ if (status != INTEGRITY_PASS &&
+ (digest_cache_mask & DIGEST_CACHE_APPRAISE_CONTENT)) {
+ set_bit(IMA_DIGSIG, &iint->atomic_flags);
+ status = INTEGRITY_PASS;
+ }
goto out;
}

diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 54d006fc490..b458ef62c4c 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -383,7 +383,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_mask);
inode_unlock(inode);
}
if (!rc)
--
2.34.1