1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Module sysfs support
4 *
5 * Copyright (C) 2008 Rusty Russell
6 */
7
8#include <linux/module.h>
9#include <linux/kernel.h>
10#include <linux/fs.h>
11#include <linux/sysfs.h>
12#include <linux/slab.h>
13#include <linux/kallsyms.h>
14#include <linux/mutex.h>
15#include "internal.h"
16
17/*
18 * /sys/module/foo/sections stuff
19 * J. Corbet <corbet@lwn.net>
20 */
21#ifdef CONFIG_KALLSYMS
22struct module_sect_attr {
23	struct bin_attribute battr;
24	unsigned long address;
25};
26
27struct module_sect_attrs {
28	struct attribute_group grp;
29	unsigned int nsections;
30	struct module_sect_attr attrs[];
31};
32
33#define MODULE_SECT_READ_SIZE (3 /* "0x", "\n" */ + (BITS_PER_LONG / 4))
34static ssize_t module_sect_read(struct file *file, struct kobject *kobj,
35				struct bin_attribute *battr,
36				char *buf, loff_t pos, size_t count)
37{
38	struct module_sect_attr *sattr =
39		container_of(battr, struct module_sect_attr, battr);
40	char bounce[MODULE_SECT_READ_SIZE + 1];
41	size_t wrote;
42
43	if (pos != 0)
44		return -EINVAL;
45
46	/*
47	 * Since we're a binary read handler, we must account for the
48	 * trailing NUL byte that sprintf will write: if "buf" is
49	 * too small to hold the NUL, or the NUL is exactly the last
50	 * byte, the read will look like it got truncated by one byte.
51	 * Since there is no way to ask sprintf nicely to not write
52	 * the NUL, we have to use a bounce buffer.
53	 */
54	wrote = scnprintf(bounce, sizeof(bounce), "0x%px\n",
55			  kallsyms_show_value(file->f_cred)
56				? (void *)sattr->address : NULL);
57	count = min(count, wrote);
58	memcpy(buf, bounce, count);
59
60	return count;
61}
62
63static void free_sect_attrs(struct module_sect_attrs *sect_attrs)
64{
65	unsigned int section;
66
67	for (section = 0; section < sect_attrs->nsections; section++)
68		kfree(sect_attrs->attrs[section].battr.attr.name);
69	kfree(sect_attrs);
70}
71
72static void add_sect_attrs(struct module *mod, const struct load_info *info)
73{
74	unsigned int nloaded = 0, i, size[2];
75	struct module_sect_attrs *sect_attrs;
76	struct module_sect_attr *sattr;
77	struct bin_attribute **gattr;
78
79	/* Count loaded sections and allocate structures */
80	for (i = 0; i < info->hdr->e_shnum; i++)
81		if (!sect_empty(&info->sechdrs[i]))
82			nloaded++;
83	size[0] = ALIGN(struct_size(sect_attrs, attrs, nloaded),
84			sizeof(sect_attrs->grp.bin_attrs[0]));
85	size[1] = (nloaded + 1) * sizeof(sect_attrs->grp.bin_attrs[0]);
86	sect_attrs = kzalloc(size[0] + size[1], GFP_KERNEL);
87	if (!sect_attrs)
88		return;
89
90	/* Setup section attributes. */
91	sect_attrs->grp.name = "sections";
92	sect_attrs->grp.bin_attrs = (void *)sect_attrs + size[0];
93
94	sect_attrs->nsections = 0;
95	sattr = &sect_attrs->attrs[0];
96	gattr = &sect_attrs->grp.bin_attrs[0];
97	for (i = 0; i < info->hdr->e_shnum; i++) {
98		Elf_Shdr *sec = &info->sechdrs[i];
99
100		if (sect_empty(sec))
101			continue;
102		sysfs_bin_attr_init(&sattr->battr);
103		sattr->address = sec->sh_addr;
104		sattr->battr.attr.name =
105			kstrdup(info->secstrings + sec->sh_name, GFP_KERNEL);
106		if (!sattr->battr.attr.name)
107			goto out;
108		sect_attrs->nsections++;
109		sattr->battr.read = module_sect_read;
110		sattr->battr.size = MODULE_SECT_READ_SIZE;
111		sattr->battr.attr.mode = 0400;
112		*(gattr++) = &(sattr++)->battr;
113	}
114	*gattr = NULL;
115
116	if (sysfs_create_group(&mod->mkobj.kobj, &sect_attrs->grp))
117		goto out;
118
119	mod->sect_attrs = sect_attrs;
120	return;
121out:
122	free_sect_attrs(sect_attrs);
123}
124
125static void remove_sect_attrs(struct module *mod)
126{
127	if (mod->sect_attrs) {
128		sysfs_remove_group(&mod->mkobj.kobj,
129				   &mod->sect_attrs->grp);
130		/*
131		 * We are positive that no one is using any sect attrs
132		 * at this point.  Deallocate immediately.
133		 */
134		free_sect_attrs(mod->sect_attrs);
135		mod->sect_attrs = NULL;
136	}
137}
138
139/*
140 * /sys/module/foo/notes/.section.name gives contents of SHT_NOTE sections.
141 */
142
143struct module_notes_attrs {
144	struct kobject *dir;
145	unsigned int notes;
146	struct bin_attribute attrs[] __counted_by(notes);
147};
148
149static ssize_t module_notes_read(struct file *filp, struct kobject *kobj,
150				 struct bin_attribute *bin_attr,
151				 char *buf, loff_t pos, size_t count)
152{
153	/*
154	 * The caller checked the pos and count against our size.
155	 */
156	memcpy(buf, bin_attr->private + pos, count);
157	return count;
158}
159
160static void free_notes_attrs(struct module_notes_attrs *notes_attrs,
161			     unsigned int i)
162{
163	if (notes_attrs->dir) {
164		while (i-- > 0)
165			sysfs_remove_bin_file(notes_attrs->dir,
166					      &notes_attrs->attrs[i]);
167		kobject_put(notes_attrs->dir);
168	}
169	kfree(notes_attrs);
170}
171
172static void add_notes_attrs(struct module *mod, const struct load_info *info)
173{
174	unsigned int notes, loaded, i;
175	struct module_notes_attrs *notes_attrs;
176	struct bin_attribute *nattr;
177
178	/* failed to create section attributes, so can't create notes */
179	if (!mod->sect_attrs)
180		return;
181
182	/* Count notes sections and allocate structures.  */
183	notes = 0;
184	for (i = 0; i < info->hdr->e_shnum; i++)
185		if (!sect_empty(&info->sechdrs[i]) &&
186		    info->sechdrs[i].sh_type == SHT_NOTE)
187			++notes;
188
189	if (notes == 0)
190		return;
191
192	notes_attrs = kzalloc(struct_size(notes_attrs, attrs, notes),
193			      GFP_KERNEL);
194	if (!notes_attrs)
195		return;
196
197	notes_attrs->notes = notes;
198	nattr = &notes_attrs->attrs[0];
199	for (loaded = i = 0; i < info->hdr->e_shnum; ++i) {
200		if (sect_empty(&info->sechdrs[i]))
201			continue;
202		if (info->sechdrs[i].sh_type == SHT_NOTE) {
203			sysfs_bin_attr_init(nattr);
204			nattr->attr.name = mod->sect_attrs->attrs[loaded].battr.attr.name;
205			nattr->attr.mode = 0444;
206			nattr->size = info->sechdrs[i].sh_size;
207			nattr->private = (void *)info->sechdrs[i].sh_addr;
208			nattr->read = module_notes_read;
209			++nattr;
210		}
211		++loaded;
212	}
213
214	notes_attrs->dir = kobject_create_and_add("notes", &mod->mkobj.kobj);
215	if (!notes_attrs->dir)
216		goto out;
217
218	for (i = 0; i < notes; ++i)
219		if (sysfs_create_bin_file(notes_attrs->dir,
220					  &notes_attrs->attrs[i]))
221			goto out;
222
223	mod->notes_attrs = notes_attrs;
224	return;
225
226out:
227	free_notes_attrs(notes_attrs, i);
228}
229
230static void remove_notes_attrs(struct module *mod)
231{
232	if (mod->notes_attrs)
233		free_notes_attrs(mod->notes_attrs, mod->notes_attrs->notes);
234}
235
236#else /* !CONFIG_KALLSYMS */
237static inline void add_sect_attrs(struct module *mod, const struct load_info *info) { }
238static inline void remove_sect_attrs(struct module *mod) { }
239static inline void add_notes_attrs(struct module *mod, const struct load_info *info) { }
240static inline void remove_notes_attrs(struct module *mod) { }
241#endif /* CONFIG_KALLSYMS */
242
243static void del_usage_links(struct module *mod)
244{
245#ifdef CONFIG_MODULE_UNLOAD
246	struct module_use *use;
247
248	mutex_lock(&module_mutex);
249	list_for_each_entry(use, &mod->target_list, target_list)
250		sysfs_remove_link(use->target->holders_dir, mod->name);
251	mutex_unlock(&module_mutex);
252#endif
253}
254
255static int add_usage_links(struct module *mod)
256{
257	int ret = 0;
258#ifdef CONFIG_MODULE_UNLOAD
259	struct module_use *use;
260
261	mutex_lock(&module_mutex);
262	list_for_each_entry(use, &mod->target_list, target_list) {
263		ret = sysfs_create_link(use->target->holders_dir,
264					&mod->mkobj.kobj, mod->name);
265		if (ret)
266			break;
267	}
268	mutex_unlock(&module_mutex);
269	if (ret)
270		del_usage_links(mod);
271#endif
272	return ret;
273}
274
275static void module_remove_modinfo_attrs(struct module *mod, int end)
276{
277	struct module_attribute *attr;
278	int i;
279
280	for (i = 0; (attr = &mod->modinfo_attrs[i]); i++) {
281		if (end >= 0 && i > end)
282			break;
283		/* pick a field to test for end of list */
284		if (!attr->attr.name)
285			break;
286		sysfs_remove_file(&mod->mkobj.kobj, &attr->attr);
287		if (attr->free)
288			attr->free(mod);
289	}
290	kfree(mod->modinfo_attrs);
291}
292
293static int module_add_modinfo_attrs(struct module *mod)
294{
295	struct module_attribute *attr;
296	struct module_attribute *temp_attr;
297	int error = 0;
298	int i;
299
300	mod->modinfo_attrs = kzalloc((sizeof(struct module_attribute) *
301					(modinfo_attrs_count + 1)),
302					GFP_KERNEL);
303	if (!mod->modinfo_attrs)
304		return -ENOMEM;
305
306	temp_attr = mod->modinfo_attrs;
307	for (i = 0; (attr = modinfo_attrs[i]); i++) {
308		if (!attr->test || attr->test(mod)) {
309			memcpy(temp_attr, attr, sizeof(*temp_attr));
310			sysfs_attr_init(&temp_attr->attr);
311			error = sysfs_create_file(&mod->mkobj.kobj,
312						  &temp_attr->attr);
313			if (error)
314				goto error_out;
315			++temp_attr;
316		}
317	}
318
319	return 0;
320
321error_out:
322	if (i > 0)
323		module_remove_modinfo_attrs(mod, --i);
324	else
325		kfree(mod->modinfo_attrs);
326	return error;
327}
328
329static void mod_kobject_put(struct module *mod)
330{
331	DECLARE_COMPLETION_ONSTACK(c);
332
333	mod->mkobj.kobj_completion = &c;
334	kobject_put(&mod->mkobj.kobj);
335	wait_for_completion(&c);
336}
337
338static int mod_sysfs_init(struct module *mod)
339{
340	int err;
341	struct kobject *kobj;
342
343	if (!module_kset) {
344		pr_err("%s: module sysfs not initialized\n", mod->name);
345		err = -EINVAL;
346		goto out;
347	}
348
349	kobj = kset_find_obj(module_kset, mod->name);
350	if (kobj) {
351		pr_err("%s: module is already loaded\n", mod->name);
352		kobject_put(kobj);
353		err = -EINVAL;
354		goto out;
355	}
356
357	mod->mkobj.mod = mod;
358
359	memset(&mod->mkobj.kobj, 0, sizeof(mod->mkobj.kobj));
360	mod->mkobj.kobj.kset = module_kset;
361	err = kobject_init_and_add(&mod->mkobj.kobj, &module_ktype, NULL,
362				   "%s", mod->name);
363	if (err)
364		mod_kobject_put(mod);
365
366out:
367	return err;
368}
369
370int mod_sysfs_setup(struct module *mod,
371		    const struct load_info *info,
372			   struct kernel_param *kparam,
373			   unsigned int num_params)
374{
375	int err;
376
377	err = mod_sysfs_init(mod);
378	if (err)
379		goto out;
380
381	mod->holders_dir = kobject_create_and_add("holders", &mod->mkobj.kobj);
382	if (!mod->holders_dir) {
383		err = -ENOMEM;
384		goto out_unreg;
385	}
386
387	err = module_param_sysfs_setup(mod, kparam, num_params);
388	if (err)
389		goto out_unreg_holders;
390
391	err = module_add_modinfo_attrs(mod);
392	if (err)
393		goto out_unreg_param;
394
395	err = add_usage_links(mod);
396	if (err)
397		goto out_unreg_modinfo_attrs;
398
399	add_sect_attrs(mod, info);
400	add_notes_attrs(mod, info);
401
402	return 0;
403
404out_unreg_modinfo_attrs:
405	module_remove_modinfo_attrs(mod, -1);
406out_unreg_param:
407	module_param_sysfs_remove(mod);
408out_unreg_holders:
409	kobject_put(mod->holders_dir);
410out_unreg:
411	mod_kobject_put(mod);
412out:
413	return err;
414}
415
416static void mod_sysfs_fini(struct module *mod)
417{
418	remove_notes_attrs(mod);
419	remove_sect_attrs(mod);
420	mod_kobject_put(mod);
421}
422
423void mod_sysfs_teardown(struct module *mod)
424{
425	del_usage_links(mod);
426	module_remove_modinfo_attrs(mod, -1);
427	module_param_sysfs_remove(mod);
428	kobject_put(mod->mkobj.drivers_dir);
429	kobject_put(mod->holders_dir);
430	mod_sysfs_fini(mod);
431}
432
433void init_param_lock(struct module *mod)
434{
435	mutex_init(&mod->param_lock);
436}
437