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

TOMOYO Linux Cross Reference
Linux/lib/codetag.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ 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 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, "__start_", section),
153                 get_symbol(mod, "__stop_", 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 void 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 
223 bool 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 
261 struct codetag_type *
262 codetag_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 }
289 

~ [ 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