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 { 8 #define UBSAN_TEST(config, ...) do { \ 9 pr_info("%s " __VA_ARGS__ "%s( 9 pr_info("%s " __VA_ARGS__ "%s(%s=%s)\n", __func__, \ 10 sizeof(" " __VA_ARGS__ 10 sizeof(" " __VA_ARGS__) > 2 ? " " : "", \ 11 #config, IS_ENABLED(co 11 #config, IS_ENABLED(config) ? "y" : "n"); \ 12 } while (0) 12 } while (0) 13 13 14 static void test_ubsan_add_overflow(void) << 15 { << 16 volatile int val = INT_MAX; << 17 << 18 UBSAN_TEST(CONFIG_UBSAN_SIGNED_WRAP); << 19 val += 2; << 20 } << 21 << 22 static void test_ubsan_sub_overflow(void) << 23 { << 24 volatile int val = INT_MIN; << 25 volatile int val2 = 2; << 26 << 27 UBSAN_TEST(CONFIG_UBSAN_SIGNED_WRAP); << 28 val -= val2; << 29 } << 30 << 31 static void test_ubsan_mul_overflow(void) << 32 { << 33 volatile int val = INT_MAX / 2; << 34 << 35 UBSAN_TEST(CONFIG_UBSAN_SIGNED_WRAP); << 36 val *= 3; << 37 } << 38 << 39 static void test_ubsan_negate_overflow(void) << 40 { << 41 volatile int val = INT_MIN; << 42 << 43 UBSAN_TEST(CONFIG_UBSAN_SIGNED_WRAP); << 44 val = -val; << 45 } << 46 << 47 static void test_ubsan_divrem_overflow(void) 14 static void test_ubsan_divrem_overflow(void) 48 { 15 { 49 volatile int val = 16; 16 volatile int val = 16; 50 volatile int val2 = 0; 17 volatile int val2 = 0; 51 18 52 UBSAN_TEST(CONFIG_UBSAN_DIV_ZERO); 19 UBSAN_TEST(CONFIG_UBSAN_DIV_ZERO); 53 val /= val2; 20 val /= val2; 54 } 21 } 55 22 56 static void test_ubsan_shift_out_of_bounds(voi 23 static void test_ubsan_shift_out_of_bounds(void) 57 { 24 { 58 volatile int neg = -1, wrap = 4; 25 volatile int neg = -1, wrap = 4; 59 volatile int val1 = 10; !! 26 int val1 = 10; 60 volatile int val2 = INT_MAX; !! 27 int val2 = INT_MAX; 61 28 62 UBSAN_TEST(CONFIG_UBSAN_SHIFT, "negati 29 UBSAN_TEST(CONFIG_UBSAN_SHIFT, "negative exponent"); 63 val1 <<= neg; 30 val1 <<= neg; 64 31 65 UBSAN_TEST(CONFIG_UBSAN_SHIFT, "left o 32 UBSAN_TEST(CONFIG_UBSAN_SHIFT, "left overflow"); 66 val2 <<= wrap; 33 val2 <<= wrap; 67 } 34 } 68 35 69 static void test_ubsan_out_of_bounds(void) 36 static void test_ubsan_out_of_bounds(void) 70 { 37 { 71 volatile int i = 4, j = 5, k = -1; 38 volatile int i = 4, j = 5, k = -1; 72 volatile char above[4] = { }; /* Prote 39 volatile char above[4] = { }; /* Protect surrounding memory. */ 73 volatile int arr[4]; 40 volatile int arr[4]; 74 volatile char below[4] = { }; /* Prote 41 volatile char below[4] = { }; /* Protect surrounding memory. */ 75 42 76 above[0] = below[0]; 43 above[0] = below[0]; 77 44 78 UBSAN_TEST(CONFIG_UBSAN_BOUNDS, "above 45 UBSAN_TEST(CONFIG_UBSAN_BOUNDS, "above"); 79 arr[j] = i; 46 arr[j] = i; 80 47 81 UBSAN_TEST(CONFIG_UBSAN_BOUNDS, "below 48 UBSAN_TEST(CONFIG_UBSAN_BOUNDS, "below"); 82 arr[k] = i; 49 arr[k] = i; 83 } 50 } 84 51 85 enum ubsan_test_enum { 52 enum ubsan_test_enum { 86 UBSAN_TEST_ZERO = 0, 53 UBSAN_TEST_ZERO = 0, 87 UBSAN_TEST_ONE, 54 UBSAN_TEST_ONE, 88 UBSAN_TEST_MAX, 55 UBSAN_TEST_MAX, 89 }; 56 }; 90 57 91 static void test_ubsan_load_invalid_value(void 58 static void test_ubsan_load_invalid_value(void) 92 { 59 { 93 volatile char *dst, *src; 60 volatile char *dst, *src; 94 bool val, val2, *ptr; 61 bool val, val2, *ptr; 95 enum ubsan_test_enum eval, eval2, *ept 62 enum ubsan_test_enum eval, eval2, *eptr; 96 unsigned char c = 0xff; 63 unsigned char c = 0xff; 97 64 98 UBSAN_TEST(CONFIG_UBSAN_BOOL, "bool"); 65 UBSAN_TEST(CONFIG_UBSAN_BOOL, "bool"); 99 dst = (char *)&val; 66 dst = (char *)&val; 100 src = &c; 67 src = &c; 101 *dst = *src; 68 *dst = *src; 102 69 103 ptr = &val2; 70 ptr = &val2; 104 val2 = val; 71 val2 = val; 105 72 106 UBSAN_TEST(CONFIG_UBSAN_ENUM, "enum"); 73 UBSAN_TEST(CONFIG_UBSAN_ENUM, "enum"); 107 dst = (char *)&eval; 74 dst = (char *)&eval; 108 src = &c; 75 src = &c; 109 *dst = *src; 76 *dst = *src; 110 77 111 eptr = &eval2; 78 eptr = &eval2; 112 eval2 = eval; 79 eval2 = eval; 113 } 80 } 114 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 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); 96 UBSAN_TEST(CONFIG_UBSAN_ALIGNMENT); 121 ptr = (int *)(arr + 1); 97 ptr = (int *)(arr + 1); 122 *ptr = val; 98 *ptr = val; 123 } 99 } 124 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 125 static const test_ubsan_fp test_ubsan_array[] 112 static const test_ubsan_fp test_ubsan_array[] = { 126 test_ubsan_add_overflow, << 127 test_ubsan_sub_overflow, << 128 test_ubsan_mul_overflow, << 129 test_ubsan_negate_overflow, << 130 test_ubsan_shift_out_of_bounds, 113 test_ubsan_shift_out_of_bounds, 131 test_ubsan_out_of_bounds, 114 test_ubsan_out_of_bounds, 132 test_ubsan_load_invalid_value, 115 test_ubsan_load_invalid_value, 133 test_ubsan_misaligned_access, 116 test_ubsan_misaligned_access, >> 117 test_ubsan_object_size_mismatch, 134 }; 118 }; 135 119 136 /* Excluded because they Oops the module. */ 120 /* Excluded because they Oops the module. */ 137 static __used const test_ubsan_fp skip_ubsan_a !! 121 static const test_ubsan_fp skip_ubsan_array[] = { 138 test_ubsan_divrem_overflow, 122 test_ubsan_divrem_overflow, >> 123 test_ubsan_null_ptr_deref, 139 }; 124 }; 140 125 141 static int __init test_ubsan_init(void) 126 static int __init test_ubsan_init(void) 142 { 127 { 143 unsigned int i; 128 unsigned int i; 144 129 145 for (i = 0; i < ARRAY_SIZE(test_ubsan_ 130 for (i = 0; i < ARRAY_SIZE(test_ubsan_array); i++) 146 test_ubsan_array[i](); 131 test_ubsan_array[i](); 147 132 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.