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