292 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2#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 else36 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 inline62struct 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 } else98 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 else117 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_MODULES160 if (mod)161 return mod->name;162#endif163 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_MODULES210void 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 /* await any module's kfree_rcu() operations to complete */232 kvfree_rcu_barrier();233 234 mutex_lock(&codetag_lock);235 list_for_each_entry(cttype, &codetag_types, link) {236 struct codetag_module *found = NULL;237 struct codetag_module *cmod;238 unsigned long mod_id, tmp;239 240 down_write(&cttype->mod_lock);241 idr_for_each_entry_ul(&cttype->mod_idr, cmod, tmp, mod_id) {242 if (cmod->mod && cmod->mod == mod) {243 found = cmod;244 break;245 }246 }247 if (found) {248 if (cttype->desc.module_unload)249 if (!cttype->desc.module_unload(cttype, cmod))250 unload_ok = false;251 252 cttype->count -= range_size(cttype, &cmod->range);253 idr_remove(&cttype->mod_idr, mod_id);254 kfree(cmod);255 }256 up_write(&cttype->mod_lock);257 }258 mutex_unlock(&codetag_lock);259 260 return unload_ok;261}262#endif /* CONFIG_MODULES */263 264struct codetag_type *265codetag_register_type(const struct codetag_type_desc *desc)266{267 struct codetag_type *cttype;268 int err;269 270 BUG_ON(desc->tag_size <= 0);271 272 cttype = kzalloc(sizeof(*cttype), GFP_KERNEL);273 if (unlikely(!cttype))274 return ERR_PTR(-ENOMEM);275 276 cttype->desc = *desc;277 idr_init(&cttype->mod_idr);278 init_rwsem(&cttype->mod_lock);279 280 err = codetag_module_init(cttype, NULL);281 if (unlikely(err)) {282 kfree(cttype);283 return ERR_PTR(err);284 }285 286 mutex_lock(&codetag_lock);287 list_add_tail(&cttype->link, &codetag_types);288 mutex_unlock(&codetag_lock);289 290 return cttype;291}292