Skip to content

Commit 63dff3e

Browse files
committed
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: [email protected] Reported-by: [email protected] Closes: https://lore.kernel.org/r/[email protected] Signed-off-by: Paul Moore <[email protected]>
1 parent 711f5c5 commit 63dff3e

File tree

6 files changed

+33
-33
lines changed

6 files changed

+33
-33
lines changed

include/linux/lsm_hook_defs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ LSM_HOOK(int, 0, path_notify, const struct path *path, u64 mask,
114114
unsigned int obj_type)
115115
LSM_HOOK(int, 0, inode_alloc_security, struct inode *inode)
116116
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)
117118
LSM_HOOK(int, -EOPNOTSUPP, inode_init_security, struct inode *inode,
118119
struct inode *dir, const struct qstr *qstr, struct xattr *xattrs,
119120
int *xattr_count)

security/integrity/ima/ima.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ static inline void ima_inode_set_iint(const struct inode *inode,
223223

224224
struct ima_iint_cache *ima_iint_find(struct inode *inode);
225225
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);
227227
void __init ima_iintcache_init(void);
228228

229229
extern const int read_idmap[];

security/integrity/ima/ima_iint.c

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -109,22 +109,18 @@ struct ima_iint_cache *ima_inode_get(struct inode *inode)
109109
}
110110

111111
/**
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
114114
*
115-
* Free the iint associated with an inode.
115+
* Free the IMA data associated with an inode.
116116
*/
117-
void ima_inode_free(struct inode *inode)
117+
void ima_inode_free_rcu(void *inode_security)
118118
{
119-
struct ima_iint_cache *iint;
120-
121-
if (!IS_IMA(inode))
122-
return;
123-
124-
iint = ima_iint_find(inode);
125-
ima_inode_set_iint(inode, NULL);
119+
struct ima_iint_cache **iint_p = inode_security + ima_blob_sizes.lbs_inode;
126120

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);
128124
}
129125

130126
static void ima_iint_init_once(void *foo)

security/integrity/ima/ima_main.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1193,7 +1193,7 @@ static struct security_hook_list ima_hooks[] __ro_after_init = {
11931193
#ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS
11941194
LSM_HOOK_INIT(kernel_module_request, ima_kernel_module_request),
11951195
#endif
1196-
LSM_HOOK_INIT(inode_free_security, ima_inode_free),
1196+
LSM_HOOK_INIT(inode_free_security_rcu, ima_inode_free_rcu),
11971197
};
11981198

11991199
static const struct lsm_id ima_lsmid = {

security/landlock/fs.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1207,13 +1207,16 @@ static int current_check_refer_path(struct dentry *const old_dentry,
12071207

12081208
/* Inode hooks */
12091209

1210-
static void hook_inode_free_security(struct inode *const inode)
1210+
static void hook_inode_free_security_rcu(void *inode_security)
12111211
{
1212+
struct landlock_inode_security *inode_sec;
1213+
12121214
/*
12131215
* All inodes must already have been untied from their object by
12141216
* release_inode() or hook_sb_delete().
12151217
*/
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);
12171220
}
12181221

12191222
/* Super-block hooks */
@@ -1637,7 +1640,7 @@ static int hook_file_ioctl_compat(struct file *file, unsigned int cmd,
16371640
}
16381641

16391642
static struct security_hook_list landlock_hooks[] __ro_after_init = {
1640-
LSM_HOOK_INIT(inode_free_security, hook_inode_free_security),
1643+
LSM_HOOK_INIT(inode_free_security_rcu, hook_inode_free_security_rcu),
16411644

16421645
LSM_HOOK_INIT(sb_delete, hook_sb_delete),
16431646
LSM_HOOK_INIT(sb_mount, hook_sb_mount),

security/security.c

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1609,33 +1609,33 @@ int security_inode_alloc(struct inode *inode)
16091609

16101610
static void inode_free_by_rcu(struct rcu_head *head)
16111611
{
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);
16151614
kmem_cache_free(lsm_inode_cache, head);
16161615
}
16171616

16181617
/**
16191618
* security_inode_free() - Free an inode's LSM blob
16201619
* @inode: the inode
16211620
*
1622-
* Deallocate the inode security structure and set @inode->i_security to NULL.
1621+
* Release any LSM resources associated with @inode, although due to the
1622+
* inode's RCU protections it is possible that the resources will not be
1623+
* fully released until after the current RCU grace period has elapsed.
1624+
*
1625+
* It is important for LSMs to note that despite being present in a call to
1626+
* security_inode_free(), @inode may still be referenced in a VFS path walk
1627+
* and calls to security_inode_permission() may be made during, or after,
1628+
* a call to security_inode_free(). For this reason the inode->i_security
1629+
* field is released via a call_rcu() callback and any LSMs which need to
1630+
* retain inode state for use in security_inode_permission() should only
1631+
* release that state in the inode_free_security_rcu() LSM hook callback.
16231632
*/
16241633
void security_inode_free(struct inode *inode)
16251634
{
16261635
call_void_hook(inode_free_security, inode);
1627-
/*
1628-
* The inode may still be referenced in a path walk and
1629-
* a call to security_inode_permission() can be made
1630-
* after inode_free_security() is called. Ideally, the VFS
1631-
* wouldn't do this, but fixing that is a much harder
1632-
* job. For now, simply free the i_security via RCU, and
1633-
* leave the current inode->i_security pointer intact.
1634-
* The inode will be freed after the RCU grace period too.
1635-
*/
1636-
if (inode->i_security)
1637-
call_rcu((struct rcu_head *)inode->i_security,
1638-
inode_free_by_rcu);
1636+
if (!inode->i_security)
1637+
return;
1638+
call_rcu((struct rcu_head *)inode->i_security, inode_free_by_rcu);
16391639
}
16401640

16411641
/**

0 commit comments

Comments
 (0)