From: Roberto Sassu <[email protected]>
Move hardcoded IMA function calls (not appraisal-specific functions) from
various places in the kernel to the LSM infrastructure, by introducing a
new LSM named 'ima' (at the end of the LSM list and always enabled like
'integrity').
Having IMA before EVM in the Makefile is sufficient to preserve the
relative order of the new 'ima' LSM in respect to the upcoming 'evm' LSM,
and thus the order of IMA and EVM function calls as when they were
hardcoded.
Make moved functions as static (except ima_post_key_create_or_update(),
which is not in ima_main.c), and register them as implementation of the
respective hooks in the new function init_ima_lsm(). Conditionally register
ima_post_path_mknod() if CONFIG_SECURITY_PATH is enabled, otherwise the
path_post_mknod hook won't be available.
Signed-off-by: Roberto Sassu <[email protected]>
Acked-by: Chuck Lever <[email protected]>
---
fs/file_table.c | 2 -
fs/namei.c | 6 --
fs/nfsd/vfs.c | 7 ---
fs/open.c | 1 -
include/linux/ima.h | 94 -------------------------------
include/uapi/linux/lsm.h | 1 +
security/integrity/Makefile | 1 +
security/integrity/ima/ima.h | 6 ++
security/integrity/ima/ima_main.c | 76 ++++++++++++++++++-------
security/integrity/integrity.h | 1 +
security/keys/key.c | 9 +--
security/security.c | 56 ++++--------------
12 files changed, 77 insertions(+), 183 deletions(-)
diff --git a/fs/file_table.c b/fs/file_table.c
index c72dc75f2bd3..0401ac98281c 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -26,7 +26,6 @@
#include <linux/percpu_counter.h>
#include <linux/percpu.h>
#include <linux/task_work.h>
-#include <linux/ima.h>
#include <linux/swap.h>
#include <linux/kmemleak.h>
@@ -386,7 +385,6 @@ static void __fput(struct file *file)
locks_remove_file(file);
security_file_release(file);
- ima_file_free(file);
if (unlikely(file->f_flags & FASYNC)) {
if (file->f_op->fasync)
file->f_op->fasync(-1, file, 0);
diff --git a/fs/namei.c b/fs/namei.c
index adb3ab27951a..37cc0988308f 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -27,7 +27,6 @@
#include <linux/fsnotify.h>
#include <linux/personality.h>
#include <linux/security.h>
-#include <linux/ima.h>
#include <linux/syscalls.h>
#include <linux/mount.h>
#include <linux/audit.h>
@@ -3622,8 +3621,6 @@ static int do_open(struct nameidata *nd,
error = vfs_open(&nd->path, file);
if (!error)
error = security_file_post_open(file, op->acc_mode);
- if (!error)
- error = ima_file_check(file, op->acc_mode);
if (!error && do_truncate)
error = handle_truncate(idmap, file);
if (unlikely(error > 0)) {
@@ -3687,7 +3684,6 @@ static int vfs_tmpfile(struct mnt_idmap *idmap,
spin_unlock(&inode->i_lock);
}
security_inode_post_create_tmpfile(idmap, inode);
- ima_post_create_tmpfile(idmap, inode);
return 0;
}
@@ -4036,8 +4032,6 @@ static int do_mknodat(int dfd, struct filename *name, umode_t mode,
case 0: case S_IFREG:
error = vfs_create(idmap, path.dentry->d_inode,
dentry, mode, true);
- if (!error)
- ima_post_path_mknod(idmap, dentry);
break;
case S_IFCHR: case S_IFBLK:
error = vfs_mknod(idmap, path.dentry->d_inode,
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index b0c3f07a8bba..e491392a1243 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -25,7 +25,6 @@
#include <linux/posix_acl_xattr.h>
#include <linux/xattr.h>
#include <linux/jhash.h>
-#include <linux/ima.h>
#include <linux/pagemap.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
@@ -883,12 +882,6 @@ __nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type,
goto out;
}
- host_err = ima_file_check(file, may_flags);
- if (host_err) {
- fput(file);
- goto out;
- }
-
if (may_flags & NFSD_MAY_64BIT_COOKIE)
file->f_mode |= FMODE_64BITHASH;
else
diff --git a/fs/open.c b/fs/open.c
index 02dc608d40d8..c8bb9bd5259f 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -29,7 +29,6 @@
#include <linux/audit.h>
#include <linux/falloc.h>
#include <linux/fs_struct.h>
-#include <linux/ima.h>
#include <linux/dnotify.h>
#include <linux/compat.h>
#include <linux/mnt_idmapping.h>
diff --git a/include/linux/ima.h b/include/linux/ima.h
index 31ef6c3c3207..23ae24b60ecf 100644
--- a/include/linux/ima.h
+++ b/include/linux/ima.h
@@ -16,24 +16,6 @@ struct linux_binprm;
#ifdef CONFIG_IMA
extern enum hash_algo ima_get_current_hash_algo(void);
-extern int ima_bprm_check(struct linux_binprm *bprm);
-extern int ima_file_check(struct file *file, int mask);
-extern void ima_post_create_tmpfile(struct mnt_idmap *idmap,
- struct inode *inode);
-extern void ima_file_free(struct file *file);
-extern int ima_file_mmap(struct file *file, unsigned long reqprot,
- unsigned long prot, unsigned long flags);
-extern int ima_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
- unsigned long prot);
-extern int ima_load_data(enum kernel_load_data_id id, bool contents);
-extern int ima_post_load_data(char *buf, loff_t size,
- enum kernel_load_data_id id, char *description);
-extern int ima_read_file(struct file *file, enum kernel_read_file_id id,
- bool contents);
-extern int ima_post_read_file(struct file *file, char *buf, loff_t size,
- enum kernel_read_file_id id);
-extern void ima_post_path_mknod(struct mnt_idmap *idmap,
- struct dentry *dentry);
extern int ima_file_hash(struct file *file, char *buf, size_t buf_size);
extern int ima_inode_hash(struct inode *inode, char *buf, size_t buf_size);
extern void ima_kexec_cmdline(int kernel_fd, const void *buf, int size);
@@ -58,68 +40,6 @@ static inline enum hash_algo ima_get_current_hash_algo(void)
return HASH_ALGO__LAST;
}
-static inline int ima_bprm_check(struct linux_binprm *bprm)
-{
- return 0;
-}
-
-static inline int ima_file_check(struct file *file, int mask)
-{
- return 0;
-}
-
-static inline void ima_post_create_tmpfile(struct mnt_idmap *idmap,
- struct inode *inode)
-{
-}
-
-static inline void ima_file_free(struct file *file)
-{
- return;
-}
-
-static inline int ima_file_mmap(struct file *file, unsigned long reqprot,
- unsigned long prot, unsigned long flags)
-{
- return 0;
-}
-
-static inline int ima_file_mprotect(struct vm_area_struct *vma,
- unsigned long reqprot, unsigned long prot)
-{
- return 0;
-}
-
-static inline int ima_load_data(enum kernel_load_data_id id, bool contents)
-{
- return 0;
-}
-
-static inline int ima_post_load_data(char *buf, loff_t size,
- enum kernel_load_data_id id,
- char *description)
-{
- return 0;
-}
-
-static inline int ima_read_file(struct file *file, enum kernel_read_file_id id,
- bool contents)
-{
- return 0;
-}
-
-static inline int ima_post_read_file(struct file *file, char *buf, loff_t size,
- enum kernel_read_file_id id)
-{
- return 0;
-}
-
-static inline void ima_post_path_mknod(struct mnt_idmap *idmap,
- struct dentry *dentry)
-{
- return;
-}
-
static inline int ima_file_hash(struct file *file, char *buf, size_t buf_size)
{
return -EOPNOTSUPP;
@@ -170,20 +90,6 @@ static inline void ima_add_kexec_buffer(struct kimage *image)
{}
#endif
-#ifdef CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS
-extern void ima_post_key_create_or_update(struct key *keyring,
- struct key *key,
- const void *payload, size_t plen,
- unsigned long flags, bool create);
-#else
-static inline void ima_post_key_create_or_update(struct key *keyring,
- struct key *key,
- const void *payload,
- size_t plen,
- unsigned long flags,
- bool create) {}
-#endif /* CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS */
-
#ifdef CONFIG_IMA_APPRAISE
extern bool is_ima_appraise_enabled(void);
extern void ima_inode_post_setattr(struct mnt_idmap *idmap,
diff --git a/include/uapi/linux/lsm.h b/include/uapi/linux/lsm.h
index f0386880a78e..ee7d034255a9 100644
--- a/include/uapi/linux/lsm.h
+++ b/include/uapi/linux/lsm.h
@@ -61,6 +61,7 @@ struct lsm_ctx {
#define LSM_ID_LOCKDOWN 108
#define LSM_ID_BPF 109
#define LSM_ID_LANDLOCK 110
+#define LSM_ID_IMA 111
/*
* LSM_ATTR_XXX definitions identify different LSM attributes
diff --git a/security/integrity/Makefile b/security/integrity/Makefile
index d0ffe37dc1d6..92b63039c654 100644
--- a/security/integrity/Makefile
+++ b/security/integrity/Makefile
@@ -18,5 +18,6 @@ integrity-$(CONFIG_LOAD_IPL_KEYS) += platform_certs/load_ipl_s390.o
integrity-$(CONFIG_LOAD_PPC_KEYS) += platform_certs/efi_parser.o \
platform_certs/load_powerpc.o \
platform_certs/keyring_handler.o
+# The relative order of the 'ima' and 'evm' LSMs depends on the order below.
obj-$(CONFIG_IMA) += ima/
obj-$(CONFIG_EVM) += evm/
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index c29db699c996..c0412100023e 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -127,6 +127,12 @@ void ima_load_kexec_buffer(void);
static inline void ima_load_kexec_buffer(void) {}
#endif /* CONFIG_HAVE_IMA_KEXEC */
+#ifdef CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS
+void ima_post_key_create_or_update(struct key *keyring, struct key *key,
+ const void *payload, size_t plen,
+ unsigned long flags, bool create);
+#endif
+
/*
* The default binary_runtime_measurements list format is defined as the
* platform native format. The canonical format is defined as little-endian.
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 02021ee467d3..17bd05e6a759 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -189,7 +189,7 @@ static void ima_check_last_writer(struct integrity_iint_cache *iint,
*
* Flag files that changed, based on i_version
*/
-void ima_file_free(struct file *file)
+static void ima_file_free(struct file *file)
{
struct inode *inode = file_inode(file);
struct integrity_iint_cache *iint;
@@ -427,8 +427,8 @@ static int process_measurement(struct file *file, const struct cred *cred,
* On success return 0. On integrity appraisal error, assuming the file
* is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
*/
-int ima_file_mmap(struct file *file, unsigned long reqprot,
- unsigned long prot, unsigned long flags)
+static int ima_file_mmap(struct file *file, unsigned long reqprot,
+ unsigned long prot, unsigned long flags)
{
u32 secid;
int ret;
@@ -466,8 +466,8 @@ int ima_file_mmap(struct file *file, unsigned long reqprot,
*
* On mprotect change success, return 0. On failure, return -EACESS.
*/
-int ima_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
- unsigned long prot)
+static int ima_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
+ unsigned long prot)
{
struct ima_template_desc *template = NULL;
struct file *file;
@@ -525,7 +525,7 @@ int ima_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
* On success return 0. On integrity appraisal error, assuming the file
* is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
*/
-int ima_bprm_check(struct linux_binprm *bprm)
+static int ima_bprm_check(struct linux_binprm *bprm)
{
int ret;
u32 secid;
@@ -551,7 +551,7 @@ int ima_bprm_check(struct linux_binprm *bprm)
* On success return 0. On integrity appraisal error, assuming the file
* is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
*/
-int ima_file_check(struct file *file, int mask)
+static int ima_file_check(struct file *file, int mask)
{
u32 secid;
@@ -560,7 +560,6 @@ int ima_file_check(struct file *file, int mask)
mask & (MAY_READ | MAY_WRITE | MAY_EXEC |
MAY_APPEND), FILE_CHECK);
}
-EXPORT_SYMBOL_GPL(ima_file_check);
static int __ima_inode_hash(struct inode *inode, struct file *file, char *buf,
size_t buf_size)
@@ -685,8 +684,9 @@ EXPORT_SYMBOL_GPL(ima_inode_hash);
* Skip calling process_measurement(), but indicate which newly, created
* tmpfiles are in policy.
*/
-void ima_post_create_tmpfile(struct mnt_idmap *idmap,
- struct inode *inode)
+static void ima_post_create_tmpfile(struct mnt_idmap *idmap,
+ struct inode *inode)
+
{
struct integrity_iint_cache *iint;
int must_appraise;
@@ -717,8 +717,8 @@ void ima_post_create_tmpfile(struct mnt_idmap *idmap,
* Mark files created via the mknodat syscall as new, so that the
* file data can be written later.
*/
-void ima_post_path_mknod(struct mnt_idmap *idmap,
- struct dentry *dentry)
+static void __maybe_unused
+ima_post_path_mknod(struct mnt_idmap *idmap, struct dentry *dentry)
{
struct integrity_iint_cache *iint;
struct inode *inode = dentry->d_inode;
@@ -753,8 +753,8 @@ void ima_post_path_mknod(struct mnt_idmap *idmap,
*
* For permission return 0, otherwise return -EACCES.
*/
-int ima_read_file(struct file *file, enum kernel_read_file_id read_id,
- bool contents)
+static int ima_read_file(struct file *file, enum kernel_read_file_id read_id,
+ bool contents)
{
enum ima_hooks func;
u32 secid;
@@ -803,8 +803,8 @@ const int read_idmap[READING_MAX_ID] = {
* On success return 0. On integrity appraisal error, assuming the file
* is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
*/
-int ima_post_read_file(struct file *file, char *buf, loff_t size,
- enum kernel_read_file_id read_id)
+static int ima_post_read_file(struct file *file, char *buf, loff_t size,
+ enum kernel_read_file_id read_id)
{
enum ima_hooks func;
u32 secid;
@@ -837,7 +837,7 @@ int ima_post_read_file(struct file *file, char *buf, loff_t size,
*
* For permission return 0, otherwise return -EACCES.
*/
-int ima_load_data(enum kernel_load_data_id id, bool contents)
+static int ima_load_data(enum kernel_load_data_id id, bool contents)
{
bool ima_enforce, sig_enforce;
@@ -891,9 +891,9 @@ int ima_load_data(enum kernel_load_data_id id, bool contents)
* On success return 0. On integrity appraisal error, assuming the file
* is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
*/
-int ima_post_load_data(char *buf, loff_t size,
- enum kernel_load_data_id load_id,
- char *description)
+static int ima_post_load_data(char *buf, loff_t size,
+ enum kernel_load_data_id load_id,
+ char *description)
{
if (load_id == LOADING_FIRMWARE) {
if ((ima_appraise & IMA_APPRAISE_FIRMWARE) &&
@@ -1122,4 +1122,40 @@ static int __init init_ima(void)
return error;
}
+static struct security_hook_list ima_hooks[] __ro_after_init = {
+ LSM_HOOK_INIT(bprm_check_security, ima_bprm_check),
+ LSM_HOOK_INIT(file_post_open, ima_file_check),
+ LSM_HOOK_INIT(inode_post_create_tmpfile, ima_post_create_tmpfile),
+ LSM_HOOK_INIT(file_release, ima_file_free),
+ LSM_HOOK_INIT(mmap_file, ima_file_mmap),
+ LSM_HOOK_INIT(file_mprotect, ima_file_mprotect),
+ LSM_HOOK_INIT(kernel_load_data, ima_load_data),
+ LSM_HOOK_INIT(kernel_post_load_data, ima_post_load_data),
+ LSM_HOOK_INIT(kernel_read_file, ima_read_file),
+ LSM_HOOK_INIT(kernel_post_read_file, ima_post_read_file),
+#ifdef CONFIG_SECURITY_PATH
+ LSM_HOOK_INIT(path_post_mknod, ima_post_path_mknod),
+#endif
+#ifdef CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS
+ LSM_HOOK_INIT(key_post_create_or_update, ima_post_key_create_or_update),
+#endif
+};
+
+static const struct lsm_id ima_lsmid = {
+ .name = "ima",
+ .id = LSM_ID_IMA,
+};
+
+static int __init init_ima_lsm(void)
+{
+ security_add_hooks(ima_hooks, ARRAY_SIZE(ima_hooks), &ima_lsmid);
+ return 0;
+}
+
+DEFINE_LSM(ima) = {
+ .name = "ima",
+ .init = init_ima_lsm,
+ .order = LSM_ORDER_LAST,
+};
+
late_initcall(init_ima); /* Start IMA after the TPM is available */
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index 9561db7cf6b4..59eaddd84434 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -18,6 +18,7 @@
#include <crypto/hash.h>
#include <linux/key.h>
#include <linux/audit.h>
+#include <linux/lsm_hooks.h>
/* iint action cache flags */
#define IMA_MEASURE 0x00000001
diff --git a/security/keys/key.c b/security/keys/key.c
index f75fe66c2f03..80fc2f203a0c 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -13,7 +13,6 @@
#include <linux/security.h>
#include <linux/workqueue.h>
#include <linux/random.h>
-#include <linux/ima.h>
#include <linux/err.h>
#include "internal.h"
@@ -937,8 +936,6 @@ static key_ref_t __key_create_or_update(key_ref_t keyring_ref,
security_key_post_create_or_update(keyring, key, payload, plen, flags,
true);
- ima_post_key_create_or_update(keyring, key, payload, plen,
- flags, true);
key_ref = make_key_ref(key, is_key_possessed(keyring_ref));
@@ -970,13 +967,9 @@ static key_ref_t __key_create_or_update(key_ref_t keyring_ref,
key_ref = __key_update(key_ref, &prep);
- if (!IS_ERR(key_ref)) {
+ if (!IS_ERR(key_ref))
security_key_post_create_or_update(keyring, key, payload, plen,
flags, false);
- ima_post_key_create_or_update(keyring, key,
- payload, plen,
- flags, false);
- }
goto error_free_prep;
}
diff --git a/security/security.c b/security/security.c
index 423d53092604..65baa4742156 100644
--- a/security/security.c
+++ b/security/security.c
@@ -50,7 +50,8 @@
(IS_ENABLED(CONFIG_SECURITY_SAFESETID) ? 1 : 0) + \
(IS_ENABLED(CONFIG_SECURITY_LOCKDOWN_LSM) ? 1 : 0) + \
(IS_ENABLED(CONFIG_BPF_LSM) ? 1 : 0) + \
- (IS_ENABLED(CONFIG_SECURITY_LANDLOCK) ? 1 : 0))
+ (IS_ENABLED(CONFIG_SECURITY_LANDLOCK) ? 1 : 0) + \
+ (IS_ENABLED(CONFIG_IMA) ? 1 : 0))
/*
* These are descriptions of the reasons that can be passed to the
@@ -1182,12 +1183,7 @@ int security_bprm_creds_from_file(struct linux_binprm *bprm, const struct file *
*/
int security_bprm_check(struct linux_binprm *bprm)
{
- int ret;
-
- ret = call_int_hook(bprm_check_security, 0, bprm);
- if (ret)
- return ret;
- return ima_bprm_check(bprm);
+ return call_int_hook(bprm_check_security, 0, bprm);
}
/**
@@ -2883,13 +2879,8 @@ static inline unsigned long mmap_prot(struct file *file, unsigned long prot)
int security_mmap_file(struct file *file, unsigned long prot,
unsigned long flags)
{
- unsigned long prot_adj = mmap_prot(file, prot);
- int ret;
-
- ret = call_int_hook(mmap_file, 0, file, prot, prot_adj, flags);
- if (ret)
- return ret;
- return ima_file_mmap(file, prot, prot_adj, flags);
+ return call_int_hook(mmap_file, 0, file, prot, mmap_prot(file, prot),
+ flags);
}
/**
@@ -2918,12 +2909,7 @@ int security_mmap_addr(unsigned long addr)
int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
unsigned long prot)
{
- int ret;
-
- ret = call_int_hook(file_mprotect, 0, vma, reqprot, prot);
- if (ret)
- return ret;
- return ima_file_mprotect(vma, reqprot, prot);
+ return call_int_hook(file_mprotect, 0, vma, reqprot, prot);
}
/**
@@ -3253,12 +3239,7 @@ int security_kernel_module_request(char *kmod_name)
int security_kernel_read_file(struct file *file, enum kernel_read_file_id id,
bool contents)
{
- int ret;
-
- ret = call_int_hook(kernel_read_file, 0, file, id, contents);
- if (ret)
- return ret;
- return ima_read_file(file, id, contents);
+ return call_int_hook(kernel_read_file, 0, file, id, contents);
}
EXPORT_SYMBOL_GPL(security_kernel_read_file);
@@ -3278,12 +3259,7 @@ EXPORT_SYMBOL_GPL(security_kernel_read_file);
int security_kernel_post_read_file(struct file *file, char *buf, loff_t size,
enum kernel_read_file_id id)
{
- int ret;
-
- ret = call_int_hook(kernel_post_read_file, 0, file, buf, size, id);
- if (ret)
- return ret;
- return ima_post_read_file(file, buf, size, id);
+ return call_int_hook(kernel_post_read_file, 0, file, buf, size, id);
}
EXPORT_SYMBOL_GPL(security_kernel_post_read_file);
@@ -3298,12 +3274,7 @@ EXPORT_SYMBOL_GPL(security_kernel_post_read_file);
*/
int security_kernel_load_data(enum kernel_load_data_id id, bool contents)
{
- int ret;
-
- ret = call_int_hook(kernel_load_data, 0, id, contents);
- if (ret)
- return ret;
- return ima_load_data(id, contents);
+ return call_int_hook(kernel_load_data, 0, id, contents);
}
EXPORT_SYMBOL_GPL(security_kernel_load_data);
@@ -3325,13 +3296,8 @@ int security_kernel_post_load_data(char *buf, loff_t size,
enum kernel_load_data_id id,
char *description)
{
- int ret;
-
- ret = call_int_hook(kernel_post_load_data, 0, buf, size, id,
- description);
- if (ret)
- return ret;
- return ima_post_load_data(buf, size, id, description);
+ return call_int_hook(kernel_post_load_data, 0, buf, size, id,
+ description);
}
EXPORT_SYMBOL_GPL(security_kernel_post_load_data);
--
2.34.1
From: Roberto Sassu <[email protected]>
Do the registration of IMA-Appraisal only functions separately from the
rest of IMA functions, as appraisal is a separate feature not necessarily
enabled in the kernel configuration.
Reuse the same approach as for other IMA functions, move hardcoded calls
from various places in the kernel to the LSM infrastructure. Declare the
functions as static and register them as hook implementations in
init_ima_appraise_lsm(), called by init_ima_lsm().
Signed-off-by: Roberto Sassu <[email protected]>
Reviewed-by: Stefan Berger <[email protected]>
Reviewed-by: Mimi Zohar <[email protected]>
---
fs/attr.c | 2 -
include/linux/ima.h | 55 ---------------------------
security/integrity/ima/ima.h | 5 +++
security/integrity/ima/ima_appraise.c | 38 +++++++++++++-----
security/integrity/ima/ima_main.c | 1 +
security/security.c | 13 -------
6 files changed, 35 insertions(+), 79 deletions(-)
diff --git a/fs/attr.c b/fs/attr.c
index 221d2bb0a906..38841f3ebbcb 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -17,7 +17,6 @@
#include <linux/filelock.h>
#include <linux/security.h>
#include <linux/evm.h>
-#include <linux/ima.h>
#include "internal.h"
@@ -503,7 +502,6 @@ int notify_change(struct mnt_idmap *idmap, struct dentry *dentry,
if (!error) {
fsnotify_change(dentry, ia_valid);
security_inode_post_setattr(idmap, dentry, ia_valid);
- ima_inode_post_setattr(idmap, dentry, ia_valid);
evm_inode_post_setattr(idmap, dentry, ia_valid);
}
diff --git a/include/linux/ima.h b/include/linux/ima.h
index 23ae24b60ecf..0bae61a15b60 100644
--- a/include/linux/ima.h
+++ b/include/linux/ima.h
@@ -92,66 +92,11 @@ static inline void ima_add_kexec_buffer(struct kimage *image)
#ifdef CONFIG_IMA_APPRAISE
extern bool is_ima_appraise_enabled(void);
-extern void ima_inode_post_setattr(struct mnt_idmap *idmap,
- struct dentry *dentry, int ia_valid);
-extern int ima_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
- const char *xattr_name, const void *xattr_value,
- size_t xattr_value_len, int flags);
-extern int ima_inode_set_acl(struct mnt_idmap *idmap,
- struct dentry *dentry, const char *acl_name,
- struct posix_acl *kacl);
-static inline int ima_inode_remove_acl(struct mnt_idmap *idmap,
- struct dentry *dentry,
- const char *acl_name)
-{
- return ima_inode_set_acl(idmap, dentry, acl_name, NULL);
-}
-
-extern int ima_inode_removexattr(struct mnt_idmap *idmap, struct dentry *dentry,
- const char *xattr_name);
#else
static inline bool is_ima_appraise_enabled(void)
{
return 0;
}
-
-static inline void ima_inode_post_setattr(struct mnt_idmap *idmap,
- struct dentry *dentry, int ia_valid)
-{
- return;
-}
-
-static inline int ima_inode_setxattr(struct mnt_idmap *idmap,
- struct dentry *dentry,
- const char *xattr_name,
- const void *xattr_value,
- size_t xattr_value_len,
- int flags)
-{
- return 0;
-}
-
-static inline int ima_inode_set_acl(struct mnt_idmap *idmap,
- struct dentry *dentry, const char *acl_name,
- struct posix_acl *kacl)
-{
-
- return 0;
-}
-
-static inline int ima_inode_removexattr(struct mnt_idmap *idmap,
- struct dentry *dentry,
- const char *xattr_name)
-{
- return 0;
-}
-
-static inline int ima_inode_remove_acl(struct mnt_idmap *idmap,
- struct dentry *dentry,
- const char *acl_name)
-{
- return 0;
-}
#endif /* CONFIG_IMA_APPRAISE */
#if defined(CONFIG_IMA_APPRAISE) && defined(CONFIG_INTEGRITY_TRUSTED_KEYRING)
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index c0412100023e..a27fc10f84f7 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -334,6 +334,7 @@ enum hash_algo ima_get_hash_algo(const struct evm_ima_xattr_data *xattr_value,
int xattr_len);
int ima_read_xattr(struct dentry *dentry,
struct evm_ima_xattr_data **xattr_value, int xattr_len);
+void __init init_ima_appraise_lsm(const struct lsm_id *lsmid);
#else
static inline int ima_check_blacklist(struct integrity_iint_cache *iint,
@@ -385,6 +386,10 @@ static inline int ima_read_xattr(struct dentry *dentry,
return 0;
}
+static inline void __init init_ima_appraise_lsm(const struct lsm_id *lsmid)
+{
+}
+
#endif /* CONFIG_IMA_APPRAISE */
#ifdef CONFIG_IMA_APPRAISE_MODSIG
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index 36abc84ba299..076451109637 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -636,8 +636,8 @@ void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file)
* This function is called from notify_change(), which expects the caller
* to lock the inode's i_mutex.
*/
-void ima_inode_post_setattr(struct mnt_idmap *idmap,
- struct dentry *dentry, int ia_valid)
+static void ima_inode_post_setattr(struct mnt_idmap *idmap,
+ struct dentry *dentry, int ia_valid)
{
struct inode *inode = d_backing_inode(dentry);
struct integrity_iint_cache *iint;
@@ -750,9 +750,9 @@ static int validate_hash_algo(struct dentry *dentry,
return -EACCES;
}
-int ima_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
- const char *xattr_name, const void *xattr_value,
- size_t xattr_value_len, int flags)
+static int ima_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
+ const char *xattr_name, const void *xattr_value,
+ size_t xattr_value_len, int flags)
{
const struct evm_ima_xattr_data *xvalue = xattr_value;
int digsig = 0;
@@ -781,8 +781,8 @@ int ima_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
return result;
}
-int ima_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
- const char *acl_name, struct posix_acl *kacl)
+static int ima_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
+ const char *acl_name, struct posix_acl *kacl)
{
if (evm_revalidate_status(acl_name))
ima_reset_appraise_flags(d_backing_inode(dentry), 0);
@@ -790,8 +790,8 @@ int ima_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
return 0;
}
-int ima_inode_removexattr(struct mnt_idmap *idmap, struct dentry *dentry,
- const char *xattr_name)
+static int ima_inode_removexattr(struct mnt_idmap *idmap, struct dentry *dentry,
+ const char *xattr_name)
{
int result;
@@ -803,3 +803,23 @@ int ima_inode_removexattr(struct mnt_idmap *idmap, struct dentry *dentry,
}
return result;
}
+
+static int ima_inode_remove_acl(struct mnt_idmap *idmap, struct dentry *dentry,
+ const char *acl_name)
+{
+ return ima_inode_set_acl(idmap, dentry, acl_name, NULL);
+}
+
+static struct security_hook_list ima_appraise_hooks[] __ro_after_init = {
+ LSM_HOOK_INIT(inode_post_setattr, ima_inode_post_setattr),
+ LSM_HOOK_INIT(inode_setxattr, ima_inode_setxattr),
+ LSM_HOOK_INIT(inode_set_acl, ima_inode_set_acl),
+ LSM_HOOK_INIT(inode_removexattr, ima_inode_removexattr),
+ LSM_HOOK_INIT(inode_remove_acl, ima_inode_remove_acl),
+};
+
+void __init init_ima_appraise_lsm(const struct lsm_id *lsmid)
+{
+ security_add_hooks(ima_appraise_hooks, ARRAY_SIZE(ima_appraise_hooks),
+ lsmid);
+}
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 17bd05e6a759..079f629bf369 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -1149,6 +1149,7 @@ static const struct lsm_id ima_lsmid = {
static int __init init_ima_lsm(void)
{
security_add_hooks(ima_hooks, ARRAY_SIZE(ima_hooks), &ima_lsmid);
+ init_ima_appraise_lsm(&ima_lsmid);
return 0;
}
diff --git a/security/security.c b/security/security.c
index 65baa4742156..c7303282efd3 100644
--- a/security/security.c
+++ b/security/security.c
@@ -20,7 +20,6 @@
#include <linux/kernel_read_file.h>
#include <linux/lsm_hooks.h>
#include <linux/integrity.h>
-#include <linux/ima.h>
#include <linux/evm.h>
#include <linux/fsnotify.h>
#include <linux/mman.h>
@@ -2308,9 +2307,6 @@ int security_inode_setxattr(struct mnt_idmap *idmap,
if (ret == 1)
ret = cap_inode_setxattr(dentry, name, value, size, flags);
- if (ret)
- return ret;
- ret = ima_inode_setxattr(idmap, dentry, name, value, size, flags);
if (ret)
return ret;
return evm_inode_setxattr(idmap, dentry, name, value, size, flags);
@@ -2338,9 +2334,6 @@ int security_inode_set_acl(struct mnt_idmap *idmap,
return 0;
ret = call_int_hook(inode_set_acl, 0, idmap, dentry, acl_name,
kacl);
- if (ret)
- return ret;
- ret = ima_inode_set_acl(idmap, dentry, acl_name, kacl);
if (ret)
return ret;
return evm_inode_set_acl(idmap, dentry, acl_name, kacl);
@@ -2401,9 +2394,6 @@ int security_inode_remove_acl(struct mnt_idmap *idmap,
if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
return 0;
ret = call_int_hook(inode_remove_acl, 0, idmap, dentry, acl_name);
- if (ret)
- return ret;
- ret = ima_inode_remove_acl(idmap, dentry, acl_name);
if (ret)
return ret;
return evm_inode_remove_acl(idmap, dentry, acl_name);
@@ -2503,9 +2493,6 @@ int security_inode_removexattr(struct mnt_idmap *idmap,
ret = call_int_hook(inode_removexattr, 1, idmap, dentry, name);
if (ret == 1)
ret = cap_inode_removexattr(idmap, dentry, name);
- if (ret)
- return ret;
- ret = ima_inode_removexattr(idmap, dentry, name);
if (ret)
return ret;
return evm_inode_removexattr(idmap, dentry, name);
--
2.34.1
From: Roberto Sassu <[email protected]>
As for IMA, move hardcoded EVM function calls from various places in the
kernel to the LSM infrastructure, by introducing a new LSM named 'evm'
(last and always enabled like 'ima'). The order in the Makefile ensures
that 'evm' hooks are executed after 'ima' ones.
Make EVM functions as static (except for evm_inode_init_security(), which
is exported), and register them as hook implementations in init_evm_lsm().
Finally, switch to the LSM reservation mechanism for the EVM xattr, and
consequently decrement by one the number of xattrs to allocate in
security_inode_init_security().
Signed-off-by: Roberto Sassu <[email protected]>
---
fs/attr.c | 2 -
fs/posix_acl.c | 3 -
fs/xattr.c | 2 -
include/linux/evm.h | 107 --------------------------
include/uapi/linux/lsm.h | 1 +
security/integrity/evm/evm_main.c | 120 ++++++++++++++++++++++++++----
security/security.c | 45 +++--------
7 files changed, 117 insertions(+), 163 deletions(-)
diff --git a/fs/attr.c b/fs/attr.c
index 38841f3ebbcb..b51bd7c9b4a7 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -16,7 +16,6 @@
#include <linux/fcntl.h>
#include <linux/filelock.h>
#include <linux/security.h>
-#include <linux/evm.h>
#include "internal.h"
@@ -502,7 +501,6 @@ int notify_change(struct mnt_idmap *idmap, struct dentry *dentry,
if (!error) {
fsnotify_change(dentry, ia_valid);
security_inode_post_setattr(idmap, dentry, ia_valid);
- evm_inode_post_setattr(idmap, dentry, ia_valid);
}
return error;
diff --git a/fs/posix_acl.c b/fs/posix_acl.c
index e3fbe1a9f3f5..ae67479cd2b6 100644
--- a/fs/posix_acl.c
+++ b/fs/posix_acl.c
@@ -26,7 +26,6 @@
#include <linux/mnt_idmapping.h>
#include <linux/iversion.h>
#include <linux/security.h>
-#include <linux/evm.h>
#include <linux/fsnotify.h>
#include <linux/filelock.h>
@@ -1138,7 +1137,6 @@ int vfs_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
if (!error) {
fsnotify_xattr(dentry);
security_inode_post_set_acl(dentry, acl_name, kacl);
- evm_inode_post_set_acl(dentry, acl_name, kacl);
}
out_inode_unlock:
@@ -1247,7 +1245,6 @@ int vfs_remove_acl(struct mnt_idmap *idmap, struct dentry *dentry,
if (!error) {
fsnotify_xattr(dentry);
security_inode_post_remove_acl(idmap, dentry, acl_name);
- evm_inode_post_remove_acl(idmap, dentry, acl_name);
}
out_inode_unlock:
diff --git a/fs/xattr.c b/fs/xattr.c
index f891c260a971..f8b643f91a98 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -16,7 +16,6 @@
#include <linux/mount.h>
#include <linux/namei.h>
#include <linux/security.h>
-#include <linux/evm.h>
#include <linux/syscalls.h>
#include <linux/export.h>
#include <linux/fsnotify.h>
@@ -557,7 +556,6 @@ __vfs_removexattr_locked(struct mnt_idmap *idmap,
fsnotify_xattr(dentry);
security_inode_post_removexattr(dentry, name);
- evm_inode_post_removexattr(dentry, name);
out:
return error;
diff --git a/include/linux/evm.h b/include/linux/evm.h
index 437d4076a3b3..cb481eccc967 100644
--- a/include/linux/evm.h
+++ b/include/linux/evm.h
@@ -21,44 +21,6 @@ extern enum integrity_status evm_verifyxattr(struct dentry *dentry,
void *xattr_value,
size_t xattr_value_len,
struct integrity_iint_cache *iint);
-extern int evm_inode_setattr(struct mnt_idmap *idmap,
- struct dentry *dentry, struct iattr *attr);
-extern void evm_inode_post_setattr(struct mnt_idmap *idmap,
- struct dentry *dentry, int ia_valid);
-extern int evm_inode_setxattr(struct mnt_idmap *idmap,
- struct dentry *dentry, const char *name,
- const void *value, size_t size, int flags);
-extern void evm_inode_post_setxattr(struct dentry *dentry,
- const char *xattr_name,
- const void *xattr_value,
- size_t xattr_value_len,
- int flags);
-extern int evm_inode_removexattr(struct mnt_idmap *idmap,
- struct dentry *dentry, const char *xattr_name);
-extern void evm_inode_post_removexattr(struct dentry *dentry,
- const char *xattr_name);
-static inline void evm_inode_post_remove_acl(struct mnt_idmap *idmap,
- struct dentry *dentry,
- const char *acl_name)
-{
- evm_inode_post_removexattr(dentry, acl_name);
-}
-extern int evm_inode_set_acl(struct mnt_idmap *idmap,
- struct dentry *dentry, const char *acl_name,
- struct posix_acl *kacl);
-static inline int evm_inode_remove_acl(struct mnt_idmap *idmap,
- struct dentry *dentry,
- const char *acl_name)
-{
- return evm_inode_set_acl(idmap, dentry, acl_name, NULL);
-}
-static inline void evm_inode_post_set_acl(struct dentry *dentry,
- const char *acl_name,
- struct posix_acl *kacl)
-{
- return evm_inode_post_setxattr(dentry, acl_name, NULL, 0, 0);
-}
-
int evm_inode_init_security(struct inode *inode, struct inode *dir,
const struct qstr *qstr, struct xattr *xattrs,
int *xattr_count);
@@ -93,75 +55,6 @@ static inline enum integrity_status evm_verifyxattr(struct dentry *dentry,
}
#endif
-static inline int evm_inode_setattr(struct mnt_idmap *idmap,
- struct dentry *dentry, struct iattr *attr)
-{
- return 0;
-}
-
-static inline void evm_inode_post_setattr(struct mnt_idmap *idmap,
- struct dentry *dentry, int ia_valid)
-{
- return;
-}
-
-static inline int evm_inode_setxattr(struct mnt_idmap *idmap,
- struct dentry *dentry, const char *name,
- const void *value, size_t size, int flags)
-{
- return 0;
-}
-
-static inline void evm_inode_post_setxattr(struct dentry *dentry,
- const char *xattr_name,
- const void *xattr_value,
- size_t xattr_value_len,
- int flags)
-{
- return;
-}
-
-static inline int evm_inode_removexattr(struct mnt_idmap *idmap,
- struct dentry *dentry,
- const char *xattr_name)
-{
- return 0;
-}
-
-static inline void evm_inode_post_removexattr(struct dentry *dentry,
- const char *xattr_name)
-{
- return;
-}
-
-static inline void evm_inode_post_remove_acl(struct mnt_idmap *idmap,
- struct dentry *dentry,
- const char *acl_name)
-{
- return;
-}
-
-static inline int evm_inode_set_acl(struct mnt_idmap *idmap,
- struct dentry *dentry, const char *acl_name,
- struct posix_acl *kacl)
-{
- return 0;
-}
-
-static inline int evm_inode_remove_acl(struct mnt_idmap *idmap,
- struct dentry *dentry,
- const char *acl_name)
-{
- return 0;
-}
-
-static inline void evm_inode_post_set_acl(struct dentry *dentry,
- const char *acl_name,
- struct posix_acl *kacl)
-{
- return;
-}
-
static inline int evm_inode_init_security(struct inode *inode, struct inode *dir,
const struct qstr *qstr,
struct xattr *xattrs,
diff --git a/include/uapi/linux/lsm.h b/include/uapi/linux/lsm.h
index ee7d034255a9..825339bcd580 100644
--- a/include/uapi/linux/lsm.h
+++ b/include/uapi/linux/lsm.h
@@ -62,6 +62,7 @@ struct lsm_ctx {
#define LSM_ID_BPF 109
#define LSM_ID_LANDLOCK 110
#define LSM_ID_IMA 111
+#define LSM_ID_EVM 112
/*
* LSM_ATTR_XXX definitions identify different LSM attributes
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index ea84a6f835ff..ce45f4eebcec 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -566,9 +566,9 @@ static int evm_protect_xattr(struct mnt_idmap *idmap,
* userspace from writing HMAC value. Writing 'security.evm' requires
* requires CAP_SYS_ADMIN privileges.
*/
-int evm_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
- const char *xattr_name, const void *xattr_value,
- size_t xattr_value_len, int flags)
+static int evm_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
+ const char *xattr_name, const void *xattr_value,
+ size_t xattr_value_len, int flags)
{
const struct evm_ima_xattr_data *xattr_data = xattr_value;
@@ -598,8 +598,8 @@ int evm_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
* Removing 'security.evm' requires CAP_SYS_ADMIN privileges and that
* the current value is valid.
*/
-int evm_inode_removexattr(struct mnt_idmap *idmap,
- struct dentry *dentry, const char *xattr_name)
+static int evm_inode_removexattr(struct mnt_idmap *idmap, struct dentry *dentry,
+ const char *xattr_name)
{
/* Policy permits modification of the protected xattrs even though
* there's no HMAC key loaded
@@ -649,9 +649,11 @@ static inline int evm_inode_set_acl_change(struct mnt_idmap *idmap,
* Prevent modifying posix acls causing the EVM HMAC to be re-calculated
* and 'security.evm' xattr updated, unless the existing 'security.evm' is
* valid.
+ *
+ * Return: zero on success, -EPERM on failure.
*/
-int evm_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
- const char *acl_name, struct posix_acl *kacl)
+static int evm_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
+ const char *acl_name, struct posix_acl *kacl)
{
enum integrity_status evm_status;
@@ -690,6 +692,24 @@ int evm_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
return -EPERM;
}
+/**
+ * evm_inode_remove_acl - Protect the EVM extended attribute from posix acls
+ * @idmap: idmap of the mount
+ * @dentry: pointer to the affected dentry
+ * @acl_name: name of the posix acl
+ *
+ * Prevent removing posix acls causing the EVM HMAC to be re-calculated
+ * and 'security.evm' xattr updated, unless the existing 'security.evm' is
+ * valid.
+ *
+ * Return: zero on success, -EPERM on failure.
+ */
+static int evm_inode_remove_acl(struct mnt_idmap *idmap, struct dentry *dentry,
+ const char *acl_name)
+{
+ return evm_inode_set_acl(idmap, dentry, acl_name, NULL);
+}
+
static void evm_reset_status(struct inode *inode)
{
struct integrity_iint_cache *iint;
@@ -738,9 +758,11 @@ bool evm_revalidate_status(const char *xattr_name)
* __vfs_setxattr_noperm(). The caller of which has taken the inode's
* i_mutex lock.
*/
-void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,
- const void *xattr_value, size_t xattr_value_len,
- int flags)
+static void evm_inode_post_setxattr(struct dentry *dentry,
+ const char *xattr_name,
+ const void *xattr_value,
+ size_t xattr_value_len,
+ int flags)
{
if (!evm_revalidate_status(xattr_name))
return;
@@ -756,6 +778,21 @@ void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,
evm_update_evmxattr(dentry, xattr_name, xattr_value, xattr_value_len);
}
+/**
+ * evm_inode_post_set_acl - Update the EVM extended attribute from posix acls
+ * @dentry: pointer to the affected dentry
+ * @acl_name: name of the posix acl
+ * @kacl: pointer to the posix acls
+ *
+ * Update the 'security.evm' xattr with the EVM HMAC re-calculated after setting
+ * posix acls.
+ */
+static void evm_inode_post_set_acl(struct dentry *dentry, const char *acl_name,
+ struct posix_acl *kacl)
+{
+ return evm_inode_post_setxattr(dentry, acl_name, NULL, 0, 0);
+}
+
/**
* evm_inode_post_removexattr - update 'security.evm' after removing the xattr
* @dentry: pointer to the affected dentry
@@ -766,7 +803,8 @@ void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,
* No need to take the i_mutex lock here, as this function is called from
* vfs_removexattr() which takes the i_mutex.
*/
-void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name)
+static void evm_inode_post_removexattr(struct dentry *dentry,
+ const char *xattr_name)
{
if (!evm_revalidate_status(xattr_name))
return;
@@ -782,6 +820,22 @@ void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name)
evm_update_evmxattr(dentry, xattr_name, NULL, 0);
}
+/**
+ * evm_inode_post_remove_acl - Update the EVM extended attribute from posix acls
+ * @idmap: idmap of the mount
+ * @dentry: pointer to the affected dentry
+ * @acl_name: name of the posix acl
+ *
+ * Update the 'security.evm' xattr with the EVM HMAC re-calculated after
+ * removing posix acls.
+ */
+static inline void evm_inode_post_remove_acl(struct mnt_idmap *idmap,
+ struct dentry *dentry,
+ const char *acl_name)
+{
+ evm_inode_post_removexattr(dentry, acl_name);
+}
+
static int evm_attr_change(struct mnt_idmap *idmap,
struct dentry *dentry, struct iattr *attr)
{
@@ -805,8 +859,8 @@ static int evm_attr_change(struct mnt_idmap *idmap,
* Permit update of file attributes when files have a valid EVM signature,
* except in the case of them having an immutable portable signature.
*/
-int evm_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
- struct iattr *attr)
+static int evm_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
+ struct iattr *attr)
{
unsigned int ia_valid = attr->ia_valid;
enum integrity_status evm_status;
@@ -853,8 +907,8 @@ int evm_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
* This function is called from notify_change(), which expects the caller
* to lock the inode's i_mutex.
*/
-void evm_inode_post_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
- int ia_valid)
+static void evm_inode_post_setattr(struct mnt_idmap *idmap,
+ struct dentry *dentry, int ia_valid)
{
if (!evm_revalidate_status(NULL))
return;
@@ -964,4 +1018,40 @@ static int __init init_evm(void)
return error;
}
+static struct security_hook_list evm_hooks[] __ro_after_init = {
+ LSM_HOOK_INIT(inode_setattr, evm_inode_setattr),
+ LSM_HOOK_INIT(inode_post_setattr, evm_inode_post_setattr),
+ LSM_HOOK_INIT(inode_setxattr, evm_inode_setxattr),
+ LSM_HOOK_INIT(inode_set_acl, evm_inode_set_acl),
+ LSM_HOOK_INIT(inode_post_set_acl, evm_inode_post_set_acl),
+ LSM_HOOK_INIT(inode_remove_acl, evm_inode_remove_acl),
+ LSM_HOOK_INIT(inode_post_remove_acl, evm_inode_post_remove_acl),
+ LSM_HOOK_INIT(inode_post_setxattr, evm_inode_post_setxattr),
+ LSM_HOOK_INIT(inode_removexattr, evm_inode_removexattr),
+ LSM_HOOK_INIT(inode_post_removexattr, evm_inode_post_removexattr),
+ LSM_HOOK_INIT(inode_init_security, evm_inode_init_security),
+};
+
+static const struct lsm_id evm_lsmid = {
+ .name = "evm",
+ .id = LSM_ID_EVM,
+};
+
+static int __init init_evm_lsm(void)
+{
+ security_add_hooks(evm_hooks, ARRAY_SIZE(evm_hooks), &evm_lsmid);
+ return 0;
+}
+
+static struct lsm_blob_sizes evm_blob_sizes __ro_after_init = {
+ .lbs_xattr_count = 1,
+};
+
+DEFINE_LSM(evm) = {
+ .name = "evm",
+ .init = init_evm_lsm,
+ .order = LSM_ORDER_LAST,
+ .blobs = &evm_blob_sizes,
+};
+
late_initcall(init_evm);
diff --git a/security/security.c b/security/security.c
index c7303282efd3..778043a626a6 100644
--- a/security/security.c
+++ b/security/security.c
@@ -20,13 +20,13 @@
#include <linux/kernel_read_file.h>
#include <linux/lsm_hooks.h>
#include <linux/integrity.h>
-#include <linux/evm.h>
#include <linux/fsnotify.h>
#include <linux/mman.h>
#include <linux/mount.h>
#include <linux/personality.h>
#include <linux/backing-dev.h>
#include <linux/string.h>
+#include <linux/xattr.h>
#include <linux/msg.h>
#include <net/flow.h>
@@ -50,7 +50,8 @@
(IS_ENABLED(CONFIG_SECURITY_LOCKDOWN_LSM) ? 1 : 0) + \
(IS_ENABLED(CONFIG_BPF_LSM) ? 1 : 0) + \
(IS_ENABLED(CONFIG_SECURITY_LANDLOCK) ? 1 : 0) + \
- (IS_ENABLED(CONFIG_IMA) ? 1 : 0))
+ (IS_ENABLED(CONFIG_IMA) ? 1 : 0) + \
+ (IS_ENABLED(CONFIG_EVM) ? 1 : 0))
/*
* These are descriptions of the reasons that can be passed to the
@@ -1715,8 +1716,8 @@ int security_inode_init_security(struct inode *inode, struct inode *dir,
return 0;
if (initxattrs) {
- /* Allocate +1 for EVM and +1 as terminator. */
- new_xattrs = kcalloc(blob_sizes.lbs_xattr_count + 2,
+ /* Allocate +1 as terminator. */
+ new_xattrs = kcalloc(blob_sizes.lbs_xattr_count + 1,
sizeof(*new_xattrs), GFP_NOFS);
if (!new_xattrs)
return -ENOMEM;
@@ -1740,10 +1741,6 @@ int security_inode_init_security(struct inode *inode, struct inode *dir,
if (!xattr_count)
goto out;
- ret = evm_inode_init_security(inode, dir, qstr, new_xattrs,
- &xattr_count);
- if (ret)
- goto out;
ret = initxattrs(inode, new_xattrs, fs_data);
out:
for (; xattr_count > 0; xattr_count--)
@@ -2235,14 +2232,9 @@ int security_inode_permission(struct inode *inode, int mask)
int security_inode_setattr(struct mnt_idmap *idmap,
struct dentry *dentry, struct iattr *attr)
{
- int ret;
-
if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
return 0;
- ret = call_int_hook(inode_setattr, 0, idmap, dentry, attr);
- if (ret)
- return ret;
- return evm_inode_setattr(idmap, dentry, attr);
+ return call_int_hook(inode_setattr, 0, idmap, dentry, attr);
}
EXPORT_SYMBOL_GPL(security_inode_setattr);
@@ -2307,9 +2299,7 @@ int security_inode_setxattr(struct mnt_idmap *idmap,
if (ret == 1)
ret = cap_inode_setxattr(dentry, name, value, size, flags);
- if (ret)
- return ret;
- return evm_inode_setxattr(idmap, dentry, name, value, size, flags);
+ return ret;
}
/**
@@ -2328,15 +2318,10 @@ int security_inode_set_acl(struct mnt_idmap *idmap,
struct dentry *dentry, const char *acl_name,
struct posix_acl *kacl)
{
- int ret;
-
if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
return 0;
- ret = call_int_hook(inode_set_acl, 0, idmap, dentry, acl_name,
- kacl);
- if (ret)
- return ret;
- return evm_inode_set_acl(idmap, dentry, acl_name, kacl);
+ return call_int_hook(inode_set_acl, 0, idmap, dentry, acl_name,
+ kacl);
}
/**
@@ -2389,14 +2374,9 @@ int security_inode_get_acl(struct mnt_idmap *idmap,
int security_inode_remove_acl(struct mnt_idmap *idmap,
struct dentry *dentry, const char *acl_name)
{
- int ret;
-
if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
return 0;
- ret = call_int_hook(inode_remove_acl, 0, idmap, dentry, acl_name);
- if (ret)
- return ret;
- return evm_inode_remove_acl(idmap, dentry, acl_name);
+ return call_int_hook(inode_remove_acl, 0, idmap, dentry, acl_name);
}
/**
@@ -2432,7 +2412,6 @@ void security_inode_post_setxattr(struct dentry *dentry, const char *name,
if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
return;
call_void_hook(inode_post_setxattr, dentry, name, value, size, flags);
- evm_inode_post_setxattr(dentry, name, value, size, flags);
}
/**
@@ -2493,9 +2472,7 @@ int security_inode_removexattr(struct mnt_idmap *idmap,
ret = call_int_hook(inode_removexattr, 1, idmap, dentry, name);
if (ret == 1)
ret = cap_inode_removexattr(idmap, dentry, name);
- if (ret)
- return ret;
- return evm_inode_removexattr(idmap, dentry, name);
+ return ret;
}
/**
--
2.34.1
From: Roberto Sassu <[email protected]>
Before the security field of kernel objects could be shared among LSMs with
the LSM stacking feature, IMA and EVM had to rely on an alternative storage
of inode metadata. The association between inode metadata and inode is
maintained through an rbtree.
With the reservation mechanism offered by the LSM infrastructure, the
rbtree is no longer necessary, as each LSM could reserve a space in the
security blob for each inode.
With the 'integrity' LSM removed, and with the 'ima' LSM taking its role,
reserve space from the 'ima' LSM for a pointer to the integrity_iint_cache
structure directly, rather than embedding the whole structure in the inode
security blob, to minimize the changes and to avoid waste of memory.
If IMA is disabled, EVM faces the same problems as before making it an
LSM, metadata verification fails for new files due to not setting the
IMA_NEW_FILE flag in ima_post_path_mknod(), and evm_verifyxattr()
returns INTEGRITY_UNKNOWN since IMA didn't call integrity_inode_get().
The only difference caused to moving the integrity metadata management
to the 'ima' LSM is the fact that EVM cannot take advantage of cached
verification results, and has to do the verification again. However,
this case should never happen, since the only public API available to
all kernel components, evm_verifyxattr(), does not work if IMA is
disabled.
Introduce two primitives for getting and setting the pointer of
integrity_iint_cache in the security blob, respectively
integrity_inode_get_iint() and integrity_inode_set_iint(). This would make
the code more understandable, as they directly replace rbtree operations.
Locking is not needed, as access to inode metadata is not shared, it is per
inode.
Keep the blob size and the new primitives definition at the common level in
security/integrity rather than moving them in IMA itself, so that EVM can
still call integrity_inode_get() and integrity_iint_find() while IMA is
disabled. Just add an extra check in integrity_inode_get() to return NULL
if that is the case.
Signed-off-by: Roberto Sassu <[email protected]>
---
security/integrity/iint.c | 70 ++++---------------------------
security/integrity/ima/ima_main.c | 1 +
security/integrity/integrity.h | 20 ++++++++-
3 files changed, 29 insertions(+), 62 deletions(-)
diff --git a/security/integrity/iint.c b/security/integrity/iint.c
index c36054041b84..8fc9455dda11 100644
--- a/security/integrity/iint.c
+++ b/security/integrity/iint.c
@@ -14,56 +14,25 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/spinlock.h>
-#include <linux/rbtree.h>
#include <linux/file.h>
#include <linux/uaccess.h>
#include <linux/security.h>
#include <linux/lsm_hooks.h>
#include "integrity.h"
-static struct rb_root integrity_iint_tree = RB_ROOT;
-static DEFINE_RWLOCK(integrity_iint_lock);
static struct kmem_cache *iint_cache __ro_after_init;
struct dentry *integrity_dir;
-/*
- * __integrity_iint_find - return the iint associated with an inode
- */
-static struct integrity_iint_cache *__integrity_iint_find(struct inode *inode)
-{
- struct integrity_iint_cache *iint;
- struct rb_node *n = integrity_iint_tree.rb_node;
-
- while (n) {
- iint = rb_entry(n, struct integrity_iint_cache, rb_node);
-
- if (inode < iint->inode)
- n = n->rb_left;
- else if (inode > iint->inode)
- n = n->rb_right;
- else
- return iint;
- }
-
- return NULL;
-}
-
/*
* integrity_iint_find - return the iint associated with an inode
*/
struct integrity_iint_cache *integrity_iint_find(struct inode *inode)
{
- struct integrity_iint_cache *iint;
-
if (!IS_IMA(inode))
return NULL;
- read_lock(&integrity_iint_lock);
- iint = __integrity_iint_find(inode);
- read_unlock(&integrity_iint_lock);
-
- return iint;
+ return integrity_inode_get_iint(inode);
}
#define IMA_MAX_NESTING (FILESYSTEM_MAX_STACK_DEPTH+1)
@@ -123,9 +92,7 @@ static void iint_free(struct integrity_iint_cache *iint)
*/
struct integrity_iint_cache *integrity_inode_get(struct inode *inode)
{
- struct rb_node **p;
- struct rb_node *node, *parent = NULL;
- struct integrity_iint_cache *iint, *test_iint;
+ struct integrity_iint_cache *iint;
/*
* After removing the 'integrity' LSM, the 'ima' LSM calls
@@ -144,31 +111,10 @@ struct integrity_iint_cache *integrity_inode_get(struct inode *inode)
iint_init_always(iint, inode);
- write_lock(&integrity_iint_lock);
-
- p = &integrity_iint_tree.rb_node;
- while (*p) {
- parent = *p;
- test_iint = rb_entry(parent, struct integrity_iint_cache,
- rb_node);
- if (inode < test_iint->inode) {
- p = &(*p)->rb_left;
- } else if (inode > test_iint->inode) {
- p = &(*p)->rb_right;
- } else {
- write_unlock(&integrity_iint_lock);
- kmem_cache_free(iint_cache, iint);
- return test_iint;
- }
- }
-
iint->inode = inode;
- node = &iint->rb_node;
inode->i_flags |= S_IMA;
- rb_link_node(node, parent, p);
- rb_insert_color(node, &integrity_iint_tree);
+ integrity_inode_set_iint(inode, iint);
- write_unlock(&integrity_iint_lock);
return iint;
}
@@ -185,10 +131,8 @@ void integrity_inode_free(struct inode *inode)
if (!IS_IMA(inode))
return;
- write_lock(&integrity_iint_lock);
- iint = __integrity_iint_find(inode);
- rb_erase(&iint->rb_node, &integrity_iint_tree);
- write_unlock(&integrity_iint_lock);
+ iint = integrity_iint_find(inode);
+ integrity_inode_set_iint(inode, NULL);
iint_free(iint);
}
@@ -212,6 +156,10 @@ int __init integrity_iintcache_init(void)
return 0;
}
+struct lsm_blob_sizes integrity_blob_sizes __ro_after_init = {
+ .lbs_inode = sizeof(struct integrity_iint_cache *),
+};
+
/*
* integrity_kernel_read - read data from the file
*
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 3f59cce3fa02..52b4a3bba45a 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -1162,6 +1162,7 @@ DEFINE_LSM(ima) = {
.name = "ima",
.init = init_ima_lsm,
.order = LSM_ORDER_LAST,
+ .blobs = &integrity_blob_sizes,
};
late_initcall(init_ima); /* Start IMA after the TPM is available */
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index 26d3b08dca1c..2fb35c67d64d 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -158,7 +158,6 @@ struct ima_file_id {
/* integrity data associated with an inode */
struct integrity_iint_cache {
- struct rb_node rb_node; /* rooted in integrity_iint_tree */
struct mutex mutex; /* protects: version, flags, digest */
struct inode *inode; /* back pointer to inode in question */
u64 version; /* track inode changes */
@@ -194,6 +193,25 @@ int integrity_kernel_read(struct file *file, loff_t offset,
#define INTEGRITY_KEYRING_MAX 4
extern struct dentry *integrity_dir;
+extern struct lsm_blob_sizes integrity_blob_sizes;
+
+static inline struct integrity_iint_cache *
+integrity_inode_get_iint(const struct inode *inode)
+{
+ struct integrity_iint_cache **iint_sec;
+
+ iint_sec = inode->i_security + integrity_blob_sizes.lbs_inode;
+ return *iint_sec;
+}
+
+static inline void integrity_inode_set_iint(const struct inode *inode,
+ struct integrity_iint_cache *iint)
+{
+ struct integrity_iint_cache **iint_sec;
+
+ iint_sec = inode->i_security + integrity_blob_sizes.lbs_inode;
+ *iint_sec = iint;
+}
struct modsig;
--
2.34.1
On 12/1/2023 12:19 AM, Roberto Sassu wrote:
> From: Roberto Sassu <[email protected]>
>
> Before the security field of kernel objects could be shared among LSMs with
> the LSM stacking feature, IMA and EVM had to rely on an alternative storage
> of inode metadata. The association between inode metadata and inode is
> maintained through an rbtree.
>
> With the reservation mechanism offered by the LSM infrastructure, the
> rbtree is no longer necessary, as each LSM could reserve a space in the
> security blob for each inode.
>
> With the 'integrity' LSM removed, and with the 'ima' LSM taking its role,
> reserve space from the 'ima' LSM for a pointer to the integrity_iint_cache
> structure directly, rather than embedding the whole structure in the inode
> security blob, to minimize the changes and to avoid waste of memory.
>
> If IMA is disabled, EVM faces the same problems as before making it an
> LSM, metadata verification fails for new files due to not setting the
> IMA_NEW_FILE flag in ima_post_path_mknod(), and evm_verifyxattr()
> returns INTEGRITY_UNKNOWN since IMA didn't call integrity_inode_get().
>
> The only difference caused to moving the integrity metadata management
> to the 'ima' LSM is the fact that EVM cannot take advantage of cached
> verification results, and has to do the verification again. However,
> this case should never happen, since the only public API available to
> all kernel components, evm_verifyxattr(), does not work if IMA is
> disabled.
This needs some explanation on how EVM can be used currently. EVM
verifies inode metadata in the set* LSM hooks, eventually updates the
HMAC in the post_set* hooks.
If integrity metadata are not available (IMA is disabled), EVM has to do
the inode metadata verification every time, which means that this patch
set would introduce a performance regression compared to when integrity
metadata were always available and managed by the 'integrity' LSM.
However, the get* LSM hooks are not mediated, user space can freely get
a corrupted inode metadata and EVM would not tell anything.
So, at this point it is clear that the main use case of EVM was a kernel
component querying EVM about the integrity of inode metadata, by calling
evm_verifyxattr(). One suitable place where this function can be called
is the d_instantiate LSM hook, when an LSM is getting xattrs from the
filesystem to populate the inode security blob.
But as I mentioned, evm_verifyxattr() does not work if IMA is disabled,
so there should not be systems using this configuration for which we are
introducing a performance regression.
Roberto
> Introduce two primitives for getting and setting the pointer of
> integrity_iint_cache in the security blob, respectively
> integrity_inode_get_iint() and integrity_inode_set_iint(). This would make
> the code more understandable, as they directly replace rbtree operations.
>
> Locking is not needed, as access to inode metadata is not shared, it is per
> inode.
>
> Keep the blob size and the new primitives definition at the common level in
> security/integrity rather than moving them in IMA itself, so that EVM can
> still call integrity_inode_get() and integrity_iint_find() while IMA is
> disabled. Just add an extra check in integrity_inode_get() to return NULL
> if that is the case.
>
> Signed-off-by: Roberto Sassu <[email protected]>
> ---
> security/integrity/iint.c | 70 ++++---------------------------
> security/integrity/ima/ima_main.c | 1 +
> security/integrity/integrity.h | 20 ++++++++-
> 3 files changed, 29 insertions(+), 62 deletions(-)
>
> diff --git a/security/integrity/iint.c b/security/integrity/iint.c
> index c36054041b84..8fc9455dda11 100644
> --- a/security/integrity/iint.c
> +++ b/security/integrity/iint.c
> @@ -14,56 +14,25 @@
> #include <linux/slab.h>
> #include <linux/init.h>
> #include <linux/spinlock.h>
> -#include <linux/rbtree.h>
> #include <linux/file.h>
> #include <linux/uaccess.h>
> #include <linux/security.h>
> #include <linux/lsm_hooks.h>
> #include "integrity.h"
>
> -static struct rb_root integrity_iint_tree = RB_ROOT;
> -static DEFINE_RWLOCK(integrity_iint_lock);
> static struct kmem_cache *iint_cache __ro_after_init;
>
> struct dentry *integrity_dir;
>
> -/*
> - * __integrity_iint_find - return the iint associated with an inode
> - */
> -static struct integrity_iint_cache *__integrity_iint_find(struct inode *inode)
> -{
> - struct integrity_iint_cache *iint;
> - struct rb_node *n = integrity_iint_tree.rb_node;
> -
> - while (n) {
> - iint = rb_entry(n, struct integrity_iint_cache, rb_node);
> -
> - if (inode < iint->inode)
> - n = n->rb_left;
> - else if (inode > iint->inode)
> - n = n->rb_right;
> - else
> - return iint;
> - }
> -
> - return NULL;
> -}
> -
> /*
> * integrity_iint_find - return the iint associated with an inode
> */
> struct integrity_iint_cache *integrity_iint_find(struct inode *inode)
> {
> - struct integrity_iint_cache *iint;
> -
> if (!IS_IMA(inode))
> return NULL;
>
> - read_lock(&integrity_iint_lock);
> - iint = __integrity_iint_find(inode);
> - read_unlock(&integrity_iint_lock);
> -
> - return iint;
> + return integrity_inode_get_iint(inode);
> }
>
> #define IMA_MAX_NESTING (FILESYSTEM_MAX_STACK_DEPTH+1)
> @@ -123,9 +92,7 @@ static void iint_free(struct integrity_iint_cache *iint)
> */
> struct integrity_iint_cache *integrity_inode_get(struct inode *inode)
> {
> - struct rb_node **p;
> - struct rb_node *node, *parent = NULL;
> - struct integrity_iint_cache *iint, *test_iint;
> + struct integrity_iint_cache *iint;
>
> /*
> * After removing the 'integrity' LSM, the 'ima' LSM calls
> @@ -144,31 +111,10 @@ struct integrity_iint_cache *integrity_inode_get(struct inode *inode)
>
> iint_init_always(iint, inode);
>
> - write_lock(&integrity_iint_lock);
> -
> - p = &integrity_iint_tree.rb_node;
> - while (*p) {
> - parent = *p;
> - test_iint = rb_entry(parent, struct integrity_iint_cache,
> - rb_node);
> - if (inode < test_iint->inode) {
> - p = &(*p)->rb_left;
> - } else if (inode > test_iint->inode) {
> - p = &(*p)->rb_right;
> - } else {
> - write_unlock(&integrity_iint_lock);
> - kmem_cache_free(iint_cache, iint);
> - return test_iint;
> - }
> - }
> -
> iint->inode = inode;
> - node = &iint->rb_node;
> inode->i_flags |= S_IMA;
> - rb_link_node(node, parent, p);
> - rb_insert_color(node, &integrity_iint_tree);
> + integrity_inode_set_iint(inode, iint);
>
> - write_unlock(&integrity_iint_lock);
> return iint;
> }
>
> @@ -185,10 +131,8 @@ void integrity_inode_free(struct inode *inode)
> if (!IS_IMA(inode))
> return;
>
> - write_lock(&integrity_iint_lock);
> - iint = __integrity_iint_find(inode);
> - rb_erase(&iint->rb_node, &integrity_iint_tree);
> - write_unlock(&integrity_iint_lock);
> + iint = integrity_iint_find(inode);
> + integrity_inode_set_iint(inode, NULL);
>
> iint_free(iint);
> }
> @@ -212,6 +156,10 @@ int __init integrity_iintcache_init(void)
> return 0;
> }
>
> +struct lsm_blob_sizes integrity_blob_sizes __ro_after_init = {
> + .lbs_inode = sizeof(struct integrity_iint_cache *),
> +};
> +
> /*
> * integrity_kernel_read - read data from the file
> *
> diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
> index 3f59cce3fa02..52b4a3bba45a 100644
> --- a/security/integrity/ima/ima_main.c
> +++ b/security/integrity/ima/ima_main.c
> @@ -1162,6 +1162,7 @@ DEFINE_LSM(ima) = {
> .name = "ima",
> .init = init_ima_lsm,
> .order = LSM_ORDER_LAST,
> + .blobs = &integrity_blob_sizes,
> };
>
> late_initcall(init_ima); /* Start IMA after the TPM is available */
> diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
> index 26d3b08dca1c..2fb35c67d64d 100644
> --- a/security/integrity/integrity.h
> +++ b/security/integrity/integrity.h
> @@ -158,7 +158,6 @@ struct ima_file_id {
>
> /* integrity data associated with an inode */
> struct integrity_iint_cache {
> - struct rb_node rb_node; /* rooted in integrity_iint_tree */
> struct mutex mutex; /* protects: version, flags, digest */
> struct inode *inode; /* back pointer to inode in question */
> u64 version; /* track inode changes */
> @@ -194,6 +193,25 @@ int integrity_kernel_read(struct file *file, loff_t offset,
> #define INTEGRITY_KEYRING_MAX 4
>
> extern struct dentry *integrity_dir;
> +extern struct lsm_blob_sizes integrity_blob_sizes;
> +
> +static inline struct integrity_iint_cache *
> +integrity_inode_get_iint(const struct inode *inode)
> +{
> + struct integrity_iint_cache **iint_sec;
> +
> + iint_sec = inode->i_security + integrity_blob_sizes.lbs_inode;
> + return *iint_sec;
> +}
> +
> +static inline void integrity_inode_set_iint(const struct inode *inode,
> + struct integrity_iint_cache *iint)
> +{
> + struct integrity_iint_cache **iint_sec;
> +
> + iint_sec = inode->i_security + integrity_blob_sizes.lbs_inode;
> + *iint_sec = iint;
> +}
>
> struct modsig;
>