]> Git Repo - linux.git/blob - lib/codetag.c
Merge tag 'tty-6.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
[linux.git] / lib / codetag.c
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
10 struct 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
18 struct codetag_range {
19         struct codetag *start;
20         struct codetag *stop;
21 };
22
23 struct codetag_module {
24         struct module *mod;
25         struct codetag_range range;
26 };
27
28 static DEFINE_MUTEX(codetag_lock);
29 static LIST_HEAD(codetag_types);
30
31 void 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
39 bool codetag_trylock_module_list(struct codetag_type *cttype)
40 {
41         return down_read_trylock(&cttype->mod_lock) != 0;
42 }
43
44 struct 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
56 static 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
61 static inline
62 struct 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
70 struct 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
110 void 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
121 static 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
128 static 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
148 static struct codetag_range get_section_range(struct module *mod,
149                                               const char *section)
150 {
151         return (struct codetag_range) {
152                 get_symbol(mod, CODETAG_SECTION_START_PREFIX, section),
153                 get_symbol(mod, CODETAG_SECTION_STOP_PREFIX, section),
154         };
155 }
156
157 static 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
166 static 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
210 #define CODETAG_SECTION_PREFIX  ".codetag."
211
212 /* Some codetag types need a separate module section */
213 bool codetag_needs_module_section(struct module *mod, const char *name,
214                                   unsigned long size)
215 {
216         const char *type_name;
217         struct codetag_type *cttype;
218         bool ret = false;
219
220         if (strncmp(name, CODETAG_SECTION_PREFIX, strlen(CODETAG_SECTION_PREFIX)))
221                 return false;
222
223         type_name = name + strlen(CODETAG_SECTION_PREFIX);
224         mutex_lock(&codetag_lock);
225         list_for_each_entry(cttype, &codetag_types, link) {
226                 if (strcmp(type_name, cttype->desc.section) == 0) {
227                         if (!cttype->desc.needs_section_mem)
228                                 break;
229
230                         down_write(&cttype->mod_lock);
231                         ret = cttype->desc.needs_section_mem(mod, size);
232                         up_write(&cttype->mod_lock);
233                         break;
234                 }
235         }
236         mutex_unlock(&codetag_lock);
237
238         return ret;
239 }
240
241 void *codetag_alloc_module_section(struct module *mod, const char *name,
242                                    unsigned long size, unsigned int prepend,
243                                    unsigned long align)
244 {
245         const char *type_name = name + strlen(CODETAG_SECTION_PREFIX);
246         struct codetag_type *cttype;
247         void *ret = ERR_PTR(-EINVAL);
248
249         mutex_lock(&codetag_lock);
250         list_for_each_entry(cttype, &codetag_types, link) {
251                 if (strcmp(type_name, cttype->desc.section) == 0) {
252                         if (WARN_ON(!cttype->desc.alloc_section_mem))
253                                 break;
254
255                         down_write(&cttype->mod_lock);
256                         ret = cttype->desc.alloc_section_mem(mod, size, prepend, align);
257                         up_write(&cttype->mod_lock);
258                         break;
259                 }
260         }
261         mutex_unlock(&codetag_lock);
262
263         return ret;
264 }
265
266 void codetag_free_module_sections(struct module *mod)
267 {
268         struct codetag_type *cttype;
269
270         mutex_lock(&codetag_lock);
271         list_for_each_entry(cttype, &codetag_types, link) {
272                 if (!cttype->desc.free_section_mem)
273                         continue;
274
275                 down_write(&cttype->mod_lock);
276                 cttype->desc.free_section_mem(mod, false);
277                 up_write(&cttype->mod_lock);
278         }
279         mutex_unlock(&codetag_lock);
280 }
281
282 void codetag_module_replaced(struct module *mod, struct module *new_mod)
283 {
284         struct codetag_type *cttype;
285
286         mutex_lock(&codetag_lock);
287         list_for_each_entry(cttype, &codetag_types, link) {
288                 if (!cttype->desc.module_replaced)
289                         continue;
290
291                 down_write(&cttype->mod_lock);
292                 cttype->desc.module_replaced(mod, new_mod);
293                 up_write(&cttype->mod_lock);
294         }
295         mutex_unlock(&codetag_lock);
296 }
297
298 void codetag_load_module(struct module *mod)
299 {
300         struct codetag_type *cttype;
301
302         if (!mod)
303                 return;
304
305         mutex_lock(&codetag_lock);
306         list_for_each_entry(cttype, &codetag_types, link)
307                 codetag_module_init(cttype, mod);
308         mutex_unlock(&codetag_lock);
309 }
310
311 void codetag_unload_module(struct module *mod)
312 {
313         struct codetag_type *cttype;
314
315         if (!mod)
316                 return;
317
318         /* await any module's kfree_rcu() operations to complete */
319         kvfree_rcu_barrier();
320
321         mutex_lock(&codetag_lock);
322         list_for_each_entry(cttype, &codetag_types, link) {
323                 struct codetag_module *found = NULL;
324                 struct codetag_module *cmod;
325                 unsigned long mod_id, tmp;
326
327                 down_write(&cttype->mod_lock);
328                 idr_for_each_entry_ul(&cttype->mod_idr, cmod, tmp, mod_id) {
329                         if (cmod->mod && cmod->mod == mod) {
330                                 found = cmod;
331                                 break;
332                         }
333                 }
334                 if (found) {
335                         if (cttype->desc.module_unload)
336                                 cttype->desc.module_unload(cttype, cmod);
337
338                         cttype->count -= range_size(cttype, &cmod->range);
339                         idr_remove(&cttype->mod_idr, mod_id);
340                         kfree(cmod);
341                 }
342                 up_write(&cttype->mod_lock);
343                 if (found && cttype->desc.free_section_mem)
344                         cttype->desc.free_section_mem(mod, true);
345         }
346         mutex_unlock(&codetag_lock);
347 }
348 #endif /* CONFIG_MODULES */
349
350 struct codetag_type *
351 codetag_register_type(const struct codetag_type_desc *desc)
352 {
353         struct codetag_type *cttype;
354         int err;
355
356         BUG_ON(desc->tag_size <= 0);
357
358         cttype = kzalloc(sizeof(*cttype), GFP_KERNEL);
359         if (unlikely(!cttype))
360                 return ERR_PTR(-ENOMEM);
361
362         cttype->desc = *desc;
363         idr_init(&cttype->mod_idr);
364         init_rwsem(&cttype->mod_lock);
365
366         err = codetag_module_init(cttype, NULL);
367         if (unlikely(err)) {
368                 kfree(cttype);
369                 return ERR_PTR(err);
370         }
371
372         mutex_lock(&codetag_lock);
373         list_add_tail(&cttype->link, &codetag_types);
374         mutex_unlock(&codetag_lock);
375
376         return cttype;
377 }
This page took 0.052253 seconds and 4 git commands to generate.