~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/lib/codetag.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 #ifdef CONFIG_MODULES
129 static void *get_symbol(struct module *mod, const char *prefix, const char *name)
130 {
131         DECLARE_SEQ_BUF(sb, KSYM_NAME_LEN);
132         const char *buf;
133         void *ret;
134 
135         seq_buf_printf(&sb, "%s%s", prefix, name);
136         if (seq_buf_has_overflowed(&sb))
137                 return NULL;
138 
139         buf = seq_buf_str(&sb);
140         preempt_disable();
141         ret = mod ?
142                 (void *)find_kallsyms_symbol_value(mod, buf) :
143                 (void *)kallsyms_lookup_name(buf);
144         preempt_enable();
145 
146         return ret;
147 }
148 
149 static struct codetag_range get_section_range(struct module *mod,
150                                               const char *section)
151 {
152         return (struct codetag_range) {
153                 get_symbol(mod, "__start_", section),
154                 get_symbol(mod, "__stop_", section),
155         };
156 }
157 
158 static int codetag_module_init(struct codetag_type *cttype, struct module *mod)
159 {
160         struct codetag_range range;
161         struct codetag_module *cmod;
162         int err;
163 
164         range = get_section_range(mod, cttype->desc.section);
165         if (!range.start || !range.stop) {
166                 pr_warn("Failed to load code tags of type %s from the module %s\n",
167                         cttype->desc.section,
168                         mod ? mod->name : "(built-in)");
169                 return -EINVAL;
170         }
171 
172         /* Ignore empty ranges */
173         if (range.start == range.stop)
174                 return 0;
175 
176         BUG_ON(range.start > range.stop);
177 
178         cmod = kmalloc(sizeof(*cmod), GFP_KERNEL);
179         if (unlikely(!cmod))
180                 return -ENOMEM;
181 
182         cmod->mod = mod;
183         cmod->range = range;
184 
185         down_write(&cttype->mod_lock);
186         err = idr_alloc(&cttype->mod_idr, cmod, 0, 0, GFP_KERNEL);
187         if (err >= 0) {
188                 cttype->count += range_size(cttype, &range);
189                 if (cttype->desc.module_load)
190                         cttype->desc.module_load(cttype, cmod);
191         }
192         up_write(&cttype->mod_lock);
193 
194         if (err < 0) {
195                 kfree(cmod);
196                 return err;
197         }
198 
199         return 0;
200 }
201 
202 void codetag_load_module(struct module *mod)
203 {
204         struct codetag_type *cttype;
205 
206         if (!mod)
207                 return;
208 
209         mutex_lock(&codetag_lock);
210         list_for_each_entry(cttype, &codetag_types, link)
211                 codetag_module_init(cttype, mod);
212         mutex_unlock(&codetag_lock);
213 }
214 
215 bool codetag_unload_module(struct module *mod)
216 {
217         struct codetag_type *cttype;
218         bool unload_ok = true;
219 
220         if (!mod)
221                 return true;
222 
223         mutex_lock(&codetag_lock);
224         list_for_each_entry(cttype, &codetag_types, link) {
225                 struct codetag_module *found = NULL;
226                 struct codetag_module *cmod;
227                 unsigned long mod_id, tmp;
228 
229                 down_write(&cttype->mod_lock);
230                 idr_for_each_entry_ul(&cttype->mod_idr, cmod, tmp, mod_id) {
231                         if (cmod->mod && cmod->mod == mod) {
232                                 found = cmod;
233                                 break;
234                         }
235                 }
236                 if (found) {
237                         if (cttype->desc.module_unload)
238                                 if (!cttype->desc.module_unload(cttype, cmod))
239                                         unload_ok = false;
240 
241                         cttype->count -= range_size(cttype, &cmod->range);
242                         idr_remove(&cttype->mod_idr, mod_id);
243                         kfree(cmod);
244                 }
245                 up_write(&cttype->mod_lock);
246         }
247         mutex_unlock(&codetag_lock);
248 
249         return unload_ok;
250 }
251 
252 #else /* CONFIG_MODULES */
253 static int codetag_module_init(struct codetag_type *cttype, struct module *mod) { return 0; }
254 #endif /* CONFIG_MODULES */
255 
256 struct codetag_type *
257 codetag_register_type(const struct codetag_type_desc *desc)
258 {
259         struct codetag_type *cttype;
260         int err;
261 
262         BUG_ON(desc->tag_size <= 0);
263 
264         cttype = kzalloc(sizeof(*cttype), GFP_KERNEL);
265         if (unlikely(!cttype))
266                 return ERR_PTR(-ENOMEM);
267 
268         cttype->desc = *desc;
269         idr_init(&cttype->mod_idr);
270         init_rwsem(&cttype->mod_lock);
271 
272         err = codetag_module_init(cttype, NULL);
273         if (unlikely(err)) {
274                 kfree(cttype);
275                 return ERR_PTR(err);
276         }
277 
278         mutex_lock(&codetag_lock);
279         list_add_tail(&cttype->link, &codetag_types);
280         mutex_unlock(&codetag_lock);
281 
282         return cttype;
283 }
284 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php