@@ -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;
}
@@ -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);
@@ -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
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 <stefanb@linux.ibm.com> --- include/linux/integrity.h | 8 ++++++-- security/integrity/iint.c | 15 +++++++++++++-- security/security.c | 2 +- 3 files changed, 20 insertions(+), 5 deletions(-)