[RFC][PATCH 7/7] ima: Add support for appraisal with digest lists

From: Roberto Sassu
Date: Thu Sep 30 2021 - 07:57:09 EST


Introduce a new appraisal method based on the lookup of the file and
metadata digest in the DIGLIM hash table, enabled with the use_diglim
directive.

First pass to ima_appraise_measurement() the actions performed on the
digest lists containing the found digests.

Then, consider the metadata verification as successful if EVM returned the
status INTEGRITY_NOLABEL (no security.evm), if the metadata digest was
found in the DIGLIM hash table and at least one digest list containing it
was succefully appraised with a signature.

Finally, consider the file content verification as successful if there is
no security.ima or appended signature, if the file or metadata digest
(calculated with the actual file digest) were found in the DIGLIM hash
table and at least one digest list containing it has a valid signature.

Furthermore, mark the file as immutable if the COMPACT_MOD_IMMUTABLE
modifier was set in the header of the digest lists containing the found
digests.

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

diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 550805b79984..631e9e4c343b 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -319,7 +319,9 @@ 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,
+ u16 file_modifiers, u8 file_actions,
+ u16 metadata_modifiers, u8 metadata_actions);
int ima_must_appraise(struct user_namespace *mnt_userns, struct inode *inode,
int mask, enum ima_hooks func);
void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file);
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index e1b9a5bc4252..a0885272411e 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -377,7 +377,9 @@ 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,
+ u16 file_modifiers, u8 file_actions,
+ u16 metadata_modifiers, u8 metadata_actions)
{
static const char op[] = "appraise_data";
const char *cause = "unknown";
@@ -387,12 +389,26 @@ int ima_appraise_measurement(enum ima_hooks func,
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)
+ /* We are interested only in appraisal-related flags. */
+ file_actions &= COMPACT_ACTION_IMA_APPRAISED_DIGSIG;
+ metadata_actions &= COMPACT_ACTION_IMA_APPRAISED_DIGSIG;
+
+ /* Disable DIGLIM method for appraisal if not enabled in the policy. */
+ if (!(iint->flags & IMA_USE_DIGLIM_APPRAISE)) {
+ file_actions = 0;
+ metadata_actions = 0;
+ }
+
+ /* If not appraising a modsig or using DIGLIM, we need an xattr. */
+ if (!(inode->i_opflags & IOP_XATTR) && !try_modsig &&
+ !file_actions && !metadata_actions)
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, there's no modsig and the DIGLIM
+ * appraisal method is not available, error out.
+ */
+ if (rc <= 0 && !try_modsig && !file_actions && !metadata_actions) {
if (rc && rc != -ENODATA)
goto out;

@@ -420,6 +436,10 @@ int ima_appraise_measurement(enum ima_hooks func,
break;
fallthrough;
case INTEGRITY_NOLABEL: /* No security.evm xattr. */
+ if (metadata_actions) {
+ status = INTEGRITY_PASS_IMMUTABLE;
+ break;
+ }
cause = "missing-HMAC";
goto out;
case INTEGRITY_FAIL_IMMUTABLE:
@@ -455,6 +475,13 @@ int ima_appraise_measurement(enum ima_hooks func,
rc == -ENOKEY))
rc = modsig_verify(func, modsig, &status, &cause);

+ if (!xattr_value && !try_modsig && (file_actions || metadata_actions)) {
+ status = INTEGRITY_PASS;
+
+ if ((file_modifiers & (1 << COMPACT_MOD_IMMUTABLE)) ||
+ (metadata_modifiers & (1 << COMPACT_MOD_IMMUTABLE)))
+ set_bit(IMA_DIGSIG, &iint->atomic_flags);
+ }
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 7add0e70f67a..7a9a2392d49c 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -416,7 +416,11 @@ 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,
+ file_modifiers,
+ file_actions,
+ metadata_modifiers,
+ metadata_actions);
inode_unlock(inode);
}
if (!rc)
--
2.32.0