Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Test cases for compiler-based stack variable zeroing via
0004  * -ftrivial-auto-var-init={zero,pattern} or CONFIG_GCC_PLUGIN_STRUCTLEAK*.
0005  * For example, see:
0006  * https://www.kernel.org/doc/html/latest/dev-tools/kunit/kunit-tool.html#configuring-building-and-running-tests
0007  *  ./tools/testing/kunit/kunit.py run stackinit [--raw_output] \
0008  *      --make_option LLVM=1 \
0009  *      --kconfig_add CONFIG_INIT_STACK_ALL_ZERO=y
0010  *
0011  */
0012 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0013 
0014 #include <kunit/test.h>
0015 #include <linux/init.h>
0016 #include <linux/kernel.h>
0017 #include <linux/module.h>
0018 #include <linux/string.h>
0019 
0020 /* Exfiltration buffer. */
0021 #define MAX_VAR_SIZE    128
0022 static u8 check_buf[MAX_VAR_SIZE];
0023 
0024 /* Character array to trigger stack protector in all functions. */
0025 #define VAR_BUFFER   32
0026 
0027 /* Volatile mask to convince compiler to copy memory with 0xff. */
0028 static volatile u8 forced_mask = 0xff;
0029 
0030 /* Location and size tracking to validate fill and test are colocated. */
0031 static void *fill_start, *target_start;
0032 static size_t fill_size, target_size;
0033 
0034 static bool range_contains(char *haystack_start, size_t haystack_size,
0035                char *needle_start, size_t needle_size)
0036 {
0037     if (needle_start >= haystack_start &&
0038         needle_start + needle_size <= haystack_start + haystack_size)
0039         return true;
0040     return false;
0041 }
0042 
0043 /* Whether the test is expected to fail. */
0044 #define WANT_SUCCESS                0
0045 #define XFAIL                   1
0046 
0047 #define DO_NOTHING_TYPE_SCALAR(var_type)    var_type
0048 #define DO_NOTHING_TYPE_STRING(var_type)    void
0049 #define DO_NOTHING_TYPE_STRUCT(var_type)    void
0050 
0051 #define DO_NOTHING_RETURN_SCALAR(ptr)       *(ptr)
0052 #define DO_NOTHING_RETURN_STRING(ptr)       /**/
0053 #define DO_NOTHING_RETURN_STRUCT(ptr)       /**/
0054 
0055 #define DO_NOTHING_CALL_SCALAR(var, name)           \
0056         (var) = do_nothing_ ## name(&(var))
0057 #define DO_NOTHING_CALL_STRING(var, name)           \
0058         do_nothing_ ## name(var)
0059 #define DO_NOTHING_CALL_STRUCT(var, name)           \
0060         do_nothing_ ## name(&(var))
0061 
0062 #define FETCH_ARG_SCALAR(var)       &var
0063 #define FETCH_ARG_STRING(var)       var
0064 #define FETCH_ARG_STRUCT(var)       &var
0065 
0066 #define FILL_SIZE_STRING        16
0067 
0068 #define INIT_CLONE_SCALAR       /**/
0069 #define INIT_CLONE_STRING       [FILL_SIZE_STRING]
0070 #define INIT_CLONE_STRUCT       /**/
0071 
0072 #define ZERO_CLONE_SCALAR(zero)     memset(&(zero), 0x00, sizeof(zero))
0073 #define ZERO_CLONE_STRING(zero)     memset(&(zero), 0x00, sizeof(zero))
0074 /*
0075  * For the struct, intentionally poison padding to see if it gets
0076  * copied out in direct assignments.
0077  * */
0078 #define ZERO_CLONE_STRUCT(zero)             \
0079     do {                        \
0080         memset(&(zero), 0xFF, sizeof(zero));    \
0081         zero.one = 0;               \
0082         zero.two = 0;               \
0083         zero.three = 0;             \
0084         zero.four = 0;              \
0085     } while (0)
0086 
0087 #define INIT_SCALAR_none(var_type)  /**/
0088 #define INIT_SCALAR_zero(var_type)  = 0
0089 
0090 #define INIT_STRING_none(var_type)  [FILL_SIZE_STRING] /**/
0091 #define INIT_STRING_zero(var_type)  [FILL_SIZE_STRING] = { }
0092 
0093 #define INIT_STRUCT_none(var_type)  /**/
0094 #define INIT_STRUCT_zero(var_type)  = { }
0095 
0096 
0097 #define __static_partial        { .two = 0, }
0098 #define __static_all            { .one = 0,         \
0099                       .two = 0,         \
0100                       .three = 0,           \
0101                       .four = 0,            \
0102                     }
0103 #define __dynamic_partial       { .two = arg->two, }
0104 #define __dynamic_all           { .one = arg->one,      \
0105                       .two = arg->two,      \
0106                       .three = arg->three,      \
0107                       .four = arg->four,        \
0108                     }
0109 #define __runtime_partial       var.two = 0
0110 #define __runtime_all           var.one = 0;            \
0111                     var.two = 0;            \
0112                     var.three = 0;          \
0113                     var.four = 0
0114 
0115 #define INIT_STRUCT_static_partial(var_type)                \
0116                     = __static_partial
0117 #define INIT_STRUCT_static_all(var_type)                \
0118                     = __static_all
0119 #define INIT_STRUCT_dynamic_partial(var_type)               \
0120                     = __dynamic_partial
0121 #define INIT_STRUCT_dynamic_all(var_type)               \
0122                     = __dynamic_all
0123 #define INIT_STRUCT_runtime_partial(var_type)               \
0124                     ; __runtime_partial
0125 #define INIT_STRUCT_runtime_all(var_type)               \
0126                     ; __runtime_all
0127 
0128 #define INIT_STRUCT_assigned_static_partial(var_type)           \
0129                     ; var = (var_type)__static_partial
0130 #define INIT_STRUCT_assigned_static_all(var_type)           \
0131                     ; var = (var_type)__static_all
0132 #define INIT_STRUCT_assigned_dynamic_partial(var_type)          \
0133                     ; var = (var_type)__dynamic_partial
0134 #define INIT_STRUCT_assigned_dynamic_all(var_type)          \
0135                     ; var = (var_type)__dynamic_all
0136 
0137 #define INIT_STRUCT_assigned_copy(var_type)             \
0138                     ; var = *(arg)
0139 
0140 /*
0141  * @name: unique string name for the test
0142  * @var_type: type to be tested for zeroing initialization
0143  * @which: is this a SCALAR, STRING, or STRUCT type?
0144  * @init_level: what kind of initialization is performed
0145  * @xfail: is this test expected to fail?
0146  */
0147 #define DEFINE_TEST_DRIVER(name, var_type, which, xfail)    \
0148 /* Returns 0 on success, 1 on failure. */           \
0149 static noinline void test_ ## name (struct kunit *test)     \
0150 {                               \
0151     var_type zero INIT_CLONE_ ## which;         \
0152     int ignored;                        \
0153     u8 sum = 0, i;                      \
0154                                 \
0155     /* Notice when a new test is larger than expected. */   \
0156     BUILD_BUG_ON(sizeof(zero) > MAX_VAR_SIZE);      \
0157                                 \
0158     /* Fill clone type with zero for per-field init. */ \
0159     ZERO_CLONE_ ## which(zero);             \
0160     /* Clear entire check buffer for 0xFF overlap test. */  \
0161     memset(check_buf, 0x00, sizeof(check_buf));     \
0162     /* Fill stack with 0xFF. */             \
0163     ignored = leaf_ ##name((unsigned long)&ignored, 1,  \
0164                 FETCH_ARG_ ## which(zero)); \
0165     /* Verify all bytes overwritten with 0xFF. */       \
0166     for (sum = 0, i = 0; i < target_size; i++)      \
0167         sum += (check_buf[i] != 0xFF);          \
0168     KUNIT_ASSERT_EQ_MSG(test, sum, 0,           \
0169                 "leaf fill was not 0xFF!?\n");  \
0170     /* Clear entire check buffer for later bit tests. */    \
0171     memset(check_buf, 0x00, sizeof(check_buf));     \
0172     /* Extract stack-defined variable contents. */      \
0173     ignored = leaf_ ##name((unsigned long)&ignored, 0,  \
0174                 FETCH_ARG_ ## which(zero)); \
0175                                 \
0176     /* Validate that compiler lined up fill and target. */  \
0177     KUNIT_ASSERT_TRUE_MSG(test,             \
0178         range_contains(fill_start, fill_size,       \
0179                 target_start, target_size),     \
0180         "stack fill missed target!? "           \
0181         "(fill %zu wide, target offset by %d)\n",   \
0182         fill_size,                  \
0183         (int)((ssize_t)(uintptr_t)fill_start -      \
0184               (ssize_t)(uintptr_t)target_start));   \
0185                                 \
0186     /* Look for any bytes still 0xFF in check region. */    \
0187     for (sum = 0, i = 0; i < target_size; i++)      \
0188         sum += (check_buf[i] == 0xFF);          \
0189                                 \
0190     if (sum != 0 && xfail)                  \
0191         kunit_skip(test,                \
0192                "XFAIL uninit bytes: %d\n",      \
0193                sum);                \
0194     KUNIT_ASSERT_EQ_MSG(test, sum, 0,           \
0195         "uninit bytes: %d\n", sum);         \
0196 }
0197 #define DEFINE_TEST(name, var_type, which, init_level, xfail)   \
0198 /* no-op to force compiler into ignoring "uninitialized" vars */\
0199 static noinline DO_NOTHING_TYPE_ ## which(var_type)     \
0200 do_nothing_ ## name(var_type *ptr)              \
0201 {                               \
0202     /* Will always be true, but compiler doesn't know. */   \
0203     if ((unsigned long)ptr > 0x2)               \
0204         return DO_NOTHING_RETURN_ ## which(ptr);    \
0205     else                            \
0206         return DO_NOTHING_RETURN_ ## which(ptr + 1);    \
0207 }                               \
0208 static noinline int leaf_ ## name(unsigned long sp, bool fill,  \
0209                   var_type *arg)        \
0210 {                               \
0211     char buf[VAR_BUFFER];                   \
0212     var_type var                        \
0213         INIT_ ## which ## _ ## init_level(var_type);    \
0214                                 \
0215     target_start = &var;                    \
0216     target_size = sizeof(var);              \
0217     /*                          \
0218      * Keep this buffer around to make sure we've got a \
0219      * stack frame of SOME kind...              \
0220      */                         \
0221     memset(buf, (char)(sp & 0xff), sizeof(buf));        \
0222     /* Fill variable with 0xFF. */              \
0223     if (fill) {                     \
0224         fill_start = &var;              \
0225         fill_size = sizeof(var);            \
0226         memset(fill_start,              \
0227                (char)((sp & 0xff) | forced_mask),   \
0228                fill_size);              \
0229     }                           \
0230                                 \
0231     /* Silence "never initialized" warnings. */     \
0232     DO_NOTHING_CALL_ ## which(var, name);           \
0233                                 \
0234     /* Exfiltrate "var". */                 \
0235     memcpy(check_buf, target_start, target_size);       \
0236                                 \
0237     return (int)buf[0] | (int)buf[sizeof(buf) - 1];     \
0238 }                               \
0239 DEFINE_TEST_DRIVER(name, var_type, which, xfail)
0240 
0241 /* Structure with no padding. */
0242 struct test_packed {
0243     unsigned long one;
0244     unsigned long two;
0245     unsigned long three;
0246     unsigned long four;
0247 };
0248 
0249 /* Simple structure with padding likely to be covered by compiler. */
0250 struct test_small_hole {
0251     size_t one;
0252     char two;
0253     /* 3 byte padding hole here. */
0254     int three;
0255     unsigned long four;
0256 };
0257 
0258 /* Trigger unhandled padding in a structure. */
0259 struct test_big_hole {
0260     u8 one;
0261     u8 two;
0262     u8 three;
0263     /* 61 byte padding hole here. */
0264     u8 four __aligned(64);
0265 } __aligned(64);
0266 
0267 struct test_trailing_hole {
0268     char *one;
0269     char *two;
0270     char *three;
0271     char four;
0272     /* "sizeof(unsigned long) - 1" byte padding hole here. */
0273 };
0274 
0275 /* Test if STRUCTLEAK is clearing structs with __user fields. */
0276 struct test_user {
0277     u8 one;
0278     unsigned long two;
0279     char __user *three;
0280     unsigned long four;
0281 };
0282 
0283 #define ALWAYS_PASS WANT_SUCCESS
0284 #define ALWAYS_FAIL XFAIL
0285 
0286 #ifdef CONFIG_INIT_STACK_NONE
0287 # define USER_PASS  XFAIL
0288 # define BYREF_PASS XFAIL
0289 # define STRONG_PASS    XFAIL
0290 #elif defined(CONFIG_GCC_PLUGIN_STRUCTLEAK_USER)
0291 # define USER_PASS  WANT_SUCCESS
0292 # define BYREF_PASS XFAIL
0293 # define STRONG_PASS    XFAIL
0294 #elif defined(CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF)
0295 # define USER_PASS  WANT_SUCCESS
0296 # define BYREF_PASS WANT_SUCCESS
0297 # define STRONG_PASS    XFAIL
0298 #else
0299 # define USER_PASS  WANT_SUCCESS
0300 # define BYREF_PASS WANT_SUCCESS
0301 # define STRONG_PASS    WANT_SUCCESS
0302 #endif
0303 
0304 #define DEFINE_SCALAR_TEST(name, init, xfail)           \
0305         DEFINE_TEST(name ## _ ## init, name, SCALAR,    \
0306                 init, xfail)
0307 
0308 #define DEFINE_SCALAR_TESTS(init, xfail)            \
0309         DEFINE_SCALAR_TEST(u8, init, xfail);        \
0310         DEFINE_SCALAR_TEST(u16, init, xfail);       \
0311         DEFINE_SCALAR_TEST(u32, init, xfail);       \
0312         DEFINE_SCALAR_TEST(u64, init, xfail);       \
0313         DEFINE_TEST(char_array_ ## init, unsigned char, \
0314                 STRING, init, xfail)
0315 
0316 #define DEFINE_STRUCT_TEST(name, init, xfail)           \
0317         DEFINE_TEST(name ## _ ## init,          \
0318                 struct test_ ## name, STRUCT, init, \
0319                 xfail)
0320 
0321 #define DEFINE_STRUCT_TESTS(init, xfail)            \
0322         DEFINE_STRUCT_TEST(small_hole, init, xfail);    \
0323         DEFINE_STRUCT_TEST(big_hole, init, xfail);  \
0324         DEFINE_STRUCT_TEST(trailing_hole, init, xfail); \
0325         DEFINE_STRUCT_TEST(packed, init, xfail)
0326 
0327 #define DEFINE_STRUCT_INITIALIZER_TESTS(base, xfail)        \
0328         DEFINE_STRUCT_TESTS(base ## _ ## partial,   \
0329                     xfail);         \
0330         DEFINE_STRUCT_TESTS(base ## _ ## all, xfail)
0331 
0332 /* These should be fully initialized all the time! */
0333 DEFINE_SCALAR_TESTS(zero, ALWAYS_PASS);
0334 DEFINE_STRUCT_TESTS(zero, ALWAYS_PASS);
0335 /* Struct initializers: padding may be left uninitialized. */
0336 DEFINE_STRUCT_INITIALIZER_TESTS(static, STRONG_PASS);
0337 DEFINE_STRUCT_INITIALIZER_TESTS(dynamic, STRONG_PASS);
0338 DEFINE_STRUCT_INITIALIZER_TESTS(runtime, STRONG_PASS);
0339 DEFINE_STRUCT_INITIALIZER_TESTS(assigned_static, STRONG_PASS);
0340 DEFINE_STRUCT_INITIALIZER_TESTS(assigned_dynamic, STRONG_PASS);
0341 DEFINE_STRUCT_TESTS(assigned_copy, ALWAYS_FAIL);
0342 /* No initialization without compiler instrumentation. */
0343 DEFINE_SCALAR_TESTS(none, STRONG_PASS);
0344 DEFINE_STRUCT_TESTS(none, BYREF_PASS);
0345 /* Initialization of members with __user attribute. */
0346 DEFINE_TEST(user, struct test_user, STRUCT, none, USER_PASS);
0347 
0348 /*
0349  * Check two uses through a variable declaration outside either path,
0350  * which was noticed as a special case in porting earlier stack init
0351  * compiler logic.
0352  */
0353 static int noinline __leaf_switch_none(int path, bool fill)
0354 {
0355     switch (path) {
0356         /*
0357          * This is intentionally unreachable. To silence the
0358          * warning, build with -Wno-switch-unreachable
0359          */
0360         uint64_t var[10];
0361 
0362     case 1:
0363         target_start = &var;
0364         target_size = sizeof(var);
0365         if (fill) {
0366             fill_start = &var;
0367             fill_size = sizeof(var);
0368 
0369             memset(fill_start, forced_mask | 0x55, fill_size);
0370         }
0371         memcpy(check_buf, target_start, target_size);
0372         break;
0373     case 2:
0374         target_start = &var;
0375         target_size = sizeof(var);
0376         if (fill) {
0377             fill_start = &var;
0378             fill_size = sizeof(var);
0379 
0380             memset(fill_start, forced_mask | 0xaa, fill_size);
0381         }
0382         memcpy(check_buf, target_start, target_size);
0383         break;
0384     default:
0385         var[1] = 5;
0386         return var[1] & forced_mask;
0387     }
0388     return 0;
0389 }
0390 
0391 static noinline int leaf_switch_1_none(unsigned long sp, bool fill,
0392                           uint64_t *arg)
0393 {
0394     return __leaf_switch_none(1, fill);
0395 }
0396 
0397 static noinline int leaf_switch_2_none(unsigned long sp, bool fill,
0398                           uint64_t *arg)
0399 {
0400     return __leaf_switch_none(2, fill);
0401 }
0402 
0403 /*
0404  * These are expected to fail for most configurations because neither
0405  * GCC nor Clang have a way to perform initialization of variables in
0406  * non-code areas (i.e. in a switch statement before the first "case").
0407  * https://bugs.llvm.org/show_bug.cgi?id=44916
0408  */
0409 DEFINE_TEST_DRIVER(switch_1_none, uint64_t, SCALAR, ALWAYS_FAIL);
0410 DEFINE_TEST_DRIVER(switch_2_none, uint64_t, SCALAR, ALWAYS_FAIL);
0411 
0412 #define KUNIT_test_scalars(init)            \
0413         KUNIT_CASE(test_u8_ ## init),       \
0414         KUNIT_CASE(test_u16_ ## init),      \
0415         KUNIT_CASE(test_u32_ ## init),      \
0416         KUNIT_CASE(test_u64_ ## init),      \
0417         KUNIT_CASE(test_char_array_ ## init)
0418 
0419 #define KUNIT_test_structs(init)            \
0420         KUNIT_CASE(test_small_hole_ ## init),   \
0421         KUNIT_CASE(test_big_hole_ ## init), \
0422         KUNIT_CASE(test_trailing_hole_ ## init),\
0423         KUNIT_CASE(test_packed_ ## init)    \
0424 
0425 static struct kunit_case stackinit_test_cases[] = {
0426     /* These are explicitly initialized and should always pass. */
0427     KUNIT_test_scalars(zero),
0428     KUNIT_test_structs(zero),
0429     /* Padding here appears to be accidentally always initialized? */
0430     KUNIT_test_structs(dynamic_partial),
0431     KUNIT_test_structs(assigned_dynamic_partial),
0432     /* Padding initialization depends on compiler behaviors. */
0433     KUNIT_test_structs(static_partial),
0434     KUNIT_test_structs(static_all),
0435     KUNIT_test_structs(dynamic_all),
0436     KUNIT_test_structs(runtime_partial),
0437     KUNIT_test_structs(runtime_all),
0438     KUNIT_test_structs(assigned_static_partial),
0439     KUNIT_test_structs(assigned_static_all),
0440     KUNIT_test_structs(assigned_dynamic_all),
0441     /* Everything fails this since it effectively performs a memcpy(). */
0442     KUNIT_test_structs(assigned_copy),
0443     /* STRUCTLEAK_BYREF_ALL should cover everything from here down. */
0444     KUNIT_test_scalars(none),
0445     KUNIT_CASE(test_switch_1_none),
0446     KUNIT_CASE(test_switch_2_none),
0447     /* STRUCTLEAK_BYREF should cover from here down. */
0448     KUNIT_test_structs(none),
0449     /* STRUCTLEAK will only cover this. */
0450     KUNIT_CASE(test_user),
0451     {}
0452 };
0453 
0454 static struct kunit_suite stackinit_test_suite = {
0455     .name = "stackinit",
0456     .test_cases = stackinit_test_cases,
0457 };
0458 
0459 kunit_test_suites(&stackinit_test_suite);
0460 
0461 MODULE_LICENSE("GPL");