Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/livepatching
Pull livepatching updates from Jiri Kosina: - RO/NX attribute fixes for patch module relocations from Josh Poimboeuf. As part of this effort, module.c has been cleaned up as well and livepatching is piggy-backing on this cleanup. Rusty is OK with this whole lot going through livepatching tree. - symbol disambiguation support from Chris J Arges. That series is also Reviewed-by: Miroslav Benes <mbenes@suse.cz> but this came in only after I've alredy pushed out. Didn't want to rebase because of that, hence I am mentioning it here. - symbol lookup fix from Miroslav Benes * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/livepatching: livepatch: Cleanup module page permission changes module: keep percpu symbols in module's symtab module: clean up RO/NX handling. module: use a structure to encapsulate layout. gcov: use within_module() helper. module: Use the same logic for setting and unsetting RO/NX livepatch: function,sympos scheme in livepatch sysfs directory livepatch: add sympos as disambiguator field to klp_reloc livepatch: add old_sympos as disambiguator field to klp_func
This commit is contained in:
commit
0f0836b7eb
18 changed files with 343 additions and 430 deletions
355
kernel/module.c
355
kernel/module.c
|
@ -80,15 +80,6 @@
|
|||
# define debug_align(X) (X)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Given BASE and SIZE this macro calculates the number of pages the
|
||||
* memory regions occupies
|
||||
*/
|
||||
#define MOD_NUMBER_OF_PAGES(BASE, SIZE) (((SIZE) > 0) ? \
|
||||
(PFN_DOWN((unsigned long)(BASE) + (SIZE) - 1) - \
|
||||
PFN_DOWN((unsigned long)BASE) + 1) \
|
||||
: (0UL))
|
||||
|
||||
/* If this is set, the section belongs in the init part of the module */
|
||||
#define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1))
|
||||
|
||||
|
@ -108,13 +99,6 @@ static LIST_HEAD(modules);
|
|||
* Use a latched RB-tree for __module_address(); this allows us to use
|
||||
* RCU-sched lookups of the address from any context.
|
||||
*
|
||||
* Because modules have two address ranges: init and core, we need two
|
||||
* latch_tree_nodes entries. Therefore we need the back-pointer from
|
||||
* mod_tree_node.
|
||||
*
|
||||
* Because init ranges are short lived we mark them unlikely and have placed
|
||||
* them outside the critical cacheline in struct module.
|
||||
*
|
||||
* This is conditional on PERF_EVENTS || TRACING because those can really hit
|
||||
* __module_address() hard by doing a lot of stack unwinding; potentially from
|
||||
* NMI context.
|
||||
|
@ -122,24 +106,16 @@ static LIST_HEAD(modules);
|
|||
|
||||
static __always_inline unsigned long __mod_tree_val(struct latch_tree_node *n)
|
||||
{
|
||||
struct mod_tree_node *mtn = container_of(n, struct mod_tree_node, node);
|
||||
struct module *mod = mtn->mod;
|
||||
struct module_layout *layout = container_of(n, struct module_layout, mtn.node);
|
||||
|
||||
if (unlikely(mtn == &mod->mtn_init))
|
||||
return (unsigned long)mod->module_init;
|
||||
|
||||
return (unsigned long)mod->module_core;
|
||||
return (unsigned long)layout->base;
|
||||
}
|
||||
|
||||
static __always_inline unsigned long __mod_tree_size(struct latch_tree_node *n)
|
||||
{
|
||||
struct mod_tree_node *mtn = container_of(n, struct mod_tree_node, node);
|
||||
struct module *mod = mtn->mod;
|
||||
struct module_layout *layout = container_of(n, struct module_layout, mtn.node);
|
||||
|
||||
if (unlikely(mtn == &mod->mtn_init))
|
||||
return (unsigned long)mod->init_size;
|
||||
|
||||
return (unsigned long)mod->core_size;
|
||||
return (unsigned long)layout->size;
|
||||
}
|
||||
|
||||
static __always_inline bool
|
||||
|
@ -197,23 +173,23 @@ static void __mod_tree_remove(struct mod_tree_node *node)
|
|||
*/
|
||||
static void mod_tree_insert(struct module *mod)
|
||||
{
|
||||
mod->mtn_core.mod = mod;
|
||||
mod->mtn_init.mod = mod;
|
||||
mod->core_layout.mtn.mod = mod;
|
||||
mod->init_layout.mtn.mod = mod;
|
||||
|
||||
__mod_tree_insert(&mod->mtn_core);
|
||||
if (mod->init_size)
|
||||
__mod_tree_insert(&mod->mtn_init);
|
||||
__mod_tree_insert(&mod->core_layout.mtn);
|
||||
if (mod->init_layout.size)
|
||||
__mod_tree_insert(&mod->init_layout.mtn);
|
||||
}
|
||||
|
||||
static void mod_tree_remove_init(struct module *mod)
|
||||
{
|
||||
if (mod->init_size)
|
||||
__mod_tree_remove(&mod->mtn_init);
|
||||
if (mod->init_layout.size)
|
||||
__mod_tree_remove(&mod->init_layout.mtn);
|
||||
}
|
||||
|
||||
static void mod_tree_remove(struct module *mod)
|
||||
{
|
||||
__mod_tree_remove(&mod->mtn_core);
|
||||
__mod_tree_remove(&mod->core_layout.mtn);
|
||||
mod_tree_remove_init(mod);
|
||||
}
|
||||
|
||||
|
@ -267,9 +243,9 @@ static void __mod_update_bounds(void *base, unsigned int size)
|
|||
|
||||
static void mod_update_bounds(struct module *mod)
|
||||
{
|
||||
__mod_update_bounds(mod->module_core, mod->core_size);
|
||||
if (mod->init_size)
|
||||
__mod_update_bounds(mod->module_init, mod->init_size);
|
||||
__mod_update_bounds(mod->core_layout.base, mod->core_layout.size);
|
||||
if (mod->init_layout.size)
|
||||
__mod_update_bounds(mod->init_layout.base, mod->init_layout.size);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_KGDB_KDB
|
||||
|
@ -1214,7 +1190,7 @@ struct module_attribute module_uevent =
|
|||
static ssize_t show_coresize(struct module_attribute *mattr,
|
||||
struct module_kobject *mk, char *buffer)
|
||||
{
|
||||
return sprintf(buffer, "%u\n", mk->mod->core_size);
|
||||
return sprintf(buffer, "%u\n", mk->mod->core_layout.size);
|
||||
}
|
||||
|
||||
static struct module_attribute modinfo_coresize =
|
||||
|
@ -1223,7 +1199,7 @@ static struct module_attribute modinfo_coresize =
|
|||
static ssize_t show_initsize(struct module_attribute *mattr,
|
||||
struct module_kobject *mk, char *buffer)
|
||||
{
|
||||
return sprintf(buffer, "%u\n", mk->mod->init_size);
|
||||
return sprintf(buffer, "%u\n", mk->mod->init_layout.size);
|
||||
}
|
||||
|
||||
static struct module_attribute modinfo_initsize =
|
||||
|
@ -1873,64 +1849,75 @@ static void mod_sysfs_teardown(struct module *mod)
|
|||
/*
|
||||
* LKM RO/NX protection: protect module's text/ro-data
|
||||
* from modification and any data from execution.
|
||||
*
|
||||
* General layout of module is:
|
||||
* [text] [read-only-data] [writable data]
|
||||
* text_size -----^ ^ ^
|
||||
* ro_size ------------------------| |
|
||||
* size -------------------------------------------|
|
||||
*
|
||||
* These values are always page-aligned (as is base)
|
||||
*/
|
||||
void set_page_attributes(void *start, void *end, int (*set)(unsigned long start, int num_pages))
|
||||
static void frob_text(const struct module_layout *layout,
|
||||
int (*set_memory)(unsigned long start, int num_pages))
|
||||
{
|
||||
unsigned long begin_pfn = PFN_DOWN((unsigned long)start);
|
||||
unsigned long end_pfn = PFN_DOWN((unsigned long)end);
|
||||
|
||||
if (end_pfn > begin_pfn)
|
||||
set(begin_pfn << PAGE_SHIFT, end_pfn - begin_pfn);
|
||||
BUG_ON((unsigned long)layout->base & (PAGE_SIZE-1));
|
||||
BUG_ON((unsigned long)layout->text_size & (PAGE_SIZE-1));
|
||||
set_memory((unsigned long)layout->base,
|
||||
layout->text_size >> PAGE_SHIFT);
|
||||
}
|
||||
|
||||
static void set_section_ro_nx(void *base,
|
||||
unsigned long text_size,
|
||||
unsigned long ro_size,
|
||||
unsigned long total_size)
|
||||
static void frob_rodata(const struct module_layout *layout,
|
||||
int (*set_memory)(unsigned long start, int num_pages))
|
||||
{
|
||||
/* begin and end PFNs of the current subsection */
|
||||
unsigned long begin_pfn;
|
||||
unsigned long end_pfn;
|
||||
|
||||
/*
|
||||
* Set RO for module text and RO-data:
|
||||
* - Always protect first page.
|
||||
* - Do not protect last partial page.
|
||||
*/
|
||||
if (ro_size > 0)
|
||||
set_page_attributes(base, base + ro_size, set_memory_ro);
|
||||
|
||||
/*
|
||||
* Set NX permissions for module data:
|
||||
* - Do not protect first partial page.
|
||||
* - Always protect last page.
|
||||
*/
|
||||
if (total_size > text_size) {
|
||||
begin_pfn = PFN_UP((unsigned long)base + text_size);
|
||||
end_pfn = PFN_UP((unsigned long)base + total_size);
|
||||
if (end_pfn > begin_pfn)
|
||||
set_memory_nx(begin_pfn << PAGE_SHIFT, end_pfn - begin_pfn);
|
||||
}
|
||||
BUG_ON((unsigned long)layout->base & (PAGE_SIZE-1));
|
||||
BUG_ON((unsigned long)layout->text_size & (PAGE_SIZE-1));
|
||||
BUG_ON((unsigned long)layout->ro_size & (PAGE_SIZE-1));
|
||||
set_memory((unsigned long)layout->base + layout->text_size,
|
||||
(layout->ro_size - layout->text_size) >> PAGE_SHIFT);
|
||||
}
|
||||
|
||||
static void unset_module_core_ro_nx(struct module *mod)
|
||||
static void frob_writable_data(const struct module_layout *layout,
|
||||
int (*set_memory)(unsigned long start, int num_pages))
|
||||
{
|
||||
set_page_attributes(mod->module_core + mod->core_text_size,
|
||||
mod->module_core + mod->core_size,
|
||||
set_memory_x);
|
||||
set_page_attributes(mod->module_core,
|
||||
mod->module_core + mod->core_ro_size,
|
||||
set_memory_rw);
|
||||
BUG_ON((unsigned long)layout->base & (PAGE_SIZE-1));
|
||||
BUG_ON((unsigned long)layout->ro_size & (PAGE_SIZE-1));
|
||||
BUG_ON((unsigned long)layout->size & (PAGE_SIZE-1));
|
||||
set_memory((unsigned long)layout->base + layout->ro_size,
|
||||
(layout->size - layout->ro_size) >> PAGE_SHIFT);
|
||||
}
|
||||
|
||||
static void unset_module_init_ro_nx(struct module *mod)
|
||||
/* livepatching wants to disable read-only so it can frob module. */
|
||||
void module_disable_ro(const struct module *mod)
|
||||
{
|
||||
set_page_attributes(mod->module_init + mod->init_text_size,
|
||||
mod->module_init + mod->init_size,
|
||||
set_memory_x);
|
||||
set_page_attributes(mod->module_init,
|
||||
mod->module_init + mod->init_ro_size,
|
||||
set_memory_rw);
|
||||
frob_text(&mod->core_layout, set_memory_rw);
|
||||
frob_rodata(&mod->core_layout, set_memory_rw);
|
||||
frob_text(&mod->init_layout, set_memory_rw);
|
||||
frob_rodata(&mod->init_layout, set_memory_rw);
|
||||
}
|
||||
|
||||
void module_enable_ro(const struct module *mod)
|
||||
{
|
||||
frob_text(&mod->core_layout, set_memory_ro);
|
||||
frob_rodata(&mod->core_layout, set_memory_ro);
|
||||
frob_text(&mod->init_layout, set_memory_ro);
|
||||
frob_rodata(&mod->init_layout, set_memory_ro);
|
||||
}
|
||||
|
||||
static void module_enable_nx(const struct module *mod)
|
||||
{
|
||||
frob_rodata(&mod->core_layout, set_memory_nx);
|
||||
frob_writable_data(&mod->core_layout, set_memory_nx);
|
||||
frob_rodata(&mod->init_layout, set_memory_nx);
|
||||
frob_writable_data(&mod->init_layout, set_memory_nx);
|
||||
}
|
||||
|
||||
static void module_disable_nx(const struct module *mod)
|
||||
{
|
||||
frob_rodata(&mod->core_layout, set_memory_x);
|
||||
frob_writable_data(&mod->core_layout, set_memory_x);
|
||||
frob_rodata(&mod->init_layout, set_memory_x);
|
||||
frob_writable_data(&mod->init_layout, set_memory_x);
|
||||
}
|
||||
|
||||
/* Iterate through all modules and set each module's text as RW */
|
||||
|
@ -1942,16 +1929,9 @@ void set_all_modules_text_rw(void)
|
|||
list_for_each_entry_rcu(mod, &modules, list) {
|
||||
if (mod->state == MODULE_STATE_UNFORMED)
|
||||
continue;
|
||||
if ((mod->module_core) && (mod->core_text_size)) {
|
||||
set_page_attributes(mod->module_core,
|
||||
mod->module_core + mod->core_text_size,
|
||||
set_memory_rw);
|
||||
}
|
||||
if ((mod->module_init) && (mod->init_text_size)) {
|
||||
set_page_attributes(mod->module_init,
|
||||
mod->module_init + mod->init_text_size,
|
||||
set_memory_rw);
|
||||
}
|
||||
|
||||
frob_text(&mod->core_layout, set_memory_rw);
|
||||
frob_text(&mod->init_layout, set_memory_rw);
|
||||
}
|
||||
mutex_unlock(&module_mutex);
|
||||
}
|
||||
|
@ -1965,23 +1945,25 @@ void set_all_modules_text_ro(void)
|
|||
list_for_each_entry_rcu(mod, &modules, list) {
|
||||
if (mod->state == MODULE_STATE_UNFORMED)
|
||||
continue;
|
||||
if ((mod->module_core) && (mod->core_text_size)) {
|
||||
set_page_attributes(mod->module_core,
|
||||
mod->module_core + mod->core_text_size,
|
||||
set_memory_ro);
|
||||
}
|
||||
if ((mod->module_init) && (mod->init_text_size)) {
|
||||
set_page_attributes(mod->module_init,
|
||||
mod->module_init + mod->init_text_size,
|
||||
set_memory_ro);
|
||||
}
|
||||
|
||||
frob_text(&mod->core_layout, set_memory_ro);
|
||||
frob_text(&mod->init_layout, set_memory_ro);
|
||||
}
|
||||
mutex_unlock(&module_mutex);
|
||||
}
|
||||
|
||||
static void disable_ro_nx(const struct module_layout *layout)
|
||||
{
|
||||
frob_text(layout, set_memory_rw);
|
||||
frob_rodata(layout, set_memory_rw);
|
||||
frob_rodata(layout, set_memory_x);
|
||||
frob_writable_data(layout, set_memory_x);
|
||||
}
|
||||
|
||||
#else
|
||||
static inline void set_section_ro_nx(void *base, unsigned long text_size, unsigned long ro_size, unsigned long total_size) { }
|
||||
static void unset_module_core_ro_nx(struct module *mod) { }
|
||||
static void unset_module_init_ro_nx(struct module *mod) { }
|
||||
static void disable_ro_nx(const struct module_layout *layout) { }
|
||||
static void module_enable_nx(const struct module *mod) { }
|
||||
static void module_disable_nx(const struct module *mod) { }
|
||||
#endif
|
||||
|
||||
void __weak module_memfree(void *module_region)
|
||||
|
@ -2033,19 +2015,19 @@ static void free_module(struct module *mod)
|
|||
synchronize_sched();
|
||||
mutex_unlock(&module_mutex);
|
||||
|
||||
/* This may be NULL, but that's OK */
|
||||
unset_module_init_ro_nx(mod);
|
||||
/* This may be empty, but that's OK */
|
||||
disable_ro_nx(&mod->init_layout);
|
||||
module_arch_freeing_init(mod);
|
||||
module_memfree(mod->module_init);
|
||||
module_memfree(mod->init_layout.base);
|
||||
kfree(mod->args);
|
||||
percpu_modfree(mod);
|
||||
|
||||
/* Free lock-classes; relies on the preceding sync_rcu(). */
|
||||
lockdep_free_key_range(mod->module_core, mod->core_size);
|
||||
lockdep_free_key_range(mod->core_layout.base, mod->core_layout.size);
|
||||
|
||||
/* Finally, free the core (containing the module structure) */
|
||||
unset_module_core_ro_nx(mod);
|
||||
module_memfree(mod->module_core);
|
||||
disable_ro_nx(&mod->core_layout);
|
||||
module_memfree(mod->core_layout.base);
|
||||
|
||||
#ifdef CONFIG_MPU
|
||||
update_protections(current->mm);
|
||||
|
@ -2248,20 +2230,20 @@ static void layout_sections(struct module *mod, struct load_info *info)
|
|||
|| s->sh_entsize != ~0UL
|
||||
|| strstarts(sname, ".init"))
|
||||
continue;
|
||||
s->sh_entsize = get_offset(mod, &mod->core_size, s, i);
|
||||
s->sh_entsize = get_offset(mod, &mod->core_layout.size, s, i);
|
||||
pr_debug("\t%s\n", sname);
|
||||
}
|
||||
switch (m) {
|
||||
case 0: /* executable */
|
||||
mod->core_size = debug_align(mod->core_size);
|
||||
mod->core_text_size = mod->core_size;
|
||||
mod->core_layout.size = debug_align(mod->core_layout.size);
|
||||
mod->core_layout.text_size = mod->core_layout.size;
|
||||
break;
|
||||
case 1: /* RO: text and ro-data */
|
||||
mod->core_size = debug_align(mod->core_size);
|
||||
mod->core_ro_size = mod->core_size;
|
||||
mod->core_layout.size = debug_align(mod->core_layout.size);
|
||||
mod->core_layout.ro_size = mod->core_layout.size;
|
||||
break;
|
||||
case 3: /* whole core */
|
||||
mod->core_size = debug_align(mod->core_size);
|
||||
mod->core_layout.size = debug_align(mod->core_layout.size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -2277,21 +2259,21 @@ static void layout_sections(struct module *mod, struct load_info *info)
|
|||
|| s->sh_entsize != ~0UL
|
||||
|| !strstarts(sname, ".init"))
|
||||
continue;
|
||||
s->sh_entsize = (get_offset(mod, &mod->init_size, s, i)
|
||||
s->sh_entsize = (get_offset(mod, &mod->init_layout.size, s, i)
|
||||
| INIT_OFFSET_MASK);
|
||||
pr_debug("\t%s\n", sname);
|
||||
}
|
||||
switch (m) {
|
||||
case 0: /* executable */
|
||||
mod->init_size = debug_align(mod->init_size);
|
||||
mod->init_text_size = mod->init_size;
|
||||
mod->init_layout.size = debug_align(mod->init_layout.size);
|
||||
mod->init_layout.text_size = mod->init_layout.size;
|
||||
break;
|
||||
case 1: /* RO: text and ro-data */
|
||||
mod->init_size = debug_align(mod->init_size);
|
||||
mod->init_ro_size = mod->init_size;
|
||||
mod->init_layout.size = debug_align(mod->init_layout.size);
|
||||
mod->init_layout.ro_size = mod->init_layout.size;
|
||||
break;
|
||||
case 3: /* whole init */
|
||||
mod->init_size = debug_align(mod->init_size);
|
||||
mod->init_layout.size = debug_align(mod->init_layout.size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -2401,7 +2383,7 @@ static char elf_type(const Elf_Sym *sym, const struct load_info *info)
|
|||
}
|
||||
if (sym->st_shndx == SHN_UNDEF)
|
||||
return 'U';
|
||||
if (sym->st_shndx == SHN_ABS)
|
||||
if (sym->st_shndx == SHN_ABS || sym->st_shndx == info->index.pcpu)
|
||||
return 'a';
|
||||
if (sym->st_shndx >= SHN_LORESERVE)
|
||||
return '?';
|
||||
|
@ -2430,7 +2412,7 @@ static char elf_type(const Elf_Sym *sym, const struct load_info *info)
|
|||
}
|
||||
|
||||
static bool is_core_symbol(const Elf_Sym *src, const Elf_Shdr *sechdrs,
|
||||
unsigned int shnum)
|
||||
unsigned int shnum, unsigned int pcpundx)
|
||||
{
|
||||
const Elf_Shdr *sec;
|
||||
|
||||
|
@ -2439,6 +2421,11 @@ static bool is_core_symbol(const Elf_Sym *src, const Elf_Shdr *sechdrs,
|
|||
|| !src->st_name)
|
||||
return false;
|
||||
|
||||
#ifdef CONFIG_KALLSYMS_ALL
|
||||
if (src->st_shndx == pcpundx)
|
||||
return true;
|
||||
#endif
|
||||
|
||||
sec = sechdrs + src->st_shndx;
|
||||
if (!(sec->sh_flags & SHF_ALLOC)
|
||||
#ifndef CONFIG_KALLSYMS_ALL
|
||||
|
@ -2466,7 +2453,7 @@ static void layout_symtab(struct module *mod, struct load_info *info)
|
|||
|
||||
/* Put symbol section at end of init part of module. */
|
||||
symsect->sh_flags |= SHF_ALLOC;
|
||||
symsect->sh_entsize = get_offset(mod, &mod->init_size, symsect,
|
||||
symsect->sh_entsize = get_offset(mod, &mod->init_layout.size, symsect,
|
||||
info->index.sym) | INIT_OFFSET_MASK;
|
||||
pr_debug("\t%s\n", info->secstrings + symsect->sh_name);
|
||||
|
||||
|
@ -2476,23 +2463,24 @@ static void layout_symtab(struct module *mod, struct load_info *info)
|
|||
/* Compute total space required for the core symbols' strtab. */
|
||||
for (ndst = i = 0; i < nsrc; i++) {
|
||||
if (i == 0 ||
|
||||
is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum)) {
|
||||
is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum,
|
||||
info->index.pcpu)) {
|
||||
strtab_size += strlen(&info->strtab[src[i].st_name])+1;
|
||||
ndst++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Append room for core symbols at end of core part. */
|
||||
info->symoffs = ALIGN(mod->core_size, symsect->sh_addralign ?: 1);
|
||||
info->stroffs = mod->core_size = info->symoffs + ndst * sizeof(Elf_Sym);
|
||||
mod->core_size += strtab_size;
|
||||
mod->core_size = debug_align(mod->core_size);
|
||||
info->symoffs = ALIGN(mod->core_layout.size, symsect->sh_addralign ?: 1);
|
||||
info->stroffs = mod->core_layout.size = info->symoffs + ndst * sizeof(Elf_Sym);
|
||||
mod->core_layout.size += strtab_size;
|
||||
mod->core_layout.size = debug_align(mod->core_layout.size);
|
||||
|
||||
/* Put string table section at end of init part of module. */
|
||||
strsect->sh_flags |= SHF_ALLOC;
|
||||
strsect->sh_entsize = get_offset(mod, &mod->init_size, strsect,
|
||||
strsect->sh_entsize = get_offset(mod, &mod->init_layout.size, strsect,
|
||||
info->index.str) | INIT_OFFSET_MASK;
|
||||
mod->init_size = debug_align(mod->init_size);
|
||||
mod->init_layout.size = debug_align(mod->init_layout.size);
|
||||
pr_debug("\t%s\n", info->secstrings + strsect->sh_name);
|
||||
}
|
||||
|
||||
|
@ -2513,12 +2501,13 @@ static void add_kallsyms(struct module *mod, const struct load_info *info)
|
|||
for (i = 0; i < mod->num_symtab; i++)
|
||||
mod->symtab[i].st_info = elf_type(&mod->symtab[i], info);
|
||||
|
||||
mod->core_symtab = dst = mod->module_core + info->symoffs;
|
||||
mod->core_strtab = s = mod->module_core + info->stroffs;
|
||||
mod->core_symtab = dst = mod->core_layout.base + info->symoffs;
|
||||
mod->core_strtab = s = mod->core_layout.base + info->stroffs;
|
||||
src = mod->symtab;
|
||||
for (ndst = i = 0; i < mod->num_symtab; i++) {
|
||||
if (i == 0 ||
|
||||
is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum)) {
|
||||
is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum,
|
||||
info->index.pcpu)) {
|
||||
dst[ndst] = src[i];
|
||||
dst[ndst++].st_name = s - mod->core_strtab;
|
||||
s += strlcpy(s, &mod->strtab[src[i].st_name],
|
||||
|
@ -2964,7 +2953,7 @@ static int move_module(struct module *mod, struct load_info *info)
|
|||
void *ptr;
|
||||
|
||||
/* Do the allocs. */
|
||||
ptr = module_alloc(mod->core_size);
|
||||
ptr = module_alloc(mod->core_layout.size);
|
||||
/*
|
||||
* The pointer to this block is stored in the module structure
|
||||
* which is inside the block. Just mark it as not being a
|
||||
|
@ -2974,11 +2963,11 @@ static int move_module(struct module *mod, struct load_info *info)
|
|||
if (!ptr)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(ptr, 0, mod->core_size);
|
||||
mod->module_core = ptr;
|
||||
memset(ptr, 0, mod->core_layout.size);
|
||||
mod->core_layout.base = ptr;
|
||||
|
||||
if (mod->init_size) {
|
||||
ptr = module_alloc(mod->init_size);
|
||||
if (mod->init_layout.size) {
|
||||
ptr = module_alloc(mod->init_layout.size);
|
||||
/*
|
||||
* The pointer to this block is stored in the module structure
|
||||
* which is inside the block. This block doesn't need to be
|
||||
|
@ -2987,13 +2976,13 @@ static int move_module(struct module *mod, struct load_info *info)
|
|||
*/
|
||||
kmemleak_ignore(ptr);
|
||||
if (!ptr) {
|
||||
module_memfree(mod->module_core);
|
||||
module_memfree(mod->core_layout.base);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(ptr, 0, mod->init_size);
|
||||
mod->module_init = ptr;
|
||||
memset(ptr, 0, mod->init_layout.size);
|
||||
mod->init_layout.base = ptr;
|
||||
} else
|
||||
mod->module_init = NULL;
|
||||
mod->init_layout.base = NULL;
|
||||
|
||||
/* Transfer each section which specifies SHF_ALLOC */
|
||||
pr_debug("final section addresses:\n");
|
||||
|
@ -3005,10 +2994,10 @@ static int move_module(struct module *mod, struct load_info *info)
|
|||
continue;
|
||||
|
||||
if (shdr->sh_entsize & INIT_OFFSET_MASK)
|
||||
dest = mod->module_init
|
||||
dest = mod->init_layout.base
|
||||
+ (shdr->sh_entsize & ~INIT_OFFSET_MASK);
|
||||
else
|
||||
dest = mod->module_core + shdr->sh_entsize;
|
||||
dest = mod->core_layout.base + shdr->sh_entsize;
|
||||
|
||||
if (shdr->sh_type != SHT_NOBITS)
|
||||
memcpy(dest, (void *)shdr->sh_addr, shdr->sh_size);
|
||||
|
@ -3070,12 +3059,12 @@ static void flush_module_icache(const struct module *mod)
|
|||
* Do it before processing of module parameters, so the module
|
||||
* can provide parameter accessor functions of its own.
|
||||
*/
|
||||
if (mod->module_init)
|
||||
flush_icache_range((unsigned long)mod->module_init,
|
||||
(unsigned long)mod->module_init
|
||||
+ mod->init_size);
|
||||
flush_icache_range((unsigned long)mod->module_core,
|
||||
(unsigned long)mod->module_core + mod->core_size);
|
||||
if (mod->init_layout.base)
|
||||
flush_icache_range((unsigned long)mod->init_layout.base,
|
||||
(unsigned long)mod->init_layout.base
|
||||
+ mod->init_layout.size);
|
||||
flush_icache_range((unsigned long)mod->core_layout.base,
|
||||
(unsigned long)mod->core_layout.base + mod->core_layout.size);
|
||||
|
||||
set_fs(old_fs);
|
||||
}
|
||||
|
@ -3133,8 +3122,8 @@ static void module_deallocate(struct module *mod, struct load_info *info)
|
|||
{
|
||||
percpu_modfree(mod);
|
||||
module_arch_freeing_init(mod);
|
||||
module_memfree(mod->module_init);
|
||||
module_memfree(mod->module_core);
|
||||
module_memfree(mod->init_layout.base);
|
||||
module_memfree(mod->core_layout.base);
|
||||
}
|
||||
|
||||
int __weak module_finalize(const Elf_Ehdr *hdr,
|
||||
|
@ -3221,7 +3210,7 @@ static noinline int do_init_module(struct module *mod)
|
|||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
freeinit->module_init = mod->module_init;
|
||||
freeinit->module_init = mod->init_layout.base;
|
||||
|
||||
/*
|
||||
* We want to find out whether @mod uses async during init. Clear
|
||||
|
@ -3279,12 +3268,12 @@ static noinline int do_init_module(struct module *mod)
|
|||
mod->strtab = mod->core_strtab;
|
||||
#endif
|
||||
mod_tree_remove_init(mod);
|
||||
unset_module_init_ro_nx(mod);
|
||||
disable_ro_nx(&mod->init_layout);
|
||||
module_arch_freeing_init(mod);
|
||||
mod->module_init = NULL;
|
||||
mod->init_size = 0;
|
||||
mod->init_ro_size = 0;
|
||||
mod->init_text_size = 0;
|
||||
mod->init_layout.base = NULL;
|
||||
mod->init_layout.size = 0;
|
||||
mod->init_layout.ro_size = 0;
|
||||
mod->init_layout.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
|
||||
|
@ -3373,17 +3362,9 @@ static int complete_formation(struct module *mod, struct load_info *info)
|
|||
/* This relies on module_mutex for list integrity. */
|
||||
module_bug_finalize(info->hdr, info->sechdrs, mod);
|
||||
|
||||
/* Set RO and NX regions for core */
|
||||
set_section_ro_nx(mod->module_core,
|
||||
mod->core_text_size,
|
||||
mod->core_ro_size,
|
||||
mod->core_size);
|
||||
|
||||
/* Set RO and NX regions for init */
|
||||
set_section_ro_nx(mod->module_init,
|
||||
mod->init_text_size,
|
||||
mod->init_ro_size,
|
||||
mod->init_size);
|
||||
/* Set RO and NX regions */
|
||||
module_enable_ro(mod);
|
||||
module_enable_nx(mod);
|
||||
|
||||
/* Mark state as coming so strong_try_module_get() ignores us,
|
||||
* but kallsyms etc. can see us. */
|
||||
|
@ -3548,8 +3529,8 @@ static int load_module(struct load_info *info, const char __user *uargs,
|
|||
MODULE_STATE_GOING, mod);
|
||||
|
||||
/* we can't deallocate the module until we clear memory protection */
|
||||
unset_module_init_ro_nx(mod);
|
||||
unset_module_core_ro_nx(mod);
|
||||
module_disable_ro(mod);
|
||||
module_disable_nx(mod);
|
||||
|
||||
ddebug_cleanup:
|
||||
dynamic_debug_remove(info->debug);
|
||||
|
@ -3578,7 +3559,7 @@ static int load_module(struct load_info *info, const char __user *uargs,
|
|||
*/
|
||||
ftrace_release_mod(mod);
|
||||
/* Free lock-classes; relies on the preceding sync_rcu() */
|
||||
lockdep_free_key_range(mod->module_core, mod->core_size);
|
||||
lockdep_free_key_range(mod->core_layout.base, mod->core_layout.size);
|
||||
|
||||
module_deallocate(mod, info);
|
||||
free_copy:
|
||||
|
@ -3656,9 +3637,9 @@ static const char *get_ksymbol(struct module *mod,
|
|||
|
||||
/* At worse, next value is at end of module */
|
||||
if (within_module_init(addr, mod))
|
||||
nextval = (unsigned long)mod->module_init+mod->init_text_size;
|
||||
nextval = (unsigned long)mod->init_layout.base+mod->init_layout.text_size;
|
||||
else
|
||||
nextval = (unsigned long)mod->module_core+mod->core_text_size;
|
||||
nextval = (unsigned long)mod->core_layout.base+mod->core_layout.text_size;
|
||||
|
||||
/* Scan for closest preceding symbol, and next symbol. (ELF
|
||||
starts real symbols at 1). */
|
||||
|
@ -3905,7 +3886,7 @@ static int m_show(struct seq_file *m, void *p)
|
|||
return 0;
|
||||
|
||||
seq_printf(m, "%s %u",
|
||||
mod->name, mod->init_size + mod->core_size);
|
||||
mod->name, mod->init_layout.size + mod->core_layout.size);
|
||||
print_unload_info(m, mod);
|
||||
|
||||
/* Informative for users. */
|
||||
|
@ -3914,7 +3895,7 @@ static int m_show(struct seq_file *m, void *p)
|
|||
mod->state == MODULE_STATE_COMING ? "Loading" :
|
||||
"Live");
|
||||
/* Used by oprofile and other similar tools. */
|
||||
seq_printf(m, " 0x%pK", mod->module_core);
|
||||
seq_printf(m, " 0x%pK", mod->core_layout.base);
|
||||
|
||||
/* Taints info */
|
||||
if (mod->taints)
|
||||
|
@ -4057,8 +4038,8 @@ 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))
|
||||
if (!within(addr, mod->init_layout.base, mod->init_layout.text_size)
|
||||
&& !within(addr, mod->core_layout.base, mod->core_layout.text_size))
|
||||
mod = NULL;
|
||||
}
|
||||
return mod;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue