|
6 | 6 | |
7 | 7 | * |
8 | 8 | * File: integrity_iint.c |
9 | | - * - implements the integrity hooks: integrity_inode_alloc, |
10 | | - * integrity_inode_free |
11 | | - * - cache integrity information associated with an inode |
12 | | - * using a rbtree tree. |
| 9 | + * - initialize the integrity directory in securityfs |
| 10 | + * - load IMA and EVM keys |
13 | 11 | */ |
14 | | -#include <linux/slab.h> |
15 | | -#include <linux/init.h> |
16 | | -#include <linux/spinlock.h> |
17 | | -#include <linux/rbtree.h> |
18 | | -#include <linux/file.h> |
19 | | -#include <linux/uaccess.h> |
20 | 12 | #include <linux/security.h> |
21 | | -#include <linux/lsm_hooks.h> |
22 | 13 | #include "integrity.h" |
23 | 14 |
|
24 | | -static struct rb_root integrity_iint_tree = RB_ROOT; |
25 | | -static DEFINE_RWLOCK(integrity_iint_lock); |
26 | | -static struct kmem_cache *iint_cache __ro_after_init; |
27 | | - |
28 | 15 | struct dentry *integrity_dir; |
29 | 16 |
|
30 | | -/* |
31 | | - * __integrity_iint_find - return the iint associated with an inode |
32 | | - */ |
33 | | -static struct integrity_iint_cache *__integrity_iint_find(struct inode *inode) |
34 | | -{ |
35 | | - struct integrity_iint_cache *iint; |
36 | | - struct rb_node *n = integrity_iint_tree.rb_node; |
37 | | - |
38 | | - while (n) { |
39 | | - iint = rb_entry(n, struct integrity_iint_cache, rb_node); |
40 | | - |
41 | | - if (inode < iint->inode) |
42 | | - n = n->rb_left; |
43 | | - else if (inode > iint->inode) |
44 | | - n = n->rb_right; |
45 | | - else |
46 | | - return iint; |
47 | | - } |
48 | | - |
49 | | - return NULL; |
50 | | -} |
51 | | - |
52 | | -/* |
53 | | - * integrity_iint_find - return the iint associated with an inode |
54 | | - */ |
55 | | -struct integrity_iint_cache *integrity_iint_find(struct inode *inode) |
56 | | -{ |
57 | | - struct integrity_iint_cache *iint; |
58 | | - |
59 | | - if (!IS_IMA(inode)) |
60 | | - return NULL; |
61 | | - |
62 | | - read_lock(&integrity_iint_lock); |
63 | | - iint = __integrity_iint_find(inode); |
64 | | - read_unlock(&integrity_iint_lock); |
65 | | - |
66 | | - return iint; |
67 | | -} |
68 | | - |
69 | | -#define IMA_MAX_NESTING (FILESYSTEM_MAX_STACK_DEPTH+1) |
70 | | - |
71 | | -/* |
72 | | - * It is not clear that IMA should be nested at all, but as long is it measures |
73 | | - * files both on overlayfs and on underlying fs, we need to annotate the iint |
74 | | - * mutex to avoid lockdep false positives related to IMA + overlayfs. |
75 | | - * See ovl_lockdep_annotate_inode_mutex_key() for more details. |
76 | | - */ |
77 | | -static inline void iint_lockdep_annotate(struct integrity_iint_cache *iint, |
78 | | - struct inode *inode) |
79 | | -{ |
80 | | -#ifdef CONFIG_LOCKDEP |
81 | | - static struct lock_class_key iint_mutex_key[IMA_MAX_NESTING]; |
82 | | - |
83 | | - int depth = inode->i_sb->s_stack_depth; |
84 | | - |
85 | | - if (WARN_ON_ONCE(depth < 0 || depth >= IMA_MAX_NESTING)) |
86 | | - depth = 0; |
87 | | - |
88 | | - lockdep_set_class(&iint->mutex, &iint_mutex_key[depth]); |
89 | | -#endif |
90 | | -} |
91 | | - |
92 | | -static void iint_init_always(struct integrity_iint_cache *iint, |
93 | | - struct inode *inode) |
94 | | -{ |
95 | | - iint->ima_hash = NULL; |
96 | | - iint->version = 0; |
97 | | - iint->flags = 0UL; |
98 | | - iint->atomic_flags = 0UL; |
99 | | - iint->ima_file_status = INTEGRITY_UNKNOWN; |
100 | | - iint->ima_mmap_status = INTEGRITY_UNKNOWN; |
101 | | - iint->ima_bprm_status = INTEGRITY_UNKNOWN; |
102 | | - iint->ima_read_status = INTEGRITY_UNKNOWN; |
103 | | - iint->ima_creds_status = INTEGRITY_UNKNOWN; |
104 | | - iint->evm_status = INTEGRITY_UNKNOWN; |
105 | | - iint->measured_pcrs = 0; |
106 | | - mutex_init(&iint->mutex); |
107 | | - iint_lockdep_annotate(iint, inode); |
108 | | -} |
109 | | - |
110 | | -static void iint_free(struct integrity_iint_cache *iint) |
111 | | -{ |
112 | | - kfree(iint->ima_hash); |
113 | | - mutex_destroy(&iint->mutex); |
114 | | - kmem_cache_free(iint_cache, iint); |
115 | | -} |
116 | | - |
117 | | -/** |
118 | | - * integrity_inode_get - find or allocate an iint associated with an inode |
119 | | - * @inode: pointer to the inode |
120 | | - * @return: allocated iint |
121 | | - * |
122 | | - * Caller must lock i_mutex |
123 | | - */ |
124 | | -struct integrity_iint_cache *integrity_inode_get(struct inode *inode) |
125 | | -{ |
126 | | - struct rb_node **p; |
127 | | - struct rb_node *node, *parent = NULL; |
128 | | - struct integrity_iint_cache *iint, *test_iint; |
129 | | - |
130 | | - iint = integrity_iint_find(inode); |
131 | | - if (iint) |
132 | | - return iint; |
133 | | - |
134 | | - iint = kmem_cache_alloc(iint_cache, GFP_NOFS); |
135 | | - if (!iint) |
136 | | - return NULL; |
137 | | - |
138 | | - iint_init_always(iint, inode); |
139 | | - |
140 | | - write_lock(&integrity_iint_lock); |
141 | | - |
142 | | - p = &integrity_iint_tree.rb_node; |
143 | | - while (*p) { |
144 | | - parent = *p; |
145 | | - test_iint = rb_entry(parent, struct integrity_iint_cache, |
146 | | - rb_node); |
147 | | - if (inode < test_iint->inode) { |
148 | | - p = &(*p)->rb_left; |
149 | | - } else if (inode > test_iint->inode) { |
150 | | - p = &(*p)->rb_right; |
151 | | - } else { |
152 | | - write_unlock(&integrity_iint_lock); |
153 | | - kmem_cache_free(iint_cache, iint); |
154 | | - return test_iint; |
155 | | - } |
156 | | - } |
157 | | - |
158 | | - iint->inode = inode; |
159 | | - node = &iint->rb_node; |
160 | | - inode->i_flags |= S_IMA; |
161 | | - rb_link_node(node, parent, p); |
162 | | - rb_insert_color(node, &integrity_iint_tree); |
163 | | - |
164 | | - write_unlock(&integrity_iint_lock); |
165 | | - return iint; |
166 | | -} |
167 | | - |
168 | | -/** |
169 | | - * integrity_inode_free - called on security_inode_free |
170 | | - * @inode: pointer to the inode |
171 | | - * |
172 | | - * Free the integrity information(iint) associated with an inode. |
173 | | - */ |
174 | | -void integrity_inode_free(struct inode *inode) |
175 | | -{ |
176 | | - struct integrity_iint_cache *iint; |
177 | | - |
178 | | - if (!IS_IMA(inode)) |
179 | | - return; |
180 | | - |
181 | | - write_lock(&integrity_iint_lock); |
182 | | - iint = __integrity_iint_find(inode); |
183 | | - rb_erase(&iint->rb_node, &integrity_iint_tree); |
184 | | - write_unlock(&integrity_iint_lock); |
185 | | - |
186 | | - iint_free(iint); |
187 | | -} |
188 | | - |
189 | | -static void iint_init_once(void *foo) |
190 | | -{ |
191 | | - struct integrity_iint_cache *iint = (struct integrity_iint_cache *) foo; |
192 | | - |
193 | | - memset(iint, 0, sizeof(*iint)); |
194 | | -} |
195 | | - |
196 | | -static int __init integrity_iintcache_init(void) |
197 | | -{ |
198 | | - iint_cache = |
199 | | - kmem_cache_create("iint_cache", sizeof(struct integrity_iint_cache), |
200 | | - 0, SLAB_PANIC, iint_init_once); |
201 | | - return 0; |
202 | | -} |
203 | | -DEFINE_LSM(integrity) = { |
204 | | - .name = "integrity", |
205 | | - .init = integrity_iintcache_init, |
206 | | - .order = LSM_ORDER_LAST, |
207 | | -}; |
208 | | - |
209 | | - |
210 | 17 | /* |
211 | 18 | * integrity_kernel_read - read data from the file |
212 | 19 | * |
|
0 commit comments