aboutsummaryrefslogtreecommitdiffstats
path: root/security/integrity/ima/ima_iint.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/integrity/ima/ima_iint.c')
-rw-r--r--security/integrity/ima/ima_iint.c153
1 files changed, 87 insertions, 66 deletions
diff --git a/security/integrity/ima/ima_iint.c b/security/integrity/ima/ima_iint.c
index afba4aef812f..4ae73040ab7b 100644
--- a/security/integrity/ima/ima_iint.c
+++ b/security/integrity/ima/ima_iint.c
@@ -12,98 +12,119 @@
12 * File: ima_iint.c 12 * File: ima_iint.c
13 * - implements the IMA hooks: ima_inode_alloc, ima_inode_free 13 * - implements the IMA hooks: ima_inode_alloc, ima_inode_free
14 * - cache integrity information associated with an inode 14 * - cache integrity information associated with an inode
15 * using a radix tree. 15 * using a rbtree tree.
16 */ 16 */
17#include <linux/slab.h> 17#include <linux/slab.h>
18#include <linux/module.h> 18#include <linux/module.h>
19#include <linux/spinlock.h> 19#include <linux/spinlock.h>
20#include <linux/radix-tree.h> 20#include <linux/rbtree.h>
21#include "ima.h" 21#include "ima.h"
22 22
23RADIX_TREE(ima_iint_store, GFP_ATOMIC); 23static struct rb_root ima_iint_tree = RB_ROOT;
24DEFINE_SPINLOCK(ima_iint_lock); 24static DEFINE_SPINLOCK(ima_iint_lock);
25static struct kmem_cache *iint_cache __read_mostly; 25static struct kmem_cache *iint_cache __read_mostly;
26 26
27int iint_initialized = 0; 27int iint_initialized = 0;
28 28
29/* ima_iint_find_get - return the iint associated with an inode 29/*
30 * 30 * __ima_iint_find - return the iint associated with an inode
31 * ima_iint_find_get gets a reference to the iint. Caller must
32 * remember to put the iint reference.
33 */ 31 */
34struct ima_iint_cache *ima_iint_find_get(struct inode *inode) 32static struct ima_iint_cache *__ima_iint_find(struct inode *inode)
35{ 33{
36 struct ima_iint_cache *iint; 34 struct ima_iint_cache *iint;
35 struct rb_node *n = ima_iint_tree.rb_node;
36
37 assert_spin_locked(&ima_iint_lock);
38
39 while (n) {
40 iint = rb_entry(n, struct ima_iint_cache, rb_node);
41
42 if (inode < iint->inode)
43 n = n->rb_left;
44 else if (inode > iint->inode)
45 n = n->rb_right;
46 else
47 break;
48 }
49 if (!n)
50 return NULL;
37 51
38 rcu_read_lock();
39 iint = radix_tree_lookup(&ima_iint_store, (unsigned long)inode);
40 if (!iint)
41 goto out;
42 kref_get(&iint->refcount);
43out:
44 rcu_read_unlock();
45 return iint; 52 return iint;
46} 53}
47 54
48/** 55/*
49 * ima_inode_alloc - allocate an iint associated with an inode 56 * ima_iint_find - return the iint associated with an inode
50 * @inode: pointer to the inode
51 */ 57 */
52int ima_inode_alloc(struct inode *inode) 58struct ima_iint_cache *ima_iint_find(struct inode *inode)
53{ 59{
54 struct ima_iint_cache *iint = NULL; 60 struct ima_iint_cache *iint;
55 int rc = 0;
56
57 iint = kmem_cache_alloc(iint_cache, GFP_NOFS);
58 if (!iint)
59 return -ENOMEM;
60 61
61 rc = radix_tree_preload(GFP_NOFS); 62 if (!IS_IMA(inode))
62 if (rc < 0) 63 return NULL;
63 goto out;
64 64
65 spin_lock(&ima_iint_lock); 65 spin_lock(&ima_iint_lock);
66 rc = radix_tree_insert(&ima_iint_store, (unsigned long)inode, iint); 66 iint = __ima_iint_find(inode);
67 spin_unlock(&ima_iint_lock); 67 spin_unlock(&ima_iint_lock);
68 radix_tree_preload_end();
69out:
70 if (rc < 0)
71 kmem_cache_free(iint_cache, iint);
72 68
73 return rc; 69 return iint;
74} 70}
75 71
76/* iint_free - called when the iint refcount goes to zero */ 72static void iint_free(struct ima_iint_cache *iint)
77void iint_free(struct kref *kref)
78{ 73{
79 struct ima_iint_cache *iint = container_of(kref, struct ima_iint_cache,
80 refcount);
81 iint->version = 0; 74 iint->version = 0;
82 iint->flags = 0UL; 75 iint->flags = 0UL;
83 if (iint->readcount != 0) {
84 printk(KERN_INFO "%s: readcount: %ld\n", __func__,
85 iint->readcount);
86 iint->readcount = 0;
87 }
88 if (iint->writecount != 0) {
89 printk(KERN_INFO "%s: writecount: %ld\n", __func__,
90 iint->writecount);
91 iint->writecount = 0;
92 }
93 if (iint->opencount != 0) {
94 printk(KERN_INFO "%s: opencount: %ld\n", __func__,
95 iint->opencount);
96 iint->opencount = 0;
97 }
98 kref_init(&iint->refcount);
99 kmem_cache_free(iint_cache, iint); 76 kmem_cache_free(iint_cache, iint);
100} 77}
101 78
102void iint_rcu_free(struct rcu_head *rcu_head) 79/**
80 * ima_inode_alloc - allocate an iint associated with an inode
81 * @inode: pointer to the inode
82 */
83int ima_inode_alloc(struct inode *inode)
103{ 84{
104 struct ima_iint_cache *iint = container_of(rcu_head, 85 struct rb_node **p;
105 struct ima_iint_cache, rcu); 86 struct rb_node *new_node, *parent = NULL;
106 kref_put(&iint->refcount, iint_free); 87 struct ima_iint_cache *new_iint, *test_iint;
88 int rc;
89
90 new_iint = kmem_cache_alloc(iint_cache, GFP_NOFS);
91 if (!new_iint)
92 return -ENOMEM;
93
94 new_iint->inode = inode;
95 new_node = &new_iint->rb_node;
96
97 mutex_lock(&inode->i_mutex); /* i_flags */
98 spin_lock(&ima_iint_lock);
99
100 p = &ima_iint_tree.rb_node;
101 while (*p) {
102 parent = *p;
103 test_iint = rb_entry(parent, struct ima_iint_cache, rb_node);
104
105 rc = -EEXIST;
106 if (inode < test_iint->inode)
107 p = &(*p)->rb_left;
108 else if (inode > test_iint->inode)
109 p = &(*p)->rb_right;
110 else
111 goto out_err;
112 }
113
114 inode->i_flags |= S_IMA;
115 rb_link_node(new_node, parent, p);
116 rb_insert_color(new_node, &ima_iint_tree);
117
118 spin_unlock(&ima_iint_lock);
119 mutex_unlock(&inode->i_mutex); /* i_flags */
120
121 return 0;
122out_err:
123 spin_unlock(&ima_iint_lock);
124 mutex_unlock(&inode->i_mutex); /* i_flags */
125 iint_free(new_iint);
126
127 return rc;
107} 128}
108 129
109/** 130/**
@@ -116,11 +137,15 @@ void ima_inode_free(struct inode *inode)
116{ 137{
117 struct ima_iint_cache *iint; 138 struct ima_iint_cache *iint;
118 139
140 if (!IS_IMA(inode))
141 return;
142
119 spin_lock(&ima_iint_lock); 143 spin_lock(&ima_iint_lock);
120 iint = radix_tree_delete(&ima_iint_store, (unsigned long)inode); 144 iint = __ima_iint_find(inode);
145 rb_erase(&iint->rb_node, &ima_iint_tree);
121 spin_unlock(&ima_iint_lock); 146 spin_unlock(&ima_iint_lock);
122 if (iint) 147
123 call_rcu(&iint->rcu, iint_rcu_free); 148 iint_free(iint);
124} 149}
125 150
126static void init_once(void *foo) 151static void init_once(void *foo)
@@ -131,10 +156,6 @@ static void init_once(void *foo)
131 iint->version = 0; 156 iint->version = 0;
132 iint->flags = 0UL; 157 iint->flags = 0UL;
133 mutex_init(&iint->mutex); 158 mutex_init(&iint->mutex);
134 iint->readcount = 0;
135 iint->writecount = 0;
136 iint->opencount = 0;
137 kref_init(&iint->refcount);
138} 159}
139 160
140static int __init ima_iintcache_init(void) 161static int __init ima_iintcache_init(void)