diff options
author | Paul Moore <paul@paul-moore.com> | 2024-07-09 19:43:06 -0400 |
---|---|---|
committer | Paul Moore <paul@paul-moore.com> | 2024-08-12 15:35:04 -0400 |
commit | 63dff3e48871b0583be5032ff8fb7260c349a18c (patch) | |
tree | 658e21e7c21fc865f459a1c6dcd9fad7059f0323 /security/security.c | |
parent | 711f5c5ce6c2c640c1b3b569ab2a8847be5ab21f (diff) |
lsm: add the inode_free_security_rcu() LSM implementation hook
The LSM framework has an existing inode_free_security() hook which
is used by LSMs that manage state associated with an inode, but
due to the use of RCU to protect the inode, special care must be
taken to ensure that the LSMs do not fully release the inode state
until it is safe from a RCU perspective.
This patch implements a new inode_free_security_rcu() implementation
hook which is called when it is safe to free the LSM's internal inode
state. Unfortunately, this new hook does not have access to the inode
itself as it may already be released, so the existing
inode_free_security() hook is retained for those LSMs which require
access to the inode.
Cc: stable@vger.kernel.org
Reported-by: syzbot+5446fbf332b0602ede0b@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/r/00000000000076ba3b0617f65cc8@google.com
Signed-off-by: Paul Moore <paul@paul-moore.com>
Diffstat (limited to 'security/security.c')
-rw-r--r-- | security/security.c | 32 |
1 files changed, 16 insertions, 16 deletions
diff --git a/security/security.c b/security/security.c index b316e6586be2..611d3c124ba6 100644 --- a/security/security.c +++ b/security/security.c @@ -1609,9 +1609,8 @@ int security_inode_alloc(struct inode *inode) static void inode_free_by_rcu(struct rcu_head *head) { - /* - * The rcu head is at the start of the inode blob - */ + /* The rcu head is at the start of the inode blob */ + call_void_hook(inode_free_security_rcu, head); kmem_cache_free(lsm_inode_cache, head); } @@ -1619,23 +1618,24 @@ static void inode_free_by_rcu(struct rcu_head *head) * security_inode_free() - Free an inode's LSM blob * @inode: the inode * - * Deallocate the inode security structure and set @inode->i_security to NULL. + * Release any LSM resources associated with @inode, although due to the + * inode's RCU protections it is possible that the resources will not be + * fully released until after the current RCU grace period has elapsed. + * + * It is important for LSMs to note that despite being present in a call to + * security_inode_free(), @inode may still be referenced in a VFS path walk + * and calls to security_inode_permission() may be made during, or after, + * a call to security_inode_free(). For this reason the inode->i_security + * field is released via a call_rcu() callback and any LSMs which need to + * retain inode state for use in security_inode_permission() should only + * release that state in the inode_free_security_rcu() LSM hook callback. */ void security_inode_free(struct inode *inode) { call_void_hook(inode_free_security, inode); - /* - * The inode may still be referenced in a path walk and - * a call to security_inode_permission() can be made - * after inode_free_security() is called. Ideally, the VFS - * wouldn't do this, but fixing that is a much harder - * job. For now, simply free the i_security via RCU, and - * leave the current inode->i_security pointer intact. - * The inode will be freed after the RCU grace period too. - */ - if (inode->i_security) - call_rcu((struct rcu_head *)inode->i_security, - inode_free_by_rcu); + if (!inode->i_security) + return; + call_rcu((struct rcu_head *)inode->i_security, inode_free_by_rcu); } /** |