|
@@ -68,7 +68,8 @@
|
|
|
|
|
|
/* List of modules, protected by module_mutex or preempt_disable
|
|
|
* (delete uses stop_machine/add uses RCU list operations). */
|
|
|
-static DEFINE_MUTEX(module_mutex);
|
|
|
+DEFINE_MUTEX(module_mutex);
|
|
|
+EXPORT_SYMBOL_GPL(module_mutex);
|
|
|
static LIST_HEAD(modules);
|
|
|
|
|
|
/* Waiting for a module to finish initializing? */
|
|
@@ -76,7 +77,7 @@ static DECLARE_WAIT_QUEUE_HEAD(module_wq);
|
|
|
|
|
|
static BLOCKING_NOTIFIER_HEAD(module_notify_list);
|
|
|
|
|
|
-/* Bounds of module allocation, for speeding __module_text_address */
|
|
|
+/* Bounds of module allocation, for speeding __module_address */
|
|
|
static unsigned long module_addr_min = -1UL, module_addr_max = 0;
|
|
|
|
|
|
int register_module_notifier(struct notifier_block * nb)
|
|
@@ -186,17 +187,6 @@ extern const unsigned long __start___kcrctab_unused_gpl[];
|
|
|
#define symversion(base, idx) ((base != NULL) ? ((base) + (idx)) : NULL)
|
|
|
#endif
|
|
|
|
|
|
-struct symsearch {
|
|
|
- const struct kernel_symbol *start, *stop;
|
|
|
- const unsigned long *crcs;
|
|
|
- enum {
|
|
|
- NOT_GPL_ONLY,
|
|
|
- GPL_ONLY,
|
|
|
- WILL_BE_GPL_ONLY,
|
|
|
- } licence;
|
|
|
- bool unused;
|
|
|
-};
|
|
|
-
|
|
|
static bool each_symbol_in_section(const struct symsearch *arr,
|
|
|
unsigned int arrsize,
|
|
|
struct module *owner,
|
|
@@ -217,10 +207,8 @@ static bool each_symbol_in_section(const struct symsearch *arr,
|
|
|
}
|
|
|
|
|
|
/* Returns true as soon as fn returns true, otherwise false. */
|
|
|
-static bool each_symbol(bool (*fn)(const struct symsearch *arr,
|
|
|
- struct module *owner,
|
|
|
- unsigned int symnum, void *data),
|
|
|
- void *data)
|
|
|
+bool each_symbol(bool (*fn)(const struct symsearch *arr, struct module *owner,
|
|
|
+ unsigned int symnum, void *data), void *data)
|
|
|
{
|
|
|
struct module *mod;
|
|
|
const struct symsearch arr[] = {
|
|
@@ -273,6 +261,7 @@ static bool each_symbol(bool (*fn)(const struct symsearch *arr,
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
+EXPORT_SYMBOL_GPL(each_symbol);
|
|
|
|
|
|
struct find_symbol_arg {
|
|
|
/* Input */
|
|
@@ -283,7 +272,7 @@ struct find_symbol_arg {
|
|
|
/* Output */
|
|
|
struct module *owner;
|
|
|
const unsigned long *crc;
|
|
|
- unsigned long value;
|
|
|
+ const struct kernel_symbol *sym;
|
|
|
};
|
|
|
|
|
|
static bool find_symbol_in_section(const struct symsearch *syms,
|
|
@@ -324,17 +313,17 @@ static bool find_symbol_in_section(const struct symsearch *syms,
|
|
|
|
|
|
fsa->owner = owner;
|
|
|
fsa->crc = symversion(syms->crcs, symnum);
|
|
|
- fsa->value = syms->start[symnum].value;
|
|
|
+ fsa->sym = &syms->start[symnum];
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
-/* Find a symbol, return value, (optional) crc and (optional) module
|
|
|
- * which owns it */
|
|
|
-static unsigned long find_symbol(const char *name,
|
|
|
- struct module **owner,
|
|
|
- const unsigned long **crc,
|
|
|
- bool gplok,
|
|
|
- bool warn)
|
|
|
+/* Find a symbol and return it, along with, (optional) crc and
|
|
|
+ * (optional) module which owns it */
|
|
|
+const struct kernel_symbol *find_symbol(const char *name,
|
|
|
+ struct module **owner,
|
|
|
+ const unsigned long **crc,
|
|
|
+ bool gplok,
|
|
|
+ bool warn)
|
|
|
{
|
|
|
struct find_symbol_arg fsa;
|
|
|
|
|
@@ -347,15 +336,16 @@ static unsigned long find_symbol(const char *name,
|
|
|
*owner = fsa.owner;
|
|
|
if (crc)
|
|
|
*crc = fsa.crc;
|
|
|
- return fsa.value;
|
|
|
+ return fsa.sym;
|
|
|
}
|
|
|
|
|
|
DEBUGP("Failed to find symbol %s\n", name);
|
|
|
- return -ENOENT;
|
|
|
+ return NULL;
|
|
|
}
|
|
|
+EXPORT_SYMBOL_GPL(find_symbol);
|
|
|
|
|
|
/* Search for module by name: must hold module_mutex. */
|
|
|
-static struct module *find_module(const char *name)
|
|
|
+struct module *find_module(const char *name)
|
|
|
{
|
|
|
struct module *mod;
|
|
|
|
|
@@ -365,6 +355,7 @@ static struct module *find_module(const char *name)
|
|
|
}
|
|
|
return NULL;
|
|
|
}
|
|
|
+EXPORT_SYMBOL_GPL(find_module);
|
|
|
|
|
|
#ifdef CONFIG_SMP
|
|
|
|
|
@@ -641,7 +632,7 @@ static int already_uses(struct module *a, struct module *b)
|
|
|
}
|
|
|
|
|
|
/* Module a uses b */
|
|
|
-static int use_module(struct module *a, struct module *b)
|
|
|
+int use_module(struct module *a, struct module *b)
|
|
|
{
|
|
|
struct module_use *use;
|
|
|
int no_warn, err;
|
|
@@ -674,6 +665,7 @@ static int use_module(struct module *a, struct module *b)
|
|
|
no_warn = sysfs_create_link(b->holders_dir, &a->mkobj.kobj, a->name);
|
|
|
return 1;
|
|
|
}
|
|
|
+EXPORT_SYMBOL_GPL(use_module);
|
|
|
|
|
|
/* Clear the unload stuff of the module. */
|
|
|
static void module_unload_free(struct module *mod)
|
|
@@ -894,7 +886,7 @@ void __symbol_put(const char *symbol)
|
|
|
struct module *owner;
|
|
|
|
|
|
preempt_disable();
|
|
|
- if (IS_ERR_VALUE(find_symbol(symbol, &owner, NULL, true, false)))
|
|
|
+ if (!find_symbol(symbol, &owner, NULL, true, false))
|
|
|
BUG();
|
|
|
module_put(owner);
|
|
|
preempt_enable();
|
|
@@ -908,8 +900,10 @@ void symbol_put_addr(void *addr)
|
|
|
if (core_kernel_text((unsigned long)addr))
|
|
|
return;
|
|
|
|
|
|
- if (!(modaddr = module_text_address((unsigned long)addr)))
|
|
|
- BUG();
|
|
|
+ /* module_text_address is safe here: we're supposed to have reference
|
|
|
+ * to module from symbol_get, so it can't go away. */
|
|
|
+ modaddr = __module_text_address((unsigned long)addr);
|
|
|
+ BUG_ON(!modaddr);
|
|
|
module_put(modaddr);
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(symbol_put_addr);
|
|
@@ -949,10 +943,11 @@ static inline void module_unload_free(struct module *mod)
|
|
|
{
|
|
|
}
|
|
|
|
|
|
-static inline int use_module(struct module *a, struct module *b)
|
|
|
+int use_module(struct module *a, struct module *b)
|
|
|
{
|
|
|
return strong_try_module_get(b) == 0;
|
|
|
}
|
|
|
+EXPORT_SYMBOL_GPL(use_module);
|
|
|
|
|
|
static inline void module_unload_init(struct module *mod)
|
|
|
{
|
|
@@ -995,12 +990,12 @@ static struct module_attribute *modinfo_attrs[] = {
|
|
|
|
|
|
static const char vermagic[] = VERMAGIC_STRING;
|
|
|
|
|
|
-static int try_to_force_load(struct module *mod, const char *symname)
|
|
|
+static int try_to_force_load(struct module *mod, const char *reason)
|
|
|
{
|
|
|
#ifdef CONFIG_MODULE_FORCE_LOAD
|
|
|
if (!test_taint(TAINT_FORCED_MODULE))
|
|
|
- printk("%s: no version for \"%s\" found: kernel tainted.\n",
|
|
|
- mod->name, symname);
|
|
|
+ printk(KERN_WARNING "%s: %s: kernel tainted.\n",
|
|
|
+ mod->name, reason);
|
|
|
add_taint_module(mod, TAINT_FORCED_MODULE);
|
|
|
return 0;
|
|
|
#else
|
|
@@ -1057,9 +1052,9 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs,
|
|
|
{
|
|
|
const unsigned long *crc;
|
|
|
|
|
|
- if (IS_ERR_VALUE(find_symbol("struct_module", NULL, &crc, true, false)))
|
|
|
+ if (!find_symbol("module_layout", NULL, &crc, true, false))
|
|
|
BUG();
|
|
|
- return check_version(sechdrs, versindex, "struct_module", mod, crc);
|
|
|
+ return check_version(sechdrs, versindex, "module_layout", mod, crc);
|
|
|
}
|
|
|
|
|
|
/* First part is kernel version, which we ignore if module has crcs. */
|
|
@@ -1098,25 +1093,25 @@ static inline int same_magic(const char *amagic, const char *bmagic,
|
|
|
|
|
|
/* Resolve a symbol for this module. I.e. if we find one, record usage.
|
|
|
Must be holding module_mutex. */
|
|
|
-static unsigned long resolve_symbol(Elf_Shdr *sechdrs,
|
|
|
- unsigned int versindex,
|
|
|
- const char *name,
|
|
|
- struct module *mod)
|
|
|
+static const struct kernel_symbol *resolve_symbol(Elf_Shdr *sechdrs,
|
|
|
+ unsigned int versindex,
|
|
|
+ const char *name,
|
|
|
+ struct module *mod)
|
|
|
{
|
|
|
struct module *owner;
|
|
|
- unsigned long ret;
|
|
|
+ const struct kernel_symbol *sym;
|
|
|
const unsigned long *crc;
|
|
|
|
|
|
- ret = find_symbol(name, &owner, &crc,
|
|
|
+ sym = find_symbol(name, &owner, &crc,
|
|
|
!(mod->taints & (1 << TAINT_PROPRIETARY_MODULE)), true);
|
|
|
- if (!IS_ERR_VALUE(ret)) {
|
|
|
- /* use_module can fail due to OOM,
|
|
|
- or module initialization or unloading */
|
|
|
+ /* use_module can fail due to OOM,
|
|
|
+ or module initialization or unloading */
|
|
|
+ if (sym) {
|
|
|
if (!check_version(sechdrs, versindex, name, mod, crc) ||
|
|
|
!use_module(mod, owner))
|
|
|
- ret = -EINVAL;
|
|
|
+ sym = NULL;
|
|
|
}
|
|
|
- return ret;
|
|
|
+ return sym;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -1491,6 +1486,9 @@ static void free_module(struct module *mod)
|
|
|
/* Module unload stuff */
|
|
|
module_unload_free(mod);
|
|
|
|
|
|
+ /* Free any allocated parameters. */
|
|
|
+ destroy_params(mod->kp, mod->num_kp);
|
|
|
+
|
|
|
/* release any pointers to mcount in this module */
|
|
|
ftrace_release(mod->module_core, mod->core_size);
|
|
|
|
|
@@ -1513,17 +1511,15 @@ static void free_module(struct module *mod)
|
|
|
void *__symbol_get(const char *symbol)
|
|
|
{
|
|
|
struct module *owner;
|
|
|
- unsigned long value;
|
|
|
+ const struct kernel_symbol *sym;
|
|
|
|
|
|
preempt_disable();
|
|
|
- value = find_symbol(symbol, &owner, NULL, true, true);
|
|
|
- if (IS_ERR_VALUE(value))
|
|
|
- value = 0;
|
|
|
- else if (strong_try_module_get(owner))
|
|
|
- value = 0;
|
|
|
+ sym = find_symbol(symbol, &owner, NULL, true, true);
|
|
|
+ if (sym && strong_try_module_get(owner))
|
|
|
+ sym = NULL;
|
|
|
preempt_enable();
|
|
|
|
|
|
- return (void *)value;
|
|
|
+ return sym ? (void *)sym->value : NULL;
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(__symbol_get);
|
|
|
|
|
@@ -1551,8 +1547,7 @@ static int verify_export_symbols(struct module *mod)
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(arr); i++) {
|
|
|
for (s = arr[i].sym; s < arr[i].sym + arr[i].num; s++) {
|
|
|
- if (!IS_ERR_VALUE(find_symbol(s->name, &owner,
|
|
|
- NULL, true, false))) {
|
|
|
+ if (find_symbol(s->name, &owner, NULL, true, false)) {
|
|
|
printk(KERN_ERR
|
|
|
"%s: exports duplicate symbol %s"
|
|
|
" (owned by %s)\n",
|
|
@@ -1576,6 +1571,7 @@ static int simplify_symbols(Elf_Shdr *sechdrs,
|
|
|
unsigned long secbase;
|
|
|
unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym);
|
|
|
int ret = 0;
|
|
|
+ const struct kernel_symbol *ksym;
|
|
|
|
|
|
for (i = 1; i < n; i++) {
|
|
|
switch (sym[i].st_shndx) {
|
|
@@ -1595,13 +1591,14 @@ static int simplify_symbols(Elf_Shdr *sechdrs,
|
|
|
break;
|
|
|
|
|
|
case SHN_UNDEF:
|
|
|
- sym[i].st_value
|
|
|
- = resolve_symbol(sechdrs, versindex,
|
|
|
- strtab + sym[i].st_name, mod);
|
|
|
-
|
|
|
+ ksym = resolve_symbol(sechdrs, versindex,
|
|
|
+ strtab + sym[i].st_name, mod);
|
|
|
/* Ok if resolved. */
|
|
|
- if (!IS_ERR_VALUE(sym[i].st_value))
|
|
|
+ if (ksym) {
|
|
|
+ sym[i].st_value = ksym->value;
|
|
|
break;
|
|
|
+ }
|
|
|
+
|
|
|
/* Ok if weak. */
|
|
|
if (ELF_ST_BIND(sym[i].st_info) == STB_WEAK)
|
|
|
break;
|
|
@@ -1676,8 +1673,7 @@ static void layout_sections(struct module *mod,
|
|
|
if ((s->sh_flags & masks[m][0]) != masks[m][0]
|
|
|
|| (s->sh_flags & masks[m][1])
|
|
|
|| s->sh_entsize != ~0UL
|
|
|
- || strncmp(secstrings + s->sh_name,
|
|
|
- ".init", 5) == 0)
|
|
|
+ || strstarts(secstrings + s->sh_name, ".init"))
|
|
|
continue;
|
|
|
s->sh_entsize = get_offset(mod, &mod->core_size, s, i);
|
|
|
DEBUGP("\t%s\n", secstrings + s->sh_name);
|
|
@@ -1694,8 +1690,7 @@ static void layout_sections(struct module *mod,
|
|
|
if ((s->sh_flags & masks[m][0]) != masks[m][0]
|
|
|
|| (s->sh_flags & masks[m][1])
|
|
|
|| s->sh_entsize != ~0UL
|
|
|
- || strncmp(secstrings + s->sh_name,
|
|
|
- ".init", 5) != 0)
|
|
|
+ || !strstarts(secstrings + s->sh_name, ".init"))
|
|
|
continue;
|
|
|
s->sh_entsize = (get_offset(mod, &mod->init_size, s, i)
|
|
|
| INIT_OFFSET_MASK);
|
|
@@ -1828,8 +1823,7 @@ static char elf_type(const Elf_Sym *sym,
|
|
|
else
|
|
|
return 'b';
|
|
|
}
|
|
|
- if (strncmp(secstrings + sechdrs[sym->st_shndx].sh_name,
|
|
|
- ".debug", strlen(".debug")) == 0)
|
|
|
+ if (strstarts(secstrings + sechdrs[sym->st_shndx].sh_name, ".debug"))
|
|
|
return 'n';
|
|
|
return '?';
|
|
|
}
|
|
@@ -1898,8 +1892,7 @@ static noinline struct module *load_module(void __user *umod,
|
|
|
unsigned int symindex = 0;
|
|
|
unsigned int strindex = 0;
|
|
|
unsigned int modindex, versindex, infoindex, pcpuindex;
|
|
|
- unsigned int num_kp, num_mcount;
|
|
|
- struct kernel_param *kp;
|
|
|
+ unsigned int num_mcount;
|
|
|
struct module *mod;
|
|
|
long err = 0;
|
|
|
void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
|
|
@@ -1916,12 +1909,6 @@ static noinline struct module *load_module(void __user *umod,
|
|
|
if (len > 64 * 1024 * 1024 || (hdr = vmalloc(len)) == NULL)
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
- /* Create stop_machine threads since the error path relies on
|
|
|
- * a non-failing stop_machine call. */
|
|
|
- err = stop_machine_create();
|
|
|
- if (err)
|
|
|
- goto free_hdr;
|
|
|
-
|
|
|
if (copy_from_user(hdr, umod, len) != 0) {
|
|
|
err = -EFAULT;
|
|
|
goto free_hdr;
|
|
@@ -1962,9 +1949,12 @@ static noinline struct module *load_module(void __user *umod,
|
|
|
}
|
|
|
#ifndef CONFIG_MODULE_UNLOAD
|
|
|
/* Don't load .exit sections */
|
|
|
- if (strncmp(secstrings+sechdrs[i].sh_name, ".exit", 5) == 0)
|
|
|
+ if (strstarts(secstrings+sechdrs[i].sh_name, ".exit"))
|
|
|
sechdrs[i].sh_flags &= ~(unsigned long)SHF_ALLOC;
|
|
|
#endif
|
|
|
+ /* Don't keep __versions around; it's just for loading. */
|
|
|
+ if (strcmp(secstrings + sechdrs[i].sh_name, "__versions") == 0)
|
|
|
+ sechdrs[i].sh_flags &= ~(unsigned long)SHF_ALLOC;
|
|
|
}
|
|
|
|
|
|
modindex = find_sec(hdr, sechdrs, secstrings,
|
|
@@ -2006,7 +1996,7 @@ static noinline struct module *load_module(void __user *umod,
|
|
|
modmagic = get_modinfo(sechdrs, infoindex, "vermagic");
|
|
|
/* This is allowed: modprobe --force will invalidate it. */
|
|
|
if (!modmagic) {
|
|
|
- err = try_to_force_load(mod, "magic");
|
|
|
+ err = try_to_force_load(mod, "bad vermagic");
|
|
|
if (err)
|
|
|
goto free_hdr;
|
|
|
} else if (!same_magic(modmagic, vermagic, versindex)) {
|
|
@@ -2144,8 +2134,8 @@ static noinline struct module *load_module(void __user *umod,
|
|
|
|
|
|
/* Now we've got everything in the final locations, we can
|
|
|
* find optional sections. */
|
|
|
- kp = section_objs(hdr, sechdrs, secstrings, "__param", sizeof(*kp),
|
|
|
- &num_kp);
|
|
|
+ mod->kp = section_objs(hdr, sechdrs, secstrings, "__param",
|
|
|
+ sizeof(*mod->kp), &mod->num_kp);
|
|
|
mod->syms = section_objs(hdr, sechdrs, secstrings, "__ksymtab",
|
|
|
sizeof(*mod->syms), &mod->num_syms);
|
|
|
mod->crcs = section_addr(hdr, sechdrs, secstrings, "__kcrctab");
|
|
@@ -2195,8 +2185,8 @@ static noinline struct module *load_module(void __user *umod,
|
|
|
|| (mod->num_unused_gpl_syms && !mod->unused_gpl_crcs)
|
|
|
#endif
|
|
|
) {
|
|
|
- printk(KERN_WARNING "%s: No versions for exported symbols.\n", mod->name);
|
|
|
- err = try_to_force_load(mod, "nocrc");
|
|
|
+ err = try_to_force_load(mod,
|
|
|
+ "no versions for exported symbols");
|
|
|
if (err)
|
|
|
goto cleanup;
|
|
|
}
|
|
@@ -2291,11 +2281,11 @@ static noinline struct module *load_module(void __user *umod,
|
|
|
*/
|
|
|
list_add_rcu(&mod->list, &modules);
|
|
|
|
|
|
- err = parse_args(mod->name, mod->args, kp, num_kp, NULL);
|
|
|
+ err = parse_args(mod->name, mod->args, mod->kp, mod->num_kp, NULL);
|
|
|
if (err < 0)
|
|
|
goto unlink;
|
|
|
|
|
|
- err = mod_sysfs_setup(mod, kp, num_kp);
|
|
|
+ err = mod_sysfs_setup(mod, mod->kp, mod->num_kp);
|
|
|
if (err < 0)
|
|
|
goto unlink;
|
|
|
add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs);
|
|
@@ -2304,12 +2294,13 @@ static noinline struct module *load_module(void __user *umod,
|
|
|
/* Get rid of temporary copy */
|
|
|
vfree(hdr);
|
|
|
|
|
|
- stop_machine_destroy();
|
|
|
/* Done! */
|
|
|
return mod;
|
|
|
|
|
|
unlink:
|
|
|
- stop_machine(__unlink_module, mod, NULL);
|
|
|
+ /* Unlink carefully: kallsyms could be walking list. */
|
|
|
+ list_del_rcu(&mod->list);
|
|
|
+ synchronize_sched();
|
|
|
module_arch_cleanup(mod);
|
|
|
cleanup:
|
|
|
kobject_del(&mod->mkobj.kobj);
|
|
@@ -2317,8 +2308,8 @@ static noinline struct module *load_module(void __user *umod,
|
|
|
ftrace_release(mod->module_core, mod->core_size);
|
|
|
free_unload:
|
|
|
module_unload_free(mod);
|
|
|
- free_init:
|
|
|
#if defined(CONFIG_MODULE_UNLOAD) && defined(CONFIG_SMP)
|
|
|
+ free_init:
|
|
|
percpu_modfree(mod->refptr);
|
|
|
#endif
|
|
|
module_free(mod, mod->module_init);
|
|
@@ -2332,7 +2323,6 @@ static noinline struct module *load_module(void __user *umod,
|
|
|
kfree(args);
|
|
|
free_hdr:
|
|
|
vfree(hdr);
|
|
|
- stop_machine_destroy();
|
|
|
return ERR_PTR(err);
|
|
|
|
|
|
truncated:
|
|
@@ -2609,6 +2599,25 @@ unsigned long module_kallsyms_lookup_name(const char *name)
|
|
|
preempt_enable();
|
|
|
return ret;
|
|
|
}
|
|
|
+
|
|
|
+int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *,
|
|
|
+ struct module *, unsigned long),
|
|
|
+ void *data)
|
|
|
+{
|
|
|
+ struct module *mod;
|
|
|
+ unsigned int i;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ list_for_each_entry(mod, &modules, list) {
|
|
|
+ for (i = 0; i < mod->num_symtab; i++) {
|
|
|
+ ret = fn(data, mod->strtab + mod->symtab[i].st_name,
|
|
|
+ mod, mod->symtab[i].st_value);
|
|
|
+ if (ret != 0)
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
#endif /* CONFIG_KALLSYMS */
|
|
|
|
|
|
static char *module_flags(struct module *mod, char *buf)
|
|
@@ -2744,29 +2753,31 @@ const struct exception_table_entry *search_module_extables(unsigned long addr)
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * Is this a valid module address?
|
|
|
+ * is_module_address - is this address inside a module?
|
|
|
+ * @addr: the address to check.
|
|
|
+ *
|
|
|
+ * See is_module_text_address() if you simply want to see if the address
|
|
|
+ * is code (not data).
|
|
|
*/
|
|
|
-int is_module_address(unsigned long addr)
|
|
|
+bool is_module_address(unsigned long addr)
|
|
|
{
|
|
|
- struct module *mod;
|
|
|
+ bool ret;
|
|
|
|
|
|
preempt_disable();
|
|
|
-
|
|
|
- list_for_each_entry_rcu(mod, &modules, list) {
|
|
|
- if (within_module_core(addr, mod)) {
|
|
|
- preempt_enable();
|
|
|
- return 1;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
+ ret = __module_address(addr) != NULL;
|
|
|
preempt_enable();
|
|
|
|
|
|
- return 0;
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-/* Is this a valid kernel address? */
|
|
|
-__notrace_funcgraph struct module *__module_text_address(unsigned long addr)
|
|
|
+/*
|
|
|
+ * __module_address - get the module which contains an address.
|
|
|
+ * @addr: the address.
|
|
|
+ *
|
|
|
+ * Must be called with preempt disabled or module mutex held so that
|
|
|
+ * module doesn't get freed during this.
|
|
|
+ */
|
|
|
+__notrace_funcgraph struct module *__module_address(unsigned long addr)
|
|
|
{
|
|
|
struct module *mod;
|
|
|
|
|
@@ -2774,22 +2785,51 @@ __notrace_funcgraph struct module *__module_text_address(unsigned long addr)
|
|
|
return NULL;
|
|
|
|
|
|
list_for_each_entry_rcu(mod, &modules, list)
|
|
|
- if (within(addr, mod->module_init, mod->init_text_size)
|
|
|
- || within(addr, mod->module_core, mod->core_text_size))
|
|
|
+ if (within_module_core(addr, mod)
|
|
|
+ || within_module_init(addr, mod))
|
|
|
return mod;
|
|
|
return NULL;
|
|
|
}
|
|
|
+EXPORT_SYMBOL_GPL(__module_address);
|
|
|
|
|
|
-struct module *module_text_address(unsigned long addr)
|
|
|
+/*
|
|
|
+ * is_module_text_address - is this address inside module code?
|
|
|
+ * @addr: the address to check.
|
|
|
+ *
|
|
|
+ * See is_module_address() if you simply want to see if the address is
|
|
|
+ * anywhere in a module. See kernel_text_address() for testing if an
|
|
|
+ * address corresponds to kernel or module code.
|
|
|
+ */
|
|
|
+bool is_module_text_address(unsigned long addr)
|
|
|
{
|
|
|
- struct module *mod;
|
|
|
+ bool ret;
|
|
|
|
|
|
preempt_disable();
|
|
|
- mod = __module_text_address(addr);
|
|
|
+ ret = __module_text_address(addr) != NULL;
|
|
|
preempt_enable();
|
|
|
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * __module_text_address - get the module whose code contains an address.
|
|
|
+ * @addr: the address.
|
|
|
+ *
|
|
|
+ * Must be called with preempt disabled or module mutex held so that
|
|
|
+ * module doesn't get freed during this.
|
|
|
+ */
|
|
|
+struct module *__module_text_address(unsigned long addr)
|
|
|
+{
|
|
|
+ struct module *mod = __module_address(addr);
|
|
|
+ if (mod) {
|
|
|
+ /* Make sure it's within the text section. */
|
|
|
+ if (!within(addr, mod->module_init, mod->init_text_size)
|
|
|
+ && !within(addr, mod->module_core, mod->core_text_size))
|
|
|
+ mod = NULL;
|
|
|
+ }
|
|
|
return mod;
|
|
|
}
|
|
|
+EXPORT_SYMBOL_GPL(__module_text_address);
|
|
|
|
|
|
/* Don't grab lock, we're oopsing. */
|
|
|
void print_modules(void)
|
|
@@ -2809,9 +2849,17 @@ void print_modules(void)
|
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_MODVERSIONS
|
|
|
-/* Generate the signature for struct module here, too, for modversions. */
|
|
|
-void struct_module(struct module *mod) { return; }
|
|
|
-EXPORT_SYMBOL(struct_module);
|
|
|
+/* Generate the signature for all relevant module structures here.
|
|
|
+ * If these change, we don't want to try to parse the module. */
|
|
|
+void module_layout(struct module *mod,
|
|
|
+ struct modversion_info *ver,
|
|
|
+ struct kernel_param *kp,
|
|
|
+ struct kernel_symbol *ks,
|
|
|
+ struct marker *marker,
|
|
|
+ struct tracepoint *tp)
|
|
|
+{
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(module_layout);
|
|
|
#endif
|
|
|
|
|
|
#ifdef CONFIG_MARKERS
|