Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 22980444 authored by Kees Cook's avatar Kees Cook Committed by Gerrit - the friendly Code Review server
Browse files

lkdtm: Avoid more compiler optimizations for bad writes



It seems at least Clang is able to throw away writes it knows are
destined for read-only memory, which makes things like the WRITE_RO test
fail, as the write gets elided. Instead, force the variable to be
volatile, and make similar changes through-out other tests in an effort
to avoid needing to repeat fixing these kinds of problems. Also includes
pr_err() calls in failure paths so that kernel logs are more clear in
the failure case.

Change-Id: I5de9481b78a7bb7fde5cd0b6043e229cb5ccee5f
Reported-by: default avatarPrasad Sodagudi <psodagud@codeaurora.org>
Suggested-by: default avatarSami Tolvanen <samitolvanen@google.com>
Fixes: 9ae113ce ("lkdtm: add tests for additional page permissions")
Signed-off-by: default avatarKees Cook <keescook@chromium.org>
Link: https://lore.kernel.org/r/20200625203704.317097-2-keescook@chromium.org


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Git-commit: 464e86b4abadfc490f426954b431e2ec6a9d7bd2
Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git


[prsood@codeaurora.org: resolve trivial merge conflicts]
Signed-off-by: default avatarPrateek Sood <prsood@codeaurora.org>
parent 923dfa71
Loading
Loading
Loading
Loading
+4 −6
Original line number Diff line number Diff line
@@ -97,9 +97,8 @@ noinline void lkdtm_CORRUPT_STACK(void)
	/* Use default char array length that triggers stack protection. */
	char data[8] __aligned(sizeof(void *));

	__lkdtm_CORRUPT_STACK(&data);

	pr_info("Corrupted stack containing char array ...\n");
	pr_info("Corrupting stack containing char array ...\n");
	__lkdtm_CORRUPT_STACK((void *)&data);
}

/* Same as above but will only get a canary with -fstack-protector-strong */
@@ -110,9 +109,8 @@ noinline void lkdtm_CORRUPT_STACK_STRONG(void)
		unsigned long *ptr;
	} data __aligned(sizeof(void *));

	__lkdtm_CORRUPT_STACK(&data);

	pr_info("Corrupted stack containing union ...\n");
	pr_info("Corrupting stack containing union ...\n");
	__lkdtm_CORRUPT_STACK((void *)&data);
}

void lkdtm_UNALIGNED_LOAD_STORE_WRITE(void)
+15 −7
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@ static noinline void execute_location(void *dst, bool write)
	}
	pr_info("attempting bad execution at %px\n", func);
	func();
	pr_err("FAIL: func returned\n");
}

static void execute_user_location(void *dst)
@@ -75,20 +76,22 @@ static void execute_user_location(void *dst)
		return;
	pr_info("attempting bad execution at %px\n", func);
	func();
	pr_err("FAIL: func returned\n");
}

void lkdtm_WRITE_RO(void)
{
	/* Explicitly cast away "const" for the test. */
	unsigned long *ptr = (unsigned long *)&rodata;
	/* Explicitly cast away "const" for the test and make volatile. */
	volatile unsigned long *ptr = (unsigned long *)&rodata;

	pr_info("attempting bad rodata write at %px\n", ptr);
	*ptr ^= 0xabcd1234;
	pr_err("FAIL: survived bad write\n");
}

void lkdtm_WRITE_RO_AFTER_INIT(void)
{
	unsigned long *ptr = &ro_after_init;
	volatile unsigned long *ptr = &ro_after_init;

	/*
	 * Verify we were written to during init. Since an Oops
@@ -102,12 +105,13 @@ void lkdtm_WRITE_RO_AFTER_INIT(void)

	pr_info("attempting bad ro_after_init write at %px\n", ptr);
	*ptr ^= 0xabcd1234;
	pr_err("FAIL: survived bad write\n");
}

void lkdtm_WRITE_KERN(void)
{
	size_t size;
	unsigned char *ptr;
	volatile unsigned char *ptr;

	if ((unsigned long)do_overwritten < (unsigned long)do_nothing)
		size = (unsigned long)do_nothing -
@@ -118,8 +122,9 @@ void lkdtm_WRITE_KERN(void)
	ptr = (unsigned char *)do_overwritten;

	pr_info("attempting bad %zu byte write at %px\n", size, ptr);
	memcpy(ptr, (unsigned char *)do_nothing, size);
	memcpy((void *)ptr, (unsigned char *)do_nothing, size);
	flush_icache_range((unsigned long)ptr, (unsigned long)(ptr + size));
	pr_err("FAIL: survived bad write\n");

	do_overwritten();
}
@@ -198,9 +203,11 @@ void lkdtm_ACCESS_USERSPACE(void)
	pr_info("attempting bad read at %px\n", ptr);
	tmp = *ptr;
	tmp += 0xc0dec0de;
	pr_err("FAIL: survived bad read\n");

	pr_info("attempting bad write at %px\n", ptr);
	*ptr = tmp;
	pr_err("FAIL: survived bad write\n");

	vm_munmap(user_addr, PAGE_SIZE);
}
@@ -208,19 +215,20 @@ void lkdtm_ACCESS_USERSPACE(void)
void lkdtm_ACCESS_NULL(void)
{
	unsigned long tmp;
	unsigned long *ptr = (unsigned long *)NULL;
	volatile unsigned long *ptr = (unsigned long *)NULL;

	pr_info("attempting bad read at %px\n", ptr);
	tmp = *ptr;
	tmp += 0xc0dec0de;
	pr_err("FAIL: survived bad read\n");

	pr_info("attempting bad write at %px\n", ptr);
	*ptr = tmp;
	pr_err("FAIL: survived bad write\n");
}

void __init lkdtm_perms_init(void)
{
	/* Make sure we can write to __ro_after_init values during __init */
	ro_after_init |= 0xAA;

}
+5 −2
Original line number Diff line number Diff line
@@ -304,19 +304,22 @@ void lkdtm_USERCOPY_KERNEL(void)
		return;
	}

	pr_info("attempting good copy_to_user from kernel rodata\n");
	pr_info("attempting good copy_to_user from kernel rodata: %px\n",
		test_text);
	if (copy_to_user((void __user *)user_addr, test_text,
			 unconst + sizeof(test_text))) {
		pr_warn("copy_to_user failed unexpectedly?!\n");
		goto free_user;
	}

	pr_info("attempting bad copy_to_user from kernel text\n");
	pr_info("attempting bad copy_to_user from kernel text: %px\n",
		vm_mmap);
	if (copy_to_user((void __user *)user_addr, vm_mmap,
			 unconst + PAGE_SIZE)) {
		pr_warn("copy_to_user failed, but lacked Oops\n");
		goto free_user;
	}
	pr_err("FAIL: survived bad copy_to_user()\n");

free_user:
	vm_munmap(user_addr, PAGE_SIZE);