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
128#ifdef CONFIG_MODULES
129static void *get_symbol(struct module *mod, const char *prefix, const char *name)
130{
131	DECLARE_SEQ_BUF(sb, KSYM_NAME_LEN);
132	const char *buf;
133	void *ret;
134
135	seq_buf_printf(&sb, "%s%s", prefix, name);
136	if (seq_buf_has_overflowed(&sb))
137		return NULL;
138
139	buf = seq_buf_str(&sb);
140	preempt_disable();
141	ret = mod ?
142		(void *)find_kallsyms_symbol_value(mod, buf) :
143		(void *)kallsyms_lookup_name(buf);
144	preempt_enable();
145
146	return ret;
147}
148
149static struct codetag_range get_section_range(struct module *mod,
150					      const char *section)
151{
152	return (struct codetag_range) {
153		get_symbol(mod, "__start_", section),
154		get_symbol(mod, "__stop_", section),
155	};
156}
157
158static int codetag_module_init(struct codetag_type *cttype, struct module *mod)
159{
160	struct codetag_range range;
161	struct codetag_module *cmod;
162	int err;
163
164	range = get_section_range(mod, cttype->desc.section);
165	if (!range.start || !range.stop) {
166		pr_warn("Failed to load code tags of type %s from the module %s\n",
167			cttype->desc.section,
168			mod ? mod->name : "(built-in)");
169		return -EINVAL;
170	}
171
172	/* Ignore empty ranges */
173	if (range.start == range.stop)
174		return 0;
175
176	BUG_ON(range.start > range.stop);
177
178	cmod = kmalloc(sizeof(*cmod), GFP_KERNEL);
179	if (unlikely(!cmod))
180		return -ENOMEM;
181
182	cmod->mod = mod;
183	cmod->range = range;
184
185	down_write(&cttype->mod_lock);
186	err = idr_alloc(&cttype->mod_idr, cmod, 0, 0, GFP_KERNEL);
187	if (err >= 0) {
188		cttype->count += range_size(cttype, &range);
189		if (cttype->desc.module_load)
190			cttype->desc.module_load(cttype, cmod);
191	}
192	up_write(&cttype->mod_lock);
193
194	if (err < 0) {
195		kfree(cmod);
196		return err;
197	}
198
199	return 0;
200}
201
202void codetag_load_module(struct module *mod)
203{
204	struct codetag_type *cttype;
205
206	if (!mod)
207		return;
208
209	mutex_lock(&codetag_lock);
210	list_for_each_entry(cttype, &codetag_types, link)
211		codetag_module_init(cttype, mod);
212	mutex_unlock(&codetag_lock);
213}
214
215bool codetag_unload_module(struct module *mod)
216{
217	struct codetag_type *cttype;
218	bool unload_ok = true;
219
220	if (!mod)
221		return true;
222
223	mutex_lock(&codetag_lock);
224	list_for_each_entry(cttype, &codetag_types, link) {
225		struct codetag_module *found = NULL;
226		struct codetag_module *cmod;
227		unsigned long mod_id, tmp;
228
229		down_write(&cttype->mod_lock);
230		idr_for_each_entry_ul(&cttype->mod_idr, cmod, tmp, mod_id) {
231			if (cmod->mod && cmod->mod == mod) {
232				found = cmod;
233				break;
234			}
235		}
236		if (found) {
237			if (cttype->desc.module_unload)
238				if (!cttype->desc.module_unload(cttype, cmod))
239					unload_ok = false;
240
241			cttype->count -= range_size(cttype, &cmod->range);
242			idr_remove(&cttype->mod_idr, mod_id);
243			kfree(cmod);
244		}
245		up_write(&cttype->mod_lock);
246	}
247	mutex_unlock(&codetag_lock);
248
249	return unload_ok;
250}
251
252#else /* CONFIG_MODULES */
253static int codetag_module_init(struct codetag_type *cttype, struct module *mod) { return 0; }
254#endif /* CONFIG_MODULES */
255
256struct codetag_type *
257codetag_register_type(const struct codetag_type_desc *desc)
258{
259	struct codetag_type *cttype;
260	int err;
261
262	BUG_ON(desc->tag_size <= 0);
263
264	cttype = kzalloc(sizeof(*cttype), GFP_KERNEL);
265	if (unlikely(!cttype))
266		return ERR_PTR(-ENOMEM);
267
268	cttype->desc = *desc;
269	idr_init(&cttype->mod_idr);
270	init_rwsem(&cttype->mod_lock);
271
272	err = codetag_module_init(cttype, NULL);
273	if (unlikely(err)) {
274		kfree(cttype);
275		return ERR_PTR(err);
276	}
277
278	mutex_lock(&codetag_lock);
279	list_add_tail(&cttype->link, &codetag_types);
280	mutex_unlock(&codetag_lock);
281
282	return cttype;
283}
284