1 // SPDX-License-Identifier: GPL-2.0 1 // SPDX-License-Identifier: GPL-2.0 2 #include <linux/init.h> 2 #include <linux/init.h> 3 #include <linux/kernel.h> 3 #include <linux/kernel.h> 4 #include <linux/module.h> 4 #include <linux/module.h> 5 5 6 typedef void(*test_ubsan_fp)(void); 6 typedef void(*test_ubsan_fp)(void); 7 7 8 #define UBSAN_TEST(config, ...) do { << 9 pr_info("%s " __VA_ARGS__ "%s( << 10 sizeof(" " __VA_ARGS__ << 11 #config, IS_ENABLED(co << 12 } while (0) << 13 << 14 static void test_ubsan_add_overflow(void) 8 static void test_ubsan_add_overflow(void) 15 { 9 { 16 volatile int val = INT_MAX; 10 volatile int val = INT_MAX; 17 11 18 UBSAN_TEST(CONFIG_UBSAN_SIGNED_WRAP); << 19 val += 2; 12 val += 2; 20 } 13 } 21 14 22 static void test_ubsan_sub_overflow(void) 15 static void test_ubsan_sub_overflow(void) 23 { 16 { 24 volatile int val = INT_MIN; 17 volatile int val = INT_MIN; 25 volatile int val2 = 2; 18 volatile int val2 = 2; 26 19 27 UBSAN_TEST(CONFIG_UBSAN_SIGNED_WRAP); << 28 val -= val2; 20 val -= val2; 29 } 21 } 30 22 31 static void test_ubsan_mul_overflow(void) 23 static void test_ubsan_mul_overflow(void) 32 { 24 { 33 volatile int val = INT_MAX / 2; 25 volatile int val = INT_MAX / 2; 34 26 35 UBSAN_TEST(CONFIG_UBSAN_SIGNED_WRAP); << 36 val *= 3; 27 val *= 3; 37 } 28 } 38 29 39 static void test_ubsan_negate_overflow(void) 30 static void test_ubsan_negate_overflow(void) 40 { 31 { 41 volatile int val = INT_MIN; 32 volatile int val = INT_MIN; 42 33 43 UBSAN_TEST(CONFIG_UBSAN_SIGNED_WRAP); << 44 val = -val; 34 val = -val; 45 } 35 } 46 36 47 static void test_ubsan_divrem_overflow(void) 37 static void test_ubsan_divrem_overflow(void) 48 { 38 { 49 volatile int val = 16; 39 volatile int val = 16; 50 volatile int val2 = 0; 40 volatile int val2 = 0; 51 41 52 UBSAN_TEST(CONFIG_UBSAN_DIV_ZERO); << 53 val /= val2; 42 val /= val2; 54 } 43 } 55 44 56 static void test_ubsan_shift_out_of_bounds(voi !! 45 static void test_ubsan_vla_bound_not_positive(void) 57 { 46 { 58 volatile int neg = -1, wrap = 4; !! 47 volatile int size = -1; 59 volatile int val1 = 10; !! 48 char buf[size]; 60 volatile int val2 = INT_MAX; !! 49 >> 50 (void)buf; >> 51 } 61 52 62 UBSAN_TEST(CONFIG_UBSAN_SHIFT, "negati !! 53 static void test_ubsan_shift_out_of_bounds(void) 63 val1 <<= neg; !! 54 { >> 55 volatile int val = -1; >> 56 int val2 = 10; 64 57 65 UBSAN_TEST(CONFIG_UBSAN_SHIFT, "left o !! 58 val2 <<= val; 66 val2 <<= wrap; << 67 } 59 } 68 60 69 static void test_ubsan_out_of_bounds(void) 61 static void test_ubsan_out_of_bounds(void) 70 { 62 { 71 volatile int i = 4, j = 5, k = -1; !! 63 volatile int i = 4, j = 5; 72 volatile char above[4] = { }; /* Prote !! 64 volatile int arr[i]; 73 volatile int arr[4]; << 74 volatile char below[4] = { }; /* Prote << 75 65 76 above[0] = below[0]; << 77 << 78 UBSAN_TEST(CONFIG_UBSAN_BOUNDS, "above << 79 arr[j] = i; 66 arr[j] = i; 80 << 81 UBSAN_TEST(CONFIG_UBSAN_BOUNDS, "below << 82 arr[k] = i; << 83 } 67 } 84 68 85 enum ubsan_test_enum { << 86 UBSAN_TEST_ZERO = 0, << 87 UBSAN_TEST_ONE, << 88 UBSAN_TEST_MAX, << 89 }; << 90 << 91 static void test_ubsan_load_invalid_value(void 69 static void test_ubsan_load_invalid_value(void) 92 { 70 { 93 volatile char *dst, *src; 71 volatile char *dst, *src; 94 bool val, val2, *ptr; 72 bool val, val2, *ptr; 95 enum ubsan_test_enum eval, eval2, *ept !! 73 char c = 4; 96 unsigned char c = 0xff; << 97 74 98 UBSAN_TEST(CONFIG_UBSAN_BOOL, "bool"); << 99 dst = (char *)&val; 75 dst = (char *)&val; 100 src = &c; 76 src = &c; 101 *dst = *src; 77 *dst = *src; 102 78 103 ptr = &val2; 79 ptr = &val2; 104 val2 = val; 80 val2 = val; >> 81 } 105 82 106 UBSAN_TEST(CONFIG_UBSAN_ENUM, "enum"); !! 83 static void test_ubsan_null_ptr_deref(void) 107 dst = (char *)&eval; !! 84 { 108 src = &c; !! 85 volatile int *ptr = NULL; 109 *dst = *src; !! 86 int val; 110 87 111 eptr = &eval2; !! 88 val = *ptr; 112 eval2 = eval; << 113 } 89 } 114 90 115 static void test_ubsan_misaligned_access(void) 91 static void test_ubsan_misaligned_access(void) 116 { 92 { 117 volatile char arr[5] __aligned(4) = {1 93 volatile char arr[5] __aligned(4) = {1, 2, 3, 4, 5}; 118 volatile int *ptr, val = 6; 94 volatile int *ptr, val = 6; 119 95 120 UBSAN_TEST(CONFIG_UBSAN_ALIGNMENT); << 121 ptr = (int *)(arr + 1); 96 ptr = (int *)(arr + 1); 122 *ptr = val; 97 *ptr = val; 123 } 98 } 124 99 >> 100 static void test_ubsan_object_size_mismatch(void) >> 101 { >> 102 /* "((aligned(8)))" helps this not into be misaligned for ptr-access. */ >> 103 volatile int val __aligned(8) = 4; >> 104 volatile long long *ptr, val2; >> 105 >> 106 ptr = (long long *)&val; >> 107 val2 = *ptr; >> 108 } >> 109 125 static const test_ubsan_fp test_ubsan_array[] 110 static const test_ubsan_fp test_ubsan_array[] = { 126 test_ubsan_add_overflow, 111 test_ubsan_add_overflow, 127 test_ubsan_sub_overflow, 112 test_ubsan_sub_overflow, 128 test_ubsan_mul_overflow, 113 test_ubsan_mul_overflow, 129 test_ubsan_negate_overflow, 114 test_ubsan_negate_overflow, >> 115 test_ubsan_divrem_overflow, >> 116 test_ubsan_vla_bound_not_positive, 130 test_ubsan_shift_out_of_bounds, 117 test_ubsan_shift_out_of_bounds, 131 test_ubsan_out_of_bounds, 118 test_ubsan_out_of_bounds, 132 test_ubsan_load_invalid_value, 119 test_ubsan_load_invalid_value, >> 120 //test_ubsan_null_ptr_deref, /* exclude it because there is a crash */ 133 test_ubsan_misaligned_access, 121 test_ubsan_misaligned_access, 134 }; !! 122 test_ubsan_object_size_mismatch, 135 << 136 /* Excluded because they Oops the module. */ << 137 static __used const test_ubsan_fp skip_ubsan_a << 138 test_ubsan_divrem_overflow, << 139 }; 123 }; 140 124 141 static int __init test_ubsan_init(void) 125 static int __init test_ubsan_init(void) 142 { 126 { 143 unsigned int i; 127 unsigned int i; 144 128 145 for (i = 0; i < ARRAY_SIZE(test_ubsan_ 129 for (i = 0; i < ARRAY_SIZE(test_ubsan_array); i++) 146 test_ubsan_array[i](); 130 test_ubsan_array[i](); 147 131 >> 132 (void)test_ubsan_null_ptr_deref; /* to avoid unsed-function warning */ 148 return 0; 133 return 0; 149 } 134 } 150 module_init(test_ubsan_init); 135 module_init(test_ubsan_init); 151 136 152 static void __exit test_ubsan_exit(void) 137 static void __exit test_ubsan_exit(void) 153 { 138 { 154 /* do nothing */ 139 /* do nothing */ 155 } 140 } 156 module_exit(test_ubsan_exit); 141 module_exit(test_ubsan_exit); 157 142 158 MODULE_AUTHOR("Jinbum Park <jinb.park7@gmail.c 143 MODULE_AUTHOR("Jinbum Park <jinb.park7@gmail.com>"); 159 MODULE_DESCRIPTION("UBSAN unit test"); << 160 MODULE_LICENSE("GPL v2"); 144 MODULE_LICENSE("GPL v2"); 161 145
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.