Commit | Line | Data |
---|---|---|
854686f4 JP |
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 | ||
4a26f49b KC |
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 | ||
854686f4 JP |
14 | static void test_ubsan_add_overflow(void) |
15 | { | |
16 | volatile int val = INT_MAX; | |
4a26f49b | 17 | volatile unsigned int uval = UINT_MAX; |
854686f4 | 18 | |
4a26f49b | 19 | UBSAN_TEST(CONFIG_UBSAN_SIGNED_OVERFLOW); |
854686f4 | 20 | val += 2; |
4a26f49b KC |
21 | |
22 | UBSAN_TEST(CONFIG_UBSAN_UNSIGNED_OVERFLOW); | |
23 | uval += 2; | |
854686f4 JP |
24 | } |
25 | ||
26 | static void test_ubsan_sub_overflow(void) | |
27 | { | |
28 | volatile int val = INT_MIN; | |
4a26f49b | 29 | volatile unsigned int uval = 0; |
854686f4 JP |
30 | volatile int val2 = 2; |
31 | ||
4a26f49b | 32 | UBSAN_TEST(CONFIG_UBSAN_SIGNED_OVERFLOW); |
854686f4 | 33 | val -= val2; |
4a26f49b KC |
34 | |
35 | UBSAN_TEST(CONFIG_UBSAN_UNSIGNED_OVERFLOW); | |
36 | uval -= val2; | |
854686f4 JP |
37 | } |
38 | ||
39 | static void test_ubsan_mul_overflow(void) | |
40 | { | |
41 | volatile int val = INT_MAX / 2; | |
4a26f49b | 42 | volatile unsigned int uval = UINT_MAX / 2; |
854686f4 | 43 | |
4a26f49b | 44 | UBSAN_TEST(CONFIG_UBSAN_SIGNED_OVERFLOW); |
854686f4 | 45 | val *= 3; |
4a26f49b KC |
46 | |
47 | UBSAN_TEST(CONFIG_UBSAN_UNSIGNED_OVERFLOW); | |
48 | uval *= 3; | |
854686f4 JP |
49 | } |
50 | ||
51 | static void test_ubsan_negate_overflow(void) | |
52 | { | |
53 | volatile int val = INT_MIN; | |
54 | ||
4a26f49b | 55 | UBSAN_TEST(CONFIG_UBSAN_SIGNED_OVERFLOW); |
854686f4 JP |
56 | val = -val; |
57 | } | |
58 | ||
59 | static void test_ubsan_divrem_overflow(void) | |
60 | { | |
61 | volatile int val = 16; | |
62 | volatile int val2 = 0; | |
63 | ||
4a26f49b | 64 | UBSAN_TEST(CONFIG_UBSAN_DIV_ZERO); |
854686f4 JP |
65 | val /= val2; |
66 | } | |
67 | ||
854686f4 JP |
68 | static void test_ubsan_shift_out_of_bounds(void) |
69 | { | |
4a26f49b KC |
70 | volatile int neg = -1, wrap = 4; |
71 | int val1 = 10; | |
72 | int val2 = INT_MAX; | |
73 | ||
74 | UBSAN_TEST(CONFIG_UBSAN_SHIFT, "negative exponent"); | |
75 | val1 <<= neg; | |
854686f4 | 76 | |
4a26f49b KC |
77 | UBSAN_TEST(CONFIG_UBSAN_SHIFT, "left overflow"); |
78 | val2 <<= wrap; | |
854686f4 JP |
79 | } |
80 | ||
81 | static void test_ubsan_out_of_bounds(void) | |
82 | { | |
4a26f49b KC |
83 | volatile int i = 4, j = 5, k = -1; |
84 | volatile char above[4] = { }; /* Protect surrounding memory. */ | |
9d7ca61b | 85 | volatile int arr[4]; |
4a26f49b | 86 | volatile char below[4] = { }; /* Protect surrounding memory. */ |
854686f4 | 87 | |
4a26f49b KC |
88 | above[0] = below[0]; |
89 | ||
90 | UBSAN_TEST(CONFIG_UBSAN_BOUNDS, "above"); | |
854686f4 | 91 | arr[j] = i; |
4a26f49b KC |
92 | |
93 | UBSAN_TEST(CONFIG_UBSAN_BOUNDS, "below"); | |
94 | arr[k] = i; | |
854686f4 JP |
95 | } |
96 | ||
4a26f49b KC |
97 | enum ubsan_test_enum { |
98 | UBSAN_TEST_ZERO = 0, | |
99 | UBSAN_TEST_ONE, | |
100 | UBSAN_TEST_MAX, | |
101 | }; | |
102 | ||
854686f4 JP |
103 | static void test_ubsan_load_invalid_value(void) |
104 | { | |
105 | volatile char *dst, *src; | |
106 | bool val, val2, *ptr; | |
4a26f49b KC |
107 | enum ubsan_test_enum eval, eval2, *eptr; |
108 | unsigned char c = 0xff; | |
854686f4 | 109 | |
4a26f49b | 110 | UBSAN_TEST(CONFIG_UBSAN_BOOL, "bool"); |
854686f4 JP |
111 | dst = (char *)&val; |
112 | src = &c; | |
113 | *dst = *src; | |
114 | ||
115 | ptr = &val2; | |
116 | val2 = val; | |
4a26f49b KC |
117 | |
118 | UBSAN_TEST(CONFIG_UBSAN_ENUM, "enum"); | |
119 | dst = (char *)&eval; | |
120 | src = &c; | |
121 | *dst = *src; | |
122 | ||
123 | eptr = &eval2; | |
124 | eval2 = eval; | |
854686f4 JP |
125 | } |
126 | ||
127 | static void test_ubsan_null_ptr_deref(void) | |
128 | { | |
129 | volatile int *ptr = NULL; | |
130 | int val; | |
131 | ||
4a26f49b | 132 | UBSAN_TEST(CONFIG_UBSAN_OBJECT_SIZE); |
854686f4 JP |
133 | val = *ptr; |
134 | } | |
135 | ||
31750600 | 136 | static void test_ubsan_misaligned_access(void) |
854686f4 JP |
137 | { |
138 | volatile char arr[5] __aligned(4) = {1, 2, 3, 4, 5}; | |
139 | volatile int *ptr, val = 6; | |
140 | ||
4a26f49b | 141 | UBSAN_TEST(CONFIG_UBSAN_ALIGNMENT); |
854686f4 JP |
142 | ptr = (int *)(arr + 1); |
143 | *ptr = val; | |
144 | } | |
145 | ||
146 | static void test_ubsan_object_size_mismatch(void) | |
147 | { | |
148 | /* "((aligned(8)))" helps this not into be misaligned for ptr-access. */ | |
149 | volatile int val __aligned(8) = 4; | |
150 | volatile long long *ptr, val2; | |
151 | ||
4a26f49b | 152 | UBSAN_TEST(CONFIG_UBSAN_OBJECT_SIZE); |
854686f4 JP |
153 | ptr = (long long *)&val; |
154 | val2 = *ptr; | |
155 | } | |
156 | ||
157 | static const test_ubsan_fp test_ubsan_array[] = { | |
158 | test_ubsan_add_overflow, | |
159 | test_ubsan_sub_overflow, | |
160 | test_ubsan_mul_overflow, | |
161 | test_ubsan_negate_overflow, | |
854686f4 JP |
162 | test_ubsan_shift_out_of_bounds, |
163 | test_ubsan_out_of_bounds, | |
164 | test_ubsan_load_invalid_value, | |
854686f4 JP |
165 | test_ubsan_misaligned_access, |
166 | test_ubsan_object_size_mismatch, | |
167 | }; | |
168 | ||
4a26f49b KC |
169 | /* Excluded because they Oops the module. */ |
170 | static const test_ubsan_fp skip_ubsan_array[] = { | |
171 | test_ubsan_divrem_overflow, | |
172 | test_ubsan_null_ptr_deref, | |
173 | }; | |
174 | ||
854686f4 JP |
175 | static int __init test_ubsan_init(void) |
176 | { | |
177 | unsigned int i; | |
178 | ||
179 | for (i = 0; i < ARRAY_SIZE(test_ubsan_array); i++) | |
180 | test_ubsan_array[i](); | |
181 | ||
854686f4 JP |
182 | return 0; |
183 | } | |
184 | module_init(test_ubsan_init); | |
185 | ||
186 | static void __exit test_ubsan_exit(void) | |
187 | { | |
188 | /* do nothing */ | |
189 | } | |
190 | module_exit(test_ubsan_exit); | |
191 | ||
192 | MODULE_AUTHOR("Jinbum Park <jinb.park7@gmail.com>"); | |
193 | MODULE_LICENSE("GPL v2"); |