提交 eecf0d83 编写于 作者: K Krzysztof Struczynski 提交者: Zheng Zengkai

ima: Extend the APIs in the integrity subsystem

hulk inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I49KW1
CVE: NA

--------------------------------

Inode integrity cache will be maintained per ima namespace. Add new
functions that allow to specify the iint tree to use.
Signed-off-by: NKrzysztof Struczynski <krzysztof.struczynski@huawei.com>
Reviewed-by: NZhang Tianxing <zhangtianxing3@huawei.com>
Signed-off-by: NZheng Zengkai <zhengzengkai@huawei.com>
上级 c2b095cc
...@@ -8,6 +8,10 @@ ...@@ -8,6 +8,10 @@
#define _LINUX_INTEGRITY_H #define _LINUX_INTEGRITY_H
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/rwlock_types.h>
struct rb_root;
struct integrity_iint_tree;
enum integrity_status { enum integrity_status {
INTEGRITY_PASS = 0, INTEGRITY_PASS = 0,
...@@ -22,8 +26,15 @@ enum integrity_status { ...@@ -22,8 +26,15 @@ enum integrity_status {
/* List of EVM protected security xattrs */ /* List of EVM protected security xattrs */
#ifdef CONFIG_INTEGRITY #ifdef CONFIG_INTEGRITY
extern struct integrity_iint_cache *integrity_inode_get(struct inode *inode); extern struct integrity_iint_cache *integrity_inode_get(struct inode *inode);
extern struct integrity_iint_cache *integrity_inode_rb_get(struct
integrity_iint_tree
*iint_tree,
struct inode *inode);
extern void integrity_inode_free(struct inode *inode); extern void integrity_inode_free(struct inode *inode);
extern void integrity_inode_rb_free(struct integrity_iint_tree *iint_tree,
struct inode *inode);
extern void __init integrity_load_keys(void); extern void __init integrity_load_keys(void);
extern void integrity_iint_tree_free(struct integrity_iint_tree *iint_tree);
#else #else
static inline struct integrity_iint_cache * static inline struct integrity_iint_cache *
...@@ -32,14 +43,34 @@ static inline struct integrity_iint_cache * ...@@ -32,14 +43,34 @@ static inline struct integrity_iint_cache *
return NULL; return NULL;
} }
static inline struct integrity_iint_cache *
integrity_inode_rb_get(struct
integrity_iint_tree
*iint_tree,
struct inode *inode)
{
return NULL;
}
static inline void integrity_inode_free(struct inode *inode) static inline void integrity_inode_free(struct inode *inode)
{ {
return; return;
} }
static inline void integrity_inode_rb_free(struct integrity_iint_tree
*iint_tree,
struct inode *inode)
{
}
static inline void integrity_load_keys(void) static inline void integrity_load_keys(void)
{ {
} }
static inline void integrity_iint_tree_free(struct integrity_iint_tree
*iint_tree)
{
}
#endif /* CONFIG_INTEGRITY */ #endif /* CONFIG_INTEGRITY */
#ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS #ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS
......
...@@ -21,19 +21,29 @@ ...@@ -21,19 +21,29 @@
#include <linux/lsm_hooks.h> #include <linux/lsm_hooks.h>
#include "integrity.h" #include "integrity.h"
static struct rb_root integrity_iint_tree = RB_ROOT; struct integrity_iint_tree init_iint_tree = {
static DEFINE_RWLOCK(integrity_iint_lock); .lock = __RW_LOCK_UNLOCKED(init_iint_tree.lock),
.root = RB_ROOT
};
static struct kmem_cache *iint_cache __read_mostly; static struct kmem_cache *iint_cache __read_mostly;
struct dentry *integrity_dir; struct dentry *integrity_dir;
/* /*
* __integrity_iint_find - return the iint associated with an inode * __integrity_iint_rb_find - return the iint associated with an inode
* @iint_rb_root: pointer to the root of the iint tree
* @inode: pointer to the inode
* @return: pointer to the iint if found, NULL otherwise
*/ */
static struct integrity_iint_cache *__integrity_iint_find(struct inode *inode) static struct integrity_iint_cache *
__integrity_iint_rb_find(const struct rb_root
*iint_rb_root,
const struct inode
*inode)
{ {
struct integrity_iint_cache *iint; struct integrity_iint_cache *iint;
struct rb_node *n = integrity_iint_tree.rb_node; struct rb_node *n = iint_rb_root->rb_node;
while (n) { while (n) {
iint = rb_entry(n, struct integrity_iint_cache, rb_node); iint = rb_entry(n, struct integrity_iint_cache, rb_node);
...@@ -52,22 +62,37 @@ static struct integrity_iint_cache *__integrity_iint_find(struct inode *inode) ...@@ -52,22 +62,37 @@ static struct integrity_iint_cache *__integrity_iint_find(struct inode *inode)
} }
/* /*
* integrity_iint_find - return the iint associated with an inode * integrity_iint_rb_find - return the iint associated with an inode
* @iint_tree: pointer to the iint tree root node and the associated lock
* @inode: pointer to the inode
* @return: pointer to the iint if found, NULL otherwise
*/ */
struct integrity_iint_cache *integrity_iint_find(struct inode *inode) struct integrity_iint_cache *integrity_iint_rb_find(struct integrity_iint_tree
*iint_tree,
const struct inode *inode)
{ {
struct integrity_iint_cache *iint; struct integrity_iint_cache *iint;
if (!IS_IMA(inode)) if (!IS_IMA(inode))
return NULL; return NULL;
read_lock(&integrity_iint_lock); read_lock(&iint_tree->lock);
iint = __integrity_iint_find(inode); iint = __integrity_iint_rb_find(&iint_tree->root, inode);
read_unlock(&integrity_iint_lock); read_unlock(&iint_tree->lock);
return iint; return iint;
} }
/*
* integrity_iint_find - return the iint associated with an inode
* @inode: pointer to the inode
* @return: pointer to the iint if found, NULL otherwise
*/
struct integrity_iint_cache *integrity_iint_find(struct inode *inode)
{
return integrity_iint_rb_find(&init_iint_tree, inode);
}
static void iint_free(struct integrity_iint_cache *iint) static void iint_free(struct integrity_iint_cache *iint)
{ {
kfree(iint->ima_hash); kfree(iint->ima_hash);
...@@ -86,13 +111,36 @@ static void iint_free(struct integrity_iint_cache *iint) ...@@ -86,13 +111,36 @@ static void iint_free(struct integrity_iint_cache *iint)
} }
/** /**
* integrity_inode_get - find or allocate an iint associated with an inode * integrity_iint_tree_free - traverse the tree and free all nodes
* @iint_tree: pointer to the iint tree root node and the associated lock
*
* The tree cannot be in use. This function should be called only from the
* destructor when no locks are required.
*/
void integrity_iint_tree_free(struct integrity_iint_tree *iint_tree)
{
struct rb_root *root = &iint_tree->root;
struct integrity_iint_cache *iint, *tmp;
rbtree_postorder_for_each_entry_safe(iint, tmp, root, rb_node) {
iint_free(iint);
}
iint_tree->root = RB_ROOT;
}
/**
* integrity_inode_rb_get - find or allocate an iint associated with an inode
* @iint_tree: pointer to the iint tree root node and the associated lock
* @inode: pointer to the inode * @inode: pointer to the inode
* @return: allocated iint * @return: pointer to the existing iint if found, pointer to the allocated iint
* if it didn't exist, NULL in case of error
* *
* Caller must lock i_mutex * Caller must lock i_mutex
*/ */
struct integrity_iint_cache *integrity_inode_get(struct inode *inode) struct integrity_iint_cache *integrity_inode_rb_get(struct integrity_iint_tree
*iint_tree,
struct inode *inode)
{ {
struct rb_node **p; struct rb_node **p;
struct rb_node *node, *parent = NULL; struct rb_node *node, *parent = NULL;
...@@ -106,7 +154,7 @@ struct integrity_iint_cache *integrity_inode_get(struct inode *inode) ...@@ -106,7 +154,7 @@ struct integrity_iint_cache *integrity_inode_get(struct inode *inode)
if (!iint_cache) if (!iint_cache)
panic("%s: lsm=integrity required.\n", __func__); panic("%s: lsm=integrity required.\n", __func__);
iint = integrity_iint_find(inode); iint = integrity_iint_rb_find(iint_tree, inode);
if (iint) if (iint)
return iint; return iint;
...@@ -114,9 +162,9 @@ struct integrity_iint_cache *integrity_inode_get(struct inode *inode) ...@@ -114,9 +162,9 @@ struct integrity_iint_cache *integrity_inode_get(struct inode *inode)
if (!iint) if (!iint)
return NULL; return NULL;
write_lock(&integrity_iint_lock); write_lock(&iint_tree->lock);
p = &integrity_iint_tree.rb_node; p = &iint_tree->root.rb_node;
while (*p) { while (*p) {
parent = *p; parent = *p;
test_iint = rb_entry(parent, struct integrity_iint_cache, test_iint = rb_entry(parent, struct integrity_iint_cache,
...@@ -131,33 +179,63 @@ struct integrity_iint_cache *integrity_inode_get(struct inode *inode) ...@@ -131,33 +179,63 @@ struct integrity_iint_cache *integrity_inode_get(struct inode *inode)
node = &iint->rb_node; node = &iint->rb_node;
inode->i_flags |= S_IMA; inode->i_flags |= S_IMA;
rb_link_node(node, parent, p); rb_link_node(node, parent, p);
rb_insert_color(node, &integrity_iint_tree); rb_insert_color(node, &iint_tree->root);
write_unlock(&integrity_iint_lock); write_unlock(&iint_tree->lock);
return iint; return iint;
} }
/** /**
* integrity_inode_free - called on security_inode_free * integrity_inode_get - find or allocate an iint associated with an inode
* @inode: pointer to the inode
* @return: pointer to the existing iint if found, pointer to the allocated iint
* if it didn't exist, NULL in case of error
*
* Caller must lock i_mutex
*/
struct integrity_iint_cache *integrity_inode_get(struct inode *inode)
{
return integrity_inode_rb_get(&init_iint_tree, inode);
}
/**
* integrity_inode_rb_free - called on security_inode_free
* @iint_tree: pointer to the iint tree root node and the associated lock
* @inode: pointer to the inode * @inode: pointer to the inode
* *
* Free the integrity information(iint) associated with an inode. * Free the integrity information(iint) associated with an inode.
*/ */
void integrity_inode_free(struct inode *inode) void integrity_inode_rb_free(struct integrity_iint_tree *iint_tree,
struct inode *inode)
{ {
struct integrity_iint_cache *iint; struct integrity_iint_cache *iint;
if (!IS_IMA(inode)) if (!IS_IMA(inode))
return; return;
write_lock(&integrity_iint_lock); write_lock(&iint_tree->lock);
iint = __integrity_iint_find(inode); iint = __integrity_iint_rb_find(&iint_tree->root, inode);
rb_erase(&iint->rb_node, &integrity_iint_tree); if (!iint) {
write_unlock(&integrity_iint_lock); write_unlock(&iint_tree->lock);
return;
}
rb_erase(&iint->rb_node, &iint_tree->root);
write_unlock(&iint_tree->lock);
iint_free(iint); iint_free(iint);
} }
/**
* integrity_inode_free - called on security_inode_free
* @inode: pointer to the inode
*
* Free the integrity information(iint) associated with an inode.
*/
void integrity_inode_free(struct inode *inode)
{
integrity_inode_rb_free(&init_iint_tree, inode);
}
static void init_once(void *foo) static void init_once(void *foo)
{ {
struct integrity_iint_cache *iint = foo; struct integrity_iint_cache *iint = foo;
......
...@@ -184,11 +184,20 @@ static inline void ima_load_digest_lists(void) ...@@ -184,11 +184,20 @@ static inline void ima_load_digest_lists(void)
} }
#endif #endif
struct integrity_iint_tree {
rwlock_t lock;
struct rb_root root;
};
/* rbtree tree calls to lookup, insert, delete /* rbtree tree calls to lookup, insert, delete
* integrity data associated with an inode. * integrity data associated with an inode.
*/ */
struct integrity_iint_cache *integrity_iint_find(struct inode *inode); struct integrity_iint_cache *integrity_iint_find(struct inode *inode);
struct integrity_iint_cache *integrity_iint_rb_find(struct integrity_iint_tree
*iint_tree,
const struct inode *inode);
int integrity_kernel_read(struct file *file, loff_t offset, int integrity_kernel_read(struct file *file, loff_t offset,
void *addr, unsigned long count); void *addr, unsigned long count);
...@@ -199,6 +208,8 @@ int integrity_kernel_read(struct file *file, loff_t offset, ...@@ -199,6 +208,8 @@ int integrity_kernel_read(struct file *file, loff_t offset,
extern struct dentry *integrity_dir; extern struct dentry *integrity_dir;
extern struct integrity_iint_tree init_iint_tree;
struct modsig; struct modsig;
#ifdef CONFIG_INTEGRITY_SIGNATURE #ifdef CONFIG_INTEGRITY_SIGNATURE
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册