diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/module.c | 24 |
1 files changed, 22 insertions, 2 deletions
diff --git a/kernel/module.c b/kernel/module.c index 5c7eb0695b3..d8b5605132a 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -70,6 +70,9 @@ static DECLARE_WAIT_QUEUE_HEAD(module_wq); | |||
70 | 70 | ||
71 | static BLOCKING_NOTIFIER_HEAD(module_notify_list); | 71 | static BLOCKING_NOTIFIER_HEAD(module_notify_list); |
72 | 72 | ||
73 | /* Bounds of module allocation, for speeding __module_text_address */ | ||
74 | static unsigned long module_addr_min = -1UL, module_addr_max = 0; | ||
75 | |||
73 | int register_module_notifier(struct notifier_block * nb) | 76 | int register_module_notifier(struct notifier_block * nb) |
74 | { | 77 | { |
75 | return blocking_notifier_chain_register(&module_notify_list, nb); | 78 | return blocking_notifier_chain_register(&module_notify_list, nb); |
@@ -1779,6 +1782,20 @@ static inline void add_kallsyms(struct module *mod, | |||
1779 | } | 1782 | } |
1780 | #endif /* CONFIG_KALLSYMS */ | 1783 | #endif /* CONFIG_KALLSYMS */ |
1781 | 1784 | ||
1785 | static void *module_alloc_update_bounds(unsigned long size) | ||
1786 | { | ||
1787 | void *ret = module_alloc(size); | ||
1788 | |||
1789 | if (ret) { | ||
1790 | /* Update module bounds. */ | ||
1791 | if ((unsigned long)ret < module_addr_min) | ||
1792 | module_addr_min = (unsigned long)ret; | ||
1793 | if ((unsigned long)ret + size > module_addr_max) | ||
1794 | module_addr_max = (unsigned long)ret + size; | ||
1795 | } | ||
1796 | return ret; | ||
1797 | } | ||
1798 | |||
1782 | /* Allocate and load the module: note that size of section 0 is always | 1799 | /* Allocate and load the module: note that size of section 0 is always |
1783 | zero, and we rely on this for optional sections. */ | 1800 | zero, and we rely on this for optional sections. */ |
1784 | static struct module *load_module(void __user *umod, | 1801 | static struct module *load_module(void __user *umod, |
@@ -1980,7 +1997,7 @@ static struct module *load_module(void __user *umod, | |||
1980 | layout_sections(mod, hdr, sechdrs, secstrings); | 1997 | layout_sections(mod, hdr, sechdrs, secstrings); |
1981 | 1998 | ||
1982 | /* Do the allocs. */ | 1999 | /* Do the allocs. */ |
1983 | ptr = module_alloc(mod->core_size); | 2000 | ptr = module_alloc_update_bounds(mod->core_size); |
1984 | if (!ptr) { | 2001 | if (!ptr) { |
1985 | err = -ENOMEM; | 2002 | err = -ENOMEM; |
1986 | goto free_percpu; | 2003 | goto free_percpu; |
@@ -1988,7 +2005,7 @@ static struct module *load_module(void __user *umod, | |||
1988 | memset(ptr, 0, mod->core_size); | 2005 | memset(ptr, 0, mod->core_size); |
1989 | mod->module_core = ptr; | 2006 | mod->module_core = ptr; |
1990 | 2007 | ||
1991 | ptr = module_alloc(mod->init_size); | 2008 | ptr = module_alloc_update_bounds(mod->init_size); |
1992 | if (!ptr && mod->init_size) { | 2009 | if (!ptr && mod->init_size) { |
1993 | err = -ENOMEM; | 2010 | err = -ENOMEM; |
1994 | goto free_core; | 2011 | goto free_core; |
@@ -2645,6 +2662,9 @@ struct module *__module_text_address(unsigned long addr) | |||
2645 | { | 2662 | { |
2646 | struct module *mod; | 2663 | struct module *mod; |
2647 | 2664 | ||
2665 | if (addr < module_addr_min || addr > module_addr_max) | ||
2666 | return NULL; | ||
2667 | |||
2648 | list_for_each_entry(mod, &modules, list) | 2668 | list_for_each_entry(mod, &modules, list) |
2649 | if (within(addr, mod->module_init, mod->init_text_size) | 2669 | if (within(addr, mod->module_init, mod->init_text_size) |
2650 | || within(addr, mod->module_core, mod->core_text_size)) | 2670 | || within(addr, mod->module_core, mod->core_text_size)) |