Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0-only
2#include <linux/codetag.h>
3#include <linux/idr.h>
4#include <linux/kallsyms.h>
5#include <linux/module.h>
6#include <linux/seq_buf.h>
7#include <linux/slab.h>
8#include <linux/vmalloc.h>
9
10struct codetag_type {
11 struct list_head link;
12 unsigned int count;
13 struct idr mod_idr;
14 struct rw_semaphore mod_lock; /* protects mod_idr */
15 struct codetag_type_desc desc;
16};
17
18struct codetag_range {
19 struct codetag *start;
20 struct codetag *stop;
21};
22
23struct codetag_module {
24 struct module *mod;
25 struct codetag_range range;
26};
27
28static DEFINE_MUTEX(codetag_lock);
29static LIST_HEAD(codetag_types);
30
31void codetag_lock_module_list(struct codetag_type *cttype, bool lock)
32{
33 if (lock)
34 down_read(&cttype->mod_lock);
35 else
36 up_read(&cttype->mod_lock);
37}
38
39bool codetag_trylock_module_list(struct codetag_type *cttype)
40{
41 return down_read_trylock(&cttype->mod_lock) != 0;
42}
43
44struct codetag_iterator codetag_get_ct_iter(struct codetag_type *cttype)
45{
46 struct codetag_iterator iter = {
47 .cttype = cttype,
48 .cmod = NULL,
49 .mod_id = 0,
50 .ct = NULL,
51 };
52
53 return iter;
54}
55
56static inline struct codetag *get_first_module_ct(struct codetag_module *cmod)
57{
58 return cmod->range.start < cmod->range.stop ? cmod->range.start : NULL;
59}
60
61static inline
62struct codetag *get_next_module_ct(struct codetag_iterator *iter)
63{
64 struct codetag *res = (struct codetag *)
65 ((char *)iter->ct + iter->cttype->desc.tag_size);
66
67 return res < iter->cmod->range.stop ? res : NULL;
68}
69
70struct codetag *codetag_next_ct(struct codetag_iterator *iter)
71{
72 struct codetag_type *cttype = iter->cttype;
73 struct codetag_module *cmod;
74 struct codetag *ct;
75
76 lockdep_assert_held(&cttype->mod_lock);
77
78 if (unlikely(idr_is_empty(&cttype->mod_idr)))
79 return NULL;
80
81 ct = NULL;
82 while (true) {
83 cmod = idr_find(&cttype->mod_idr, iter->mod_id);
84
85 /* If module was removed move to the next one */
86 if (!cmod)
87 cmod = idr_get_next_ul(&cttype->mod_idr,
88 &iter->mod_id);
89
90 /* Exit if no more modules */
91 if (!cmod)
92 break;
93
94 if (cmod != iter->cmod) {
95 iter->cmod = cmod;
96 ct = get_first_module_ct(cmod);
97 } else
98 ct = get_next_module_ct(iter);
99
100 if (ct)
101 break;
102
103 iter->mod_id++;
104 }
105
106 iter->ct = ct;
107 return ct;
108}
109
110void codetag_to_text(struct seq_buf *out, struct codetag *ct)
111{
112 if (ct->modname)
113 seq_buf_printf(out, "%s:%u [%s] func:%s",
114 ct->filename, ct->lineno,
115 ct->modname, ct->function);
116 else
117 seq_buf_printf(out, "%s:%u func:%s",
118 ct->filename, ct->lineno, ct->function);
119}
120
121static inline size_t range_size(const struct codetag_type *cttype,
122 const struct codetag_range *range)
123{
124 return ((char *)range->stop - (char *)range->start) /
125 cttype->desc.tag_size;
126}
127
128static void *get_symbol(struct module *mod, const char *prefix, const char *name)
129{
130 DECLARE_SEQ_BUF(sb, KSYM_NAME_LEN);
131 const char *buf;
132 void *ret;
133
134 seq_buf_printf(&sb, "%s%s", prefix, name);
135 if (seq_buf_has_overflowed(&sb))
136 return NULL;
137
138 buf = seq_buf_str(&sb);
139 preempt_disable();
140 ret = mod ?
141 (void *)find_kallsyms_symbol_value(mod, buf) :
142 (void *)kallsyms_lookup_name(buf);
143 preempt_enable();
144
145 return ret;
146}
147
148static struct codetag_range get_section_range(struct module *mod,
149 const char *section)
150{
151 return (struct codetag_range) {
152 get_symbol(mod, "__start_", section),
153 get_symbol(mod, "__stop_", section),
154 };
155}
156
157static const char *get_mod_name(__maybe_unused struct module *mod)
158{
159#ifdef CONFIG_MODULES
160 if (mod)
161 return mod->name;
162#endif
163 return "(built-in)";
164}
165
166static int codetag_module_init(struct codetag_type *cttype, struct module *mod)
167{
168 struct codetag_range range;
169 struct codetag_module *cmod;
170 int err;
171
172 range = get_section_range(mod, cttype->desc.section);
173 if (!range.start || !range.stop) {
174 pr_warn("Failed to load code tags of type %s from the module %s\n",
175 cttype->desc.section, get_mod_name(mod));
176 return -EINVAL;
177 }
178
179 /* Ignore empty ranges */
180 if (range.start == range.stop)
181 return 0;
182
183 BUG_ON(range.start > range.stop);
184
185 cmod = kmalloc(sizeof(*cmod), GFP_KERNEL);
186 if (unlikely(!cmod))
187 return -ENOMEM;
188
189 cmod->mod = mod;
190 cmod->range = range;
191
192 down_write(&cttype->mod_lock);
193 err = idr_alloc(&cttype->mod_idr, cmod, 0, 0, GFP_KERNEL);
194 if (err >= 0) {
195 cttype->count += range_size(cttype, &range);
196 if (cttype->desc.module_load)
197 cttype->desc.module_load(cttype, cmod);
198 }
199 up_write(&cttype->mod_lock);
200
201 if (err < 0) {
202 kfree(cmod);
203 return err;
204 }
205
206 return 0;
207}
208
209#ifdef CONFIG_MODULES
210void codetag_load_module(struct module *mod)
211{
212 struct codetag_type *cttype;
213
214 if (!mod)
215 return;
216
217 mutex_lock(&codetag_lock);
218 list_for_each_entry(cttype, &codetag_types, link)
219 codetag_module_init(cttype, mod);
220 mutex_unlock(&codetag_lock);
221}
222
223bool codetag_unload_module(struct module *mod)
224{
225 struct codetag_type *cttype;
226 bool unload_ok = true;
227
228 if (!mod)
229 return true;
230
231 mutex_lock(&codetag_lock);
232 list_for_each_entry(cttype, &codetag_types, link) {
233 struct codetag_module *found = NULL;
234 struct codetag_module *cmod;
235 unsigned long mod_id, tmp;
236
237 down_write(&cttype->mod_lock);
238 idr_for_each_entry_ul(&cttype->mod_idr, cmod, tmp, mod_id) {
239 if (cmod->mod && cmod->mod == mod) {
240 found = cmod;
241 break;
242 }
243 }
244 if (found) {
245 if (cttype->desc.module_unload)
246 if (!cttype->desc.module_unload(cttype, cmod))
247 unload_ok = false;
248
249 cttype->count -= range_size(cttype, &cmod->range);
250 idr_remove(&cttype->mod_idr, mod_id);
251 kfree(cmod);
252 }
253 up_write(&cttype->mod_lock);
254 }
255 mutex_unlock(&codetag_lock);
256
257 return unload_ok;
258}
259#endif /* CONFIG_MODULES */
260
261struct codetag_type *
262codetag_register_type(const struct codetag_type_desc *desc)
263{
264 struct codetag_type *cttype;
265 int err;
266
267 BUG_ON(desc->tag_size <= 0);
268
269 cttype = kzalloc(sizeof(*cttype), GFP_KERNEL);
270 if (unlikely(!cttype))
271 return ERR_PTR(-ENOMEM);
272
273 cttype->desc = *desc;
274 idr_init(&cttype->mod_idr);
275 init_rwsem(&cttype->mod_lock);
276
277 err = codetag_module_init(cttype, NULL);
278 if (unlikely(err)) {
279 kfree(cttype);
280 return ERR_PTR(err);
281 }
282
283 mutex_lock(&codetag_lock);
284 list_add_tail(&cttype->link, &codetag_types);
285 mutex_unlock(&codetag_lock);
286
287 return cttype;
288}