Commit 0f0836b7 authored by Linus Torvalds's avatar Linus Torvalds

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: default avatarMiroslav 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
parents c2848f2e b56b36ee
...@@ -33,7 +33,7 @@ Description: ...@@ -33,7 +33,7 @@ Description:
The object directory contains subdirectories for each function The object directory contains subdirectories for each function
that is patched within the object. that is patched within the object.
What: /sys/kernel/livepatch/<patch>/<object>/<function> What: /sys/kernel/livepatch/<patch>/<object>/<function,sympos>
Date: Nov 2014 Date: Nov 2014
KernelVersion: 3.19.0 KernelVersion: 3.19.0
Contact: live-patching@vger.kernel.org Contact: live-patching@vger.kernel.org
...@@ -41,4 +41,8 @@ Description: ...@@ -41,4 +41,8 @@ Description:
The function directory contains attributes regarding the The function directory contains attributes regarding the
properties and state of the patched function. properties and state of the patched function.
The directory name contains the patched function name and a
sympos number corresponding to the nth occurrence of the symbol
name in kallsyms for the patched object.
There are currently no such attributes. There are currently no such attributes.
...@@ -160,7 +160,7 @@ apply_relocate_add(Elf64_Shdr *sechdrs, const char *strtab, ...@@ -160,7 +160,7 @@ apply_relocate_add(Elf64_Shdr *sechdrs, const char *strtab,
/* The small sections were sorted to the end of the segment. /* The small sections were sorted to the end of the segment.
The following should definitely cover them. */ The following should definitely cover them. */
gp = (u64)me->module_core + me->core_size - 0x8000; gp = (u64)me->core_layout.base + me->core_layout.size - 0x8000;
got = sechdrs[me->arch.gotsecindex].sh_addr; got = sechdrs[me->arch.gotsecindex].sh_addr;
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
......
...@@ -385,8 +385,8 @@ void *unwind_add_table(struct module *module, const void *table_start, ...@@ -385,8 +385,8 @@ void *unwind_add_table(struct module *module, const void *table_start,
return NULL; return NULL;
init_unwind_table(table, module->name, init_unwind_table(table, module->name,
module->module_core, module->core_size, module->core_layout.base, module->core_layout.size,
module->module_init, module->init_size, module->init_layout.base, module->init_layout.size,
table_start, table_size, table_start, table_size,
NULL, 0); NULL, 0);
......
...@@ -32,7 +32,7 @@ struct plt_entries { ...@@ -32,7 +32,7 @@ struct plt_entries {
static bool in_init(const struct module *mod, u32 addr) static bool in_init(const struct module *mod, u32 addr)
{ {
return addr - (u32)mod->module_init < mod->init_size; return addr - (u32)mod->init_layout.base < mod->init_layout.size;
} }
u32 get_module_plt(struct module *mod, unsigned long loc, Elf32_Addr val) u32 get_module_plt(struct module *mod, unsigned long loc, Elf32_Addr val)
......
...@@ -118,9 +118,9 @@ int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, ...@@ -118,9 +118,9 @@ int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
* Increase core size to make room for GOT and set start * Increase core size to make room for GOT and set start
* offset for GOT. * offset for GOT.
*/ */
module->core_size = ALIGN(module->core_size, 4); module->core_layout.size = ALIGN(module->core_layout.size, 4);
module->arch.got_offset = module->core_size; module->arch.got_offset = module->core_layout.size;
module->core_size += module->arch.got_size; module->core_layout.size += module->arch.got_size;
return 0; return 0;
...@@ -177,7 +177,7 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab, ...@@ -177,7 +177,7 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,
if (!info->got_initialized) { if (!info->got_initialized) {
Elf32_Addr *gotent; Elf32_Addr *gotent;
gotent = (module->module_core gotent = (module->core_layout.base
+ module->arch.got_offset + module->arch.got_offset
+ info->got_offset); + info->got_offset);
*gotent = relocation; *gotent = relocation;
...@@ -255,8 +255,8 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab, ...@@ -255,8 +255,8 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,
*/ */
pr_debug("GOTPC: PC=0x%x, got_offset=0x%lx, core=0x%p\n", pr_debug("GOTPC: PC=0x%x, got_offset=0x%lx, core=0x%p\n",
relocation, module->arch.got_offset, relocation, module->arch.got_offset,
module->module_core); module->core_layout.base);
relocation -= ((unsigned long)module->module_core relocation -= ((unsigned long)module->core_layout.base
+ module->arch.got_offset); + module->arch.got_offset);
*location = relocation; *location = relocation;
break; break;
......
...@@ -486,13 +486,13 @@ module_frob_arch_sections (Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, char *secstrings, ...@@ -486,13 +486,13 @@ module_frob_arch_sections (Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, char *secstrings,
static inline int static inline int
in_init (const struct module *mod, uint64_t addr) in_init (const struct module *mod, uint64_t addr)
{ {
return addr - (uint64_t) mod->module_init < mod->init_size; return addr - (uint64_t) mod->init_layout.base < mod->init_layout.size;
} }
static inline int static inline int
in_core (const struct module *mod, uint64_t addr) in_core (const struct module *mod, uint64_t addr)
{ {
return addr - (uint64_t) mod->module_core < mod->core_size; return addr - (uint64_t) mod->core_layout.base < mod->core_layout.size;
} }
static inline int static inline int
...@@ -675,7 +675,7 @@ do_reloc (struct module *mod, uint8_t r_type, Elf64_Sym *sym, uint64_t addend, ...@@ -675,7 +675,7 @@ do_reloc (struct module *mod, uint8_t r_type, Elf64_Sym *sym, uint64_t addend,
break; break;
case RV_BDREL: case RV_BDREL:
val -= (uint64_t) (in_init(mod, val) ? mod->module_init : mod->module_core); val -= (uint64_t) (in_init(mod, val) ? mod->init_layout.base : mod->core_layout.base);
break; break;
case RV_LTV: case RV_LTV:
...@@ -810,15 +810,15 @@ apply_relocate_add (Elf64_Shdr *sechdrs, const char *strtab, unsigned int symind ...@@ -810,15 +810,15 @@ apply_relocate_add (Elf64_Shdr *sechdrs, const char *strtab, unsigned int symind
* addresses have been selected... * addresses have been selected...
*/ */
uint64_t gp; uint64_t gp;
if (mod->core_size > MAX_LTOFF) if (mod->core_layout.size > MAX_LTOFF)
/* /*
* This takes advantage of fact that SHF_ARCH_SMALL gets allocated * This takes advantage of fact that SHF_ARCH_SMALL gets allocated
* at the end of the module. * at the end of the module.
*/ */
gp = mod->core_size - MAX_LTOFF / 2; gp = mod->core_layout.size - MAX_LTOFF / 2;
else else
gp = mod->core_size / 2; gp = mod->core_layout.size / 2;
gp = (uint64_t) mod->module_core + ((gp + 7) & -8); gp = (uint64_t) mod->core_layout.base + ((gp + 7) & -8);
mod->arch.gp = gp; mod->arch.gp = gp;
DEBUGP("%s: placing gp at 0x%lx\n", __func__, gp); DEBUGP("%s: placing gp at 0x%lx\n", __func__, gp);
} }
......
...@@ -176,8 +176,8 @@ static uint32_t do_plt_call(void *location, Elf32_Addr val, ...@@ -176,8 +176,8 @@ static uint32_t do_plt_call(void *location, Elf32_Addr val,
tramp[1] = 0xac000001 | ((val & 0x0000ffff) << 3); tramp[1] = 0xac000001 | ((val & 0x0000ffff) << 3);
/* Init, or core PLT? */ /* Init, or core PLT? */
if (location >= mod->module_core if (location >= mod->core_layout.base
&& location < mod->module_core + mod->core_size) && location < mod->core_layout.base + mod->core_layout.size)
entry = (void *)sechdrs[mod->arch.core_plt_section].sh_addr; entry = (void *)sechdrs[mod->arch.core_plt_section].sh_addr;
else else
entry = (void *)sechdrs[mod->arch.init_plt_section].sh_addr; entry = (void *)sechdrs[mod->arch.init_plt_section].sh_addr;
......
...@@ -205,11 +205,11 @@ static void layout_sections(struct module *mod, const Elf_Ehdr *hdr, ...@@ -205,11 +205,11 @@ static void layout_sections(struct module *mod, const Elf_Ehdr *hdr,
|| s->sh_entsize != ~0UL) || s->sh_entsize != ~0UL)
continue; continue;
s->sh_entsize = s->sh_entsize =
get_offset((unsigned long *)&mod->core_size, s); get_offset((unsigned long *)&mod->core_layout.size, s);
} }
if (m == 0) if (m == 0)
mod->core_text_size = mod->core_size; mod->core_layout.text_size = mod->core_layout.size;
} }
} }
...@@ -641,7 +641,7 @@ static int vpe_elfload(struct vpe *v) ...@@ -641,7 +641,7 @@ static int vpe_elfload(struct vpe *v)
layout_sections(&mod, hdr, sechdrs, secstrings); layout_sections(&mod, hdr, sechdrs, secstrings);
} }
v->load_addr = alloc_progmem(mod.core_size); v->load_addr = alloc_progmem(mod.core_layout.size);
if (!v->load_addr) if (!v->load_addr)
return -ENOMEM; return -ENOMEM;
......
...@@ -42,9 +42,9 @@ ...@@ -42,9 +42,9 @@
* We are not doing SEGREL32 handling correctly. According to the ABI, we * We are not doing SEGREL32 handling correctly. According to the ABI, we
* should do a value offset, like this: * should do a value offset, like this:
* if (in_init(me, (void *)val)) * if (in_init(me, (void *)val))
* val -= (uint32_t)me->module_init; * val -= (uint32_t)me->init_layout.base;
* else * else
* val -= (uint32_t)me->module_core; * val -= (uint32_t)me->core_layout.base;
* However, SEGREL32 is used only for PARISC unwind entries, and we want * However, SEGREL32 is used only for PARISC unwind entries, and we want
* those entries to have an absolute address, and not just an offset. * those entries to have an absolute address, and not just an offset.
* *
...@@ -100,14 +100,14 @@ ...@@ -100,14 +100,14 @@
* or init pieces the location is */ * or init pieces the location is */
static inline int in_init(struct module *me, void *loc) static inline int in_init(struct module *me, void *loc)
{ {
return (loc >= me->module_init && return (loc >= me->init_layout.base &&
loc <= (me->module_init + me->init_size)); loc <= (me->init_layout.base + me->init_layout.size));
} }
static inline int in_core(struct module *me, void *loc) static inline int in_core(struct module *me, void *loc)
{ {
return (loc >= me->module_core && return (loc >= me->core_layout.base &&
loc <= (me->module_core + me->core_size)); loc <= (me->core_layout.base + me->core_layout.size));
} }
static inline int in_local(struct module *me, void *loc) static inline int in_local(struct module *me, void *loc)
...@@ -367,13 +367,13 @@ int module_frob_arch_sections(CONST Elf_Ehdr *hdr, ...@@ -367,13 +367,13 @@ int module_frob_arch_sections(CONST Elf_Ehdr *hdr,
} }
/* align things a bit */ /* align things a bit */
me->core_size = ALIGN(me->core_size, 16); me->core_layout.size = ALIGN(me->core_layout.size, 16);
me->arch.got_offset = me->core_size; me->arch.got_offset = me->core_layout.size;
me->core_size += gots * sizeof(struct got_entry); me->core_layout.size += gots * sizeof(struct got_entry);
me->core_size = ALIGN(me->core_size, 16); me->core_layout.size = ALIGN(me->core_layout.size, 16);
me->arch.fdesc_offset = me->core_size; me->arch.fdesc_offset = me->core_layout.size;
me->core_size += fdescs * sizeof(Elf_Fdesc); me->core_layout.size += fdescs * sizeof(Elf_Fdesc);
me->arch.got_max = gots; me->arch.got_max = gots;
me->arch.fdesc_max = fdescs; me->arch.fdesc_max = fdescs;
...@@ -391,7 +391,7 @@ static Elf64_Word get_got(struct module *me, unsigned long value, long addend) ...@@ -391,7 +391,7 @@ static Elf64_Word get_got(struct module *me, unsigned long value, long addend)
BUG_ON(value == 0); BUG_ON(value == 0);
got = me->module_core + me->arch.got_offset; got = me->core_layout.base + me->arch.got_offset;
for (i = 0; got[i].addr; i++) for (i = 0; got[i].addr; i++)
if (got[i].addr == value) if (got[i].addr == value)
goto out; goto out;
...@@ -409,7 +409,7 @@ static Elf64_Word get_got(struct module *me, unsigned long value, long addend) ...@@ -409,7 +409,7 @@ static Elf64_Word get_got(struct module *me, unsigned long value, long addend)
#ifdef CONFIG_64BIT #ifdef CONFIG_64BIT
static Elf_Addr get_fdesc(struct module *me, unsigned long value) static Elf_Addr get_fdesc(struct module *me, unsigned long value)
{ {
Elf_Fdesc *fdesc = me->module_core + me->arch.fdesc_offset; Elf_Fdesc *fdesc = me->core_layout.base + me->arch.fdesc_offset;
if (!value) { if (!value) {
printk(KERN_ERR "%s: zero OPD requested!\n", me->name); printk(KERN_ERR "%s: zero OPD requested!\n", me->name);
...@@ -427,7 +427,7 @@ static Elf_Addr get_fdesc(struct module *me, unsigned long value) ...@@ -427,7 +427,7 @@ static Elf_Addr get_fdesc(struct module *me, unsigned long value)
/* Create new one */ /* Create new one */
fdesc->addr = value; fdesc->addr = value;
fdesc->gp = (Elf_Addr)me->module_core + me->arch.got_offset; fdesc->gp = (Elf_Addr)me->core_layout.base + me->arch.got_offset;
return (Elf_Addr)fdesc; return (Elf_Addr)fdesc;
} }
#endif /* CONFIG_64BIT */ #endif /* CONFIG_64BIT */
...@@ -839,7 +839,7 @@ register_unwind_table(struct module *me, ...@@ -839,7 +839,7 @@ register_unwind_table(struct module *me,
table = (unsigned char *)sechdrs[me->arch.unwind_section].sh_addr; table = (unsigned char *)sechdrs[me->arch.unwind_section].sh_addr;
end = table + sechdrs[me->arch.unwind_section].sh_size; end = table + sechdrs[me->arch.unwind_section].sh_size;
gp = (Elf_Addr)me->module_core + me->arch.got_offset; gp = (Elf_Addr)me->core_layout.base + me->arch.got_offset;
DEBUGP("register_unwind_table(), sect = %d at 0x%p - 0x%p (gp=0x%lx)\n", DEBUGP("register_unwind_table(), sect = %d at 0x%p - 0x%p (gp=0x%lx)\n",
me->arch.unwind_section, table, end, gp); me->arch.unwind_section, table, end, gp);
......
...@@ -188,8 +188,8 @@ static uint32_t do_plt_call(void *location, ...@@ -188,8 +188,8 @@ static uint32_t do_plt_call(void *location,
pr_debug("Doing plt for call to 0x%x at 0x%x\n", val, (unsigned int)location); pr_debug("Doing plt for call to 0x%x at 0x%x\n", val, (unsigned int)location);
/* Init, or core PLT? */ /* Init, or core PLT? */
if (location >= mod->module_core if (location >= mod->core_layout.base
&& location < mod->module_core + mod->core_size) && location < mod->core_layout.base + mod->core_layout.size)
entry = (void *)sechdrs[mod->arch.core_plt_section].sh_addr; entry = (void *)sechdrs[mod->arch.core_plt_section].sh_addr;
else else
entry = (void *)sechdrs[mod->arch.init_plt_section].sh_addr; entry = (void *)sechdrs[mod->arch.init_plt_section].sh_addr;
...@@ -296,7 +296,7 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, ...@@ -296,7 +296,7 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
} }
#ifdef CONFIG_DYNAMIC_FTRACE #ifdef CONFIG_DYNAMIC_FTRACE
module->arch.tramp = module->arch.tramp =
do_plt_call(module->module_core, do_plt_call(module->core_layout.base,
(unsigned long)ftrace_caller, (unsigned long)ftrace_caller,
sechdrs, module); sechdrs, module);
#endif #endif
......
...@@ -159,11 +159,11 @@ int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, ...@@ -159,11 +159,11 @@ int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
/* Increase core size by size of got & plt and set start /* Increase core size by size of got & plt and set start
offsets for got and plt. */ offsets for got and plt. */
me->core_size = ALIGN(me->core_size, 4); me->core_layout.size = ALIGN(me->core_layout.size, 4);
me->arch.got_offset = me->core_size; me->arch.got_offset = me->core_layout.size;
me->core_size += me->arch.got_size; me->core_layout.size += me->arch.got_size;
me->arch.plt_offset = me->core_size; me->arch.plt_offset = me->core_layout.size;
me->core_size += me->arch.plt_size; me->core_layout.size += me->arch.plt_size;
return 0; return 0;
} }
...@@ -279,7 +279,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab, ...@@ -279,7 +279,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
if (info->got_initialized == 0) { if (info->got_initialized == 0) {
Elf_Addr *gotent; Elf_Addr *gotent;
gotent = me->module_core + me->arch.got_offset + gotent = me->core_layout.base + me->arch.got_offset +
info->got_offset; info->got_offset;
*gotent = val; *gotent = val;
info->got_initialized = 1; info->got_initialized = 1;
...@@ -302,7 +302,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab, ...@@ -302,7 +302,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
rc = apply_rela_bits(loc, val, 0, 64, 0); rc = apply_rela_bits(loc, val, 0, 64, 0);
else if (r_type == R_390_GOTENT || else if (r_type == R_390_GOTENT ||
r_type == R_390_GOTPLTENT) { r_type == R_390_GOTPLTENT) {
val += (Elf_Addr) me->module_core - loc; val += (Elf_Addr) me->core_layout.base - loc;
rc = apply_rela_bits(loc, val, 1, 32, 1); rc = apply_rela_bits(loc, val, 1, 32, 1);
} }
break; break;
...@@ -315,7 +315,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab, ...@@ -315,7 +315,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
case R_390_PLTOFF64: /* 16 bit offset from GOT to PLT. */ case R_390_PLTOFF64: /* 16 bit offset from GOT to PLT. */
if (info->plt_initialized == 0) { if (info->plt_initialized == 0) {
unsigned int *ip; unsigned int *ip;
ip = me->module_core + me->arch.plt_offset + ip = me->core_layout.base + me->arch.plt_offset +
info->plt_offset; info->plt_offset;
ip[0] = 0x0d10e310; /* basr 1,0; lg 1,10(1); br 1 */ ip[0] = 0x0d10e310; /* basr 1,0; lg 1,10(1); br 1 */
ip[1] = 0x100a0004; ip[1] = 0x100a0004;
...@@ -334,7 +334,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab, ...@@ -334,7 +334,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
val - loc + 0xffffUL < 0x1ffffeUL) || val - loc + 0xffffUL < 0x1ffffeUL) ||
(r_type == R_390_PLT32DBL && (r_type == R_390_PLT32DBL &&
val - loc + 0xffffffffULL < 0x1fffffffeULL))) val - loc + 0xffffffffULL < 0x1fffffffeULL)))
val = (Elf_Addr) me->module_core + val = (Elf_Addr) me->core_layout.base +
me->arch.plt_offset + me->arch.plt_offset +
info->plt_offset; info->plt_offset;
val += rela->r_addend - loc; val += rela->r_addend - loc;
...@@ -356,7 +356,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab, ...@@ -356,7 +356,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
case R_390_GOTOFF32: /* 32 bit offset to GOT. */ case R_390_GOTOFF32: /* 32 bit offset to GOT. */
case R_390_GOTOFF64: /* 64 bit offset to GOT. */ case R_390_GOTOFF64: /* 64 bit offset to GOT. */
val = val + rela->r_addend - val = val + rela->r_addend -
((Elf_Addr) me->module_core + me->arch.got_offset); ((Elf_Addr) me->core_layout.base + me->arch.got_offset);
if (r_type == R_390_GOTOFF16) if (r_type == R_390_GOTOFF16)
rc = apply_rela_bits(loc, val, 0, 16, 0); rc = apply_rela_bits(loc, val, 0, 16, 0);
else if (r_type == R_390_GOTOFF32) else if (r_type == R_390_GOTOFF32)
...@@ -366,7 +366,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab, ...@@ -366,7 +366,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
break; break;
case R_390_GOTPC: /* 32 bit PC relative offset to GOT. */ case R_390_GOTPC: /* 32 bit PC relative offset to GOT. */
case R_390_GOTPCDBL: /* 32 bit PC rel. off. to GOT shifted by 1. */ case R_390_GOTPCDBL: /* 32 bit PC rel. off. to GOT shifted by 1. */
val = (Elf_Addr) me->module_core + me->arch.got_offset + val = (Elf_Addr) me->core_layout.base + me->arch.got_offset +
rela->r_addend - loc; rela->r_addend - loc;
if (r_type == R_390_GOTPC) if (r_type == R_390_GOTPC)
rc = apply_rela_bits(loc, val, 1, 32, 0); rc = apply_rela_bits(loc, val, 1, 32, 0);
......
...@@ -20,8 +20,6 @@ ...@@ -20,8 +20,6 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <asm/cacheflush.h>
#include <asm/page_types.h>
#include <asm/elf.h> #include <asm/elf.h>
#include <asm/livepatch.h> #include <asm/livepatch.h>
...@@ -38,11 +36,10 @@ ...@@ -38,11 +36,10 @@
int klp_write_module_reloc(struct module *mod, unsigned long type, int klp_write_module_reloc(struct module *mod, unsigned long type,
unsigned long loc, unsigned long value) unsigned long loc, unsigned long value)
{ {
int ret, numpages, size = 4; size_t size = 4;
bool readonly;
unsigned long val; unsigned long val;
unsigned long core = (unsigned long)mod->module_core; unsigned long core = (unsigned long)mod->core_layout.base;
unsigned long core_size = mod->core_size; unsigned long core_size = mod->core_layout.size;
switch (type) { switch (type) {
case R_X86_64_NONE: case R_X86_64_NONE:
...@@ -69,23 +66,5 @@ int klp_write_module_reloc(struct module *mod, unsigned long type, ...@@ -69,23 +66,5 @@ int klp_write_module_reloc(struct module *mod, unsigned long type,
/* loc does not point to any symbol inside the module */ /* loc does not point to any symbol inside the module */
return -EINVAL; return -EINVAL;
readonly = false; return probe_kernel_write((void *)loc, &val, size);
#ifdef CONFIG_DEBUG_SET_MODULE_RONX
if (loc < core + mod->core_ro_size)
readonly = true;
#endif
/* determine if the relocation spans a page boundary */
numpages = ((loc & PAGE_MASK) == ((loc + size) & PAGE_MASK)) ? 1 : 2;
if (readonly)
set_memory_rw(loc & PAGE_MASK, numpages);
ret = probe_kernel_write((void *)loc, &val, size);
if (readonly)
set_memory_ro(loc & PAGE_MASK, numpages);
return ret;
} }
...@@ -37,8 +37,9 @@ enum klp_state { ...@@ -37,8 +37,9 @@ enum klp_state {
* struct klp_func - function structure for live patching * struct klp_func - function structure for live patching
* @old_name: name of the function to be patched * @old_name: name of the function to be patched
* @new_func: pointer to the patched function code * @new_func: pointer to the patched function code
* @old_addr: a hint conveying at what address the old function * @old_sympos: a hint indicating which symbol position the old function
* can be found (optional, vmlinux patches only) * can be found (optional)
* @old_addr: the address of the function being patched
* @kobj: kobject for sysfs resources * @kobj: kobject for sysfs resources
* @state: tracks function-level patch application state * @state: tracks function-level patch application state
* @stack_node: list node for klp_ops func_stack list * @stack_node: list node for klp_ops func_stack list
...@@ -48,16 +49,16 @@ struct klp_func { ...@@ -48,16 +49,16 @@ struct klp_func {
const char *old_name; const char *old_name;
void *new_func; void *new_func;
/* /*
* The old_addr field is optional and can be used to resolve * The old_sympos field is optional and can be used to resolve
* duplicate symbol names in the vmlinux object. If this * duplicate symbol names in livepatch objects. If this field is zero,
* information is not present, the symbol is located by name * it is expected the symbol is unique, otherwise patching fails. If
* with kallsyms. If the name is not unique and old_addr is * this value is greater than zero then that occurrence of the symbol
* not provided, the patch application fails as there is no * in kallsyms for the given object is used.
* way to resolve the ambiguity.
*/ */
unsigned long old_addr; unsigned long old_sympos;
/* internal */ /* internal */
unsigned long old_addr;
struct kobject kobj; struct kobject kobj;
enum klp_state state; enum klp_state state;
struct list_head stack_node; struct list_head stack_node;
...@@ -66,8 +67,7 @@ struct klp_func { ...@@ -66,8 +67,7 @@ struct klp_func {
/** /**
* struct klp_reloc - relocation structure for live patching * struct klp_reloc - relocation structure for live patching
* @loc: address where the relocation will be written * @loc: address where the relocation will be written
* @val: address of the referenced symbol (optional, * @sympos: position in kallsyms to disambiguate symbols (optional)
* vmlinux patches only)
* @type: ELF relocation type * @type: ELF relocation type
* @name: name of the referenced symbol (for lookup/verification) * @name: name of the referenced symbol (for lookup/verification)
* @addend: offset from the referenced symbol * @addend: offset from the referenced symbol
...@@ -75,7 +75,7 @@ struct klp_func { ...@@ -75,7 +75,7 @@ struct klp_func {
*/ */
struct klp_reloc { struct klp_reloc {
unsigned long loc; unsigned long loc;
unsigned long val; unsigned long sympos;
unsigned long type; unsigned long type;
const char *name; const char *name;
int addend; int addend;
......
...@@ -302,6 +302,28 @@ struct mod_tree_node { ...@@ -302,6 +302,28 @@ struct mod_tree_node {
struct latch_tree_node node; struct latch_tree_node node;
}; };
struct module_layout {
/* The actual code + data. */
void *base;
/* Total size. */
unsigned int size;
/* The size of the executable code. */
unsigned int text_size;
/* Size of RO section of the module (text+rodata) */
unsigned int ro_size;
#ifdef CONFIG_MODULES_TREE_LOOKUP
struct mod_tree_node mtn;
#endif
};
#ifdef CONFIG_MODULES_TREE_LOOKUP
/* Only touch one cacheline for common rbtree-for-core-layout case. */
#define __module_layout_align ____cacheline_aligned
#else
#define __module_layout_align
#endif
struct module { struct module {
enum module_state state; enum module_state state;
...@@ -366,37 +388,9 @@ struct module { ...@@ -366,37 +388,9 @@ struct module {
/* Startup function. */ /* Startup function. */
int (*init)(void); int (*init)(void);
/* /* Core layout: rbtree is accessed frequently, so keep together. */
* If this is non-NULL, vfree() after init() returns. struct module_layout core_layout __module_layout_align;
* struct module_layout init_layout;
* Cacheline align here, such that:
* module_init, module_core, init_size, core_size,
* init_text_size, core_text_size and mtn_core::{mod,node[0]}
* are on the same cacheline.
*/
void *module_init ____cacheline_aligned;
/* Here is the actual code + data, vfree'd on unload. */
void *module_core;
/* Here are the sizes of the init and core sections */
unsigned int init_size, core_size;
/* The size of the executable code in each section. */
unsigned int init_text_size, core_text_size;
#ifdef CONFIG_MODULES_TREE_LOOKUP
/*
* We want mtn_core::{mod,node[0]} to be in the same cacheline as the
* above entries such that a regular lookup will only touch one
* cacheline.
*/
struct mod_tree_node mtn_core;
struct mod_tree_node mtn_init;
#endif
/* Size of RO sections of the module (text+rodata) */
unsigned int init_ro_size, core_ro_size;
/* Arch-specific module values */ /* Arch-specific module values */
struct mod_arch_specific arch; struct mod_arch_specific arch;
...@@ -505,15 +499,15 @@ bool is_module_text_address(unsigned long addr); ...@@ -505,15 +499,15 @@ bool is_module_text_address(unsigned long addr);
static inline bool within_module_core(unsigned long addr, static inline bool within_module_core(unsigned long addr,
const struct module *mod) const struct module *mod)
{ {
return (unsigned long)mod->module_core <= addr && return (unsigned long)mod->core_layout.base <= addr &&
addr < (unsigned long)mod->module_core + mod->core_size; addr < (unsigned long)mod->core_layout.base + mod->core_layout.size;
} }
static inline bool within_module_init(unsigned long addr, static inline bool within_module_init(unsigned long addr,
const struct module *mod) const struct module *mod)
{ {
return (unsigned long)mod->module_init <= addr && return (unsigned long)mod->init_layout.base <= addr &&
addr < (unsigned long)mod->module_init + mod->init_size; addr < (unsigned long)mod->init_layout.base + mod->init_layout.size;
} }
static inline bool within_module(unsigned long addr, const struct module *mod) static inline bool within_module(unsigned long addr, const struct module *mod)
...@@ -768,9 +762,13 @@ extern int module_sysfs_initialized; ...@@ -768,9 +762,13 @@ extern int module_sysfs_initialized;
#ifdef CONFIG_DEBUG_SET_MODULE_RONX #ifdef CONFIG_DEBUG_SET_MODULE_RONX
extern void set_all_modules_text_rw(void); extern void set_all_modules_text_rw(void);
extern void set_all_modules_text_ro(void); extern void set_all_modules_text_ro(void);
extern void module_enable_ro(const struct module *mod);
extern void module_disable_ro(const struct module *mod);
#else #else
static inline void set_all_modules_text_rw(void) { } static inline void set_all_modules_text_rw(void) { }
static inline void set_all_modules_text_ro(void) { } static inline void set_all_modules_text_ro(void) { }
static inline void module_enable_ro(const struct module *mod) { }
static inline void module_disable_ro(const struct module *mod) { }
#endif #endif
#ifdef CONFIG_GENERIC_BUG #ifdef CONFIG_GENERIC_BUG
......
...@@ -2021,7 +2021,7 @@ static int kdb_lsmod(int argc, const char **argv) ...@@ -2021,7 +2021,7 @@ static int kdb_lsmod(int argc, const char **argv)
continue; continue;
kdb_printf("%-20s%8u 0x%p ", mod->name, kdb_printf("%-20s%8u 0x%p ", mod->name,
mod->core_size, (void *)mod); mod->core_layout.size, (void *)mod);
#ifdef CONFIG_MODULE_UNLOAD #ifdef CONFIG_MODULE_UNLOAD
kdb_printf("%4d ", module_refcount(mod)); kdb_printf("%4d ", module_refcount(mod));
#endif #endif
...@@ -2031,7 +2031,7 @@ static int kdb_lsmod(int argc, const char **argv) ...@@ -2031,7 +2031,7 @@ static int kdb_lsmod(int argc, const char **argv)
kdb_printf(" (Loading)"); kdb_printf(" (Loading)");
else else
kdb_printf(" (Live)"); kdb_printf(" (Live)");
kdb_printf(" 0x%p", mod->module_core); kdb_printf(" 0x%p", mod->core_layout.base);
#ifdef CONFIG_MODULE_UNLOAD #ifdef CONFIG_MODULE_UNLOAD
{ {
......
...@@ -123,11 +123,6 @@ void gcov_enable_events(void) ...@@ -123,11 +123,6 @@ void gcov_enable_events(void)
} }
#ifdef CONFIG_MODULES #ifdef CONFIG_MODULES
static inline int within(void *addr, void *start, unsigned long size)
{
return ((addr >= start) && (addr < start + size));
}
/* Update list and generate events when modules are unloaded. */ /* Update list and generate events when modules are unloaded. */
static int gcov_module_notifier(struct notifier_block *nb, unsigned long event, static int gcov_module_notifier(struct notifier_block *nb, unsigned long event,
void *data) void *data)
...@@ -142,7 +137,7 @@ static int gcov_module_notifier(struct notifier_block *nb, unsigned long event, ...@@ -142,7 +137,7 @@ static int gcov_module_notifier(struct notifier_block *nb, unsigned long event,
/* Remove entries located in module from linked list. */ /* Remove entries located in module from linked list. */
while ((info = gcov_info_next(info))) { while ((info = gcov_info_next(info))) {
if (within(info, mod->module_core, mod->core_size)) { if (within_module((unsigned long)info, mod)) {
gcov_info_unlink(prev, info); gcov_info_unlink(prev, info);
if (gcov_events_enabled) if (gcov_events_enabled)
gcov_event(GCOV_REMOVE, info); gcov_event(GCOV_REMOVE, info);
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/kallsyms.h> #include <linux/kallsyms.h>
#include <linux/livepatch.h> #include <linux/livepatch.h>
#include <asm/cacheflush.h>
/** /**
* struct klp_ops - structure for tracking registered ftrace ops structs * struct klp_ops - structure for tracking registered ftrace ops structs
...@@ -135,13 +136,8 @@ struct klp_find_arg { ...@@ -135,13 +136,8 @@ struct klp_find_arg {
const char *objname; const char *objname;
const char *name; const char *name;
unsigned long addr; unsigned long addr;
/*
* If count == 0, the symbol was not found. If count == 1, a unique
* match was found and addr is set. If count > 1, there is
* unresolvable ambiguity among "count" number of symbols with the same
* name in the same object.
*/
unsigned long count; unsigned long count;
unsigned long pos;
}; };
static int klp_find_callback(void *data, const char *name, static int klp_find_callback(void *data, const char *name,
...@@ -158,37 +154,48 @@ static int klp_find_callback(void *data, const char *name, ...@@ -158,37 +154,48 @@ static int klp_find_callback(void *data, const char *name,
if (args->objname && strcmp(args->objname, mod->name)) if (args->objname && strcmp(args->objname, mod->name))
return 0; return 0;
/*
* args->addr might be overwritten if another match is found
* but klp_find_object_symbol() handles this and only returns the
* addr if count == 1.
*/
args->addr = addr; args->addr = addr;
args->count++; args->count++;
/*
* Finish the search when the symbol is found for the desired position
* or the position is not defined for a non-unique symbol.
*/
if ((args->pos && (args->count == args->pos)) ||
(!args->pos && (args->count > 1)))
return 1;
return 0; return 0;
} }
static int klp_find_object_symbol(const char *objname, const char *name, static int klp_find_object_symbol(const char *objname, const char *name,
unsigned long *addr) unsigned long sympos, unsigned long *addr)
{ {
struct klp_find_arg args = { struct klp_find_arg args = {
.objname = objname, .objname = objname,
.name = name, .name = name,
.addr = 0, .addr = 0,
.count = 0 .count = 0,
.pos = sympos,
}; };
mutex_lock(&module_mutex); mutex_lock(&module_mutex);
kallsyms_on_each_symbol(klp_find_callback, &args); kallsyms_on_each_symbol(klp_find_callback, &args);
mutex_unlock(&module_mutex); mutex_unlock(&module_mutex);
if (args.count == 0) /*
* Ensure an address was found. If sympos is 0, ensure symbol is unique;
* otherwise ensure the symbol position count matches sympos.
*/
if (args.addr == 0)
pr_err("symbol '%s' not found in symbol table\n", name); pr_err("symbol '%s' not found in symbol table\n", name);
else if (args.count > 1) else if (args.count > 1 && sympos == 0) {
pr_err("unresolvable ambiguity (%lu matches) on symbol '%s' in object '%s'\n", pr_err("unresolvable ambiguity (%lu matches) on symbol '%s' in object '%s'\n",
args.count, name, objname); args.count, name, objname);
else { } else if (sympos != args.count && sympos > 0) {
pr_err("symbol position %lu for symbol '%s' in object '%s' not found\n",
sympos, name, objname ? objname : "vmlinux");
} else {
*addr = args.addr; *addr = args.addr;
return 0; return 0;
} }
...@@ -197,66 +204,6 @@ static int klp_find_object_symbol(const char *objname, const char *name, ...@@ -197,66 +204,6 @@ static int klp_find_object_symbol(const char *objname, const char *name,
return -EINVAL; return -EINVAL;
} }
struct klp_verify_args {
const char *name;
const unsigned long addr;
};
static int klp_verify_callback(void *data, const char *name,
struct module *mod, unsigned long addr)
{
struct klp_verify_args *args = data;
if (!mod &&
!strcmp(args->name, name) &&
args->addr == addr)
return 1;
return 0;
}
static int klp_verify_vmlinux_symbol(const char *name, unsigned long addr)
{
struct klp_verify_args args = {
.name = name,
.addr = addr,
};
int ret;
mutex_lock(&module_mutex);
ret = kallsyms_on_each_symbol(klp_verify_callback, &args);
mutex_unlock(&module_mutex);
if (!ret) {
pr_err("symbol '%s' not found at specified address 0x%016lx, kernel mismatch?\n",
name, addr);
return -EINVAL;
}
return 0;
}
static int klp_find_verify_func_addr(struct klp_object *obj,
struct klp_func *func)
{
int ret;
#if defined(CONFIG_RANDOMIZE_BASE)
/* If KASLR has been enabled, adjust old_addr accordingly */
if (kaslr_enabled() && func->old_addr)
func->old_addr += kaslr_offset();
#endif
if (!func->old_addr || klp_is_module(obj))
ret = klp_find_object_symbol(obj->name, func->old_name,
&func->old_addr);
else
ret = klp_verify_vmlinux_symbol(func->old_name,
func->old_addr);
return ret;
}
/* /*
* external symbols are located outside the parent object (where the parent * external symbols are located outside the parent object (where the parent
* object is either vmlinux or the kmod being patched). * object is either vmlinux or the kmod being patched).
...@@ -276,14 +223,18 @@ static int klp_find_external_symbol(struct module *pmod, const char *name, ...@@ -276,14 +223,18 @@ static int klp_find_external_symbol(struct module *pmod, const char *name,
} }
preempt_enable(); preempt_enable();
/* otherwise check if it's in another .o within the patch module */ /*
return klp_find_object_symbol(pmod->name, name, addr); * Check if it's in another .o within the patch module. This also
* checks that the external symbol is unique.
*/
return klp_find_object_symbol(pmod->name, name, 0, addr);
} }
static int klp_write_object_relocations(struct module *pmod, static int klp_write_object_relocations(struct module *pmod,
struct klp_object *obj) struct klp_object *obj)
{ {
int ret; int ret = 0;
unsigned long val;
struct klp_reloc *reloc; struct klp_reloc *reloc;
if (WARN_ON(!klp_is_object_loaded(obj))) if (WARN_ON(!klp_is_object_loaded(obj)))
...@@ -292,41 +243,38 @@ static int klp_write_object_relocations(struct module *pmod, ...@@ -292,41 +243,38 @@ static int klp_write_object_relocations(struct module *pmod,
if (WARN_ON(!obj->relocs)) if (WARN_ON(!obj->relocs))
return -EINVAL; return -EINVAL;
module_disable_ro(pmod);
for (reloc = obj->relocs; reloc->name; reloc++) { for (reloc = obj->relocs; reloc->name; reloc++) {
if (!klp_is_module(obj)) { /* discover the address of the referenced symbol */
if (reloc->external) {
#if defined(CONFIG_RANDOMIZE_BASE) if (reloc->sympos > 0) {
/* If KASLR has been enabled, adjust old value accordingly */ pr_err("non-zero sympos for external reloc symbol '%s' is not supported\n",
if (kaslr_enabled()) reloc->name);
reloc->val += kaslr_offset(); ret = -EINVAL;
#endif goto out;
ret = klp_verify_vmlinux_symbol(reloc->name, }
reloc->val); ret = klp_find_external_symbol(pmod, reloc->name, &val);
if (ret) } else
return ret; ret = klp_find_object_symbol(obj->name,
} else { reloc->name,
/* module, reloc->val needs to be discovered */ reloc->sympos,
if (reloc->external) &val);
ret = klp_find_external_symbol(pmod, if (ret)
reloc->name, goto out;
&reloc->val);
else
ret = klp_find_object_symbol(obj->mod->name,
reloc->name,
&reloc->val);
if (ret)
return ret;
}
ret = klp_write_module_reloc(pmod, reloc->type, reloc->loc, ret = klp_write_module_reloc(pmod, reloc->type, reloc->loc,
reloc->val + reloc->addend); val + reloc->addend);
if (ret) { if (ret) {
pr_err("relocation failed for symbol '%s' at 0x%016lx (%d)\n", pr_err("relocation failed for symbol '%s' at 0x%016lx (%d)\n",
reloc->name, reloc->val, ret); reloc->name, val, ret);
return ret; goto out;
} }
} }
return 0; out:
module_enable_ro(pmod);
return ret;
} }
static void notrace klp_ftrace_handler(unsigned long ip, static void notrace klp_ftrace_handler(unsigned long ip,
...@@ -593,7 +541,7 @@ EXPORT_SYMBOL_GPL(klp_enable_patch); ...@@ -593,7 +541,7 @@ EXPORT_SYMBOL_GPL(klp_enable_patch);
* /sys/kernel/livepatch/<patch> * /sys/kernel/livepatch/<patch>
* /sys/kernel/livepatch/<patch>/enabled * /sys/kernel/livepatch/<patch>/enabled
* /sys/kernel/livepatch/<patch>/<object> * /sys/kernel/livepatch/<patch>/<object>
* /sys/kernel/livepatch/<patch>/<object>/<func> * /sys/kernel/livepatch/<patch>/<object>/<function,sympos>
*/ */
static ssize_t enabled_store(struct kobject *kobj, struct kobj_attribute *attr, static ssize_t enabled_store(struct kobject *kobj, struct kobj_attribute *attr,
...@@ -738,8 +686,14 @@ static int klp_init_func(struct klp_object *obj, struct klp_func *func) ...@@ -738,8 +686,14 @@ static int klp_init_func(struct klp_object *obj, struct klp_func *func)
INIT_LIST_HEAD(&func->stack_node); INIT_LIST_HEAD(&func->stack_node);
func->state = KLP_DISABLED; func->state = KLP_DISABLED;
/* The format for the sysfs directory is <function,sympos> where sympos
* is the nth occurrence of this symbol in kallsyms for the patched
* object. If the user selects 0 for old_sympos, then 1 will be used
* since a unique symbol will be the first occurrence.
*/
return kobject_init_and_add(&func->kobj, &klp_ktype_func, return kobject_init_and_add(&func->kobj, &klp_ktype_func,
&obj->kobj, "%s", func->old_name); &obj->kobj, "%s,%lu", func->old_name,
func->old_sympos ? func->old_sympos : 1);
} }
/* parts of the initialization that is done only when the object is loaded */ /* parts of the initialization that is done only when the object is loaded */
...@@ -756,7 +710,9 @@ static int klp_init_object_loaded(struct klp_patch *patch, ...@@ -756,7 +710,9 @@ static int klp_init_object_loaded(struct klp_patch *patch,
} }
klp_for_each_func(obj, func) { klp_for_each_func(obj, func) {
ret = klp_find_verify_func_addr(obj, func); ret = klp_find_object_symbol(obj->name, func->old_name,
func->old_sympos,
&func->old_addr);
if (ret) if (ret)
return ret; return ret;
} }
......
...@@ -80,15 +80,6 @@ ...@@ -80,15 +80,6 @@
# define debug_align(X) (X) # define debug_align(X) (X)
#endif #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 */ /* If this is set, the section belongs in the init part of the module */
#define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1)) #define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1))
...@@ -108,13 +99,6 @@ static LIST_HEAD(modules); ...@@ -108,13 +99,6 @@ static LIST_HEAD(modules);
* Use a latched RB-tree for __module_address(); this allows us to use * Use a latched RB-tree for __module_address(); this allows us to use
* RCU-sched lookups of the address from any context. * 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 * This is conditional on PERF_EVENTS || TRACING because those can really hit
* __module_address() hard by doing a lot of stack unwinding; potentially from * __module_address() hard by doing a lot of stack unwinding; potentially from
* NMI context. * NMI context.
...@@ -122,24 +106,16 @@ static LIST_HEAD(modules); ...@@ -122,24 +106,16 @@ static LIST_HEAD(modules);
static __always_inline unsigned long __mod_tree_val(struct latch_tree_node *n) 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_layout *layout = container_of(n, struct module_layout, mtn.node);
struct module *mod = mtn->mod;
if (unlikely(mtn == &mod->mtn_init)) return (unsigned long)layout->base;
return (unsigned long)mod->module_init;
return (unsigned long)mod->module_core;
} }
static __always_inline unsigned long __mod_tree_size(struct latch_tree_node *n) 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_layout *layout = container_of(n, struct module_layout, mtn.node);
struct module *mod = mtn->mod;
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 static __always_inline bool
...@@ -197,23 +173,23 @@ static void __mod_tree_remove(struct mod_tree_node *node) ...@@ -197,23 +173,23 @@ static void __mod_tree_remove(struct mod_tree_node *node)
*/ */
static void mod_tree_insert(struct module *mod) static void mod_tree_insert(struct module *mod)
{ {
mod->mtn_core.mod = mod; mod->core_layout.mtn.mod = mod;
mod->mtn_init.mod = mod; mod->init_layout.mtn.mod = mod;
__mod_tree_insert(&mod->mtn_core); __mod_tree_insert(&mod->core_layout.mtn);
if (mod->init_size) if (mod->init_layout.size)
__mod_tree_insert(&mod->mtn_init); __mod_tree_insert(&mod->init_layout.mtn);
} }
static void mod_tree_remove_init(struct module *mod) static void mod_tree_remove_init(struct module *mod)
{ {
if (mod->init_size) if (mod->init_layout.size)
__mod_tree_remove(&mod->mtn_init); __mod_tree_remove(&mod->init_layout.mtn);
} }
static void mod_tree_remove(struct module *mod) 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); mod_tree_remove_init(mod);
} }
...@@ -267,9 +243,9 @@ static void __mod_update_bounds(void *base, unsigned int size) ...@@ -267,9 +243,9 @@ static void __mod_update_bounds(void *base, unsigned int size)
static void mod_update_bounds(struct module *mod) static void mod_update_bounds(struct module *mod)
{ {
__mod_update_bounds(mod->module_core, mod->core_size); __mod_update_bounds(mod->core_layout.base, mod->core_layout.size);
if (mod->init_size) if (mod->init_layout.size)
__mod_update_bounds(mod->module_init, mod->init_size); __mod_update_bounds(mod->init_layout.base, mod->init_layout.size);
} }
#ifdef CONFIG_KGDB_KDB #ifdef CONFIG_KGDB_KDB
...@@ -1214,7 +1190,7 @@ struct module_attribute module_uevent = ...@@ -1214,7 +1190,7 @@ struct module_attribute module_uevent =
static ssize_t show_coresize(struct module_attribute *mattr, static ssize_t show_coresize(struct module_attribute *mattr,
struct module_kobject *mk, char *buffer) 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 = static struct module_attribute modinfo_coresize =
...@@ -1223,7 +1199,7 @@ 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, static ssize_t show_initsize(struct module_attribute *mattr,
struct module_kobject *mk, char *buffer) 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 = static struct module_attribute modinfo_initsize =
...@@ -1873,64 +1849,75 @@ static void mod_sysfs_teardown(struct module *mod) ...@@ -1873,64 +1849,75 @@ static void mod_sysfs_teardown(struct module *mod)
/* /*
* LKM RO/NX protection: protect module's text/ro-data * LKM RO/NX protection: protect module's text/ro-data
* from modification and any data from execution. * 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); BUG_ON((unsigned long)layout->base & (PAGE_SIZE-1));
unsigned long end_pfn = PFN_DOWN((unsigned long)end); BUG_ON((unsigned long)layout->text_size & (PAGE_SIZE-1));
set_memory((unsigned long)layout->base,
layout->text_size >> PAGE_SHIFT);
}
if (end_pfn > begin_pfn) static void frob_rodata(const struct module_layout *layout,
set(begin_pfn << PAGE_SHIFT, end_pfn - begin_pfn); int (*set_memory)(unsigned long start, int num_pages))
{
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 set_section_ro_nx(void *base, static void frob_writable_data(const struct module_layout *layout,
unsigned long text_size, int (*set_memory)(unsigned long start, int num_pages))
unsigned long ro_size,
unsigned long total_size)
{ {
/* begin and end PFNs of the current subsection */ BUG_ON((unsigned long)layout->base & (PAGE_SIZE-1));
unsigned long begin_pfn; BUG_ON((unsigned long)layout->ro_size & (PAGE_SIZE-1));
unsigned long end_pfn; 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);
}
/* /* livepatching wants to disable read-only so it can frob module. */
* Set RO for module text and RO-data: void module_disable_ro(const struct module *mod)
* - Always protect first page. {
* - Do not protect last partial page. frob_text(&mod->core_layout, set_memory_rw);
*/ frob_rodata(&mod->core_layout, set_memory_rw);
if (ro_size > 0) frob_text(&mod->init_layout, set_memory_rw);
set_page_attributes(base, base + ro_size, set_memory_ro); frob_rodata(&mod->init_layout, set_memory_rw);
}
/* void module_enable_ro(const struct module *mod)
* Set NX permissions for module data: {
* - Do not protect first partial page. frob_text(&mod->core_layout, set_memory_ro);
* - Always protect last page. frob_rodata(&mod->core_layout, set_memory_ro);
*/ frob_text(&mod->init_layout, set_memory_ro);
if (total_size > text_size) { frob_rodata(&mod->init_layout, set_memory_ro);
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);
}
} }
static void unset_module_core_ro_nx(struct module *mod) static void module_enable_nx(const struct module *mod)
{ {
set_page_attributes(mod->module_core + mod->core_text_size, frob_rodata(&mod->core_layout, set_memory_nx);
mod->module_core + mod->core_size, frob_writable_data(&mod->core_layout, set_memory_nx);
set_memory_x); frob_rodata(&mod->init_layout, set_memory_nx);
set_page_attributes(mod->module_core, frob_writable_data(&mod->init_layout, set_memory_nx);
mod->module_core + mod->core_ro_size,
set_memory_rw);
} }
static void unset_module_init_ro_nx(struct module *mod) static void module_disable_nx(const struct module *mod)
{ {
set_page_attributes(mod->module_init + mod->init_text_size, frob_rodata(&mod->core_layout, set_memory_x);
mod->module_init + mod->init_size, frob_writable_data(&mod->core_layout, set_memory_x);
set_memory_x); frob_rodata(&mod->init_layout, set_memory_x);
set_page_attributes(mod->module_init, frob_writable_data(&mod->init_layout, set_memory_x);
mod->module_init + mod->init_ro_size,
set_memory_rw);
} }
/* Iterate through all modules and set each module's text as RW */ /* Iterate through all modules and set each module's text as RW */
...@@ -1942,16 +1929,9 @@ void set_all_modules_text_rw(void) ...@@ -1942,16 +1929,9 @@ void set_all_modules_text_rw(void)
list_for_each_entry_rcu(mod, &modules, list) { list_for_each_entry_rcu(mod, &modules, list) {
if (mod->state == MODULE_STATE_UNFORMED) if (mod->state == MODULE_STATE_UNFORMED)
continue; continue;
if ((mod->module_core) && (mod->core_text_size)) {
set_page_attributes(mod->module_core, frob_text(&mod->core_layout, set_memory_rw);
mod->module_core + mod->core_text_size, frob_text(&mod->init_layout, set_memory_rw);
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);
}
} }
mutex_unlock(&module_mutex); mutex_unlock(&module_mutex);
} }
...@@ -1965,23 +1945,25 @@ void set_all_modules_text_ro(void) ...@@ -1965,23 +1945,25 @@ void set_all_modules_text_ro(void)
list_for_each_entry_rcu(mod, &modules, list) { list_for_each_entry_rcu(mod, &modules, list) {
if (mod->state == MODULE_STATE_UNFORMED) if (mod->state == MODULE_STATE_UNFORMED)
continue; continue;
if ((mod->module_core) && (mod->core_text_size)) {
set_page_attributes(mod->module_core, frob_text(&mod->core_layout, set_memory_ro);
mod->module_core + mod->core_text_size, frob_text(&mod->init_layout, set_memory_ro);
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);
}
} }
mutex_unlock(&module_mutex); 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 #else
static inline void set_section_ro_nx(void *base, unsigned long text_size, unsigned long ro_size, unsigned long total_size) { } static void disable_ro_nx(const struct module_layout *layout) { }
static void unset_module_core_ro_nx(struct module *mod) { } static void module_enable_nx(const struct module *mod) { }
static void unset_module_init_ro_nx(struct module *mod) { } static void module_disable_nx(const struct module *mod) { }
#endif #endif
void __weak module_memfree(void *module_region) void __weak module_memfree(void *module_region)
...@@ -2033,19 +2015,19 @@ static void free_module(struct module *mod) ...@@ -2033,19 +2015,19 @@ static void free_module(struct module *mod)
synchronize_sched(); synchronize_sched();
mutex_unlock(&module_mutex); mutex_unlock(&module_mutex);
/* This may be NULL, but that's OK */ /* This may be empty, but that's OK */
unset_module_init_ro_nx(mod); disable_ro_nx(&mod->init_layout);
module_arch_freeing_init(mod); module_arch_freeing_init(mod);
module_memfree(mod->module_init); module_memfree(mod->init_layout.base);
kfree(mod->args); kfree(mod->args);
percpu_modfree(mod); percpu_modfree(mod);
/* Free lock-classes; relies on the preceding sync_rcu(). */ /* 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) */ /* Finally, free the core (containing the module structure) */
unset_module_core_ro_nx(mod); disable_ro_nx(&mod->core_layout);
module_memfree(mod->module_core); module_memfree(mod->core_layout.base);
#ifdef CONFIG_MPU #ifdef CONFIG_MPU
update_protections(current->mm); update_protections(current->mm);
...@@ -2248,20 +2230,20 @@ static void layout_sections(struct module *mod, struct load_info *info) ...@@ -2248,20 +2230,20 @@ static void layout_sections(struct module *mod, struct load_info *info)
|| s->sh_entsize != ~0UL || s->sh_entsize != ~0UL
|| strstarts(sname, ".init")) || strstarts(sname, ".init"))
continue; 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); pr_debug("\t%s\n", sname);
} }
switch (m) { switch (m) {
case 0: /* executable */ case 0: /* executable */
mod->core_size = debug_align(mod->core_size); mod->core_layout.size = debug_align(mod->core_layout.size);
mod->core_text_size = mod->core_size; mod->core_layout.text_size = mod->core_layout.size;
break; break;
case 1: /* RO: text and ro-data */ case 1: /* RO: text and ro-data */
mod->core_size = debug_align(mod->core_size); mod->core_layout.size = debug_align(mod->core_layout.size);
mod->core_ro_size = mod->core_size; mod->core_layout.ro_size = mod->core_layout.size;
break; break;
case 3: /* whole core */ case 3: /* whole core */
mod->core_size = debug_align(mod->core_size); mod->core_layout.size = debug_align(mod->core_layout.size);
break; break;
} }
} }
...@@ -2277,21 +2259,21 @@ static void layout_sections(struct module *mod, struct load_info *info) ...@@ -2277,21 +2259,21 @@ static void layout_sections(struct module *mod, struct load_info *info)
|| s->sh_entsize != ~0UL || s->sh_entsize != ~0UL
|| !strstarts(sname, ".init")) || !strstarts(sname, ".init"))
continue; 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); | INIT_OFFSET_MASK);
pr_debug("\t%s\n", sname); pr_debug("\t%s\n", sname);
} }
switch (m) { switch (m) {
case 0: /* executable */ case 0: /* executable */
mod->init_size = debug_align(mod->init_size); mod->init_layout.size = debug_align(mod->init_layout.size);
mod->init_text_size = mod->init_size; mod->init_layout.text_size = mod->init_layout.size;
break; break;
case 1: /* RO: text and ro-data */ case 1: /* RO: text and ro-data */
mod->init_size = debug_align(mod->init_size); mod->init_layout.size = debug_align(mod->init_layout.size);
mod->init_ro_size = mod->init_size; mod->init_layout.ro_size = mod->init_layout.size;
break; break;
case 3: /* whole init */ case 3: /* whole init */
mod->init_size = debug_align(mod->init_size); mod->init_layout.size = debug_align(mod->init_layout.size);
break; break;
} }
} }
...@@ -2401,7 +2383,7 @@ static char elf_type(const Elf_Sym *sym, const struct load_info *info) ...@@ -2401,7 +2383,7 @@ static char elf_type(const Elf_Sym *sym, const struct load_info *info)
} }
if (sym->st_shndx == SHN_UNDEF) if (sym->st_shndx == SHN_UNDEF)
return 'U'; return 'U';
if (sym->st_shndx == SHN_ABS) if (sym->st_shndx == SHN_ABS || sym->st_shndx == info->index.pcpu)
return 'a'; return 'a';
if (sym->st_shndx >= SHN_LORESERVE) if (sym->st_shndx >= SHN_LORESERVE)
return '?'; return '?';
...@@ -2430,7 +2412,7 @@ static char elf_type(const Elf_Sym *sym, const struct load_info *info) ...@@ -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, 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; const Elf_Shdr *sec;
...@@ -2439,6 +2421,11 @@ static bool is_core_symbol(const Elf_Sym *src, const Elf_Shdr *sechdrs, ...@@ -2439,6 +2421,11 @@ static bool is_core_symbol(const Elf_Sym *src, const Elf_Shdr *sechdrs,
|| !src->st_name) || !src->st_name)
return false; return false;
#ifdef CONFIG_KALLSYMS_ALL
if (src->st_shndx == pcpundx)
return true;
#endif
sec = sechdrs + src->st_shndx; sec = sechdrs + src->st_shndx;
if (!(sec->sh_flags & SHF_ALLOC) if (!(sec->sh_flags & SHF_ALLOC)
#ifndef CONFIG_KALLSYMS_ALL #ifndef CONFIG_KALLSYMS_ALL
...@@ -2466,7 +2453,7 @@ static void layout_symtab(struct module *mod, struct load_info *info) ...@@ -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. */ /* Put symbol section at end of init part of module. */
symsect->sh_flags |= SHF_ALLOC; 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; info->index.sym) | INIT_OFFSET_MASK;
pr_debug("\t%s\n", info->secstrings + symsect->sh_name); 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) ...@@ -2476,23 +2463,24 @@ static void layout_symtab(struct module *mod, struct load_info *info)
/* Compute total space required for the core symbols' strtab. */ /* Compute total space required for the core symbols' strtab. */
for (ndst = i = 0; i < nsrc; i++) { for (ndst = i = 0; i < nsrc; i++) {
if (i == 0 || 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; strtab_size += strlen(&info->strtab[src[i].st_name])+1;
ndst++; ndst++;
} }
} }
/* Append room for core symbols at end of core part. */ /* Append room for core symbols at end of core part. */
info->symoffs = ALIGN(mod->core_size, symsect->sh_addralign ?: 1); info->symoffs = ALIGN(mod->core_layout.size, symsect->sh_addralign ?: 1);
info->stroffs = mod->core_size = info->symoffs + ndst * sizeof(Elf_Sym); info->stroffs = mod->core_layout.size = info->symoffs + ndst * sizeof(Elf_Sym);
mod->core_size += strtab_size; mod->core_layout.size += strtab_size;
mod->core_size = debug_align(mod->core_size); mod->core_layout.size = debug_align(mod->core_layout.size);
/* Put string table section at end of init part of module. */ /* Put string table section at end of init part of module. */
strsect->sh_flags |= SHF_ALLOC; 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; 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); 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) ...@@ -2513,12 +2501,13 @@ static void add_kallsyms(struct module *mod, const struct load_info *info)
for (i = 0; i < mod->num_symtab; i++) for (i = 0; i < mod->num_symtab; i++)
mod->symtab[i].st_info = elf_type(&mod->symtab[i], info); mod->symtab[i].st_info = elf_type(&mod->symtab[i], info);
mod->core_symtab = dst = mod->module_core + info->symoffs; mod->core_symtab = dst = mod->core_layout.base + info->symoffs;
mod->core_strtab = s = mod->module_core + info->stroffs; mod->core_strtab = s = mod->core_layout.base + info->stroffs;
src = mod->symtab; src = mod->symtab;
for (ndst = i = 0; i < mod->num_symtab; i++) { for (ndst = i = 0; i < mod->num_symtab; i++) {
if (i == 0 || 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] = src[i];
dst[ndst++].st_name = s - mod->core_strtab; dst[ndst++].st_name = s - mod->core_strtab;
s += strlcpy(s, &mod->strtab[src[i].st_name], s += strlcpy(s, &mod->strtab[src[i].st_name],
...@@ -2964,7 +2953,7 @@ static int move_module(struct module *mod, struct load_info *info) ...@@ -2964,7 +2953,7 @@ static int move_module(struct module *mod, struct load_info *info)
void *ptr; void *ptr;
/* Do the allocs. */ /* 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 * The pointer to this block is stored in the module structure
* which is inside the block. Just mark it as not being a * 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) ...@@ -2974,11 +2963,11 @@ static int move_module(struct module *mod, struct load_info *info)
if (!ptr) if (!ptr)
return -ENOMEM; return -ENOMEM;
memset(ptr, 0, mod->core_size); memset(ptr, 0, mod->core_layout.size);
mod->module_core = ptr; mod->core_layout.base = ptr;
if (mod->init_size) { if (mod->init_layout.size) {
ptr = module_alloc(mod->init_size); ptr = module_alloc(mod->init_layout.size);
/* /*
* The pointer to this block is stored in the module structure * The pointer to this block is stored in the module structure
* which is inside the block. This block doesn't need to be * 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) ...@@ -2987,13 +2976,13 @@ static int move_module(struct module *mod, struct load_info *info)
*/ */
kmemleak_ignore(ptr); kmemleak_ignore(ptr);
if (!ptr) { if (!ptr) {
module_memfree(mod->module_core); module_memfree(mod->core_layout.base);
return -ENOMEM; return -ENOMEM;
} }
memset(ptr, 0, mod->init_size); memset(ptr, 0, mod->init_layout.size);
mod->module_init = ptr; mod->init_layout.base = ptr;
} else } else
mod->module_init = NULL; mod->init_layout.base = NULL;
/* Transfer each section which specifies SHF_ALLOC */ /* Transfer each section which specifies SHF_ALLOC */
pr_debug("final section addresses:\n"); pr_debug("final section addresses:\n");
...@@ -3005,10 +2994,10 @@ static int move_module(struct module *mod, struct load_info *info) ...@@ -3005,10 +2994,10 @@ static int move_module(struct module *mod, struct load_info *info)
continue; continue;
if (shdr->sh_entsize & INIT_OFFSET_MASK) if (shdr->sh_entsize & INIT_OFFSET_MASK)
dest = mod->module_init dest = mod->init_layout.base
+ (shdr->sh_entsize & ~INIT_OFFSET_MASK); + (shdr->sh_entsize & ~INIT_OFFSET_MASK);
else else
dest = mod->module_core + shdr->sh_entsize; dest = mod->core_layout.base + shdr->sh_entsize;
if (shdr->sh_type != SHT_NOBITS) if (shdr->sh_type != SHT_NOBITS)
memcpy(dest, (void *)shdr->sh_addr, shdr->sh_size); memcpy(dest, (void *)shdr->sh_addr, shdr->sh_size);
...@@ -3070,12 +3059,12 @@ static void flush_module_icache(const struct module *mod) ...@@ -3070,12 +3059,12 @@ static void flush_module_icache(const struct module *mod)
* Do it before processing of module parameters, so the module * Do it before processing of module parameters, so the module
* can provide parameter accessor functions of its own. * can provide parameter accessor functions of its own.
*/ */
if (mod->module_init) if (mod->init_layout.base)
flush_icache_range((unsigned long)mod->module_init, flush_icache_range((unsigned long)mod->init_layout.base,
(unsigned long)mod->module_init (unsigned long)mod->init_layout.base
+ mod->init_size); + mod->init_layout.size);
flush_icache_range((unsigned long)mod->module_core, flush_icache_range((unsigned long)mod->core_layout.base,
(unsigned long)mod->module_core + mod->core_size); (unsigned long)mod->core_layout.base + mod->core_layout.size);
set_fs(old_fs); set_fs(old_fs);
} }
...@@ -3133,8 +3122,8 @@ static void module_deallocate(struct module *mod, struct load_info *info) ...@@ -3133,8 +3122,8 @@ static void module_deallocate(struct module *mod, struct load_info *info)
{ {
percpu_modfree(mod); percpu_modfree(mod);
module_arch_freeing_init(mod); module_arch_freeing_init(mod);
module_memfree(mod->module_init); module_memfree(mod->init_layout.base);
module_memfree(mod->module_core); module_memfree(mod->core_layout.base);
} }
int __weak module_finalize(const Elf_Ehdr *hdr, int __weak module_finalize(const Elf_Ehdr *hdr,
...@@ -3221,7 +3210,7 @@ static noinline int do_init_module(struct module *mod) ...@@ -3221,7 +3210,7 @@ static noinline int do_init_module(struct module *mod)
ret = -ENOMEM; ret = -ENOMEM;
goto fail; 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 * 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) ...@@ -3279,12 +3268,12 @@ static noinline int do_init_module(struct module *mod)
mod->strtab = mod->core_strtab; mod->strtab = mod->core_strtab;
#endif #endif
mod_tree_remove_init(mod); mod_tree_remove_init(mod);
unset_module_init_ro_nx(mod); disable_ro_nx(&mod->init_layout);
module_arch_freeing_init(mod); module_arch_freeing_init(mod);
mod->module_init = NULL; mod->init_layout.base = NULL;
mod->init_size = 0; mod->init_layout.size = 0;
mod->init_ro_size = 0; mod->init_layout.ro_size = 0;
mod->init_text_size = 0; mod->init_layout.text_size = 0;
/* /*
* We want to free module_init, but be aware that kallsyms may be * We want to free module_init, but be aware that kallsyms may be
* walking this with preempt disabled. In all the failure paths, we * 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) ...@@ -3373,17 +3362,9 @@ static int complete_formation(struct module *mod, struct load_info *info)
/* This relies on module_mutex for list integrity. */ /* This relies on module_mutex for list integrity. */
module_bug_finalize(info->hdr, info->sechdrs, mod); module_bug_finalize(info->hdr, info->sechdrs, mod);
/* Set RO and NX regions for core */ /* Set RO and NX regions */
set_section_ro_nx(mod->module_core, module_enable_ro(mod);
mod->core_text_size, module_enable_nx(mod);
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);
/* Mark state as coming so strong_try_module_get() ignores us, /* Mark state as coming so strong_try_module_get() ignores us,
* but kallsyms etc. can see us. */ * but kallsyms etc. can see us. */
...@@ -3548,8 +3529,8 @@ static int load_module(struct load_info *info, const char __user *uargs, ...@@ -3548,8 +3529,8 @@ static int load_module(struct load_info *info, const char __user *uargs,
MODULE_STATE_GOING, mod); MODULE_STATE_GOING, mod);
/* we can't deallocate the module until we clear memory protection */ /* we can't deallocate the module until we clear memory protection */
unset_module_init_ro_nx(mod); module_disable_ro(mod);
unset_module_core_ro_nx(mod); module_disable_nx(mod);
ddebug_cleanup: ddebug_cleanup:
dynamic_debug_remove(info->debug); dynamic_debug_remove(info->debug);
...@@ -3578,7 +3559,7 @@ static int load_module(struct load_info *info, const char __user *uargs, ...@@ -3578,7 +3559,7 @@ static int load_module(struct load_info *info, const char __user *uargs,
*/ */
ftrace_release_mod(mod); ftrace_release_mod(mod);
/* Free lock-classes; relies on the preceding sync_rcu() */ /* 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); module_deallocate(mod, info);
free_copy: free_copy:
...@@ -3656,9 +3637,9 @@ static const char *get_ksymbol(struct module *mod, ...@@ -3656,9 +3637,9 @@ static const char *get_ksymbol(struct module *mod,
/* At worse, next value is at end of module */ /* At worse, next value is at end of module */
if (within_module_init(addr, mod)) 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 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 /* Scan for closest preceding symbol, and next symbol. (ELF
starts real symbols at 1). */ starts real symbols at 1). */
...@@ -3905,7 +3886,7 @@ static int m_show(struct seq_file *m, void *p) ...@@ -3905,7 +3886,7 @@ static int m_show(struct seq_file *m, void *p)
return 0; return 0;
seq_printf(m, "%s %u", 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); print_unload_info(m, mod);
/* Informative for users. */ /* Informative for users. */
...@@ -3914,7 +3895,7 @@ static int m_show(struct seq_file *m, void *p) ...@@ -3914,7 +3895,7 @@ static int m_show(struct seq_file *m, void *p)
mod->state == MODULE_STATE_COMING ? "Loading" : mod->state == MODULE_STATE_COMING ? "Loading" :
"Live"); "Live");
/* Used by oprofile and other similar tools. */ /* 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 */ /* Taints info */
if (mod->taints) if (mod->taints)
...@@ -4057,8 +4038,8 @@ struct module *__module_text_address(unsigned long addr) ...@@ -4057,8 +4038,8 @@ struct module *__module_text_address(unsigned long addr)
struct module *mod = __module_address(addr); struct module *mod = __module_address(addr);
if (mod) { if (mod) {
/* Make sure it's within the text section. */ /* Make sure it's within the text section. */
if (!within(addr, mod->module_init, mod->init_text_size) if (!within(addr, mod->init_layout.base, mod->init_layout.text_size)
&& !within(addr, mod->module_core, mod->core_text_size)) && !within(addr, mod->core_layout.base, mod->core_layout.text_size))
mod = NULL; mod = NULL;
} }
return mod; return mod;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment