| 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | /* |
| 3 | * Runtime test cases for CONFIG_FORTIFY_SOURCE. For additional memcpy() |
| 4 | * testing 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 | /* We don't need to fill dmesg with the fortify WARNs during testing. */ |
| 19 | #ifdef DEBUG |
| 20 | # define FORTIFY_REPORT_KUNIT(x...) __fortify_report(x) |
| 21 | # define FORTIFY_WARN_KUNIT(x...) WARN_ONCE(x) |
| 22 | #else |
| 23 | # define FORTIFY_REPORT_KUNIT(x...) do { } while (0) |
| 24 | # define FORTIFY_WARN_KUNIT(x...) do { } while (0) |
| 25 | #endif |
| 26 | |
| 27 | /* Redefine fortify_panic() to track failures. */ |
| 28 | void fortify_add_kunit_error(int write); |
| 29 | #define fortify_panic(func, write, avail, size, retfail) do { \ |
| 30 | FORTIFY_REPORT_KUNIT(FORTIFY_REASON(func, write), avail, size); \ |
| 31 | fortify_add_kunit_error(write); \ |
| 32 | return (retfail); \ |
| 33 | } while (0) |
| 34 | |
| 35 | /* Redefine fortify_warn_once() to track memcpy() failures. */ |
| 36 | #define fortify_warn_once(chk_func, x...) do { \ |
| 37 | bool __result = chk_func; \ |
| 38 | FORTIFY_WARN_KUNIT(__result, x); \ |
| 39 | if (__result) \ |
| 40 | fortify_add_kunit_error(1); \ |
| 41 | } while (0) |
| 42 | |
| 43 | #include <kunit/device.h> |
| 44 | #include <kunit/test.h> |
| 45 | #include <kunit/test-bug.h> |
| 46 | #include <linux/device.h> |
| 47 | #include <linux/slab.h> |
| 48 | #include <linux/string.h> |
| 49 | #include <linux/vmalloc.h> |
| 50 | |
| 51 | /* Handle being built without CONFIG_FORTIFY_SOURCE */ |
| 52 | #ifndef __compiletime_strlen |
| 53 | # define __compiletime_strlen __builtin_strlen |
| 54 | #endif |
| 55 | |
| 56 | static struct kunit_resource read_resource; |
| 57 | static struct kunit_resource write_resource; |
| 58 | static int fortify_read_overflows; |
| 59 | static int fortify_write_overflows; |
| 60 | |
| 61 | static const char array_of_10[] = "this is 10" ; |
| 62 | static const char *ptr_of_11 = "this is 11!" ; |
| 63 | static const char * const unchanging_12 = "this is 12!!" ; |
| 64 | static char array_unknown[] = "compiler thinks I might change" ; |
| 65 | |
| 66 | void fortify_add_kunit_error(int write) |
| 67 | { |
| 68 | struct kunit_resource *resource; |
| 69 | struct kunit *current_test; |
| 70 | |
| 71 | current_test = kunit_get_current_test(); |
| 72 | if (!current_test) |
| 73 | return; |
| 74 | |
| 75 | resource = kunit_find_named_resource(test: current_test, |
| 76 | name: write ? "fortify_write_overflows" |
| 77 | : "fortify_read_overflows" ); |
| 78 | if (!resource) |
| 79 | return; |
| 80 | |
| 81 | (*(int *)resource->data)++; |
| 82 | kunit_put_resource(res: resource); |
| 83 | } |
| 84 | |
| 85 | static void fortify_test_known_sizes(struct kunit *test) |
| 86 | { |
| 87 | char stack[80] = "Test!" ; |
| 88 | |
| 89 | KUNIT_EXPECT_FALSE(test, __is_constexpr(__builtin_strlen(stack))); |
| 90 | KUNIT_EXPECT_EQ(test, __compiletime_strlen(stack), 5); |
| 91 | |
| 92 | KUNIT_EXPECT_TRUE(test, __is_constexpr(__builtin_strlen("88888888" ))); |
| 93 | KUNIT_EXPECT_EQ(test, __compiletime_strlen("88888888" ), 8); |
| 94 | |
| 95 | KUNIT_EXPECT_TRUE(test, __is_constexpr(__builtin_strlen(array_of_10))); |
| 96 | KUNIT_EXPECT_EQ(test, __compiletime_strlen(array_of_10), 10); |
| 97 | |
| 98 | KUNIT_EXPECT_FALSE(test, __is_constexpr(__builtin_strlen(ptr_of_11))); |
| 99 | KUNIT_EXPECT_EQ(test, __compiletime_strlen(ptr_of_11), 11); |
| 100 | |
| 101 | KUNIT_EXPECT_TRUE(test, __is_constexpr(__builtin_strlen(unchanging_12))); |
| 102 | KUNIT_EXPECT_EQ(test, __compiletime_strlen(unchanging_12), 12); |
| 103 | |
| 104 | KUNIT_EXPECT_FALSE(test, __is_constexpr(__builtin_strlen(array_unknown))); |
| 105 | KUNIT_EXPECT_EQ(test, __compiletime_strlen(array_unknown), SIZE_MAX); |
| 106 | |
| 107 | /* Externally defined and dynamically sized string pointer: */ |
| 108 | KUNIT_EXPECT_FALSE(test, __is_constexpr(__builtin_strlen(test->name))); |
| 109 | KUNIT_EXPECT_EQ(test, __compiletime_strlen(test->name), SIZE_MAX); |
| 110 | } |
| 111 | |
| 112 | /* This is volatile so the optimizer can't perform DCE below. */ |
| 113 | static volatile int pick; |
| 114 | |
| 115 | /* Not inline to keep optimizer from figuring out which string we want. */ |
| 116 | static noinline size_t want_minus_one(int pick) |
| 117 | { |
| 118 | const char *str; |
| 119 | |
| 120 | switch (pick) { |
| 121 | case 1: |
| 122 | str = "4444" ; |
| 123 | break; |
| 124 | case 2: |
| 125 | str = "333" ; |
| 126 | break; |
| 127 | default: |
| 128 | str = "1" ; |
| 129 | break; |
| 130 | } |
| 131 | return __compiletime_strlen(str); |
| 132 | } |
| 133 | |
| 134 | static void fortify_test_control_flow_split(struct kunit *test) |
| 135 | { |
| 136 | KUNIT_EXPECT_EQ(test, want_minus_one(pick), SIZE_MAX); |
| 137 | } |
| 138 | |
| 139 | #define KUNIT_EXPECT_BOS(test, p, expected, name) \ |
| 140 | KUNIT_EXPECT_EQ_MSG(test, __builtin_object_size(p, 1), \ |
| 141 | expected, \ |
| 142 | "__alloc_size() not working with __bos on " name "\n") |
| 143 | |
| 144 | #if !__has_builtin(__builtin_dynamic_object_size) |
| 145 | #define KUNIT_EXPECT_BDOS(test, p, expected, name) \ |
| 146 | /* Silence "unused variable 'expected'" warning. */ \ |
| 147 | KUNIT_EXPECT_EQ(test, expected, expected) |
| 148 | #else |
| 149 | #define KUNIT_EXPECT_BDOS(test, p, expected, name) \ |
| 150 | KUNIT_EXPECT_EQ_MSG(test, __builtin_dynamic_object_size(p, 1), \ |
| 151 | expected, \ |
| 152 | "__alloc_size() not working with __bdos on " name "\n") |
| 153 | #endif |
| 154 | |
| 155 | /* If the execpted size is a constant value, __bos can see it. */ |
| 156 | #define check_const(_expected, alloc, free) do { \ |
| 157 | size_t |
|---|