brintos

brintos / linux-shallow public Read only

0
0
Text · 6.1 KiB · d1fbbb7 Raw
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