File Index
Files and directories
Sign in
FILE

codetag.c

File preview with syntax highlighting.

linux-6.19.14/lib/codetag.c C
  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	/*
 15	 * protects mod_idr, next_mod_seq,
 16	 * iter->mod_seq and cmod->mod_seq
 17	 */
 18	struct rw_semaphore mod_lock;
 19	struct codetag_type_desc desc;
 20	/* generates unique sequence number for module load */
 21	unsigned long next_mod_seq;
 22};
 23
 24struct codetag_range {
 25	struct codetag *start;
 26	struct codetag *stop;
 27};
 28
 29struct codetag_module {
 30	struct module *mod;
 31	struct codetag_range range;
 32	unsigned long mod_seq;
 33};
 34
 35static DEFINE_MUTEX(codetag_lock);
 36static LIST_HEAD(codetag_types);
 37
 38void codetag_lock_module_list(struct codetag_type *cttype, bool lock)
 39{
 40	if (lock)
 41		down_read(&cttype->mod_lock);
 42	else
 43		up_read(&cttype->mod_lock);
 44}
 45
 46bool codetag_trylock_module_list(struct codetag_type *cttype)
 47{
 48	return down_read_trylock(&cttype->mod_lock) != 0;
 49}
 50
 51struct codetag_iterator codetag_get_ct_iter(struct codetag_type *cttype)
 52{
 53	struct codetag_iterator iter = {
 54		.cttype = cttype,
 55		.cmod = NULL,
 56		.mod_id = 0,
 57		.ct = NULL,
 58		.mod_seq = 0,
 59	};
 60
 61	return iter;
 62}
 63
 64static inline struct codetag *get_first_module_ct(struct codetag_module *cmod)
 65{
 66	return cmod->range.start < cmod->range.stop ? cmod->range.start : NULL;
 67}
 68
 69static inline
 70struct codetag *get_next_module_ct(struct codetag_iterator *iter)
 71{
 72	struct codetag *res = (struct codetag *)
 73			((char *)iter->ct + iter->cttype->desc.tag_size);
 74
 75	return res < iter->cmod->range.stop ? res : NULL;
 76}
 77
 78struct codetag *codetag_next_ct(struct codetag_iterator *iter)
 79{
 80	struct codetag_type *cttype = iter->cttype;
 81	struct codetag_module *cmod;
 82	struct codetag *ct;
 83
 84	lockdep_assert_held(&cttype->mod_lock);
 85
 86	if (unlikely(idr_is_empty(&cttype->mod_idr)))
 87		return NULL;
 88
 89	ct = NULL;
 90	while (true) {
 91		cmod = idr_find(&cttype->mod_idr, iter->mod_id);
 92
 93		/* If module was removed move to the next one */
 94		if (!cmod)
 95			cmod = idr_get_next_ul(&cttype->mod_idr,
 96					       &iter->mod_id);
 97
 98		/* Exit if no more modules */
 99		if (!cmod)
100			break;
101
102		if (!iter->cmod || iter->mod_seq != cmod->mod_seq) {
103			iter->cmod = cmod;
104			iter->mod_seq = cmod->mod_seq;
105			ct = get_first_module_ct(cmod);
106		} else {
107			ct = get_next_module_ct(iter);
108		}
109
110		if (ct)
111			break;
112
113		iter->mod_id++;
114	}
115
116	iter->ct = ct;
117	return ct;
118}
119
120void codetag_to_text(struct seq_buf *out, struct codetag *ct)
121{
122	if (ct->modname)
123		seq_buf_printf(out, "%s:%u [%s] func:%s",
124			       ct->filename, ct->lineno,
125			       ct->modname, ct->function);
126	else
127		seq_buf_printf(out, "%s:%u func:%s",
128			       ct->filename, ct->lineno, ct->function);
129}
130
131static inline size_t range_size(const struct codetag_type *cttype,
132				const struct codetag_range *range)
133{
134	return ((char *)range->stop - (char *)range->start) /
135			cttype->desc.tag_size;
136}
137
138static void *get_symbol(struct module *mod, const char *prefix, const char *name)
139{
140	DECLARE_SEQ_BUF(sb, KSYM_NAME_LEN);
141	const char *buf;
142	void *ret;
143
144	seq_buf_printf(&sb, "%s%s", prefix, name);
145	if (seq_buf_has_overflowed(&sb))
146		return NULL;
147
148	buf = seq_buf_str(&sb);
149	preempt_disable();
150	ret = mod ?
151		(void *)find_kallsyms_symbol_value(mod, buf) :
152		(void *)kallsyms_lookup_name(buf);
153	preempt_enable();
154
155	return ret;
156}
157
158static struct codetag_range get_section_range(struct module *mod,
159					      const char *section)
160{
161	return (struct codetag_range) {
162		get_symbol(mod, CODETAG_SECTION_START_PREFIX, section),
163		get_symbol(mod, CODETAG_SECTION_STOP_PREFIX, section),
164	};
165}
166
167static const char *get_mod_name(__maybe_unused struct module *mod)
168{
169#ifdef CONFIG_MODULES
170	if (mod)
171		return mod->name;
172#endif
173	return "(built-in)";
174}
175
176static int codetag_module_init(struct codetag_type *cttype, struct module *mod)
177{
178	struct codetag_range range;
179	struct codetag_module *cmod;
180	int mod_id;
181	int err;
182
183	range = get_section_range(mod, cttype->desc.section);
184	if (!range.start || !range.stop) {
185		pr_warn("Failed to load code tags of type %s from the module %s\n",
186			cttype->desc.section, get_mod_name(mod));
187		return -EINVAL;
188	}
189
190	/* Ignore empty ranges */
191	if (range.start == range.stop)
192		return 0;
193
194	BUG_ON(range.start > range.stop);
195
196	cmod = kmalloc(sizeof(*cmod), GFP_KERNEL);
197	if (unlikely(!cmod))
198		return -ENOMEM;
199
200	cmod->mod = mod;
201	cmod->range = range;
202
203	down_write(&cttype->mod_lock);
204	cmod->mod_seq = ++cttype->next_mod_seq;
205	mod_id = idr_alloc(&cttype->mod_idr, cmod, 0, 0, GFP_KERNEL);
206	if (mod_id >= 0) {
207		if (cttype->desc.module_load) {
208			err = cttype->desc.module_load(mod, range.start, range.stop);
209			if (!err)
210				cttype->count += range_size(cttype, &range);
211			else
212				idr_remove(&cttype->mod_idr, mod_id);
213		} else {
214			cttype->count += range_size(cttype, &range);
215			err = 0;
216		}
217	} else {
218		err = mod_id;
219	}
220	up_write(&cttype->mod_lock);
221
222	if (err < 0) {
223		kfree(cmod);
224		return err;
225	}
226
227	return 0;
228}
229
230#ifdef CONFIG_MODULES
231#define CODETAG_SECTION_PREFIX	".codetag."
232
233/* Some codetag types need a separate module section */
234bool codetag_needs_module_section(struct module *mod, const char *name,
235				  unsigned long size)
236{
237	const char *type_name;
238	struct codetag_type *cttype;
239	bool ret = false;
240
241	if (strncmp(name, CODETAG_SECTION_PREFIX, strlen(CODETAG_SECTION_PREFIX)))
242		return false;
243
244	type_name = name + strlen(CODETAG_SECTION_PREFIX);
245	mutex_lock(&codetag_lock);
246	list_for_each_entry(cttype, &codetag_types, link) {
247		if (strcmp(type_name, cttype->desc.section) == 0) {
248			if (!cttype->desc.needs_section_mem)
249				break;
250
251			down_write(&cttype->mod_lock);
252			ret = cttype->desc.needs_section_mem(mod, size);
253			up_write(&cttype->mod_lock);
254			break;
255		}
256	}
257	mutex_unlock(&codetag_lock);
258
259	return ret;
260}
261
262void *codetag_alloc_module_section(struct module *mod, const char *name,
263				   unsigned long size, unsigned int prepend,
264				   unsigned long align)
265{
266	const char *type_name = name + strlen(CODETAG_SECTION_PREFIX);
267	struct codetag_type *cttype;
268	void *ret = ERR_PTR(-EINVAL);
269
270	mutex_lock(&codetag_lock);
271	list_for_each_entry(cttype, &codetag_types, link) {
272		if (strcmp(type_name, cttype->desc.section) == 0) {
273			if (WARN_ON(!cttype->desc.alloc_section_mem))
274				break;
275
276			down_write(&cttype->mod_lock);
277			ret = cttype->desc.alloc_section_mem(mod, size, prepend, align);
278			up_write(&cttype->mod_lock);
279			break;
280		}
281	}
282	mutex_unlock(&codetag_lock);
283
284	return ret;
285}
286
287void codetag_free_module_sections(struct module *mod)
288{
289	struct codetag_type *cttype;
290
291	mutex_lock(&codetag_lock);
292	list_for_each_entry(cttype, &codetag_types, link) {
293		if (!cttype->desc.free_section_mem)
294			continue;
295
296		down_write(&cttype->mod_lock);
297		cttype->desc.free_section_mem(mod, false);
298		up_write(&cttype->mod_lock);
299	}
300	mutex_unlock(&codetag_lock);
301}
302
303void codetag_module_replaced(struct module *mod, struct module *new_mod)
304{
305	struct codetag_type *cttype;
306
307	mutex_lock(&codetag_lock);
308	list_for_each_entry(cttype, &codetag_types, link) {
309		if (!cttype->desc.module_replaced)
310			continue;
311
312		down_write(&cttype->mod_lock);
313		cttype->desc.module_replaced(mod, new_mod);
314		up_write(&cttype->mod_lock);
315	}
316	mutex_unlock(&codetag_lock);
317}
318
319int codetag_load_module(struct module *mod)
320{
321	struct codetag_type *cttype;
322	int ret = 0;
323
324	if (!mod)
325		return 0;
326
327	mutex_lock(&codetag_lock);
328	list_for_each_entry(cttype, &codetag_types, link) {
329		ret = codetag_module_init(cttype, mod);
330		if (ret)
331			break;
332	}
333	mutex_unlock(&codetag_lock);
334
335	return ret;
336}
337
338void codetag_unload_module(struct module *mod)
339{
340	struct codetag_type *cttype;
341
342	if (!mod)
343		return;
344
345	/* await any module's kfree_rcu() operations to complete */
346	kvfree_rcu_barrier();
347
348	mutex_lock(&codetag_lock);
349	list_for_each_entry(cttype, &codetag_types, link) {
350		struct codetag_module *found = NULL;
351		struct codetag_module *cmod;
352		unsigned long mod_id, tmp;
353
354		down_write(&cttype->mod_lock);
355		idr_for_each_entry_ul(&cttype->mod_idr, cmod, tmp, mod_id) {
356			if (cmod->mod && cmod->mod == mod) {
357				found = cmod;
358				break;
359			}
360		}
361		if (found) {
362			if (cttype->desc.module_unload)
363				cttype->desc.module_unload(cmod->mod,
364					cmod->range.start, cmod->range.stop);
365
366			cttype->count -= range_size(cttype, &cmod->range);
367			idr_remove(&cttype->mod_idr, mod_id);
368			kfree(cmod);
369		}
370		up_write(&cttype->mod_lock);
371		if (found && cttype->desc.free_section_mem)
372			cttype->desc.free_section_mem(mod, true);
373	}
374	mutex_unlock(&codetag_lock);
375}
376#endif /* CONFIG_MODULES */
377
378struct codetag_type *
379codetag_register_type(const struct codetag_type_desc *desc)
380{
381	struct codetag_type *cttype;
382	int err;
383
384	BUG_ON(desc->tag_size <= 0);
385
386	cttype = kzalloc(sizeof(*cttype), GFP_KERNEL);
387	if (unlikely(!cttype))
388		return ERR_PTR(-ENOMEM);
389
390	cttype->desc = *desc;
391	idr_init(&cttype->mod_idr);
392	init_rwsem(&cttype->mod_lock);
393
394	err = codetag_module_init(cttype, NULL);
395	if (unlikely(err)) {
396		kfree(cttype);
397		return ERR_PTR(err);
398	}
399
400	mutex_lock(&codetag_lock);
401	list_add_tail(&cttype->link, &codetag_types);
402	mutex_unlock(&codetag_lock);
403
404	return cttype;
405}
~/ Read-only file preview.