lkml.org 
[lkml]   [2020]   [Aug]   [18]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[RFC PATCH 07/30] ima: Extend the APIs in the integrity subsystem
    Date
    From: Krzysztof Struczynski <krzysztof.struczynski@huawei.com>

    Inode integrity cache will be maintained per ima namespace. Add new
    functions that allow to specify the iint tree to use.

    Signed-off-by: Krzysztof Struczynski <krzysztof.struczynski@huawei.com>
    ---
    include/linux/integrity.h | 31 ++++++++
    security/integrity/iint.c | 126 ++++++++++++++++++++++++++-------
    security/integrity/integrity.h | 11 +++
    3 files changed, 144 insertions(+), 24 deletions(-)

    diff --git a/include/linux/integrity.h b/include/linux/integrity.h
    index 2271939c5c31..5019fedaa17a 100644
    --- a/include/linux/integrity.h
    +++ b/include/linux/integrity.h
    @@ -8,6 +8,10 @@
    #define _LINUX_INTEGRITY_H

    #include <linux/fs.h>
    +#include <linux/rwlock_types.h>
    +
    +struct rb_root;
    +struct integrity_iint_tree;

    enum integrity_status {
    INTEGRITY_PASS = 0,
    @@ -21,8 +25,15 @@ enum integrity_status {
    /* List of EVM protected security xattrs */
    #ifdef CONFIG_INTEGRITY
    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_rb_free(struct integrity_iint_tree *iint_tree,
    + struct inode *inode);
    extern void __init integrity_load_keys(void);
    +extern void integrity_iint_tree_free(struct integrity_iint_tree *iint_tree);

    #else
    static inline struct integrity_iint_cache *
    @@ -31,14 +42,34 @@ static inline struct integrity_iint_cache *
    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)
    {
    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_iint_tree_free(struct integrity_iint_tree
    + *iint_tree)
    +{
    +}
    #endif /* CONFIG_INTEGRITY */

    #ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS
    diff --git a/security/integrity/iint.c b/security/integrity/iint.c
    index 1d20003243c3..34a36f298f92 100644
    --- a/security/integrity/iint.c
    +++ b/security/integrity/iint.c
    @@ -21,19 +21,29 @@
    #include <linux/lsm_hooks.h>
    #include "integrity.h"

    -static struct rb_root integrity_iint_tree = RB_ROOT;
    -static DEFINE_RWLOCK(integrity_iint_lock);
    +struct integrity_iint_tree init_iint_tree = {
    + .lock = __RW_LOCK_UNLOCKED(init_iint_tree.lock),
    + .root = RB_ROOT
    +};
    +
    static struct kmem_cache *iint_cache __read_mostly;

    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 rb_node *n = integrity_iint_tree.rb_node;
    + struct rb_node *n = iint_rb_root->rb_node;

    while (n) {
    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)
    }

    /*
    - * 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;

    if (!IS_IMA(inode))
    return NULL;

    - read_lock(&integrity_iint_lock);
    - iint = __integrity_iint_find(inode);
    - read_unlock(&integrity_iint_lock);
    + read_lock(&iint_tree->lock);
    + iint = __integrity_iint_rb_find(&iint_tree->root, inode);
    + read_unlock(&iint_tree->lock);

    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)
    {
    kfree(iint->ima_hash);
    @@ -86,19 +111,42 @@ 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
    - * @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
    */
    -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 *node, *parent = NULL;
    struct integrity_iint_cache *iint, *test_iint;

    - iint = integrity_iint_find(inode);
    + iint = integrity_iint_rb_find(iint_tree, inode);
    if (iint)
    return iint;

    @@ -106,9 +154,9 @@ struct integrity_iint_cache *integrity_inode_get(struct inode *inode)
    if (!iint)
    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) {
    parent = *p;
    test_iint = rb_entry(parent, struct integrity_iint_cache,
    @@ -123,33 +171,63 @@ struct integrity_iint_cache *integrity_inode_get(struct inode *inode)
    node = &iint->rb_node;
    inode->i_flags |= S_IMA;
    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;
    }

    /**
    - * 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
    *
    * 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;

    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);
    + write_lock(&iint_tree->lock);
    + iint = __integrity_iint_rb_find(&iint_tree->root, inode);
    + if (!iint) {
    + write_unlock(&iint_tree->lock);
    + return;
    + }
    + rb_erase(&iint->rb_node, &iint_tree->root);
    + write_unlock(&iint_tree->lock);

    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)
    {
    struct integrity_iint_cache *iint = foo;
    diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
    index 413c803c5208..721d1850e4f9 100644
    --- a/security/integrity/integrity.h
    +++ b/security/integrity/integrity.h
    @@ -140,11 +140,20 @@ struct integrity_iint_cache {
    struct ima_digest_data *ima_hash;
    };

    +struct integrity_iint_tree {
    + rwlock_t lock;
    + struct rb_root root;
    +};
    +
    /* rbtree tree calls to lookup, insert, delete
    * integrity data associated with an 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,
    void *addr, unsigned long count);

    @@ -155,6 +164,8 @@ int integrity_kernel_read(struct file *file, loff_t offset,

    extern struct dentry *integrity_dir;

    +extern struct integrity_iint_tree init_iint_tree;
    +
    struct modsig;

    #ifdef CONFIG_INTEGRITY_SIGNATURE
    --
    2.20.1
    \
     
     \ /
      Last update: 2020-08-18 17:27    [W:3.672 / U:0.008 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site