linux/drivers/misc/lkdtm_bugs.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   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, and
   5 * lockups) along with other things that don't fit well into existing LKDTM
   6 * test source files.
   7 */
   8#include "lkdtm.h"
   9#include <linux/list.h>
  10#include <linux/sched.h>
  11#include <linux/sched/signal.h>
  12#include <linux/sched/task_stack.h>
  13#include <linux/uaccess.h>
  14
  15struct lkdtm_list {
  16        struct list_head node;
  17};
  18
  19/*
  20 * Make sure our attempts to over run the kernel stack doesn't trigger
  21 * a compiler warning when CONFIG_FRAME_WARN is set. Then make sure we
  22 * recurse past the end of THREAD_SIZE by default.
  23 */
  24#if defined(CONFIG_FRAME_WARN) && (CONFIG_FRAME_WARN > 0)
  25#define REC_STACK_SIZE (CONFIG_FRAME_WARN / 2)
  26#else
  27#define REC_STACK_SIZE (THREAD_SIZE / 8)
  28#endif
  29#define REC_NUM_DEFAULT ((THREAD_SIZE / REC_STACK_SIZE) * 2)
  30
  31static int recur_count = REC_NUM_DEFAULT;
  32
  33static DEFINE_SPINLOCK(lock_me_up);
  34
  35static int recursive_loop(int remaining)
  36{
  37        char buf[REC_STACK_SIZE];
  38
  39        /* Make sure compiler does not optimize this away. */
  40        memset(buf, (remaining & 0xff) | 0x1, REC_STACK_SIZE);
  41        if (!remaining)
  42                return 0;
  43        else
  44                return recursive_loop(remaining - 1);
  45}
  46
  47/* If the depth is negative, use the default, otherwise keep parameter. */
  48void __init lkdtm_bugs_init(int *recur_param)
  49{
  50        if (*recur_param < 0)
  51                *recur_param = recur_count;
  52        else
  53                recur_count = *recur_param;
  54}
  55
  56void lkdtm_PANIC(void)
  57{
  58        panic("dumptest");
  59}
  60
  61void lkdtm_BUG(void)
  62{
  63        BUG();
  64}
  65
  66void lkdtm_WARNING(void)
  67{
  68        WARN_ON(1);
  69}
  70
  71void lkdtm_EXCEPTION(void)
  72{
  73        *((volatile int *) 0) = 0;
  74}
  75
  76void lkdtm_LOOP(void)
  77{
  78        for (;;)
  79                ;
  80}
  81
  82void lkdtm_OVERFLOW(void)
  83{
  84        (void) recursive_loop(recur_count);
  85}
  86
  87static noinline void __lkdtm_CORRUPT_STACK(void *stack)
  88{
  89        memset(stack, '\xff', 64);
  90}
  91
  92/* This should trip the stack canary, not corrupt the return address. */
  93noinline void lkdtm_CORRUPT_STACK(void)
  94{
  95        /* Use default char array length that triggers stack protection. */
  96        char data[8] __aligned(sizeof(void *));
  97
  98        __lkdtm_CORRUPT_STACK(&data);
  99
 100        pr_info("Corrupted stack containing char array ...\n");
 101}
 102
 103/* Same as above but will only get a canary with -fstack-protector-strong */
 104noinline void lkdtm_CORRUPT_STACK_STRONG(void)
 105{
 106        union {
 107                unsigned short shorts[4];
 108                unsigned long *ptr;
 109        } data __aligned(sizeof(void *));
 110
 111        __lkdtm_CORRUPT_STACK(&data);
 112
 113        pr_info("Corrupted stack containing union ...\n");
 114}
 115
 116void lkdtm_UNALIGNED_LOAD_STORE_WRITE(void)
 117{
 118        static u8 data[5] __attribute__((aligned(4))) = {1, 2, 3, 4, 5};
 119        u32 *p;
 120        u32 val = 0x12345678;
 121
 122        p = (u32 *)(data + 1);
 123        if (*p == 0)
 124                val = 0x87654321;
 125        *p = val;
 126}
 127
 128void lkdtm_SOFTLOCKUP(void)
 129{
 130        preempt_disable();
 131        for (;;)
 132                cpu_relax();
 133}
 134
 135void lkdtm_HARDLOCKUP(void)
 136{
 137        local_irq_disable();
 138        for (;;)
 139                cpu_relax();
 140}
 141
 142void lkdtm_SPINLOCKUP(void)
 143{
 144        /* Must be called twice to trigger. */
 145        spin_lock(&lock_me_up);
 146        /* Let sparse know we intended to exit holding the lock. */
 147        __release(&lock_me_up);
 148}
 149
 150void lkdtm_HUNG_TASK(void)
 151{
 152        set_current_state(TASK_UNINTERRUPTIBLE);
 153        schedule();
 154}
 155
 156void lkdtm_CORRUPT_LIST_ADD(void)
 157{
 158        /*
 159         * Initially, an empty list via LIST_HEAD:
 160         *      test_head.next = &test_head
 161         *      test_head.prev = &test_head
 162         */
 163        LIST_HEAD(test_head);
 164        struct lkdtm_list good, bad;
 165        void *target[2] = { };
 166        void *redirection = &target;
 167
 168        pr_info("attempting good list addition\n");
 169
 170        /*
 171         * Adding to the list performs these actions:
 172         *      test_head.next->prev = &good.node
 173         *      good.node.next = test_head.next
 174         *      good.node.prev = test_head
 175         *      test_head.next = good.node
 176         */
 177        list_add(&good.node, &test_head);
 178
 179        pr_info("attempting corrupted list addition\n");
 180        /*
 181         * In simulating this "write what where" primitive, the "what" is
 182         * the address of &bad.node, and the "where" is the address held
 183         * by "redirection".
 184         */
 185        test_head.next = redirection;
 186        list_add(&bad.node, &test_head);
 187
 188        if (target[0] == NULL && target[1] == NULL)
 189                pr_err("Overwrite did not happen, but no BUG?!\n");
 190        else
 191                pr_err("list_add() corruption not detected!\n");
 192}
 193
 194void lkdtm_CORRUPT_LIST_DEL(void)
 195{
 196        LIST_HEAD(test_head);
 197        struct lkdtm_list item;
 198        void *target[2] = { };
 199        void *redirection = &target;
 200
 201        list_add(&item.node, &test_head);
 202
 203        pr_info("attempting good list removal\n");
 204        list_del(&item.node);
 205
 206        pr_info("attempting corrupted list removal\n");
 207        list_add(&item.node, &test_head);
 208
 209        /* As with the list_add() test above, this corrupts "next". */
 210        item.node.next = redirection;
 211        list_del(&item.node);
 212
 213        if (target[0] == NULL && target[1] == NULL)
 214                pr_err("Overwrite did not happen, but no BUG?!\n");
 215        else
 216                pr_err("list_del() corruption not detected!\n");
 217}
 218
 219/* Test if unbalanced set_fs(KERNEL_DS)/set_fs(USER_DS) check exists. */
 220void lkdtm_CORRUPT_USER_DS(void)
 221{
 222        pr_info("setting bad task size limit\n");
 223        set_fs(KERNEL_DS);
 224
 225        /* Make sure we do not keep running with a KERNEL_DS! */
 226        force_sig(SIGKILL, current);
 227}
 228
 229/* Test that VMAP_STACK is actually allocating with a leading guard page */
 230void lkdtm_STACK_GUARD_PAGE_LEADING(void)
 231{
 232        const unsigned char *stack = task_stack_page(current);
 233        const unsigned char *ptr = stack - 1;
 234        volatile unsigned char byte;
 235
 236        pr_info("attempting bad read from page below current stack\n");
 237
 238        byte = *ptr;
 239
 240        pr_err("FAIL: accessed page before stack!\n");
 241}
 242
 243/* Test that VMAP_STACK is actually allocating with a trailing guard page */
 244void lkdtm_STACK_GUARD_PAGE_TRAILING(void)
 245{
 246        const unsigned char *stack = task_stack_page(current);
 247        const unsigned char *ptr = stack + THREAD_SIZE;
 248        volatile unsigned char byte;
 249
 250        pr_info("attempting bad read from page above current stack\n");
 251
 252        byte = *ptr;
 253
 254        pr_err("FAIL: accessed page after stack!\n");
 255}
 256