diff options
Diffstat (limited to 'kernel/module.c')
-rw-r--r-- | kernel/module.c | 130 |
1 files changed, 113 insertions, 17 deletions
diff --git a/kernel/module.c b/kernel/module.c index db0ead0..a389b42 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -20,6 +20,7 @@ #include <linux/moduleloader.h> #include <linux/init.h> #include <linux/kallsyms.h> +#include <linux/sysfs.h> #include <linux/kernel.h> #include <linux/slab.h> #include <linux/vmalloc.h> @@ -692,8 +693,7 @@ sys_delete_module(const char __user *name_user, unsigned int flags) } /* If it has an init func, it must have an exit func to unload */ - if ((mod->init != NULL && mod->exit == NULL) - || mod->unsafe) { + if (mod->init && !mod->exit) { forced = try_force_unload(flags); if (!forced) { /* This module can't be removed */ @@ -741,11 +741,6 @@ static void print_unload_info(struct seq_file *m, struct module *mod) seq_printf(m, "%s,", use->module_which_uses->name); } - if (mod->unsafe) { - printed_something = 1; - seq_printf(m, "[unsafe],"); - } - if (mod->init != NULL && mod->exit == NULL) { printed_something = 1; seq_printf(m, "[permanent],"); @@ -1053,6 +1048,100 @@ static void remove_sect_attrs(struct module *mod) } } +/* + * /sys/module/foo/notes/.section.name gives contents of SHT_NOTE sections. + */ + +struct module_notes_attrs { + struct kobject *dir; + unsigned int notes; + struct bin_attribute attrs[0]; +}; + +static ssize_t module_notes_read(struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t pos, size_t count) +{ + /* + * The caller checked the pos and count against our size. + */ + memcpy(buf, bin_attr->private + pos, count); + return count; +} + +static void free_notes_attrs(struct module_notes_attrs *notes_attrs, + unsigned int i) +{ + if (notes_attrs->dir) { + while (i-- > 0) + sysfs_remove_bin_file(notes_attrs->dir, + ¬es_attrs->attrs[i]); + kobject_del(notes_attrs->dir); + } + kfree(notes_attrs); +} + +static void add_notes_attrs(struct module *mod, unsigned int nsect, + char *secstrings, Elf_Shdr *sechdrs) +{ + unsigned int notes, loaded, i; + struct module_notes_attrs *notes_attrs; + struct bin_attribute *nattr; + + /* Count notes sections and allocate structures. */ + notes = 0; + for (i = 0; i < nsect; i++) + if ((sechdrs[i].sh_flags & SHF_ALLOC) && + (sechdrs[i].sh_type == SHT_NOTE)) + ++notes; + + if (notes == 0) + return; + + notes_attrs = kzalloc(sizeof(*notes_attrs) + + notes * sizeof(notes_attrs->attrs[0]), + GFP_KERNEL); + if (notes_attrs == NULL) + return; + + notes_attrs->notes = notes; + nattr = ¬es_attrs->attrs[0]; + for (loaded = i = 0; i < nsect; ++i) { + if (!(sechdrs[i].sh_flags & SHF_ALLOC)) + continue; + if (sechdrs[i].sh_type == SHT_NOTE) { + nattr->attr.name = mod->sect_attrs->attrs[loaded].name; + nattr->attr.mode = S_IRUGO; + nattr->size = sechdrs[i].sh_size; + nattr->private = (void *) sechdrs[i].sh_addr; + nattr->read = module_notes_read; + ++nattr; + } + ++loaded; + } + + notes_attrs->dir = kobject_add_dir(&mod->mkobj.kobj, "notes"); + if (!notes_attrs->dir) + goto out; + + for (i = 0; i < notes; ++i) + if (sysfs_create_bin_file(notes_attrs->dir, + ¬es_attrs->attrs[i])) + goto out; + + mod->notes_attrs = notes_attrs; + return; + + out: + free_notes_attrs(notes_attrs, i); +} + +static void remove_notes_attrs(struct module *mod) +{ + if (mod->notes_attrs) + free_notes_attrs(mod->notes_attrs, mod->notes_attrs->notes); +} + #else static inline void add_sect_attrs(struct module *mod, unsigned int nsect, @@ -1063,6 +1152,15 @@ static inline void add_sect_attrs(struct module *mod, unsigned int nsect, static inline void remove_sect_attrs(struct module *mod) { } + +static inline void add_notes_attrs(struct module *mod, unsigned int nsect, + char *sectstrings, Elf_Shdr *sechdrs) +{ +} + +static inline void remove_notes_attrs(struct module *mod) +{ +} #endif /* CONFIG_KALLSYMS */ #ifdef CONFIG_SYSFS @@ -1197,6 +1295,7 @@ static void free_module(struct module *mod) { /* Delete from various lists */ stop_machine_run(__unlink_module, mod, NR_CPUS); + remove_notes_attrs(mod); remove_sect_attrs(mod); mod_kobject_remove(mod); @@ -1782,7 +1881,8 @@ static struct module *load_module(void __user *umod, module_unload_init(mod); /* Initialize kobject, so we can reference it. */ - if (mod_sysfs_init(mod) != 0) + err = mod_sysfs_init(mod); + if (err) goto cleanup; /* Set up license info based on the info section */ @@ -1924,6 +2024,7 @@ static struct module *load_module(void __user *umod, if (err < 0) goto arch_cleanup; add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs); + add_notes_attrs(mod, hdr->e_shnum, secstrings, sechdrs); /* Size of section 0 is 0, so this works well if no unwind info. */ mod->unwind_info = unwind_add_table(mod, @@ -2011,15 +2112,10 @@ sys_init_module(void __user *umod, buggy refcounters. */ mod->state = MODULE_STATE_GOING; synchronize_sched(); - if (mod->unsafe) - printk(KERN_ERR "%s: module is now stuck!\n", - mod->name); - else { - module_put(mod); - mutex_lock(&module_mutex); - free_module(mod); - mutex_unlock(&module_mutex); - } + module_put(mod); + mutex_lock(&module_mutex); + free_module(mod); + mutex_unlock(&module_mutex); return ret; } |