x86/module: Use text_poke() for late relocations
Because of late module patching, a livepatch module needs to be able to apply some of its relocations well after it has been loaded. Instead of playing games with module_{dis,en}able_ro(), use existing text poking mechanisms to apply relocations after module loading. So far only x86, s390 and Power have HAVE_LIVEPATCH but only the first two also have STRICT_MODULE_RWX. This will allow removal of the last module_disable_ro() usage in livepatch. The ultimate goal is to completely disallow making executable mappings writable. [ jpoimboe: Split up patches. Use mod state to determine whether memcpy() can be used. Implement text_poke() for UML. ] Cc: x86@kernel.org Suggested-by: Josh Poimboeuf <jpoimboe@redhat.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> Acked-by: Joe Lawrence <joe.lawrence@redhat.com> Acked-by: Miroslav Benes <mbenes@suse.cz> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
This commit is contained in:
parent
be2422612a
commit
88fc078a7a
|
@ -362,3 +362,19 @@ void __init check_bugs(void)
|
||||||
void apply_alternatives(struct alt_instr *start, struct alt_instr *end)
|
void apply_alternatives(struct alt_instr *start, struct alt_instr *end)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *text_poke(void *addr, const void *opcode, size_t len)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* In UML, the only reference to this function is in
|
||||||
|
* apply_relocate_add(), which shouldn't ever actually call this
|
||||||
|
* because UML doesn't have live patching.
|
||||||
|
*/
|
||||||
|
WARN_ON(1);
|
||||||
|
|
||||||
|
return memcpy(addr, opcode, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void text_poke_sync(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
|
@ -126,11 +126,12 @@ int apply_relocate(Elf32_Shdr *sechdrs,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#else /*X86_64*/
|
#else /*X86_64*/
|
||||||
int apply_relocate_add(Elf64_Shdr *sechdrs,
|
static int __apply_relocate_add(Elf64_Shdr *sechdrs,
|
||||||
const char *strtab,
|
const char *strtab,
|
||||||
unsigned int symindex,
|
unsigned int symindex,
|
||||||
unsigned int relsec,
|
unsigned int relsec,
|
||||||
struct module *me)
|
struct module *me,
|
||||||
|
void *(*write)(void *dest, const void *src, size_t len))
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr;
|
Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr;
|
||||||
|
@ -162,19 +163,19 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
|
||||||
case R_X86_64_64:
|
case R_X86_64_64:
|
||||||
if (*(u64 *)loc != 0)
|
if (*(u64 *)loc != 0)
|
||||||
goto invalid_relocation;
|
goto invalid_relocation;
|
||||||
*(u64 *)loc = val;
|
write(loc, &val, 8);
|
||||||
break;
|
break;
|
||||||
case R_X86_64_32:
|
case R_X86_64_32:
|
||||||
if (*(u32 *)loc != 0)
|
if (*(u32 *)loc != 0)
|
||||||
goto invalid_relocation;
|
goto invalid_relocation;
|
||||||
*(u32 *)loc = val;
|
write(loc, &val, 4);
|
||||||
if (val != *(u32 *)loc)
|
if (val != *(u32 *)loc)
|
||||||
goto overflow;
|
goto overflow;
|
||||||
break;
|
break;
|
||||||
case R_X86_64_32S:
|
case R_X86_64_32S:
|
||||||
if (*(s32 *)loc != 0)
|
if (*(s32 *)loc != 0)
|
||||||
goto invalid_relocation;
|
goto invalid_relocation;
|
||||||
*(s32 *)loc = val;
|
write(loc, &val, 4);
|
||||||
if ((s64)val != *(s32 *)loc)
|
if ((s64)val != *(s32 *)loc)
|
||||||
goto overflow;
|
goto overflow;
|
||||||
break;
|
break;
|
||||||
|
@ -183,7 +184,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
|
||||||
if (*(u32 *)loc != 0)
|
if (*(u32 *)loc != 0)
|
||||||
goto invalid_relocation;
|
goto invalid_relocation;
|
||||||
val -= (u64)loc;
|
val -= (u64)loc;
|
||||||
*(u32 *)loc = val;
|
write(loc, &val, 4);
|
||||||
#if 0
|
#if 0
|
||||||
if ((s64)val != *(s32 *)loc)
|
if ((s64)val != *(s32 *)loc)
|
||||||
goto overflow;
|
goto overflow;
|
||||||
|
@ -193,7 +194,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
|
||||||
if (*(u64 *)loc != 0)
|
if (*(u64 *)loc != 0)
|
||||||
goto invalid_relocation;
|
goto invalid_relocation;
|
||||||
val -= (u64)loc;
|
val -= (u64)loc;
|
||||||
*(u64 *)loc = val;
|
write(loc, &val, 8);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
pr_err("%s: Unknown rela relocation: %llu\n",
|
pr_err("%s: Unknown rela relocation: %llu\n",
|
||||||
|
@ -215,6 +216,29 @@ overflow:
|
||||||
me->name);
|
me->name);
|
||||||
return -ENOEXEC;
|
return -ENOEXEC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int apply_relocate_add(Elf64_Shdr *sechdrs,
|
||||||
|
const char *strtab,
|
||||||
|
unsigned int symindex,
|
||||||
|
unsigned int relsec,
|
||||||
|
struct module *me)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
bool early = me->state == MODULE_STATE_UNFORMED;
|
||||||
|
void *(*write)(void *, const void *, size_t) = memcpy;
|
||||||
|
|
||||||
|
if (!early)
|
||||||
|
write = text_poke;
|
||||||
|
|
||||||
|
ret = __apply_relocate_add(sechdrs, strtab, symindex, relsec, me,
|
||||||
|
write);
|
||||||
|
|
||||||
|
if (!early)
|
||||||
|
text_poke_sync();
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int module_finalize(const Elf_Ehdr *hdr,
|
int module_finalize(const Elf_Ehdr *hdr,
|
||||||
|
|
Loading…
Reference in a new issue