@@ -14,6 +14,7 @@ ima-$(CONFIG_HAVE_IMA_KEXEC) += ima_kexec.o
ima-$(CONFIG_IMA_BLACKLIST_KEYRING) += ima_mok.o
ima-$(CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS) += ima_asymmetric_keys.o
ima-$(CONFIG_IMA_QUEUE_EARLY_BOOT_KEYS) += ima_queue_keys.o
+ima-$(CONFIG_INTEGRITY_DIGEST_CACHE) += ima_digest_cache.o
ifeq ($(CONFIG_EFI),y)
ima-$(CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT) += ima_efi.o
@@ -198,6 +198,7 @@ struct ima_iint_cache {
enum integrity_status ima_read_status:4;
enum integrity_status ima_creds_status:4;
struct ima_digest_data *ima_hash;
+ struct digest_cache *digest_cache;
};
extern struct lsm_blob_sizes ima_blob_sizes;
new file mode 100644
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2024 Huawei Technologies Duesseldorf GmbH
+ *
+ * Author: Roberto Sassu <roberto.sassu@huawei.com>
+ *
+ * Integrate with the Integrity Digest Cache.
+ */
+
+#include <linux/digest_cache.h>
+
+#include "ima_digest_cache.h"
+
+/**
+ * ima_digest_cache_get_check - Get digest cache and check if changed
+ * @file: File descriptor of the inode for which the digest cache will be used
+ * @iint: Inode integrity metadata
+ *
+ * Get a digest cache for the file descriptor parameter and compare with the
+ * digest cache stored in the inode integrity metadata.
+ *
+ * It must be called with the iint->mutex held.
+ *
+ * Return: True if the digest cache pointer changed, false otherwise.
+ */
+bool ima_digest_cache_get_check(struct file *file,
+ struct ima_iint_cache *iint)
+{
+ struct digest_cache *digest_cache;
+
+ digest_cache = digest_cache_get(file);
+
+ /* There was no digest cache before, not changed. */
+ if (!iint->digest_cache) {
+ iint->digest_cache = digest_cache;
+ return false;
+ }
+
+ /* New digest cache not available, or digest cache changed. */
+ if (!digest_cache || iint->digest_cache != digest_cache) {
+ digest_cache_put(iint->digest_cache);
+ iint->digest_cache = digest_cache;
+ return true;
+ }
+
+ /* Digest cache not changed. */
+ digest_cache_put(digest_cache);
+ return false;
+}
new file mode 100644
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2024 Huawei Technologies Duesseldorf GmbH
+ *
+ * Author: Roberto Sassu <roberto.sassu@huawei.com>
+ *
+ * Header file of ima_digest_cache.c.
+ */
+
+#include "ima.h"
+
+#ifdef CONFIG_INTEGRITY_DIGEST_CACHE
+bool ima_digest_cache_get_check(struct file *file,
+ struct ima_iint_cache *iint);
+#else
+static inline bool ima_digest_cache_get_check(struct file *file,
+ struct ima_iint_cache *iint)
+{
+ return false;
+}
+
+#endif /* CONFIG_INTEGRITY_DIGEST_CACHE */
@@ -68,12 +68,16 @@ static void ima_iint_init_always(struct ima_iint_cache *iint,
iint->ima_read_status = INTEGRITY_UNKNOWN;
iint->ima_creds_status = INTEGRITY_UNKNOWN;
iint->measured_pcrs = 0;
+ iint->digest_cache = NULL;
mutex_init(&iint->mutex);
ima_iint_lockdep_annotate(iint, inode);
}
static void ima_iint_free(struct ima_iint_cache *iint)
{
+ if (iint->digest_cache)
+ digest_cache_put(iint->digest_cache);
+
kfree(iint->ima_hash);
mutex_destroy(&iint->mutex);
kmem_cache_free(ima_iint_cache, iint);
@@ -29,6 +29,7 @@
#include <linux/evm.h>
#include "ima.h"
+#include "ima_digest_cache.h"
#ifdef CONFIG_IMA_APPRAISE
int ima_appraise = IMA_APPRAISE_ENFORCE;
@@ -224,6 +225,7 @@ static int process_measurement(struct file *file, const struct cred *cred,
bool violation_check;
enum hash_algo hash_algo;
unsigned int allowed_algos = 0;
+ u64 policy_usage = 0ULL;
if (!ima_policy_flag || !S_ISREG(inode->i_mode))
return 0;
@@ -234,7 +236,7 @@ static int process_measurement(struct file *file, const struct cred *cred,
*/
action = ima_get_action(file_mnt_idmap(file), inode, cred, secid,
mask, func, &pcr, &template_desc, NULL,
- &allowed_algos, NULL);
+ &allowed_algos, &policy_usage);
violation_check = ((func == FILE_CHECK || func == MMAP_CHECK ||
func == MMAP_CHECK_REQPROT) &&
(ima_policy_flag & IMA_MEASURE));
@@ -266,7 +268,7 @@ static int process_measurement(struct file *file, const struct cred *cred,
if (!action)
goto out;
- mutex_lock(&iint->mutex);
+ mutex_lock_nested(&iint->mutex, digest_cache_opened_fd(file));
if (test_and_clear_bit(IMA_CHANGE_ATTR, &iint->atomic_flags))
/* reset appraisal flags if ima_inode_post_setattr was called */
@@ -287,6 +289,13 @@ static int process_measurement(struct file *file, const struct cred *cred,
iint->measured_pcrs = 0;
}
+ /* Digest cache changed, reset integrity status. */
+ if (policy_usage &&
+ ima_digest_cache_get_check(file, iint)) {
+ iint->flags &= ~IMA_DONE_MASK;
+ iint->measured_pcrs = 0;
+ }
+
/*
* On stacked filesystems, detect and re-evaluate file data and
* metadata changes.