732 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * This is for all the tests related to logic bugs (e.g. bad dereferences,4 * bad alignment, bad loops, bad locking, bad scheduling, deep stacks, and5 * lockups) along with other things that don't fit well into existing LKDTM6 * test source files.7 */8#include "lkdtm.h"9#include <linux/cpu.h>10#include <linux/list.h>11#include <linux/sched.h>12#include <linux/sched/signal.h>13#include <linux/sched/task_stack.h>14#include <linux/slab.h>15#include <linux/stop_machine.h>16#include <linux/uaccess.h>17 18#if IS_ENABLED(CONFIG_X86_32) && !IS_ENABLED(CONFIG_UML)19#include <asm/desc.h>20#endif21 22struct lkdtm_list {23 struct list_head node;24};25 26/*27 * Make sure our attempts to over run the kernel stack doesn't trigger28 * a compiler warning when CONFIG_FRAME_WARN is set. Then make sure we29 * recurse past the end of THREAD_SIZE by default.30 */31#if defined(CONFIG_FRAME_WARN) && (CONFIG_FRAME_WARN > 0)32#define REC_STACK_SIZE (_AC(CONFIG_FRAME_WARN, UL) / 2)33#else34#define REC_STACK_SIZE (THREAD_SIZE / 8UL)35#endif36#define REC_NUM_DEFAULT ((THREAD_SIZE / REC_STACK_SIZE) * 2)37 38static int recur_count = REC_NUM_DEFAULT;39 40static DEFINE_SPINLOCK(lock_me_up);41 42/*43 * Make sure compiler does not optimize this function or stack frame away:44 * - function marked noinline45 * - stack variables are marked volatile46 * - stack variables are written (memset()) and read (buf[..] passed as arg)47 * - function may have external effects (memzero_explicit())48 * - no tail recursion possible49 */50static int noinline recursive_loop(int remaining)51{52 volatile char buf[REC_STACK_SIZE];53 volatile int ret;54 55 memset((void *)buf, remaining & 0xFF, sizeof(buf));56 if (!remaining)57 ret = 0;58 else59 ret = recursive_loop((int)buf[remaining % sizeof(buf)] - 1);60 memzero_explicit((void *)buf, sizeof(buf));61 return ret;62}63 64/* If the depth is negative, use the default, otherwise keep parameter. */65void __init lkdtm_bugs_init(int *recur_param)66{67 if (*recur_param < 0)68 *recur_param = recur_count;69 else70 recur_count = *recur_param;71}72 73static void lkdtm_PANIC(void)74{75 panic("dumptest");76}77 78static int panic_stop_irqoff_fn(void *arg)79{80 atomic_t *v = arg;81 82 /*83 * As stop_machine() disables interrupts, all CPUs within this function84 * have interrupts disabled and cannot take a regular IPI.85 *86 * The last CPU which enters here will trigger a panic, and as all CPUs87 * cannot take a regular IPI, we'll only be able to stop secondaries if88 * smp_send_stop() or crash_smp_send_stop() uses an NMI.89 */90 if (atomic_inc_return(v) == num_online_cpus())91 panic("panic stop irqoff test");92 93 for (;;)94 cpu_relax();95}96 97static void lkdtm_PANIC_STOP_IRQOFF(void)98{99 atomic_t v = ATOMIC_INIT(0);100 stop_machine(panic_stop_irqoff_fn, &v, cpu_online_mask);101}102 103static void lkdtm_BUG(void)104{105 BUG();106}107 108static int warn_counter;109 110static void lkdtm_WARNING(void)111{112 WARN_ON(++warn_counter);113}114 115static void lkdtm_WARNING_MESSAGE(void)116{117 WARN(1, "Warning message trigger count: %d\n", ++warn_counter);118}119 120static void lkdtm_EXCEPTION(void)121{122 *((volatile int *) 0) = 0;123}124 125static void lkdtm_LOOP(void)126{127 for (;;)128 ;129}130 131static void lkdtm_EXHAUST_STACK(void)132{133 pr_info("Calling function with %lu frame size to depth %d ...\n",134 REC_STACK_SIZE, recur_count);135 recursive_loop(recur_count);136 pr_info("FAIL: survived without exhausting stack?!\n");137}138 139static noinline void __lkdtm_CORRUPT_STACK(void *stack)140{141 memset(stack, '\xff', 64);142}143 144/* This should trip the stack canary, not corrupt the return address. */145static noinline void lkdtm_CORRUPT_STACK(void)146{147 /* Use default char array length that triggers stack protection. */148 char data[8] __aligned(sizeof(void *));149 150 pr_info("Corrupting stack containing char array ...\n");151 __lkdtm_CORRUPT_STACK((void *)&data);152}153 154/* Same as above but will only get a canary with -fstack-protector-strong */155static noinline void lkdtm_CORRUPT_STACK_STRONG(void)156{157 union {158 unsigned short shorts[4];159 unsigned long *ptr;160 } data __aligned(sizeof(void *));161 162 pr_info("Corrupting stack containing union ...\n");163 __lkdtm_CORRUPT_STACK((void *)&data);164}165 166static pid_t stack_pid;167static unsigned long stack_addr;168 169static void lkdtm_REPORT_STACK(void)170{171 volatile uintptr_t magic;172 pid_t pid = task_pid_nr(current);173 174 if (pid != stack_pid) {175 pr_info("Starting stack offset tracking for pid %d\n", pid);176 stack_pid = pid;177 stack_addr = (uintptr_t)&magic;178 }179 180 pr_info("Stack offset: %d\n", (int)(stack_addr - (uintptr_t)&magic));181}182 183static pid_t stack_canary_pid;184static unsigned long stack_canary;185static unsigned long stack_canary_offset;186 187static noinline void __lkdtm_REPORT_STACK_CANARY(void *stack)188{189 int i = 0;190 pid_t pid = task_pid_nr(current);191 unsigned long *canary = (unsigned long *)stack;192 unsigned long current_offset = 0, init_offset = 0;193 194 /* Do our best to find the canary in a 16 word window ... */195 for (i = 1; i < 16; i++) {196 canary = (unsigned long *)stack + i;197#ifdef CONFIG_STACKPROTECTOR198 if (*canary == current->stack_canary)199 current_offset = i;200 if (*canary == init_task.stack_canary)201 init_offset = i;202#endif203 }204 205 if (current_offset == 0) {206 /*207 * If the canary doesn't match what's in the task_struct,208 * we're either using a global canary or the stack frame209 * layout changed.210 */211 if (init_offset != 0) {212 pr_err("FAIL: global stack canary found at offset %ld (canary for pid %d matches init_task's)!\n",213 init_offset, pid);214 } else {215 pr_warn("FAIL: did not correctly locate stack canary :(\n");216 pr_expected_config(CONFIG_STACKPROTECTOR);217 }218 219 return;220 } else if (init_offset != 0) {221 pr_warn("WARNING: found both current and init_task canaries nearby?!\n");222 }223 224 canary = (unsigned long *)stack + current_offset;225 if (stack_canary_pid == 0) {226 stack_canary = *canary;227 stack_canary_pid = pid;228 stack_canary_offset = current_offset;229 pr_info("Recorded stack canary for pid %d at offset %ld\n",230 stack_canary_pid, stack_canary_offset);231 } else if (pid == stack_canary_pid) {232 pr_warn("ERROR: saw pid %d again -- please use a new pid\n", pid);233 } else {234 if (current_offset != stack_canary_offset) {235 pr_warn("ERROR: canary offset changed from %ld to %ld!?\n",236 stack_canary_offset, current_offset);237 return;238 }239 240 if (*canary == stack_canary) {241 pr_warn("FAIL: canary identical for pid %d and pid %d at offset %ld!\n",242 stack_canary_pid, pid, current_offset);243 } else {244 pr_info("ok: stack canaries differ between pid %d and pid %d at offset %ld.\n",245 stack_canary_pid, pid, current_offset);246 /* Reset the test. */247 stack_canary_pid = 0;248 }249 }250}251 252static void lkdtm_REPORT_STACK_CANARY(void)253{254 /* Use default char array length that triggers stack protection. */255 char data[8] __aligned(sizeof(void *)) = { };256 257 __lkdtm_REPORT_STACK_CANARY((void *)&data);258}259 260static void lkdtm_UNALIGNED_LOAD_STORE_WRITE(void)261{262 static u8 data[5] __attribute__((aligned(4))) = {1, 2, 3, 4, 5};263 u32 *p;264 u32 val = 0x12345678;265 266 p = (u32 *)(data + 1);267 if (*p == 0)268 val = 0x87654321;269 *p = val;270 271 if (IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS))272 pr_err("XFAIL: arch has CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS\n");273}274 275static void lkdtm_SOFTLOCKUP(void)276{277 preempt_disable();278 for (;;)279 cpu_relax();280}281 282static void lkdtm_HARDLOCKUP(void)283{284 local_irq_disable();285 for (;;)286 cpu_relax();287}288 289static void __lkdtm_SMP_CALL_LOCKUP(void *unused)290{291 for (;;)292 cpu_relax();293}294 295static void lkdtm_SMP_CALL_LOCKUP(void)296{297 unsigned int cpu, target;298 299 cpus_read_lock();300 301 cpu = get_cpu();302 target = cpumask_any_but(cpu_online_mask, cpu);303 304 if (target >= nr_cpu_ids) {305 pr_err("FAIL: no other online CPUs\n");306 goto out_put_cpus;307 }308 309 smp_call_function_single(target, __lkdtm_SMP_CALL_LOCKUP, NULL, 1);310 311 pr_err("FAIL: did not hang\n");312 313out_put_cpus:314 put_cpu();315 cpus_read_unlock();316}317 318static void lkdtm_SPINLOCKUP(void)319{320 /* Must be called twice to trigger. */321 spin_lock(&lock_me_up);322 /* Let sparse know we intended to exit holding the lock. */323 __release(&lock_me_up);324}325 326static void __noreturn lkdtm_HUNG_TASK(void)327{328 set_current_state(TASK_UNINTERRUPTIBLE);329 schedule();330 BUG();331}332 333static volatile unsigned int huge = INT_MAX - 2;334static volatile unsigned int ignored;335 336static void lkdtm_OVERFLOW_SIGNED(void)337{338 int value;339 340 value = huge;341 pr_info("Normal signed addition ...\n");342 value += 1;343 ignored = value;344 345 pr_info("Overflowing signed addition ...\n");346 value += 4;347 ignored = value;348}349 350 351static void lkdtm_OVERFLOW_UNSIGNED(void)352{353 unsigned int value;354 355 value = huge;356 pr_info("Normal unsigned addition ...\n");357 value += 1;358 ignored = value;359 360 pr_info("Overflowing unsigned addition ...\n");361 value += 4;362 ignored = value;363}364 365/* Intentionally using unannotated flex array definition. */366struct array_bounds_flex_array {367 int one;368 int two;369 char data[];370};371 372struct array_bounds {373 int one;374 int two;375 char data[8];376 int three;377};378 379static void lkdtm_ARRAY_BOUNDS(void)380{381 struct array_bounds_flex_array *not_checked;382 struct array_bounds *checked;383 volatile int i;384 385 not_checked = kmalloc(sizeof(*not_checked) * 2, GFP_KERNEL);386 checked = kmalloc(sizeof(*checked) * 2, GFP_KERNEL);387 if (!not_checked || !checked) {388 kfree(not_checked);389 kfree(checked);390 return;391 }392 393 pr_info("Array access within bounds ...\n");394 /* For both, touch all bytes in the actual member size. */395 for (i = 0; i < sizeof(checked->data); i++)396 checked->data[i] = 'A';397 /*398 * For the uninstrumented flex array member, also touch 1 byte399 * beyond to verify it is correctly uninstrumented.400 */401 for (i = 0; i < 2; i++)402 not_checked->data[i] = 'A';403 404 pr_info("Array access beyond bounds ...\n");405 for (i = 0; i < sizeof(checked->data) + 1; i++)406 checked->data[i] = 'B';407 408 kfree(not_checked);409 kfree(checked);410 pr_err("FAIL: survived array bounds overflow!\n");411 if (IS_ENABLED(CONFIG_UBSAN_BOUNDS))412 pr_expected_config(CONFIG_UBSAN_TRAP);413 else414 pr_expected_config(CONFIG_UBSAN_BOUNDS);415}416 417struct lkdtm_annotated {418 unsigned long flags;419 int count;420 int array[] __counted_by(count);421};422 423static volatile int fam_count = 4;424 425static void lkdtm_FAM_BOUNDS(void)426{427 struct lkdtm_annotated *inst;428 429 inst = kzalloc(struct_size(inst, array, fam_count + 1), GFP_KERNEL);430 if (!inst) {431 pr_err("FAIL: could not allocate test struct!\n");432 return;433 }434 435 inst->count = fam_count;436 pr_info("Array access within bounds ...\n");437 inst->array[1] = fam_count;438 ignored = inst->array[1];439 440 pr_info("Array access beyond bounds ...\n");441 inst->array[fam_count] = fam_count;442 ignored = inst->array[fam_count];443 444 kfree(inst);445 446 pr_err("FAIL: survived access of invalid flexible array member index!\n");447 448 if (!__has_attribute(__counted_by__))449 pr_warn("This is expected since this %s was built with a compiler that does not support __counted_by\n",450 lkdtm_kernel_info);451 else if (IS_ENABLED(CONFIG_UBSAN_BOUNDS))452 pr_expected_config(CONFIG_UBSAN_TRAP);453 else454 pr_expected_config(CONFIG_UBSAN_BOUNDS);455}456 457static void lkdtm_CORRUPT_LIST_ADD(void)458{459 /*460 * Initially, an empty list via LIST_HEAD:461 * test_head.next = &test_head462 * test_head.prev = &test_head463 */464 LIST_HEAD(test_head);465 struct lkdtm_list good, bad;466 void *target[2] = { };467 void *redirection = ⌖468 469 pr_info("attempting good list addition\n");470 471 /*472 * Adding to the list performs these actions:473 * test_head.next->prev = &good.node474 * good.node.next = test_head.next475 * good.node.prev = test_head476 * test_head.next = good.node477 */478 list_add(&good.node, &test_head);479 480 pr_info("attempting corrupted list addition\n");481 /*482 * In simulating this "write what where" primitive, the "what" is483 * the address of &bad.node, and the "where" is the address held484 * by "redirection".485 */486 test_head.next = redirection;487 list_add(&bad.node, &test_head);488 489 if (target[0] == NULL && target[1] == NULL)490 pr_err("Overwrite did not happen, but no BUG?!\n");491 else {492 pr_err("list_add() corruption not detected!\n");493 pr_expected_config(CONFIG_LIST_HARDENED);494 }495}496 497static void lkdtm_CORRUPT_LIST_DEL(void)498{499 LIST_HEAD(test_head);500 struct lkdtm_list item;501 void *target[2] = { };502 void *redirection = ⌖503 504 list_add(&item.node, &test_head);505 506 pr_info("attempting good list removal\n");507 list_del(&item.node);508 509 pr_info("attempting corrupted list removal\n");510 list_add(&item.node, &test_head);511 512 /* As with the list_add() test above, this corrupts "next". */513 item.node.next = redirection;514 list_del(&item.node);515 516 if (target[0] == NULL && target[1] == NULL)517 pr_err("Overwrite did not happen, but no BUG?!\n");518 else {519 pr_err("list_del() corruption not detected!\n");520 pr_expected_config(CONFIG_LIST_HARDENED);521 }522}523 524/* Test that VMAP_STACK is actually allocating with a leading guard page */525static void lkdtm_STACK_GUARD_PAGE_LEADING(void)526{527 const unsigned char *stack = task_stack_page(current);528 const unsigned char *ptr = stack - 1;529 volatile unsigned char byte;530 531 pr_info("attempting bad read from page below current stack\n");532 533 byte = *ptr;534 535 pr_err("FAIL: accessed page before stack! (byte: %x)\n", byte);536}537 538/* Test that VMAP_STACK is actually allocating with a trailing guard page */539static void lkdtm_STACK_GUARD_PAGE_TRAILING(void)540{541 const unsigned char *stack = task_stack_page(current);542 const unsigned char *ptr = stack + THREAD_SIZE;543 volatile unsigned char byte;544 545 pr_info("attempting bad read from page above current stack\n");546 547 byte = *ptr;548 549 pr_err("FAIL: accessed page after stack! (byte: %x)\n", byte);550}551 552static void lkdtm_UNSET_SMEP(void)553{554#if IS_ENABLED(CONFIG_X86_64) && !IS_ENABLED(CONFIG_UML)555#define MOV_CR4_DEPTH 64556 void (*direct_write_cr4)(unsigned long val);557 unsigned char *insn;558 unsigned long cr4;559 int i;560 561 cr4 = native_read_cr4();562 563 if ((cr4 & X86_CR4_SMEP) != X86_CR4_SMEP) {564 pr_err("FAIL: SMEP not in use\n");565 return;566 }567 cr4 &= ~(X86_CR4_SMEP);568 569 pr_info("trying to clear SMEP normally\n");570 native_write_cr4(cr4);571 if (cr4 == native_read_cr4()) {572 pr_err("FAIL: pinning SMEP failed!\n");573 cr4 |= X86_CR4_SMEP;574 pr_info("restoring SMEP\n");575 native_write_cr4(cr4);576 return;577 }578 pr_info("ok: SMEP did not get cleared\n");579 580 /*581 * To test the post-write pinning verification we need to call582 * directly into the middle of native_write_cr4() where the583 * cr4 write happens, skipping any pinning. This searches for584 * the cr4 writing instruction.585 */586 insn = (unsigned char *)native_write_cr4;587 OPTIMIZER_HIDE_VAR(insn);588 for (i = 0; i < MOV_CR4_DEPTH; i++) {589 /* mov %rdi, %cr4 */590 if (insn[i] == 0x0f && insn[i+1] == 0x22 && insn[i+2] == 0xe7)591 break;592 /* mov %rdi,%rax; mov %rax, %cr4 */593 if (insn[i] == 0x48 && insn[i+1] == 0x89 &&594 insn[i+2] == 0xf8 && insn[i+3] == 0x0f &&595 insn[i+4] == 0x22 && insn[i+5] == 0xe0)596 break;597 }598 if (i >= MOV_CR4_DEPTH) {599 pr_info("ok: cannot locate cr4 writing call gadget\n");600 return;601 }602 direct_write_cr4 = (void *)(insn + i);603 604 pr_info("trying to clear SMEP with call gadget\n");605 direct_write_cr4(cr4);606 if (native_read_cr4() & X86_CR4_SMEP) {607 pr_info("ok: SMEP removal was reverted\n");608 } else {609 pr_err("FAIL: cleared SMEP not detected!\n");610 cr4 |= X86_CR4_SMEP;611 pr_info("restoring SMEP\n");612 native_write_cr4(cr4);613 }614#else615 pr_err("XFAIL: this test is x86_64-only\n");616#endif617}618 619static void lkdtm_DOUBLE_FAULT(void)620{621#if IS_ENABLED(CONFIG_X86_32) && !IS_ENABLED(CONFIG_UML)622 /*623 * Trigger #DF by setting the stack limit to zero. This clobbers624 * a GDT TLS slot, which is okay because the current task will die625 * anyway due to the double fault.626 */627 struct desc_struct d = {628 .type = 3, /* expand-up, writable, accessed data */629 .p = 1, /* present */630 .d = 1, /* 32-bit */631 .g = 0, /* limit in bytes */632 .s = 1, /* not system */633 };634 635 local_irq_disable();636 write_gdt_entry(get_cpu_gdt_rw(smp_processor_id()),637 GDT_ENTRY_TLS_MIN, &d, DESCTYPE_S);638 639 /*640 * Put our zero-limit segment in SS and then trigger a fault. The641 * 4-byte access to (%esp) will fault with #SS, and the attempt to642 * deliver the fault will recursively cause #SS and result in #DF.643 * This whole process happens while NMIs and MCEs are blocked by the644 * MOV SS window. This is nice because an NMI with an invalid SS645 * would also double-fault, resulting in the NMI or MCE being lost.646 */647 asm volatile ("movw %0, %%ss; addl $0, (%%esp)" ::648 "r" ((unsigned short)(GDT_ENTRY_TLS_MIN << 3)));649 650 pr_err("FAIL: tried to double fault but didn't die\n");651#else652 pr_err("XFAIL: this test is ia32-only\n");653#endif654}655 656#ifdef CONFIG_ARM64657static noinline void change_pac_parameters(void)658{659 if (IS_ENABLED(CONFIG_ARM64_PTR_AUTH_KERNEL)) {660 /* Reset the keys of current task */661 ptrauth_thread_init_kernel(current);662 ptrauth_thread_switch_kernel(current);663 }664}665#endif666 667static noinline void lkdtm_CORRUPT_PAC(void)668{669#ifdef CONFIG_ARM64670#define CORRUPT_PAC_ITERATE 10671 int i;672 673 if (!IS_ENABLED(CONFIG_ARM64_PTR_AUTH_KERNEL))674 pr_err("FAIL: kernel not built with CONFIG_ARM64_PTR_AUTH_KERNEL\n");675 676 if (!system_supports_address_auth()) {677 pr_err("FAIL: CPU lacks pointer authentication feature\n");678 return;679 }680 681 pr_info("changing PAC parameters to force function return failure...\n");682 /*683 * PAC is a hash value computed from input keys, return address and684 * stack pointer. As pac has fewer bits so there is a chance of685 * collision, so iterate few times to reduce the collision probability.686 */687 for (i = 0; i < CORRUPT_PAC_ITERATE; i++)688 change_pac_parameters();689 690 pr_err("FAIL: survived PAC changes! Kernel may be unstable from here\n");691#else692 pr_err("XFAIL: this test is arm64-only\n");693#endif694}695 696static struct crashtype crashtypes[] = {697 CRASHTYPE(PANIC),698 CRASHTYPE(PANIC_STOP_IRQOFF),699 CRASHTYPE(BUG),700 CRASHTYPE(WARNING),701 CRASHTYPE(WARNING_MESSAGE),702 CRASHTYPE(EXCEPTION),703 CRASHTYPE(LOOP),704 CRASHTYPE(EXHAUST_STACK),705 CRASHTYPE(CORRUPT_STACK),706 CRASHTYPE(CORRUPT_STACK_STRONG),707 CRASHTYPE(REPORT_STACK),708 CRASHTYPE(REPORT_STACK_CANARY),709 CRASHTYPE(UNALIGNED_LOAD_STORE_WRITE),710 CRASHTYPE(SOFTLOCKUP),711 CRASHTYPE(HARDLOCKUP),712 CRASHTYPE(SMP_CALL_LOCKUP),713 CRASHTYPE(SPINLOCKUP),714 CRASHTYPE(HUNG_TASK),715 CRASHTYPE(OVERFLOW_SIGNED),716 CRASHTYPE(OVERFLOW_UNSIGNED),717 CRASHTYPE(ARRAY_BOUNDS),718 CRASHTYPE(FAM_BOUNDS),719 CRASHTYPE(CORRUPT_LIST_ADD),720 CRASHTYPE(CORRUPT_LIST_DEL),721 CRASHTYPE(STACK_GUARD_PAGE_LEADING),722 CRASHTYPE(STACK_GUARD_PAGE_TRAILING),723 CRASHTYPE(UNSET_SMEP),724 CRASHTYPE(DOUBLE_FAULT),725 CRASHTYPE(CORRUPT_PAC),726};727 728struct crashtype_category bugs_crashtypes = {729 .crashtypes = crashtypes,730 .len = ARRAY_SIZE(crashtypes),731};732