diff options
Diffstat (limited to 'drivers/misc/lkdtm/stackleak.c')
| -rw-r--r-- | drivers/misc/lkdtm/stackleak.c | 150 |
1 files changed, 0 insertions, 150 deletions
diff --git a/drivers/misc/lkdtm/stackleak.c b/drivers/misc/lkdtm/stackleak.c deleted file mode 100644 index f1d022160913..000000000000 --- a/drivers/misc/lkdtm/stackleak.c +++ /dev/null @@ -1,150 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * This code tests that the current task stack is properly erased (filled - * with STACKLEAK_POISON). - * - * Authors: - * Alexander Popov <alex.popov@linux.com> - * Tycho Andersen <tycho@tycho.ws> - */ - -#include "lkdtm.h" -#include <linux/stackleak.h> - -#if defined(CONFIG_GCC_PLUGIN_STACKLEAK) -/* - * Check that stackleak tracks the lowest stack pointer and erases the stack - * below this as expected. - * - * To prevent the lowest stack pointer changing during the test, IRQs are - * masked and instrumentation of this function is disabled. We assume that the - * compiler will create a fixed-size stack frame for this function. - * - * Any non-inlined function may make further use of the stack, altering the - * lowest stack pointer and/or clobbering poison values. To avoid spurious - * failures we must avoid printing until the end of the test or have already - * encountered a failure condition. - */ -static void noinstr check_stackleak_irqoff(void) -{ - const unsigned long task_stack_base = (unsigned long)task_stack_page(current); - const unsigned long task_stack_low = stackleak_task_low_bound(current); - const unsigned long task_stack_high = stackleak_task_high_bound(current); - const unsigned long current_sp = current_stack_pointer; - const unsigned long lowest_sp = current->lowest_stack; - unsigned long untracked_high; - unsigned long poison_high, poison_low; - bool test_failed = false; - - /* - * Check that the current and lowest recorded stack pointer values fall - * within the expected task stack boundaries. These tests should never - * fail unless the boundaries are incorrect or we're clobbering the - * STACK_END_MAGIC, and in either casee something is seriously wrong. - */ - if (current_sp < task_stack_low || current_sp >= task_stack_high) { - instrumentation_begin(); - pr_err("FAIL: current_stack_pointer (0x%lx) outside of task stack bounds [0x%lx..0x%lx]\n", - current_sp, task_stack_low, task_stack_high - 1); - test_failed = true; - goto out; - } - if (lowest_sp < task_stack_low || lowest_sp >= task_stack_high) { - instrumentation_begin(); - pr_err("FAIL: current->lowest_stack (0x%lx) outside of task stack bounds [0x%lx..0x%lx]\n", - lowest_sp, task_stack_low, task_stack_high - 1); - test_failed = true; - goto out; - } - - /* - * Depending on what has run prior to this test, the lowest recorded - * stack pointer could be above or below the current stack pointer. - * Start from the lowest of the two. - * - * Poison values are naturally-aligned unsigned longs. As the current - * stack pointer might not be sufficiently aligned, we must align - * downwards to find the lowest known stack pointer value. This is the - * high boundary for a portion of the stack which may have been used - * without being tracked, and has to be scanned for poison. - */ - untracked_high = min(current_sp, lowest_sp); - untracked_high = ALIGN_DOWN(untracked_high, sizeof(unsigned long)); - - /* - * Find the top of the poison in the same way as the erasing code. - */ - poison_high = stackleak_find_top_of_poison(task_stack_low, untracked_high); - - /* - * Check whether the poisoned portion of the stack (if any) consists - * entirely of poison. This verifies the entries that - * stackleak_find_top_of_poison() should have checked. - */ - poison_low = poison_high; - while (poison_low > task_stack_low) { - poison_low -= sizeof(unsigned long); - - if (*(unsigned long *)poison_low == STACKLEAK_POISON) - continue; - - instrumentation_begin(); - pr_err("FAIL: non-poison value %lu bytes below poison boundary: 0x%lx\n", - poison_high - poison_low, *(unsigned long *)poison_low); - test_failed = true; - goto out; - } - - instrumentation_begin(); - pr_info("stackleak stack usage:\n" - " high offset: %lu bytes\n" - " current: %lu bytes\n" - " lowest: %lu bytes\n" - " tracked: %lu bytes\n" - " untracked: %lu bytes\n" - " poisoned: %lu bytes\n" - " low offset: %lu bytes\n", - task_stack_base + THREAD_SIZE - task_stack_high, - task_stack_high - current_sp, - task_stack_high - lowest_sp, - task_stack_high - untracked_high, - untracked_high - poison_high, - poison_high - task_stack_low, - task_stack_low - task_stack_base); - -out: - if (test_failed) { - pr_err("FAIL: the thread stack is NOT properly erased!\n"); - } else { - pr_info("OK: the rest of the thread stack is properly erased\n"); - } - instrumentation_end(); -} - -static void lkdtm_STACKLEAK_ERASING(void) -{ - unsigned long flags; - - local_irq_save(flags); - check_stackleak_irqoff(); - local_irq_restore(flags); -} -#else /* defined(CONFIG_GCC_PLUGIN_STACKLEAK) */ -static void lkdtm_STACKLEAK_ERASING(void) -{ - if (IS_ENABLED(CONFIG_HAVE_ARCH_STACKLEAK)) { - pr_err("XFAIL: stackleak is not enabled (CONFIG_GCC_PLUGIN_STACKLEAK=n)\n"); - } else { - pr_err("XFAIL: stackleak is not supported on this arch (HAVE_ARCH_STACKLEAK=n)\n"); - } -} -#endif /* defined(CONFIG_GCC_PLUGIN_STACKLEAK) */ - -static struct crashtype crashtypes[] = { - CRASHTYPE(STACKLEAK_ERASING), -}; - -struct crashtype_category stackleak_crashtypes = { - .crashtypes = crashtypes, - .len = ARRAY_SIZE(crashtypes), -}; |
