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:
Peter Zijlstra 2020-04-29 10:24:49 -05:00 коммит произвёл Jiri Kosina
Родитель be2422612a
Коммит 88fc078a7a
2 изменённых файлов: 47 добавлений и 7 удалений

Просмотреть файл

@ -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,