Surprising number of fixes this merge window :(
First two are minor fallout from the param rework which went in this merge window. Next three are a series which fixes a longstanding (but never previously reported and unlikely , so no CC stable) race between kallsyms and freeing the init section. Finally, a minor cleanup as our module refcount will now be -1 during unload. Thanks, Rusty. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJUwEmwAAoJENkgDmzRrbjx77kP/1cNQR2eG2sBwokg3q0tvHnQ IKqEXErW7NvxRa+RAMEmy2uQoGt6+uNklAbtyJEYM9oR1NieFbPi2yrt9Xn5SAXS Brp1S8WYBMilA3W3o6I0trFDRWHdpdtkKIQwLWgJNSEWjbTXh8bSwp/2X1rlOPyI ZmphCMOQMU2/uFEyJhTz1WMEV8eVXiRLN8OxSkPxToxdZoGln2U8IBCCCJC9OG+f Cf3eMgEcNdEXNcPKqr11NIcHkAx6M6qI/eMDOqk151PslHa8lbis6di9Z87aE0ps i8PyrkJGTmgM9cCjXwE8deNseeCmuKYlbPIF+NoxcqtvZstfaMrISwTIEuzV4JHi p13YhDxy4XiC3H6pKHub/jo7UCl+wWtFh9SqpqGgduFX/p6FtUHQJm0S0X/DFFZt C+2MFVSe6HRHE8B7bFz86+619Qd/rU7+806CLCE+NbYlYAKIBYKzWt/bml6VH3RJ OjwXhQqmznWhJjsfD3BUUUpZpHijmylI9gAe2F1oErb8YjRU6gIm7P8hlkOzD7AS TfGHPFq2raQcfAiGdVmvkbvvhvYZXnB3WVsAexrYoqrT9I8eEfRI+7SkL75MLR2E ikzhJS3SHkAUAd7fUVMt7xMwh0jmhsPjWCCqc13m6UUFoXhTaDgKgPGftltN0bI2 g85+enZ3/eca6xh/KxvW =Kf9b -----END PGP SIGNATURE----- Merge tag 'fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux Pull module and param fixes from Rusty Russell: "Surprising number of fixes this merge window :( The first two are minor fallout from the param rework which went in this merge window. The next three are a series which fixes a longstanding (but never previously reported and unlikely , so no CC stable) race between kallsyms and freeing the init section. Finally, a minor cleanup as our module refcount will now be -1 during unload" * tag 'fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux: module: make module_refcount() a signed integer. module: fix race in kallsyms resolution during module load success. module: remove mod arg from module_free, rename module_memfree(). module_arch_freeing_init(): new hook for archs before module->module_init freed. param: fix uninitialized read with CONFIG_DEBUG_LOCK_ALLOC param: initialize store function to NULL if not available.
This commit is contained in:
commit
193934123c
18 changed files with 94 additions and 65 deletions
|
@ -19,12 +19,10 @@
|
||||||
#include <linux/moduleloader.h>
|
#include <linux/moduleloader.h>
|
||||||
#include <linux/vmalloc.h>
|
#include <linux/vmalloc.h>
|
||||||
|
|
||||||
void module_free(struct module *mod, void *module_region)
|
void module_arch_freeing_init(struct module *mod)
|
||||||
{
|
{
|
||||||
vfree(mod->arch.syminfo);
|
vfree(mod->arch.syminfo);
|
||||||
mod->arch.syminfo = NULL;
|
mod->arch.syminfo = NULL;
|
||||||
|
|
||||||
vfree(module_region);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int check_rela(Elf32_Rela *rela, struct module *module,
|
static inline int check_rela(Elf32_Rela *rela, struct module *module,
|
||||||
|
@ -291,12 +289,3 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
|
|
||||||
struct module *module)
|
|
||||||
{
|
|
||||||
vfree(module->arch.syminfo);
|
|
||||||
module->arch.syminfo = NULL;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ void *module_alloc(unsigned long size)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Free memory returned from module_alloc */
|
/* Free memory returned from module_alloc */
|
||||||
void module_free(struct module *mod, void *module_region)
|
void module_memfree(void *module_region)
|
||||||
{
|
{
|
||||||
kfree(module_region);
|
kfree(module_region);
|
||||||
}
|
}
|
||||||
|
|
|
@ -305,14 +305,12 @@ plt_target (struct plt_entry *plt)
|
||||||
#endif /* !USE_BRL */
|
#endif /* !USE_BRL */
|
||||||
|
|
||||||
void
|
void
|
||||||
module_free (struct module *mod, void *module_region)
|
module_arch_freeing_init (struct module *mod)
|
||||||
{
|
{
|
||||||
if (mod && mod->arch.init_unw_table &&
|
if (mod->arch.init_unw_table) {
|
||||||
module_region == mod->module_init) {
|
|
||||||
unw_remove_unwind_table(mod->arch.init_unw_table);
|
unw_remove_unwind_table(mod->arch.init_unw_table);
|
||||||
mod->arch.init_unw_table = NULL;
|
mod->arch.init_unw_table = NULL;
|
||||||
}
|
}
|
||||||
vfree(module_region);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Have we already seen one of these relocations? */
|
/* Have we already seen one of these relocations? */
|
||||||
|
|
|
@ -1388,7 +1388,7 @@ out:
|
||||||
void bpf_jit_free(struct bpf_prog *fp)
|
void bpf_jit_free(struct bpf_prog *fp)
|
||||||
{
|
{
|
||||||
if (fp->jited)
|
if (fp->jited)
|
||||||
module_free(NULL, fp->bpf_func);
|
module_memfree(fp->bpf_func);
|
||||||
|
|
||||||
bpf_prog_unlock_free(fp);
|
bpf_prog_unlock_free(fp);
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ void *module_alloc(unsigned long size)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Free memory returned from module_alloc */
|
/* Free memory returned from module_alloc */
|
||||||
void module_free(struct module *mod, void *module_region)
|
void module_memfree(void *module_region)
|
||||||
{
|
{
|
||||||
kfree(module_region);
|
kfree(module_region);
|
||||||
}
|
}
|
||||||
|
|
|
@ -298,14 +298,10 @@ static inline unsigned long count_stubs(const Elf_Rela *rela, unsigned long n)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void module_arch_freeing_init(struct module *mod)
|
||||||
/* Free memory returned from module_alloc */
|
|
||||||
void module_free(struct module *mod, void *module_region)
|
|
||||||
{
|
{
|
||||||
kfree(mod->arch.section);
|
kfree(mod->arch.section);
|
||||||
mod->arch.section = NULL;
|
mod->arch.section = NULL;
|
||||||
|
|
||||||
vfree(module_region);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Additional bytes needed in front of individual sections */
|
/* Additional bytes needed in front of individual sections */
|
||||||
|
|
|
@ -699,7 +699,7 @@ out:
|
||||||
void bpf_jit_free(struct bpf_prog *fp)
|
void bpf_jit_free(struct bpf_prog *fp)
|
||||||
{
|
{
|
||||||
if (fp->jited)
|
if (fp->jited)
|
||||||
module_free(NULL, fp->bpf_func);
|
module_memfree(fp->bpf_func);
|
||||||
|
|
||||||
bpf_prog_unlock_free(fp);
|
bpf_prog_unlock_free(fp);
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,14 +55,10 @@ void *module_alloc(unsigned long size)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Free memory returned from module_alloc */
|
void module_arch_freeing_init(struct module *mod)
|
||||||
void module_free(struct module *mod, void *module_region)
|
|
||||||
{
|
{
|
||||||
if (mod) {
|
vfree(mod->arch.syminfo);
|
||||||
vfree(mod->arch.syminfo);
|
mod->arch.syminfo = NULL;
|
||||||
mod->arch.syminfo = NULL;
|
|
||||||
}
|
|
||||||
vfree(module_region);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void check_rela(Elf_Rela *rela, struct module *me)
|
static void check_rela(Elf_Rela *rela, struct module *me)
|
||||||
|
|
|
@ -776,7 +776,7 @@ cond_branch: f_offset = addrs[i + filter[i].jf];
|
||||||
if (unlikely(proglen + ilen > oldproglen)) {
|
if (unlikely(proglen + ilen > oldproglen)) {
|
||||||
pr_err("bpb_jit_compile fatal error\n");
|
pr_err("bpb_jit_compile fatal error\n");
|
||||||
kfree(addrs);
|
kfree(addrs);
|
||||||
module_free(NULL, image);
|
module_memfree(image);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
memcpy(image + proglen, temp, ilen);
|
memcpy(image + proglen, temp, ilen);
|
||||||
|
@ -822,7 +822,7 @@ out:
|
||||||
void bpf_jit_free(struct bpf_prog *fp)
|
void bpf_jit_free(struct bpf_prog *fp)
|
||||||
{
|
{
|
||||||
if (fp->jited)
|
if (fp->jited)
|
||||||
module_free(NULL, fp->bpf_func);
|
module_memfree(fp->bpf_func);
|
||||||
|
|
||||||
bpf_prog_unlock_free(fp);
|
bpf_prog_unlock_free(fp);
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,7 @@ error:
|
||||||
|
|
||||||
|
|
||||||
/* Free memory returned from module_alloc */
|
/* Free memory returned from module_alloc */
|
||||||
void module_free(struct module *mod, void *module_region)
|
void module_memfree(void *module_region)
|
||||||
{
|
{
|
||||||
vfree(module_region);
|
vfree(module_region);
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ void module_free(struct module *mod, void *module_region)
|
||||||
0, 0, 0, NULL, NULL, 0);
|
0, 0, 0, NULL, NULL, 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FIXME: If module_region == mod->module_init, trim exception
|
* FIXME: Add module_arch_freeing_init to trim exception
|
||||||
* table entries.
|
* table entries.
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
|
@ -674,7 +674,7 @@ static inline void *alloc_tramp(unsigned long size)
|
||||||
}
|
}
|
||||||
static inline void tramp_free(void *tramp)
|
static inline void tramp_free(void *tramp)
|
||||||
{
|
{
|
||||||
module_free(NULL, tramp);
|
module_memfree(tramp);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
/* Trampolines can only be created if modules are supported */
|
/* Trampolines can only be created if modules are supported */
|
||||||
|
|
|
@ -444,7 +444,7 @@ extern void __module_put_and_exit(struct module *mod, long code)
|
||||||
#define module_put_and_exit(code) __module_put_and_exit(THIS_MODULE, code)
|
#define module_put_and_exit(code) __module_put_and_exit(THIS_MODULE, code)
|
||||||
|
|
||||||
#ifdef CONFIG_MODULE_UNLOAD
|
#ifdef CONFIG_MODULE_UNLOAD
|
||||||
unsigned long module_refcount(struct module *mod);
|
int module_refcount(struct module *mod);
|
||||||
void __symbol_put(const char *symbol);
|
void __symbol_put(const char *symbol);
|
||||||
#define symbol_put(x) __symbol_put(VMLINUX_SYMBOL_STR(x))
|
#define symbol_put(x) __symbol_put(VMLINUX_SYMBOL_STR(x))
|
||||||
void symbol_put_addr(void *addr);
|
void symbol_put_addr(void *addr);
|
||||||
|
|
|
@ -26,7 +26,7 @@ unsigned int arch_mod_section_prepend(struct module *mod, unsigned int section);
|
||||||
void *module_alloc(unsigned long size);
|
void *module_alloc(unsigned long size);
|
||||||
|
|
||||||
/* Free memory returned from module_alloc. */
|
/* Free memory returned from module_alloc. */
|
||||||
void module_free(struct module *mod, void *module_region);
|
void module_memfree(void *module_region);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Apply the given relocation to the (simplified) ELF. Return -error
|
* Apply the given relocation to the (simplified) ELF. Return -error
|
||||||
|
@ -82,4 +82,6 @@ int module_finalize(const Elf_Ehdr *hdr,
|
||||||
/* Any cleanup needed when module leaves. */
|
/* Any cleanup needed when module leaves. */
|
||||||
void module_arch_cleanup(struct module *mod);
|
void module_arch_cleanup(struct module *mod);
|
||||||
|
|
||||||
|
/* Any cleanup before freeing mod->module_init */
|
||||||
|
void module_arch_freeing_init(struct module *mod);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -163,7 +163,7 @@ bpf_jit_binary_alloc(unsigned int proglen, u8 **image_ptr,
|
||||||
|
|
||||||
void bpf_jit_binary_free(struct bpf_binary_header *hdr)
|
void bpf_jit_binary_free(struct bpf_binary_header *hdr)
|
||||||
{
|
{
|
||||||
module_free(NULL, hdr);
|
module_memfree(hdr);
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_BPF_JIT */
|
#endif /* CONFIG_BPF_JIT */
|
||||||
|
|
||||||
|
|
|
@ -2023,7 +2023,7 @@ static int kdb_lsmod(int argc, const char **argv)
|
||||||
kdb_printf("%-20s%8u 0x%p ", mod->name,
|
kdb_printf("%-20s%8u 0x%p ", mod->name,
|
||||||
mod->core_size, (void *)mod);
|
mod->core_size, (void *)mod);
|
||||||
#ifdef CONFIG_MODULE_UNLOAD
|
#ifdef CONFIG_MODULE_UNLOAD
|
||||||
kdb_printf("%4ld ", module_refcount(mod));
|
kdb_printf("%4d ", module_refcount(mod));
|
||||||
#endif
|
#endif
|
||||||
if (mod->state == MODULE_STATE_GOING)
|
if (mod->state == MODULE_STATE_GOING)
|
||||||
kdb_printf(" (Unloading)");
|
kdb_printf(" (Unloading)");
|
||||||
|
|
|
@ -127,7 +127,7 @@ static void *alloc_insn_page(void)
|
||||||
|
|
||||||
static void free_insn_page(void *page)
|
static void free_insn_page(void *page)
|
||||||
{
|
{
|
||||||
module_free(NULL, page);
|
module_memfree(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct kprobe_insn_cache kprobe_insn_slots = {
|
struct kprobe_insn_cache kprobe_insn_slots = {
|
||||||
|
|
|
@ -772,9 +772,18 @@ static int try_stop_module(struct module *mod, int flags, int *forced)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long module_refcount(struct module *mod)
|
/**
|
||||||
|
* module_refcount - return the refcount or -1 if unloading
|
||||||
|
*
|
||||||
|
* @mod: the module we're checking
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* -1 if the module is in the process of unloading
|
||||||
|
* otherwise the number of references in the kernel to the module
|
||||||
|
*/
|
||||||
|
int module_refcount(struct module *mod)
|
||||||
{
|
{
|
||||||
return (unsigned long)atomic_read(&mod->refcnt) - MODULE_REF_BASE;
|
return atomic_read(&mod->refcnt) - MODULE_REF_BASE;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(module_refcount);
|
EXPORT_SYMBOL(module_refcount);
|
||||||
|
|
||||||
|
@ -856,7 +865,7 @@ static inline void print_unload_info(struct seq_file *m, struct module *mod)
|
||||||
struct module_use *use;
|
struct module_use *use;
|
||||||
int printed_something = 0;
|
int printed_something = 0;
|
||||||
|
|
||||||
seq_printf(m, " %lu ", module_refcount(mod));
|
seq_printf(m, " %i ", module_refcount(mod));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Always include a trailing , so userspace can differentiate
|
* Always include a trailing , so userspace can differentiate
|
||||||
|
@ -908,7 +917,7 @@ EXPORT_SYMBOL_GPL(symbol_put_addr);
|
||||||
static ssize_t show_refcnt(struct module_attribute *mattr,
|
static ssize_t show_refcnt(struct module_attribute *mattr,
|
||||||
struct module_kobject *mk, char *buffer)
|
struct module_kobject *mk, char *buffer)
|
||||||
{
|
{
|
||||||
return sprintf(buffer, "%lu\n", module_refcount(mk->mod));
|
return sprintf(buffer, "%i\n", module_refcount(mk->mod));
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct module_attribute modinfo_refcnt =
|
static struct module_attribute modinfo_refcnt =
|
||||||
|
@ -1795,7 +1804,7 @@ static void unset_module_core_ro_nx(struct module *mod) { }
|
||||||
static void unset_module_init_ro_nx(struct module *mod) { }
|
static void unset_module_init_ro_nx(struct module *mod) { }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void __weak module_free(struct module *mod, void *module_region)
|
void __weak module_memfree(void *module_region)
|
||||||
{
|
{
|
||||||
vfree(module_region);
|
vfree(module_region);
|
||||||
}
|
}
|
||||||
|
@ -1804,6 +1813,10 @@ void __weak module_arch_cleanup(struct module *mod)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void __weak module_arch_freeing_init(struct module *mod)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/* Free a module, remove from lists, etc. */
|
/* Free a module, remove from lists, etc. */
|
||||||
static void free_module(struct module *mod)
|
static void free_module(struct module *mod)
|
||||||
{
|
{
|
||||||
|
@ -1841,7 +1854,8 @@ static void free_module(struct module *mod)
|
||||||
|
|
||||||
/* This may be NULL, but that's OK */
|
/* This may be NULL, but that's OK */
|
||||||
unset_module_init_ro_nx(mod);
|
unset_module_init_ro_nx(mod);
|
||||||
module_free(mod, mod->module_init);
|
module_arch_freeing_init(mod);
|
||||||
|
module_memfree(mod->module_init);
|
||||||
kfree(mod->args);
|
kfree(mod->args);
|
||||||
percpu_modfree(mod);
|
percpu_modfree(mod);
|
||||||
|
|
||||||
|
@ -1850,7 +1864,7 @@ static void free_module(struct module *mod)
|
||||||
|
|
||||||
/* Finally, free the core (containing the module structure) */
|
/* Finally, free the core (containing the module structure) */
|
||||||
unset_module_core_ro_nx(mod);
|
unset_module_core_ro_nx(mod);
|
||||||
module_free(mod, mod->module_core);
|
module_memfree(mod->module_core);
|
||||||
|
|
||||||
#ifdef CONFIG_MPU
|
#ifdef CONFIG_MPU
|
||||||
update_protections(current->mm);
|
update_protections(current->mm);
|
||||||
|
@ -2785,7 +2799,7 @@ static int move_module(struct module *mod, struct load_info *info)
|
||||||
*/
|
*/
|
||||||
kmemleak_ignore(ptr);
|
kmemleak_ignore(ptr);
|
||||||
if (!ptr) {
|
if (!ptr) {
|
||||||
module_free(mod, mod->module_core);
|
module_memfree(mod->module_core);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
memset(ptr, 0, mod->init_size);
|
memset(ptr, 0, mod->init_size);
|
||||||
|
@ -2930,8 +2944,9 @@ static struct module *layout_and_allocate(struct load_info *info, int flags)
|
||||||
static void module_deallocate(struct module *mod, struct load_info *info)
|
static void module_deallocate(struct module *mod, struct load_info *info)
|
||||||
{
|
{
|
||||||
percpu_modfree(mod);
|
percpu_modfree(mod);
|
||||||
module_free(mod, mod->module_init);
|
module_arch_freeing_init(mod);
|
||||||
module_free(mod, mod->module_core);
|
module_memfree(mod->module_init);
|
||||||
|
module_memfree(mod->module_core);
|
||||||
}
|
}
|
||||||
|
|
||||||
int __weak module_finalize(const Elf_Ehdr *hdr,
|
int __weak module_finalize(const Elf_Ehdr *hdr,
|
||||||
|
@ -2983,10 +2998,31 @@ static void do_mod_ctors(struct module *mod)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* For freeing module_init on success, in case kallsyms traversing */
|
||||||
|
struct mod_initfree {
|
||||||
|
struct rcu_head rcu;
|
||||||
|
void *module_init;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void do_free_init(struct rcu_head *head)
|
||||||
|
{
|
||||||
|
struct mod_initfree *m = container_of(head, struct mod_initfree, rcu);
|
||||||
|
module_memfree(m->module_init);
|
||||||
|
kfree(m);
|
||||||
|
}
|
||||||
|
|
||||||
/* This is where the real work happens */
|
/* This is where the real work happens */
|
||||||
static int do_init_module(struct module *mod)
|
static int do_init_module(struct module *mod)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
struct mod_initfree *freeinit;
|
||||||
|
|
||||||
|
freeinit = kmalloc(sizeof(*freeinit), GFP_KERNEL);
|
||||||
|
if (!freeinit) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
freeinit->module_init = mod->module_init;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We want to find out whether @mod uses async during init. Clear
|
* We want to find out whether @mod uses async during init. Clear
|
||||||
|
@ -2999,18 +3035,7 @@ static int do_init_module(struct module *mod)
|
||||||
if (mod->init != NULL)
|
if (mod->init != NULL)
|
||||||
ret = do_one_initcall(mod->init);
|
ret = do_one_initcall(mod->init);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
/*
|
goto fail_free_freeinit;
|
||||||
* Init routine failed: abort. Try to protect us from
|
|
||||||
* buggy refcounters.
|
|
||||||
*/
|
|
||||||
mod->state = MODULE_STATE_GOING;
|
|
||||||
synchronize_sched();
|
|
||||||
module_put(mod);
|
|
||||||
blocking_notifier_call_chain(&module_notify_list,
|
|
||||||
MODULE_STATE_GOING, mod);
|
|
||||||
free_module(mod);
|
|
||||||
wake_up_all(&module_wq);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
if (ret > 0) {
|
if (ret > 0) {
|
||||||
pr_warn("%s: '%s'->init suspiciously returned %d, it should "
|
pr_warn("%s: '%s'->init suspiciously returned %d, it should "
|
||||||
|
@ -3055,15 +3080,35 @@ static int do_init_module(struct module *mod)
|
||||||
mod->strtab = mod->core_strtab;
|
mod->strtab = mod->core_strtab;
|
||||||
#endif
|
#endif
|
||||||
unset_module_init_ro_nx(mod);
|
unset_module_init_ro_nx(mod);
|
||||||
module_free(mod, mod->module_init);
|
module_arch_freeing_init(mod);
|
||||||
mod->module_init = NULL;
|
mod->module_init = NULL;
|
||||||
mod->init_size = 0;
|
mod->init_size = 0;
|
||||||
mod->init_ro_size = 0;
|
mod->init_ro_size = 0;
|
||||||
mod->init_text_size = 0;
|
mod->init_text_size = 0;
|
||||||
|
/*
|
||||||
|
* We want to free module_init, but be aware that kallsyms may be
|
||||||
|
* walking this with preempt disabled. In all the failure paths,
|
||||||
|
* we call synchronize_rcu/synchronize_sched, but we don't want
|
||||||
|
* to slow down the success path, so use actual RCU here.
|
||||||
|
*/
|
||||||
|
call_rcu(&freeinit->rcu, do_free_init);
|
||||||
mutex_unlock(&module_mutex);
|
mutex_unlock(&module_mutex);
|
||||||
wake_up_all(&module_wq);
|
wake_up_all(&module_wq);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
fail_free_freeinit:
|
||||||
|
kfree(freeinit);
|
||||||
|
fail:
|
||||||
|
/* Try to protect us from buggy refcounters. */
|
||||||
|
mod->state = MODULE_STATE_GOING;
|
||||||
|
synchronize_sched();
|
||||||
|
module_put(mod);
|
||||||
|
blocking_notifier_call_chain(&module_notify_list,
|
||||||
|
MODULE_STATE_GOING, mod);
|
||||||
|
free_module(mod);
|
||||||
|
wake_up_all(&module_wq);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int may_init_module(void)
|
static int may_init_module(void)
|
||||||
|
|
|
@ -642,12 +642,15 @@ static __modinit int add_sysfs_param(struct module_kobject *mk,
|
||||||
mk->mp->grp.attrs = new_attrs;
|
mk->mp->grp.attrs = new_attrs;
|
||||||
|
|
||||||
/* Tack new one on the end. */
|
/* Tack new one on the end. */
|
||||||
|
memset(&mk->mp->attrs[mk->mp->num], 0, sizeof(mk->mp->attrs[0]));
|
||||||
sysfs_attr_init(&mk->mp->attrs[mk->mp->num].mattr.attr);
|
sysfs_attr_init(&mk->mp->attrs[mk->mp->num].mattr.attr);
|
||||||
mk->mp->attrs[mk->mp->num].param = kp;
|
mk->mp->attrs[mk->mp->num].param = kp;
|
||||||
mk->mp->attrs[mk->mp->num].mattr.show = param_attr_show;
|
mk->mp->attrs[mk->mp->num].mattr.show = param_attr_show;
|
||||||
/* Do not allow runtime DAC changes to make param writable. */
|
/* Do not allow runtime DAC changes to make param writable. */
|
||||||
if ((kp->perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0)
|
if ((kp->perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0)
|
||||||
mk->mp->attrs[mk->mp->num].mattr.store = param_attr_store;
|
mk->mp->attrs[mk->mp->num].mattr.store = param_attr_store;
|
||||||
|
else
|
||||||
|
mk->mp->attrs[mk->mp->num].mattr.store = NULL;
|
||||||
mk->mp->attrs[mk->mp->num].mattr.attr.name = (char *)name;
|
mk->mp->attrs[mk->mp->num].mattr.attr.name = (char *)name;
|
||||||
mk->mp->attrs[mk->mp->num].mattr.attr.mode = kp->perm;
|
mk->mp->attrs[mk->mp->num].mattr.attr.mode = kp->perm;
|
||||||
mk->mp->num++;
|
mk->mp->num++;
|
||||||
|
|
Loading…
Add table
Reference in a new issue