linux/lib/test_ubsan.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include <linux/init.h>
   3#include <linux/kernel.h>
   4#include <linux/module.h>
   5
   6typedef void(*test_ubsan_fp)(void);
   7
   8#define UBSAN_TEST(config, ...) do {                                    \
   9                pr_info("%s " __VA_ARGS__ "%s(%s=%s)\n", __func__,      \
  10                        sizeof(" " __VA_ARGS__) > 2 ? " " : "",         \
  11                        #config, IS_ENABLED(config) ? "y" : "n");       \
  12        } while (0)
  13
  14static void test_ubsan_divrem_overflow(void)
  15{
  16        volatile int val = 16;
  17        volatile int val2 = 0;
  18
  19        UBSAN_TEST(CONFIG_UBSAN_DIV_ZERO);
  20        val /= val2;
  21}
  22
  23static void test_ubsan_shift_out_of_bounds(void)
  24{
  25        volatile int neg = -1, wrap = 4;
  26        int val1 = 10;
  27        int val2 = INT_MAX;
  28
  29        UBSAN_TEST(CONFIG_UBSAN_SHIFT, "negative exponent");
  30        val1 <<= neg;
  31
  32        UBSAN_TEST(CONFIG_UBSAN_SHIFT, "left overflow");
  33        val2 <<= wrap;
  34}
  35
  36static void test_ubsan_out_of_bounds(void)
  37{
  38        volatile int i = 4, j = 5, k = -1;
  39        volatile char above[4] = { }; /* Protect surrounding memory. */
  40        volatile int arr[4];
  41        volatile char below[4] = { }; /* Protect surrounding memory. */
  42
  43        above[0] = below[0];
  44
  45        UBSAN_TEST(CONFIG_UBSAN_BOUNDS, "above");
  46        arr[j] = i;
  47
  48        UBSAN_TEST(CONFIG_UBSAN_BOUNDS, "below");
  49        arr[k] = i;
  50}
  51
  52enum ubsan_test_enum {
  53        UBSAN_TEST_ZERO = 0,
  54        UBSAN_TEST_ONE,
  55        UBSAN_TEST_MAX,
  56};
  57
  58static void test_ubsan_load_invalid_value(void)
  59{
  60        volatile char *dst, *src;
  61        bool val, val2, *ptr;
  62        enum ubsan_test_enum eval, eval2, *eptr;
  63        unsigned char c = 0xff;
  64
  65        UBSAN_TEST(CONFIG_UBSAN_BOOL, "bool");
  66        dst = (char *)&val;
  67        src = &c;
  68        *dst = *src;
  69
  70        ptr = &val2;
  71        val2 = val;
  72
  73        UBSAN_TEST(CONFIG_UBSAN_ENUM, "enum");
  74        dst = (char *)&eval;
  75        src = &c;
  76        *dst = *src;
  77
  78        eptr = &eval2;
  79        eval2 = eval;
  80}
  81
  82static void test_ubsan_null_ptr_deref(void)
  83{
  84        volatile int *ptr = NULL;
  85        int val;
  86
  87        UBSAN_TEST(CONFIG_UBSAN_OBJECT_SIZE);
  88        val = *ptr;
  89}
  90
  91static void test_ubsan_misaligned_access(void)
  92{
  93        volatile char arr[5] __aligned(4) = {1, 2, 3, 4, 5};
  94        volatile int *ptr, val = 6;
  95
  96        UBSAN_TEST(CONFIG_UBSAN_ALIGNMENT);
  97        ptr = (int *)(arr + 1);
  98        *ptr = val;
  99}
 100
 101static void test_ubsan_object_size_mismatch(void)
 102{
 103        /* "((aligned(8)))" helps this not into be misaligned for ptr-access. */
 104        volatile int val __aligned(8) = 4;
 105        volatile long long *ptr, val2;
 106
 107        UBSAN_TEST(CONFIG_UBSAN_OBJECT_SIZE);
 108        ptr = (long long *)&val;
 109        val2 = *ptr;
 110}
 111
 112static const test_ubsan_fp test_ubsan_array[] = {
 113        test_ubsan_shift_out_of_bounds,
 114        test_ubsan_out_of_bounds,
 115        test_ubsan_load_invalid_value,
 116        test_ubsan_misaligned_access,
 117        test_ubsan_object_size_mismatch,
 118};
 119
 120/* Excluded because they Oops the module. */
 121static const test_ubsan_fp skip_ubsan_array[] = {
 122        test_ubsan_divrem_overflow,
 123        test_ubsan_null_ptr_deref,
 124};
 125
 126static int __init test_ubsan_init(void)
 127{
 128        unsigned int i;
 129
 130        for (i = 0; i < ARRAY_SIZE(test_ubsan_array); i++)
 131                test_ubsan_array[i]();
 132
 133        return 0;
 134}
 135module_init(test_ubsan_init);
 136
 137static void __exit test_ubsan_exit(void)
 138{
 139        /* do nothing */
 140}
 141module_exit(test_ubsan_exit);
 142
 143MODULE_AUTHOR("Jinbum Park <jinb.park7@gmail.com>");
 144MODULE_LICENSE("GPL v2");
 145