1// SPDX-License-Identifier: GPL-2.0 2#include <linux/init.h> 3#include <linux/kernel.h> 4#include <linux/module.h> 5 6typedef 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 14static 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 22static 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 31static 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 39static 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 47static void test_ubsan_divrem_overflow(void) 48{ 49 volatile int val = 16; 50 volatile int val2 = 0; 51 52 UBSAN_TEST(CONFIG_UBSAN_DIV_ZERO); 53 val /= val2; 54} 55 56static void test_ubsan_shift_out_of_bounds(void) 57{ 58 volatile int neg = -1, wrap = 4; 59 volatile int val1 = 10; 60 volatile int val2 = INT_MAX; 61 62 UBSAN_TEST(CONFIG_UBSAN_SHIFT, "negative exponent"); 63 val1 <<= neg; 64 65 UBSAN_TEST(CONFIG_UBSAN_SHIFT, "left overflow"); 66 val2 <<= wrap; 67} 68 69static void test_ubsan_out_of_bounds(void) 70{ 71 volatile int i = 4, j = 5, k = -1; 72 volatile char above[4] = { }; /* Protect surrounding memory. */ 73 volatile int arr[4]; 74 volatile char below[4] = { }; /* Protect surrounding memory. */ 75 76 above[0] = below[0]; 77 78 UBSAN_TEST(CONFIG_UBSAN_BOUNDS, "above"); 79 arr[j] = i; 80 81 UBSAN_TEST(CONFIG_UBSAN_BOUNDS, "below"); 82 arr[k] = i; 83} 84 85enum ubsan_test_enum { 86 UBSAN_TEST_ZERO = 0, 87 UBSAN_TEST_ONE, 88 UBSAN_TEST_MAX, 89}; 90 91static void test_ubsan_load_invalid_value(void) 92{ 93 volatile char *dst, *src; 94 bool val, val2, *ptr; 95 enum ubsan_test_enum eval, eval2, *eptr; 96 unsigned char c = 0xff; 97 98 UBSAN_TEST(CONFIG_UBSAN_BOOL, "bool"); 99 dst = (char *)&val; 100 src = &c; 101 *dst = *src; 102 103 ptr = &val2; 104 val2 = val; 105 106 UBSAN_TEST(CONFIG_UBSAN_ENUM, "enum"); 107 dst = (char *)&eval; 108 src = &c; 109 *dst = *src; 110 111 eptr = &eval2; 112 eval2 = eval; 113} 114 115static void test_ubsan_misaligned_access(void) 116{ 117 volatile char arr[5] __aligned(4) = {1, 2, 3, 4, 5}; 118 volatile int *ptr, val = 6; 119 120 UBSAN_TEST(CONFIG_UBSAN_ALIGNMENT); 121 ptr = (int *)(arr + 1); 122 *ptr = val; 123} 124 125static 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, 131 test_ubsan_out_of_bounds, 132 test_ubsan_load_invalid_value, 133 test_ubsan_misaligned_access, 134}; 135 136/* Excluded because they Oops the module. */ 137static __used const test_ubsan_fp skip_ubsan_array[] = { 138 test_ubsan_divrem_overflow, 139}; 140 141static int __init test_ubsan_init(void) 142{ 143 unsigned int i; 144 145 for (i = 0; i < ARRAY_SIZE(test_ubsan_array); i++) 146 test_ubsan_array[i](); 147 148 return 0; 149} 150module_init(test_ubsan_init); 151 152static void __exit test_ubsan_exit(void) 153{ 154 /* do nothing */ 155} 156module_exit(test_ubsan_exit); 157 158MODULE_AUTHOR("Jinbum Park <jinb.park7@gmail.com>"); 159MODULE_LICENSE("GPL v2"); 160