From: Roberto Sassu <roberto.sassu@xxxxxxxxxx> Add a digest cache pointer to the ima_iint_cache structure and introduce ima_digest_cache_get_check() to retrieve a fresh digest cache and compare with the pointer stored in the previous calls (if digest cache was enabled in the IMA policy). If the pointers don't match, reset the integrity status since the digest cache used for the previous verification might have changed. Also, initialize and put the digest cache respectively in ima_iint_init_always() and ima_iint_free(). Signed-off-by: Roberto Sassu <roberto.sassu@xxxxxxxxxx> --- security/integrity/ima/Makefile | 1 + security/integrity/ima/ima.h | 1 + security/integrity/ima/ima_digest_cache.c | 49 +++++++++++++++++++++++ security/integrity/ima/ima_digest_cache.h | 22 ++++++++++ security/integrity/ima/ima_iint.c | 4 ++ security/integrity/ima/ima_main.c | 10 ++++- 6 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 security/integrity/ima/ima_digest_cache.c create mode 100644 security/integrity/ima/ima_digest_cache.h diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile index b376d38b4ee6..b4a284634a07 100644 --- a/security/integrity/ima/Makefile +++ b/security/integrity/ima/Makefile @@ -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 diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 736fe014afbc..b2ef37a11b65 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -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; diff --git a/security/integrity/ima/ima_digest_cache.c b/security/integrity/ima/ima_digest_cache.c new file mode 100644 index 000000000000..bf720684b7b1 --- /dev/null +++ b/security/integrity/ima/ima_digest_cache.c @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2024 Huawei Technologies Duesseldorf GmbH + * + * Author: Roberto Sassu <roberto.sassu@xxxxxxxxxx> + * + * 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 + * @dentry: Dentry of the inode for which the digest cache will be used + * @iint: Inode integrity metadata + * + * Get a digest cache for the dentry 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 dentry *dentry, + struct ima_iint_cache *iint) +{ + struct digest_cache *digest_cache; + + digest_cache = digest_cache_get(dentry); + + /* 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; +} diff --git a/security/integrity/ima/ima_digest_cache.h b/security/integrity/ima/ima_digest_cache.h new file mode 100644 index 000000000000..75b6ac8732d3 --- /dev/null +++ b/security/integrity/ima/ima_digest_cache.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2024 Huawei Technologies Duesseldorf GmbH + * + * Author: Roberto Sassu <roberto.sassu@xxxxxxxxxx> + * + * Header file of ima_digest_cache.c. + */ + +#include "ima.h" + +#ifdef CONFIG_INTEGRITY_DIGEST_CACHE +bool ima_digest_cache_get_check(struct dentry *dentry, + struct ima_iint_cache *iint); +#else +static inline bool ima_digest_cache_get_check(struct dentry *dentry, + struct ima_iint_cache *iint) +{ + return false; +} + +#endif /* CONFIG_INTEGRITY_DIGEST_CACHE */ diff --git a/security/integrity/ima/ima_iint.c b/security/integrity/ima/ima_iint.c index e23412a2c56b..d6946cd4fa91 100644 --- a/security/integrity/ima/ima_iint.c +++ b/security/integrity/ima/ima_iint.c @@ -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); diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index ebf233664194..ae106f1fe144 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -224,6 +224,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 +235,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)); @@ -287,6 +288,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_dentry(file), iint)) { + iint->flags &= ~IMA_DONE_MASK; + iint->measured_pcrs = 0; + } + /* * On stacked filesystems, detect and re-evaluate file data and * metadata changes. -- 2.34.1