lkdtm/bugs: Check that a per-task stack canary exists
Introduce REPORT_STACK_CANARY to check for differing stack canaries between two processes (i.e. that an architecture is correctly implementing per-task stack canaries), using the task_struct canary as the hint to locate in the stack. Requires that one of the processes being tested not be pid 1. Cc: Ard Biesheuvel <ardb@kernel.org> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Kees Cook <keescook@chromium.org> Link: https://lore.kernel.org/r/20211022223826.330653-3-keescook@chromium.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
149538cd55
commit
d46e58ef77
5 changed files with 81 additions and 0 deletions
|
@ -151,6 +151,83 @@ void lkdtm_REPORT_STACK(void)
|
||||||
pr_info("Stack offset: %d\n", (int)(stack_addr - (uintptr_t)&magic));
|
pr_info("Stack offset: %d\n", (int)(stack_addr - (uintptr_t)&magic));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static pid_t stack_canary_pid;
|
||||||
|
static unsigned long stack_canary;
|
||||||
|
static unsigned long stack_canary_offset;
|
||||||
|
|
||||||
|
static noinline void __lkdtm_REPORT_STACK_CANARY(void *stack)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
pid_t pid = task_pid_nr(current);
|
||||||
|
unsigned long *canary = (unsigned long *)stack;
|
||||||
|
unsigned long current_offset = 0, init_offset = 0;
|
||||||
|
|
||||||
|
/* Do our best to find the canary in a 16 word window ... */
|
||||||
|
for (i = 1; i < 16; i++) {
|
||||||
|
canary = (unsigned long *)stack + i;
|
||||||
|
#ifdef CONFIG_STACKPROTECTOR
|
||||||
|
if (*canary == current->stack_canary)
|
||||||
|
current_offset = i;
|
||||||
|
if (*canary == init_task.stack_canary)
|
||||||
|
init_offset = i;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_offset == 0) {
|
||||||
|
/*
|
||||||
|
* If the canary doesn't match what's in the task_struct,
|
||||||
|
* we're either using a global canary or the stack frame
|
||||||
|
* layout changed.
|
||||||
|
*/
|
||||||
|
if (init_offset != 0) {
|
||||||
|
pr_err("FAIL: global stack canary found at offset %ld (canary for pid %d matches init_task's)!\n",
|
||||||
|
init_offset, pid);
|
||||||
|
} else {
|
||||||
|
pr_warn("FAIL: did not correctly locate stack canary :(\n");
|
||||||
|
pr_expected_config(CONFIG_STACKPROTECTOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
} else if (init_offset != 0) {
|
||||||
|
pr_warn("WARNING: found both current and init_task canaries nearby?!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
canary = (unsigned long *)stack + current_offset;
|
||||||
|
if (stack_canary_pid == 0) {
|
||||||
|
stack_canary = *canary;
|
||||||
|
stack_canary_pid = pid;
|
||||||
|
stack_canary_offset = current_offset;
|
||||||
|
pr_info("Recorded stack canary for pid %d at offset %ld\n",
|
||||||
|
stack_canary_pid, stack_canary_offset);
|
||||||
|
} else if (pid == stack_canary_pid) {
|
||||||
|
pr_warn("ERROR: saw pid %d again -- please use a new pid\n", pid);
|
||||||
|
} else {
|
||||||
|
if (current_offset != stack_canary_offset) {
|
||||||
|
pr_warn("ERROR: canary offset changed from %ld to %ld!?\n",
|
||||||
|
stack_canary_offset, current_offset);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*canary == stack_canary) {
|
||||||
|
pr_warn("FAIL: canary identical for pid %d and pid %d at offset %ld!\n",
|
||||||
|
stack_canary_pid, pid, current_offset);
|
||||||
|
} else {
|
||||||
|
pr_info("ok: stack canaries differ between pid %d and pid %d at offset %ld.\n",
|
||||||
|
stack_canary_pid, pid, current_offset);
|
||||||
|
/* Reset the test. */
|
||||||
|
stack_canary_pid = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void lkdtm_REPORT_STACK_CANARY(void)
|
||||||
|
{
|
||||||
|
/* Use default char array length that triggers stack protection. */
|
||||||
|
char data[8] __aligned(sizeof(void *)) = { };
|
||||||
|
|
||||||
|
__lkdtm_REPORT_STACK_CANARY((void *)&data);
|
||||||
|
}
|
||||||
|
|
||||||
void lkdtm_UNALIGNED_LOAD_STORE_WRITE(void)
|
void lkdtm_UNALIGNED_LOAD_STORE_WRITE(void)
|
||||||
{
|
{
|
||||||
static u8 data[5] __attribute__((aligned(4))) = {1, 2, 3, 4, 5};
|
static u8 data[5] __attribute__((aligned(4))) = {1, 2, 3, 4, 5};
|
||||||
|
|
|
@ -111,6 +111,7 @@ static const struct crashtype crashtypes[] = {
|
||||||
CRASHTYPE(CORRUPT_STACK),
|
CRASHTYPE(CORRUPT_STACK),
|
||||||
CRASHTYPE(CORRUPT_STACK_STRONG),
|
CRASHTYPE(CORRUPT_STACK_STRONG),
|
||||||
CRASHTYPE(REPORT_STACK),
|
CRASHTYPE(REPORT_STACK),
|
||||||
|
CRASHTYPE(REPORT_STACK_CANARY),
|
||||||
CRASHTYPE(CORRUPT_LIST_ADD),
|
CRASHTYPE(CORRUPT_LIST_ADD),
|
||||||
CRASHTYPE(CORRUPT_LIST_DEL),
|
CRASHTYPE(CORRUPT_LIST_DEL),
|
||||||
CRASHTYPE(STACK_GUARD_PAGE_LEADING),
|
CRASHTYPE(STACK_GUARD_PAGE_LEADING),
|
||||||
|
|
|
@ -69,6 +69,7 @@ void lkdtm_EXHAUST_STACK(void);
|
||||||
void lkdtm_CORRUPT_STACK(void);
|
void lkdtm_CORRUPT_STACK(void);
|
||||||
void lkdtm_CORRUPT_STACK_STRONG(void);
|
void lkdtm_CORRUPT_STACK_STRONG(void);
|
||||||
void lkdtm_REPORT_STACK(void);
|
void lkdtm_REPORT_STACK(void);
|
||||||
|
void lkdtm_REPORT_STACK_CANARY(void);
|
||||||
void lkdtm_UNALIGNED_LOAD_STORE_WRITE(void);
|
void lkdtm_UNALIGNED_LOAD_STORE_WRITE(void);
|
||||||
void lkdtm_SOFTLOCKUP(void);
|
void lkdtm_SOFTLOCKUP(void);
|
||||||
void lkdtm_HARDLOCKUP(void);
|
void lkdtm_HARDLOCKUP(void);
|
||||||
|
|
|
@ -8,3 +8,4 @@ CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT=y
|
||||||
CONFIG_INIT_ON_ALLOC_DEFAULT_ON=y
|
CONFIG_INIT_ON_ALLOC_DEFAULT_ON=y
|
||||||
CONFIG_UBSAN_BOUNDS=y
|
CONFIG_UBSAN_BOUNDS=y
|
||||||
CONFIG_UBSAN_TRAP=y
|
CONFIG_UBSAN_TRAP=y
|
||||||
|
CONFIG_STACKPROTECTOR_STRONG=y
|
||||||
|
|
|
@ -12,6 +12,7 @@ CORRUPT_LIST_ADD list_add corruption
|
||||||
CORRUPT_LIST_DEL list_del corruption
|
CORRUPT_LIST_DEL list_del corruption
|
||||||
STACK_GUARD_PAGE_LEADING
|
STACK_GUARD_PAGE_LEADING
|
||||||
STACK_GUARD_PAGE_TRAILING
|
STACK_GUARD_PAGE_TRAILING
|
||||||
|
REPORT_STACK_CANARY repeat:2 ok: stack canaries differ
|
||||||
UNSET_SMEP pinned CR4 bits changed:
|
UNSET_SMEP pinned CR4 bits changed:
|
||||||
DOUBLE_FAULT
|
DOUBLE_FAULT
|
||||||
CORRUPT_PAC
|
CORRUPT_PAC
|
||||||
|
|
Loading…
Reference in a new issue