1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Runtime test cases for CONFIG_FORTIFY_SOURCE. For testing memcpy(), |
4 | * see FORTIFY_MEM_* tests in LKDTM (drivers/misc/lkdtm/fortify.c). |
5 | * |
6 | * For corner cases with UBSAN, try testing with: |
7 | * |
8 | * ./tools/testing/kunit/kunit.py run --arch=x86_64 \ |
9 | * --kconfig_add CONFIG_FORTIFY_SOURCE=y \ |
10 | * --kconfig_add CONFIG_UBSAN=y \ |
11 | * --kconfig_add CONFIG_UBSAN_TRAP=y \ |
12 | * --kconfig_add CONFIG_UBSAN_BOUNDS=y \ |
13 | * --kconfig_add CONFIG_UBSAN_LOCAL_BOUNDS=y \ |
14 | * --make_options LLVM=1 fortify |
15 | */ |
16 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
17 | |
18 | /* Redefine fortify_panic() to track failures. */ |
19 | void fortify_add_kunit_error(int write); |
20 | #define fortify_panic(func, write, avail, size, retfail) do { \ |
21 | __fortify_report(FORTIFY_REASON(func, write), avail, size); \ |
22 | fortify_add_kunit_error(write); \ |
23 | return (retfail); \ |
24 | } while (0) |
25 | |
26 | #include <kunit/device.h> |
27 | #include <kunit/test.h> |
28 | #include <kunit/test-bug.h> |
29 | #include <linux/device.h> |
30 | #include <linux/slab.h> |
31 | #include <linux/string.h> |
32 | #include <linux/vmalloc.h> |
33 | |
34 | /* Handle being built without CONFIG_FORTIFY_SOURCE */ |
35 | #ifndef __compiletime_strlen |
36 | # define __compiletime_strlen __builtin_strlen |
37 | #endif |
38 | |
39 | static struct kunit_resource read_resource; |
40 | static struct kunit_resource write_resource; |
41 | static int fortify_read_overflows; |
42 | static int fortify_write_overflows; |
43 | |
44 | static const char array_of_10[] = "this is 10" ; |
45 | static const char *ptr_of_11 = "this is 11!" ; |
46 | static char array_unknown[] = "compiler thinks I might change" ; |
47 | |
48 | void fortify_add_kunit_error(int write) |
49 | { |
50 | struct kunit_resource *resource; |
51 | struct kunit *current_test; |
52 | |
53 | current_test = kunit_get_current_test(); |
54 | if (!current_test) |
55 | return; |
56 | |
57 | resource = kunit_find_named_resource(test: current_test, |
58 | name: write ? "fortify_write_overflows" |
59 | : "fortify_read_overflows" ); |
60 | if (!resource) |
61 | return; |
62 | |
63 | (*(int *)resource->data)++; |
64 | kunit_put_resource(res: resource); |
65 | } |
66 | |
67 | static void known_sizes_test(struct kunit *test) |
68 | { |
69 | KUNIT_EXPECT_EQ(test, __compiletime_strlen("88888888" ), 8); |
70 | KUNIT_EXPECT_EQ(test, __compiletime_strlen(array_of_10), 10); |
71 | KUNIT_EXPECT_EQ(test, __compiletime_strlen(ptr_of_11), 11); |
72 | |
73 | KUNIT_EXPECT_EQ(test, __compiletime_strlen(array_unknown), SIZE_MAX); |
74 | /* Externally defined and dynamically sized string pointer: */ |
75 | KUNIT_EXPECT_EQ(test, __compiletime_strlen(test->name), SIZE_MAX); |
76 | } |
77 | |
78 | /* This is volatile so the optimizer can't perform DCE below. */ |
79 | static volatile int pick; |
80 | |
81 | /* Not inline to keep optimizer from figuring out which string we want. */ |
82 | static noinline size_t want_minus_one(int pick) |
83 | { |
84 | const char *str; |
85 | |
86 | switch (pick) { |
87 | case 1: |
88 | str = "4444" ; |
89 | break; |
90 | case 2: |
91 | str = "333" ; |
92 | break; |
93 | default: |
94 | str = "1" ; |
95 | break; |
96 | } |
97 | return __compiletime_strlen(str); |
98 | } |
99 | |
100 | static void control_flow_split_test(struct kunit *test) |
101 | { |
102 | KUNIT_EXPECT_EQ(test, want_minus_one(pick), SIZE_MAX); |
103 | } |
104 | |
105 | #define KUNIT_EXPECT_BOS(test, p, expected, name) \ |
106 | KUNIT_EXPECT_EQ_MSG(test, __builtin_object_size(p, 1), \ |
107 | expected, \ |
108 | "__alloc_size() not working with __bos on " name "\n") |
109 | |
110 | #if !__has_builtin(__builtin_dynamic_object_size) |
111 | #define KUNIT_EXPECT_BDOS(test, p, expected, name) \ |
112 | /* Silence "unused variable 'expected'" warning. */ \ |
113 | KUNIT_EXPECT_EQ(test, expected, expected) |
114 | #else |
115 | #define KUNIT_EXPECT_BDOS(test, p, expected, name) \ |
116 | KUNIT_EXPECT_EQ_MSG(test, __builtin_dynamic_object_size(p, 1), \ |
117 | expected, \ |
118 | "__alloc_size() not working with __bdos on " name "\n") |
119 | #endif |
120 | |
121 | /* If the execpted size is a constant value, __bos can see it. */ |
122 | #define check_const(_expected, alloc, free) do { \ |
123 | size_t |
---|