xref: /linux/lib/codetag.c (revision 53ed0af4964229595b60594b35334d006d411ef0)
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 struct codetag_iterator codetag_get_ct_iter(struct codetag_type *cttype)
40 {
41 	struct codetag_iterator iter = {
42 		.cttype = cttype,
43 		.cmod = NULL,
44 		.mod_id = 0,
45 		.ct = NULL,
46 	};
47 
48 	return iter;
49 }
50 
51 static inline struct codetag *get_first_module_ct(struct codetag_module *cmod)
52 {
53 	return cmod->range.start < cmod->range.stop ? cmod->range.start : NULL;
54 }
55 
56 static inline
57 struct codetag *get_next_module_ct(struct codetag_iterator *iter)
58 {
59 	struct codetag *res = (struct codetag *)
60 			((char *)iter->ct + iter->cttype->desc.tag_size);
61 
62 	return res < iter->cmod->range.stop ? res : NULL;
63 }
64 
65 struct codetag *codetag_next_ct(struct codetag_iterator *iter)
66 {
67 	struct codetag_type *cttype = iter->cttype;
68 	struct codetag_module *cmod;
69 	struct codetag *ct;
70 
71 	lockdep_assert_held(&cttype->mod_lock);
72 
73 	if (unlikely(idr_is_empty(&cttype->mod_idr)))
74 		return NULL;
75 
76 	ct = NULL;
77 	while (true) {
78 		cmod = idr_find(&cttype->mod_idr, iter->mod_id);
79 
80 		/* If module was removed move to the next one */
81 		if (!cmod)
82 			cmod = idr_get_next_ul(&cttype->mod_idr,
83 					       &iter->mod_id);
84 
85 		/* Exit if no more modules */
86 		if (!cmod)
87 			break;
88 
89 		if (cmod != iter->cmod) {
90 			iter->cmod = cmod;
91 			ct = get_first_module_ct(cmod);
92 		} else
93 			ct = get_next_module_ct(iter);
94 
95 		if (ct)
96 			break;
97 
98 		iter->mod_id++;
99 	}
100 
101 	iter->ct = ct;
102 	return ct;
103 }
104 
105 void codetag_to_text(struct seq_buf *out, struct codetag *ct)
106 {
107 	if (ct->modname)
108 		seq_buf_printf(out, "%s:%u [%s] func:%s",
109 			       ct->filename, ct->lineno,
110 			       ct->modname, ct->function);
111 	else
112 		seq_buf_printf(out, "%s:%u func:%s",
113 			       ct->filename, ct->lineno, ct->function);
114 }
115 
116 static inline size_t range_size(const struct codetag_type *cttype,
117 				const struct codetag_range *range)
118 {
119 	return ((char *)range->stop - (char *)range->start) /
120 			cttype->desc.tag_size;
121 }
122 
123 #ifdef CONFIG_MODULES
124 static void *get_symbol(struct module *mod, const char *prefix, const char *name)
125 {
126 	DECLARE_SEQ_BUF(sb, KSYM_NAME_LEN);
127 	const char *buf;
128 	void *ret;
129 
130 	seq_buf_printf(&sb, "%s%s", prefix, name);
131 	if (seq_buf_has_overflowed(&sb))
132 		return NULL;
133 
134 	buf = seq_buf_str(&sb);
135 	preempt_disable();
136 	ret = mod ?
137 		(void *)find_kallsyms_symbol_value(mod, buf) :
138 		(void *)kallsyms_lookup_name(buf);
139 	preempt_enable();
140 
141 	return ret;
142 }
143 
144 static struct codetag_range get_section_range(struct module *mod,
145 					      const char *section)
146 {
147 	return (struct codetag_range) {
148 		get_symbol(mod, "__start_", section),
149 		get_symbol(mod, "__stop_", section),
150 	};
151 }
152 
153 static int codetag_module_init(struct codetag_type *cttype, struct module *mod)
154 {
155 	struct codetag_range range;
156 	struct codetag_module *cmod;
157 	int err;
158 
159 	range = get_section_range(mod, cttype->desc.section);
160 	if (!range.start || !range.stop) {
161 		pr_warn("Failed to load code tags of type %s from the module %s\n",
162 			cttype->desc.section,
163 			mod ? mod->name : "(built-in)");
164 		return -EINVAL;
165 	}
166 
167 	/* Ignore empty ranges */
168 	if (range.start == range.stop)
169 		return 0;
170 
171 	BUG_ON(range.start > range.stop);
172 
173 	cmod = kmalloc(sizeof(*cmod), GFP_KERNEL);
174 	if (unlikely(!cmod))
175 		return -ENOMEM;
176 
177 	cmod->mod = mod;
178 	cmod->range = range;
179 
180 	down_write(&cttype->mod_lock);
181 	err = idr_alloc(&cttype->mod_idr, cmod, 0, 0, GFP_KERNEL);
182 	if (err >= 0) {
183 		cttype->count += range_size(cttype, &range);
184 		if (cttype->desc.module_load)
185 			cttype->desc.module_load(cttype, cmod);
186 	}
187 	up_write(&cttype->mod_lock);
188 
189 	if (err < 0) {
190 		kfree(cmod);
191 		return err;
192 	}
193 
194 	return 0;
195 }
196 
197 void codetag_load_module(struct module *mod)
198 {
199 	struct codetag_type *cttype;
200 
201 	if (!mod)
202 		return;
203 
204 	mutex_lock(&codetag_lock);
205 	list_for_each_entry(cttype, &codetag_types, link)
206 		codetag_module_init(cttype, mod);
207 	mutex_unlock(&codetag_lock);
208 }
209 
210 bool codetag_unload_module(struct module *mod)
211 {
212 	struct codetag_type *cttype;
213 	bool unload_ok = true;
214 
215 	if (!mod)
216 		return true;
217 
218 	mutex_lock(&codetag_lock);
219 	list_for_each_entry(cttype, &codetag_types, link) {
220 		struct codetag_module *found = NULL;
221 		struct codetag_module *cmod;
222 		unsigned long mod_id, tmp;
223 
224 		down_write(&cttype->mod_lock);
225 		idr_for_each_entry_ul(&cttype->mod_idr, cmod, tmp, mod_id) {
226 			if (cmod->mod && cmod->mod == mod) {
227 				found = cmod;
228 				break;
229 			}
230 		}
231 		if (found) {
232 			if (cttype->desc.module_unload)
233 				if (!cttype->desc.module_unload(cttype, cmod))
234 					unload_ok = false;
235 
236 			cttype->count -= range_size(cttype, &cmod->range);
237 			idr_remove(&cttype->mod_idr, mod_id);
238 			kfree(cmod);
239 		}
240 		up_write(&cttype->mod_lock);
241 	}
242 	mutex_unlock(&codetag_lock);
243 
244 	return unload_ok;
245 }
246 
247 #else /* CONFIG_MODULES */
248 static int codetag_module_init(struct codetag_type *cttype, struct module *mod) { return 0; }
249 #endif /* CONFIG_MODULES */
250 
251 struct codetag_type *
252 codetag_register_type(const struct codetag_type_desc *desc)
253 {
254 	struct codetag_type *cttype;
255 	int err;
256 
257 	BUG_ON(desc->tag_size <= 0);
258 
259 	cttype = kzalloc(sizeof(*cttype), GFP_KERNEL);
260 	if (unlikely(!cttype))
261 		return ERR_PTR(-ENOMEM);
262 
263 	cttype->desc = *desc;
264 	idr_init(&cttype->mod_idr);
265 	init_rwsem(&cttype->mod_lock);
266 
267 	err = codetag_module_init(cttype, NULL);
268 	if (unlikely(err)) {
269 		kfree(cttype);
270 		return ERR_PTR(err);
271 	}
272 
273 	mutex_lock(&codetag_lock);
274 	list_add_tail(&cttype->link, &codetag_types);
275 	mutex_unlock(&codetag_lock);
276 
277 	return cttype;
278 }
279