Commit 88fc078a authored by Peter Zijlstra's avatar Peter Zijlstra Committed by Jiri Kosina
Browse files

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: default avatarJosh Poimboeuf <jpoimboe@redhat.com>
Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: default avatarJosh Poimboeuf <jpoimboe@redhat.com>
Acked-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: default avatarJoe Lawrence <joe.lawrence@redhat.com>
Acked-by: default avatarMiroslav Benes <mbenes@suse.cz>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent be242261
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -362,3 +362,19 @@ void __init check_bugs(void)
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)
{
}
+31 −7
Original line number Diff line number Diff line
@@ -126,11 +126,12 @@ int apply_relocate(Elf32_Shdr *sechdrs,
	return 0;
}
#else /*X86_64*/
int apply_relocate_add(Elf64_Shdr *sechdrs,
static int __apply_relocate_add(Elf64_Shdr *sechdrs,
		   const char *strtab,
		   unsigned int symindex,
		   unsigned int relsec,
		   struct module *me)
		   struct module *me,
		   void *(*write)(void *dest, const void *src, size_t len))
{
	unsigned int i;
	Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr;
@@ -162,19 +163,19 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
		case R_X86_64_64:
			if (*(u64 *)loc != 0)
				goto invalid_relocation;
			*(u64 *)loc = val;
			write(loc, &val, 8);
			break;
		case R_X86_64_32:
			if (*(u32 *)loc != 0)
				goto invalid_relocation;
			*(u32 *)loc = val;
			write(loc, &val, 4);
			if (val != *(u32 *)loc)
				goto overflow;
			break;
		case R_X86_64_32S:
			if (*(s32 *)loc != 0)
				goto invalid_relocation;
			*(s32 *)loc = val;
			write(loc, &val, 4);
			if ((s64)val != *(s32 *)loc)
				goto overflow;
			break;
@@ -183,7 +184,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
			if (*(u32 *)loc != 0)
				goto invalid_relocation;
			val -= (u64)loc;
			*(u32 *)loc = val;
			write(loc, &val, 4);
#if 0
			if ((s64)val != *(s32 *)loc)
				goto overflow;
@@ -193,7 +194,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
			if (*(u64 *)loc != 0)
				goto invalid_relocation;
			val -= (u64)loc;
			*(u64 *)loc = val;
			write(loc, &val, 8);
			break;
		default:
			pr_err("%s: Unknown rela relocation: %llu\n",
@@ -215,6 +216,29 @@ overflow:
	       me->name);
	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

int module_finalize(const Elf_Ehdr *hdr,