Commit 72a86433 authored by Christophe Leroy's avatar Christophe Leroy Committed by Michael Ellerman
Browse files

lkdtm: Fix execute_[user]_location()



execute_location() and execute_user_location() intent
to copy do_nothing() text and execute it at a new location.
However, at the time being it doesn't copy do_nothing() function
but do_nothing() function descriptor which still points to the
original text. So at the end it still executes do_nothing() at
its original location allthough using a copied function descriptor.

So, fix that by really copying do_nothing() text and build a new
function descriptor by copying do_nothing() function descriptor and
updating the target address with the new location.

Also fix the displayed addresses by dereferencing do_nothing()
function descriptor.

Signed-off-by: default avatarChristophe Leroy <christophe.leroy@csgroup.eu>
Acked-by: default avatarKees Cook <keescook@chromium.org>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/4055839683d8d643cd99be121f4767c7c611b970.1644928018.git.christophe.leroy@csgroup.eu
parent b6491339
Loading
Loading
Loading
Loading
+28 −9
Original line number Diff line number Diff line
@@ -44,19 +44,34 @@ static noinline void do_overwritten(void)
	return;
}

static void *setup_function_descriptor(func_desc_t *fdesc, void *dst)
{
	if (!have_function_descriptors())
		return dst;

	memcpy(fdesc, do_nothing, sizeof(*fdesc));
	fdesc->addr = (unsigned long)dst;
	barrier();

	return fdesc;
}

static noinline void execute_location(void *dst, bool write)
{
	void (*func)(void) = dst;
	void (*func)(void);
	func_desc_t fdesc;
	void *do_nothing_text = dereference_function_descriptor(do_nothing);

	pr_info("attempting ok execution at %px\n", do_nothing);
	pr_info("attempting ok execution at %px\n", do_nothing_text);
	do_nothing();

	if (write == CODE_WRITE) {
		memcpy(dst, do_nothing, EXEC_SIZE);
		memcpy(dst, do_nothing_text, EXEC_SIZE);
		flush_icache_range((unsigned long)dst,
				   (unsigned long)dst + EXEC_SIZE);
	}
	pr_info("attempting bad execution at %px\n", func);
	pr_info("attempting bad execution at %px\n", dst);
	func = setup_function_descriptor(&fdesc, dst);
	func();
	pr_err("FAIL: func returned\n");
}
@@ -66,16 +81,19 @@ static void execute_user_location(void *dst)
	int copied;

	/* Intentionally crossing kernel/user memory boundary. */
	void (*func)(void) = dst;
	void (*func)(void);
	func_desc_t fdesc;
	void *do_nothing_text = dereference_function_descriptor(do_nothing);

	pr_info("attempting ok execution at %px\n", do_nothing);
	pr_info("attempting ok execution at %px\n", do_nothing_text);
	do_nothing();

	copied = access_process_vm(current, (unsigned long)dst, do_nothing,
	copied = access_process_vm(current, (unsigned long)dst, do_nothing_text,
				   EXEC_SIZE, FOLL_WRITE);
	if (copied < EXEC_SIZE)
		return;
	pr_info("attempting bad execution at %px\n", func);
	pr_info("attempting bad execution at %px\n", dst);
	func = setup_function_descriptor(&fdesc, dst);
	func();
	pr_err("FAIL: func returned\n");
}
@@ -153,7 +171,8 @@ void lkdtm_EXEC_VMALLOC(void)

void lkdtm_EXEC_RODATA(void)
{
	execute_location(lkdtm_rodata_do_nothing, CODE_AS_IS);
	execute_location(dereference_function_descriptor(lkdtm_rodata_do_nothing),
			 CODE_AS_IS);
}

void lkdtm_EXEC_USERSPACE(void)