xref: /linux/lib/codetag.c (revision ab52c59103002b49f2455371e4b9c56ba3ef1781)
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 
10 struct 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 
18 struct codetag_range {
19 	struct codetag *start;
20 	struct codetag *stop;
21 };
22 
23 struct codetag_module {
24 	struct module *mod;
25 	struct codetag_range range;
26 };
27 
28 static DEFINE_MUTEX(codetag_lock);
29 static LIST_HEAD(codetag_types);
30 
31 void 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 
39 bool codetag_trylock_module_list(struct codetag_type *cttype)
40 {
41 	return down_read_trylock(&cttype->mod_lock) != 0;
42 }
43 
44 struct 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 
56 static 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 
61 static inline
62 struct 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 
70 struct 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 
110 void 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 
121 static 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
129 static 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 
149 static 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 
158 static 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 
202 void 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 
215 bool 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 */
253 static int codetag_module_init(struct codetag_type *cttype, struct module *mod) { return 0; }
254 #endif /* CONFIG_MODULES */
255 
256 struct codetag_type *
257 codetag_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