Add an optional callback function to integrity_inode_free() that,
if provided, must be called and determines whether the iint can be
freed. Adjust all callers of this function to provide a NULL pointer
since none of the existing callers needs this check.
Signed-off-by: Stefan Berger <[email protected]>
---
include/linux/integrity.h | 8 ++++++--
security/integrity/iint.c | 15 +++++++++++++--
security/security.c | 2 +-
3 files changed, 20 insertions(+), 5 deletions(-)
diff --git a/include/linux/integrity.h b/include/linux/integrity.h
index 2ea0f2f65ab6..9fe826b9146e 100644
--- a/include/linux/integrity.h
+++ b/include/linux/integrity.h
@@ -19,10 +19,13 @@ enum integrity_status {
INTEGRITY_UNKNOWN,
};
+struct integrity_iint_cache;
+typedef bool (*iint_removable_cb)(struct integrity_iint_cache *iint);
+
/* List of EVM protected security xattrs */
#ifdef CONFIG_INTEGRITY
extern struct integrity_iint_cache *integrity_inode_get(struct inode *inode);
-extern void integrity_inode_free(struct inode *inode);
+extern void integrity_inode_free(struct inode *inode, iint_removable_cb check);
extern void __init integrity_load_keys(void);
#else
@@ -32,7 +35,8 @@ static inline struct integrity_iint_cache *
return NULL;
}
-static inline void integrity_inode_free(struct inode *inode)
+static inline void integrity_inode_free(struct inode *inode,
+ iint_removable_cb check)
{
return;
}
diff --git a/security/integrity/iint.c b/security/integrity/iint.c
index 371cbceaf479..4580df0e716e 100644
--- a/security/integrity/iint.c
+++ b/security/integrity/iint.c
@@ -143,21 +143,32 @@ struct integrity_iint_cache *integrity_inode_get(struct inode *inode)
/**
* integrity_inode_free - called on security_inode_free
* @inode: pointer to the inode
+ * @check: optional callback function to check whether the iint can be freed
*
* Free the integrity information(iint) associated with an inode.
*/
-void integrity_inode_free(struct inode *inode)
+void integrity_inode_free(struct inode *inode, iint_removable_cb check)
{
struct integrity_iint_cache *iint;
+ bool freeit = true;
if (!IS_IMA(inode))
return;
write_lock(&integrity_iint_lock);
+
iint = __integrity_iint_find(inode);
- rb_erase(&iint->rb_node, &integrity_iint_tree);
+
+ if (check)
+ freeit = check(iint);
+ if (freeit)
+ rb_erase(&iint->rb_node, &integrity_iint_tree);
+
write_unlock(&integrity_iint_lock);
+ if (!freeit)
+ return;
+
ima_free_ns_status_list(&iint->ns_list, &iint->ns_list_lock);
iint_free(iint);
diff --git a/security/security.c b/security/security.c
index b7cf5cbfdc67..2acd11e6b6bb 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1040,7 +1040,7 @@ static void inode_free_by_rcu(struct rcu_head *head)
void security_inode_free(struct inode *inode)
{
- integrity_inode_free(inode);
+ integrity_inode_free(inode, NULL);
call_void_hook(inode_free_security, inode);
/*
* The inode may still be referenced in a path walk and
--
2.34.1