1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (C) 2008 IBM Corporation |
4 | * |
5 | * Authors: |
6 | * Mimi Zohar <zohar@us.ibm.com> |
7 | * |
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. |
13 | */ |
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 | #include <linux/security.h> |
21 | #include <linux/lsm_hooks.h> |
22 | #include "integrity.h" |
23 | |
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 | struct dentry *integrity_dir; |
29 | |
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(objp: iint->ima_hash); |
113 | mutex_destroy(lock: &iint->mutex); |
114 | kmem_cache_free(s: iint_cache, objp: 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(cachep: 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(s: iint_cache, objp: 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, rb_link: 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(name: "iint_cache" , size: sizeof(struct integrity_iint_cache), |
200 | align: 0, SLAB_PANIC, ctor: 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 | /* |
211 | * integrity_kernel_read - read data from the file |
212 | * |
213 | * This is a function for reading file content instead of kernel_read(). |
214 | * It does not perform locking checks to ensure it cannot be blocked. |
215 | * It does not perform security checks because it is irrelevant for IMA. |
216 | * |
217 | */ |
218 | int integrity_kernel_read(struct file *file, loff_t offset, |
219 | void *addr, unsigned long count) |
220 | { |
221 | return __kernel_read(file, buf: addr, count, pos: &offset); |
222 | } |
223 | |
224 | /* |
225 | * integrity_load_keys - load integrity keys hook |
226 | * |
227 | * Hooks is called from init/main.c:kernel_init_freeable() |
228 | * when rootfs is ready |
229 | */ |
230 | void __init integrity_load_keys(void) |
231 | { |
232 | ima_load_x509(); |
233 | |
234 | if (!IS_ENABLED(CONFIG_IMA_LOAD_X509)) |
235 | evm_load_x509(); |
236 | } |
237 | |
238 | static int __init integrity_fs_init(void) |
239 | { |
240 | integrity_dir = securityfs_create_dir(name: "integrity" , NULL); |
241 | if (IS_ERR(ptr: integrity_dir)) { |
242 | int ret = PTR_ERR(ptr: integrity_dir); |
243 | |
244 | if (ret != -ENODEV) |
245 | pr_err("Unable to create integrity sysfs dir: %d\n" , |
246 | ret); |
247 | integrity_dir = NULL; |
248 | return ret; |
249 | } |
250 | |
251 | return 0; |
252 | } |
253 | |
254 | late_initcall(integrity_fs_init) |
255 | |