diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2024-03-12 20:03:34 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2024-03-12 20:03:34 -0700 |
commit | cc4a875cf3b3bc07d523ea85b8ca45da1ca4f4e6 (patch) | |
tree | 01656c942e965953adf4fdac9f7268a7802a136c /security/integrity/ima/ima_iint.c | |
parent | ca661c5e1d89a65642d7de5ad3edc00b5666002a (diff) | |
parent | edc6670233a333ccfd1ec0548f068bd121d209c8 (diff) |
Merge tag 'lsm-pr-20240312' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/lsm
Pull lsm updates from Paul Moore:
- Promote IMA/EVM to a proper LSM
This is the bulk of the diffstat, and the source of all the changes
in the VFS code. Prior to the start of the LSM stacking work it was
important that IMA/EVM were separate from the rest of the LSMs,
complete with their own hooks, infrastructure, etc. as it was the
only way to enable IMA/EVM at the same time as a LSM.
However, now that the bulk of the LSM infrastructure supports
multiple simultaneous LSMs, we can simplify things greatly by
bringing IMA/EVM into the LSM infrastructure as proper LSMs. This is
something I've wanted to see happen for quite some time and Roberto
was kind enough to put in the work to make it happen.
- Use the LSM hook default values to simplify the call_int_hook() macro
Previously the call_int_hook() macro required callers to supply a
default return value, despite a default value being specified when
the LSM hook was defined.
This simplifies the macro by using the defined default return value
which makes life easier for callers and should also reduce the number
of return value bugs in the future (we've had a few pop up recently,
hence this work).
- Use the KMEM_CACHE() macro instead of kmem_cache_create()
The guidance appears to be to use the KMEM_CACHE() macro when
possible and there is no reason why we can't use the macro, so let's
use it.
- Fix a number of comment typos in the LSM hook comment blocks
Not much to say here, we fixed some questionable grammar decisions in
the LSM hook comment blocks.
* tag 'lsm-pr-20240312' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/lsm: (28 commits)
cred: Use KMEM_CACHE() instead of kmem_cache_create()
lsm: use default hook return value in call_int_hook()
lsm: fix typos in security/security.c comment headers
integrity: Remove LSM
ima: Make it independent from 'integrity' LSM
evm: Make it independent from 'integrity' LSM
evm: Move to LSM infrastructure
ima: Move IMA-Appraisal to LSM infrastructure
ima: Move to LSM infrastructure
integrity: Move integrity_kernel_module_request() to IMA
security: Introduce key_post_create_or_update hook
security: Introduce inode_post_remove_acl hook
security: Introduce inode_post_set_acl hook
security: Introduce inode_post_create_tmpfile hook
security: Introduce path_post_mknod hook
security: Introduce file_release hook
security: Introduce file_post_open hook
security: Introduce inode_post_removexattr hook
security: Introduce inode_post_setattr hook
security: Align inode_setattr hook definition with EVM
...
Diffstat (limited to 'security/integrity/ima/ima_iint.c')
-rw-r--r-- | security/integrity/ima/ima_iint.c | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/security/integrity/ima/ima_iint.c b/security/integrity/ima/ima_iint.c new file mode 100644 index 000000000000..e7c9c216c1c6 --- /dev/null +++ b/security/integrity/ima/ima_iint.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2008 IBM Corporation + * + * Authors: + * Mimi Zohar <zohar@us.ibm.com> + * + * File: ima_iint.c + * - implements the IMA hook: ima_inode_free + * - cache integrity information in the inode security blob + */ +#include <linux/slab.h> + +#include "ima.h" + +static struct kmem_cache *ima_iint_cache __ro_after_init; + +/** + * ima_iint_find - Return the iint associated with an inode + * @inode: Pointer to the inode + * + * Return the IMA integrity information (iint) associated with an inode, if the + * inode was processed by IMA. + * + * Return: Found iint or NULL. + */ +struct ima_iint_cache *ima_iint_find(struct inode *inode) +{ + if (!IS_IMA(inode)) + return NULL; + + return ima_inode_get_iint(inode); +} + +#define IMA_MAX_NESTING (FILESYSTEM_MAX_STACK_DEPTH + 1) + +/* + * It is not clear that IMA should be nested at all, but as long is it measures + * files both on overlayfs and on underlying fs, we need to annotate the iint + * mutex to avoid lockdep false positives related to IMA + overlayfs. + * See ovl_lockdep_annotate_inode_mutex_key() for more details. + */ +static inline void ima_iint_lockdep_annotate(struct ima_iint_cache *iint, + struct inode *inode) +{ +#ifdef CONFIG_LOCKDEP + static struct lock_class_key ima_iint_mutex_key[IMA_MAX_NESTING]; + + int depth = inode->i_sb->s_stack_depth; + + if (WARN_ON_ONCE(depth < 0 || depth >= IMA_MAX_NESTING)) + depth = 0; + + lockdep_set_class(&iint->mutex, &ima_iint_mutex_key[depth]); +#endif +} + +static void ima_iint_init_always(struct ima_iint_cache *iint, + struct inode *inode) +{ + iint->ima_hash = NULL; + iint->version = 0; + iint->flags = 0UL; + iint->atomic_flags = 0UL; + iint->ima_file_status = INTEGRITY_UNKNOWN; + iint->ima_mmap_status = INTEGRITY_UNKNOWN; + iint->ima_bprm_status = INTEGRITY_UNKNOWN; + iint->ima_read_status = INTEGRITY_UNKNOWN; + iint->ima_creds_status = INTEGRITY_UNKNOWN; + iint->measured_pcrs = 0; + mutex_init(&iint->mutex); + ima_iint_lockdep_annotate(iint, inode); +} + +static void ima_iint_free(struct ima_iint_cache *iint) +{ + kfree(iint->ima_hash); + mutex_destroy(&iint->mutex); + kmem_cache_free(ima_iint_cache, iint); +} + +/** + * ima_inode_get - Find or allocate an iint associated with an inode + * @inode: Pointer to the inode + * + * Find an iint associated with an inode, and allocate a new one if not found. + * Caller must lock i_mutex. + * + * Return: An iint on success, NULL on error. + */ +struct ima_iint_cache *ima_inode_get(struct inode *inode) +{ + struct ima_iint_cache *iint; + + iint = ima_iint_find(inode); + if (iint) + return iint; + + iint = kmem_cache_alloc(ima_iint_cache, GFP_NOFS); + if (!iint) + return NULL; + + ima_iint_init_always(iint, inode); + + inode->i_flags |= S_IMA; + ima_inode_set_iint(inode, iint); + + return iint; +} + +/** + * ima_inode_free - Called on inode free + * @inode: Pointer to the inode + * + * Free the iint associated with an inode. + */ +void ima_inode_free(struct inode *inode) +{ + struct ima_iint_cache *iint; + + if (!IS_IMA(inode)) + return; + + iint = ima_iint_find(inode); + ima_inode_set_iint(inode, NULL); + + ima_iint_free(iint); +} + +static void ima_iint_init_once(void *foo) +{ + struct ima_iint_cache *iint = (struct ima_iint_cache *)foo; + + memset(iint, 0, sizeof(*iint)); +} + +void __init ima_iintcache_init(void) +{ + ima_iint_cache = + kmem_cache_create("ima_iint_cache", sizeof(struct ima_iint_cache), + 0, SLAB_PANIC, ima_iint_init_once); +} |