at v6.11 6.1 kB view raw
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}