Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

+33 -33
+1
include/linux/lsm_hook_defs.h
··· 114 114 unsigned int obj_type) 115 115 LSM_HOOK(int, 0, inode_alloc_security, struct inode *inode) 116 116 LSM_HOOK(void, LSM_RET_VOID, inode_free_security, struct inode *inode) 117 + LSM_HOOK(void, LSM_RET_VOID, inode_free_security_rcu, void *inode_security) 117 118 LSM_HOOK(int, -EOPNOTSUPP, inode_init_security, struct inode *inode, 118 119 struct inode *dir, const struct qstr *qstr, struct xattr *xattrs, 119 120 int *xattr_count)
+1 -1
security/integrity/ima/ima.h
··· 223 223 224 224 struct ima_iint_cache *ima_iint_find(struct inode *inode); 225 225 struct ima_iint_cache *ima_inode_get(struct inode *inode); 226 - void ima_inode_free(struct inode *inode); 226 + void ima_inode_free_rcu(void *inode_security); 227 227 void __init ima_iintcache_init(void); 228 228 229 229 extern const int read_idmap[];
+8 -12
security/integrity/ima/ima_iint.c
··· 109 109 } 110 110 111 111 /** 112 - * ima_inode_free - Called on inode free 113 - * @inode: Pointer to the inode 112 + * ima_inode_free_rcu - Called to free an inode via a RCU callback 113 + * @inode_security: The inode->i_security pointer 114 114 * 115 - * Free the iint associated with an inode. 115 + * Free the IMA data associated with an inode. 116 116 */ 117 - void ima_inode_free(struct inode *inode) 117 + void ima_inode_free_rcu(void *inode_security) 118 118 { 119 - struct ima_iint_cache *iint; 119 + struct ima_iint_cache **iint_p = inode_security + ima_blob_sizes.lbs_inode; 120 120 121 - if (!IS_IMA(inode)) 122 - return; 123 - 124 - iint = ima_iint_find(inode); 125 - ima_inode_set_iint(inode, NULL); 126 - 127 - ima_iint_free(iint); 121 + /* *iint_p should be NULL if !IS_IMA(inode) */ 122 + if (*iint_p) 123 + ima_iint_free(*iint_p); 128 124 } 129 125 130 126 static void ima_iint_init_once(void *foo)
+1 -1
security/integrity/ima/ima_main.c
··· 1193 1193 #ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS 1194 1194 LSM_HOOK_INIT(kernel_module_request, ima_kernel_module_request), 1195 1195 #endif 1196 - LSM_HOOK_INIT(inode_free_security, ima_inode_free), 1196 + LSM_HOOK_INIT(inode_free_security_rcu, ima_inode_free_rcu), 1197 1197 }; 1198 1198 1199 1199 static const struct lsm_id ima_lsmid = {
+6 -3
security/landlock/fs.c
··· 1207 1207 1208 1208 /* Inode hooks */ 1209 1209 1210 - static void hook_inode_free_security(struct inode *const inode) 1210 + static void hook_inode_free_security_rcu(void *inode_security) 1211 1211 { 1212 + struct landlock_inode_security *inode_sec; 1213 + 1212 1214 /* 1213 1215 * All inodes must already have been untied from their object by 1214 1216 * release_inode() or hook_sb_delete(). 1215 1217 */ 1216 - WARN_ON_ONCE(landlock_inode(inode)->object); 1218 + inode_sec = inode_security + landlock_blob_sizes.lbs_inode; 1219 + WARN_ON_ONCE(inode_sec->object); 1217 1220 } 1218 1221 1219 1222 /* Super-block hooks */ ··· 1640 1637 } 1641 1638 1642 1639 static struct security_hook_list landlock_hooks[] __ro_after_init = { 1643 - LSM_HOOK_INIT(inode_free_security, hook_inode_free_security), 1640 + LSM_HOOK_INIT(inode_free_security_rcu, hook_inode_free_security_rcu), 1644 1641 1645 1642 LSM_HOOK_INIT(sb_delete, hook_sb_delete), 1646 1643 LSM_HOOK_INIT(sb_mount, hook_sb_mount),
+16 -16
security/security.c
··· 1609 1609 1610 1610 static void inode_free_by_rcu(struct rcu_head *head) 1611 1611 { 1612 - /* 1613 - * The rcu head is at the start of the inode blob 1614 - */ 1612 + /* The rcu head is at the start of the inode blob */ 1613 + call_void_hook(inode_free_security_rcu, head); 1615 1614 kmem_cache_free(lsm_inode_cache, head); 1616 1615 } 1617 1616 ··· 1618 1619 * security_inode_free() - Free an inode's LSM blob 1619 1620 * @inode: the inode 1620 1621 * 1621 - * Deallocate the inode security structure and set @inode->i_security to NULL. 1622 + * Release any LSM resources associated with @inode, although due to the 1623 + * inode's RCU protections it is possible that the resources will not be 1624 + * fully released until after the current RCU grace period has elapsed. 1625 + * 1626 + * It is important for LSMs to note that despite being present in a call to 1627 + * security_inode_free(), @inode may still be referenced in a VFS path walk 1628 + * and calls to security_inode_permission() may be made during, or after, 1629 + * a call to security_inode_free(). For this reason the inode->i_security 1630 + * field is released via a call_rcu() callback and any LSMs which need to 1631 + * retain inode state for use in security_inode_permission() should only 1632 + * release that state in the inode_free_security_rcu() LSM hook callback. 1622 1633 */ 1623 1634 void security_inode_free(struct inode *inode) 1624 1635 { 1625 1636 call_void_hook(inode_free_security, inode); 1626 - /* 1627 - * The inode may still be referenced in a path walk and 1628 - * a call to security_inode_permission() can be made 1629 - * after inode_free_security() is called. Ideally, the VFS 1630 - * wouldn't do this, but fixing that is a much harder 1631 - * job. For now, simply free the i_security via RCU, and 1632 - * leave the current inode->i_security pointer intact. 1633 - * The inode will be freed after the RCU grace period too. 1634 - */ 1635 - if (inode->i_security) 1636 - call_rcu((struct rcu_head *)inode->i_security, 1637 - inode_free_by_rcu); 1637 + if (!inode->i_security) 1638 + return; 1639 + call_rcu((struct rcu_head *)inode->i_security, inode_free_by_rcu); 1638 1640 } 1639 1641 1640 1642 /**