cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sysfs.c (10369B)


      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[];
    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_sysfs_initialized) {
    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}