0001
0002 #include <linux/init.h>
0003 #include <linux/kernel.h>
0004 #include <linux/module.h>
0005
0006 typedef void(*test_ubsan_fp)(void);
0007
0008 #define UBSAN_TEST(config, ...) do { \
0009 pr_info("%s " __VA_ARGS__ "%s(%s=%s)\n", __func__, \
0010 sizeof(" " __VA_ARGS__) > 2 ? " " : "", \
0011 #config, IS_ENABLED(config) ? "y" : "n"); \
0012 } while (0)
0013
0014 static void test_ubsan_divrem_overflow(void)
0015 {
0016 volatile int val = 16;
0017 volatile int val2 = 0;
0018
0019 UBSAN_TEST(CONFIG_UBSAN_DIV_ZERO);
0020 val /= val2;
0021 }
0022
0023 static void test_ubsan_shift_out_of_bounds(void)
0024 {
0025 volatile int neg = -1, wrap = 4;
0026 int val1 = 10;
0027 int val2 = INT_MAX;
0028
0029 UBSAN_TEST(CONFIG_UBSAN_SHIFT, "negative exponent");
0030 val1 <<= neg;
0031
0032 UBSAN_TEST(CONFIG_UBSAN_SHIFT, "left overflow");
0033 val2 <<= wrap;
0034 }
0035
0036 static void test_ubsan_out_of_bounds(void)
0037 {
0038 volatile int i = 4, j = 5, k = -1;
0039 volatile char above[4] = { };
0040 volatile int arr[4];
0041 volatile char below[4] = { };
0042
0043 above[0] = below[0];
0044
0045 UBSAN_TEST(CONFIG_UBSAN_BOUNDS, "above");
0046 arr[j] = i;
0047
0048 UBSAN_TEST(CONFIG_UBSAN_BOUNDS, "below");
0049 arr[k] = i;
0050 }
0051
0052 enum ubsan_test_enum {
0053 UBSAN_TEST_ZERO = 0,
0054 UBSAN_TEST_ONE,
0055 UBSAN_TEST_MAX,
0056 };
0057
0058 static void test_ubsan_load_invalid_value(void)
0059 {
0060 volatile char *dst, *src;
0061 bool val, val2, *ptr;
0062 enum ubsan_test_enum eval, eval2, *eptr;
0063 unsigned char c = 0xff;
0064
0065 UBSAN_TEST(CONFIG_UBSAN_BOOL, "bool");
0066 dst = (char *)&val;
0067 src = &c;
0068 *dst = *src;
0069
0070 ptr = &val2;
0071 val2 = val;
0072
0073 UBSAN_TEST(CONFIG_UBSAN_ENUM, "enum");
0074 dst = (char *)&eval;
0075 src = &c;
0076 *dst = *src;
0077
0078 eptr = &eval2;
0079 eval2 = eval;
0080 }
0081
0082 static void test_ubsan_misaligned_access(void)
0083 {
0084 volatile char arr[5] __aligned(4) = {1, 2, 3, 4, 5};
0085 volatile int *ptr, val = 6;
0086
0087 UBSAN_TEST(CONFIG_UBSAN_ALIGNMENT);
0088 ptr = (int *)(arr + 1);
0089 *ptr = val;
0090 }
0091
0092 static const test_ubsan_fp test_ubsan_array[] = {
0093 test_ubsan_shift_out_of_bounds,
0094 test_ubsan_out_of_bounds,
0095 test_ubsan_load_invalid_value,
0096 test_ubsan_misaligned_access,
0097 };
0098
0099
0100 static const test_ubsan_fp skip_ubsan_array[] = {
0101 test_ubsan_divrem_overflow,
0102 };
0103
0104 static int __init test_ubsan_init(void)
0105 {
0106 unsigned int i;
0107
0108 for (i = 0; i < ARRAY_SIZE(test_ubsan_array); i++)
0109 test_ubsan_array[i]();
0110
0111 return 0;
0112 }
0113 module_init(test_ubsan_init);
0114
0115 static void __exit test_ubsan_exit(void)
0116 {
0117
0118 }
0119 module_exit(test_ubsan_exit);
0120
0121 MODULE_AUTHOR("Jinbum Park <jinb.park7@gmail.com>");
0122 MODULE_LICENSE("GPL v2");