Piggyback the resetting of EVM status on IMA's file content detection that is triggered when a not-yet-copied-up file on the 'lower' layer was changed. However, since EVM only cares about changes to the file metadata, only reset the EVM status if the 'lower' layer file is also the one holding the file metadata. Note that in the case of a stacked filesystem (e.g., overlayfs) the iint represents the file_inode() of a file on the overlay layer. The data in the in iint must help detect file content (IMA) and file metadata (EVM) changes occurring on the lower layer for as long as the content or metadata have not been copied up yet. After copy-up the iit must continue detecting them on the overlay layer. Changes to the file metadata on the overlay layer are causing an EVM status reset through existing evm_inode_post_sattr/setxattr/removexattr functions *if* an iint for a file exist. An iint exists if the file is 'in (IMA) policy', meaning that IMA created an iint for the file's inode since the file is covered by the IMA policy. Signed-off-by: Stefan Berger <stefanb@xxxxxxxxxxxxx> --- include/linux/evm.h | 8 ++++++++ security/integrity/evm/evm_main.c | 7 +++++++ security/integrity/ima/ima_main.c | 5 +++++ 3 files changed, 20 insertions(+) diff --git a/include/linux/evm.h b/include/linux/evm.h index 840ffbdc2860..eade9fff7d0b 100644 --- a/include/linux/evm.h +++ b/include/linux/evm.h @@ -66,6 +66,8 @@ extern int evm_protected_xattr_if_enabled(const char *req_xattr_name); extern int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer, int buffer_size, char type, bool canonical_fmt); +extern void evm_reset_cache_status(struct dentry *dentry, + struct integrity_iint_cache *iint); #ifdef CONFIG_FS_POSIX_ACL extern int posix_xattr_acl(const char *xattrname); #else @@ -190,5 +192,11 @@ static inline int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer, return -EOPNOTSUPP; } +static inline void evm_reset_cache_status(struct dentry *dentry, + struct integrity_iint_cache *iint) +{ + return; +} + #endif /* CONFIG_EVM */ #endif /* LINUX_EVM_H */ diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c index 565c36471408..81c94967f136 100644 --- a/security/integrity/evm/evm_main.c +++ b/security/integrity/evm/evm_main.c @@ -721,6 +721,13 @@ static void evm_reset_status(struct inode *inode) iint->evm_status = INTEGRITY_UNKNOWN; } +void evm_reset_cache_status(struct dentry *dentry, + struct integrity_iint_cache *iint) +{ + if (d_real_inode(dentry) != d_backing_inode(dentry)) + iint->evm_status = INTEGRITY_UNKNOWN; +} + /** * evm_revalidate_status - report whether EVM status re-validation is necessary * @xattr_name: pointer to the affected extended attribute name diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index f1a01d32b92a..b6ba829c4e67 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -26,6 +26,7 @@ #include <linux/ima.h> #include <linux/fs.h> #include <linux/iversion.h> +#include <linux/evm.h> #include "ima.h" @@ -297,6 +298,10 @@ static int process_measurement(struct file *file, const struct cred *cred, !inode_eq_iversion(real_inode, iint->version)) { iint->flags &= ~IMA_DONE_MASK; iint->measured_pcrs = 0; + + if (real_inode == d_inode(d_real(file_dentry(file), + D_REAL_METADATA))) + evm_reset_cache_status(file_dentry(file), iint); } } -- 2.43.0