1 // SPDX-License-Identifier: GPL-2.0 2 #include <linux/init.h> 3 #include <linux/kernel.h> 4 #include <linux/module.h> 5 6 typedef 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 14 static 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 23 static 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 36 static 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 52 enum ubsan_test_enum { 53 UBSAN_TEST_ZERO = 0, 54 UBSAN_TEST_ONE, 55 UBSAN_TEST_MAX, 56 }; 57 58 static 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 82 static 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 91 static 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 101 static 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 112 static 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. */ 121 static const test_ubsan_fp skip_ubsan_array[] = { 122 test_ubsan_divrem_overflow, 123 test_ubsan_null_ptr_deref, 124 }; 125 126 static 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 } 135 module_init(test_ubsan_init); 136 137 static void __exit test_ubsan_exit(void) 138 { 139 /* do nothing */ 140 } 141 module_exit(test_ubsan_exit); 142 143 MODULE_AUTHOR("Jinbum Park <jinb.park7@gmail.com>"); 144 MODULE_LICENSE("GPL v2"); 145