lkdtm: Add FAM_BOUNDS test for __counted_by
authorKees Cook <keescook@chromium.org>
Thu, 17 Aug 2023 04:27:35 +0000 (21:27 -0700)
committerKees Cook <keescook@chromium.org>
Thu, 17 Aug 2023 23:46:35 +0000 (16:46 -0700)
Add new CONFIG_UBSAN_BOUNDS test for __counted_by attribute.

Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Kees Cook <keescook@chromium.org>
drivers/misc/lkdtm/bugs.c

index 963b4de..c66cc05 100644 (file)
@@ -273,8 +273,8 @@ static void lkdtm_HUNG_TASK(void)
        schedule();
 }
 
-volatile unsigned int huge = INT_MAX - 2;
-volatile unsigned int ignored;
+static volatile unsigned int huge = INT_MAX - 2;
+static volatile unsigned int ignored;
 
 static void lkdtm_OVERFLOW_SIGNED(void)
 {
@@ -305,7 +305,7 @@ static void lkdtm_OVERFLOW_UNSIGNED(void)
        ignored = value;
 }
 
-/* Intentionally using old-style flex array definition of 1 byte. */
+/* Intentionally using unannotated flex array definition. */
 struct array_bounds_flex_array {
        int one;
        int two;
@@ -357,6 +357,46 @@ static void lkdtm_ARRAY_BOUNDS(void)
                pr_expected_config(CONFIG_UBSAN_BOUNDS);
 }
 
+struct lkdtm_annotated {
+       unsigned long flags;
+       int count;
+       int array[] __counted_by(count);
+};
+
+static volatile int fam_count = 4;
+
+static void lkdtm_FAM_BOUNDS(void)
+{
+       struct lkdtm_annotated *inst;
+
+       inst = kzalloc(struct_size(inst, array, fam_count + 1), GFP_KERNEL);
+       if (!inst) {
+               pr_err("FAIL: could not allocate test struct!\n");
+               return;
+       }
+
+       inst->count = fam_count;
+       pr_info("Array access within bounds ...\n");
+       inst->array[1] = fam_count;
+       ignored = inst->array[1];
+
+       pr_info("Array access beyond bounds ...\n");
+       inst->array[fam_count] = fam_count;
+       ignored = inst->array[fam_count];
+
+       kfree(inst);
+
+       pr_err("FAIL: survived access of invalid flexible array member index!\n");
+
+       if (!__has_attribute(__counted_by__))
+               pr_warn("This is expected since this %s was built a compiler supporting __counted_by\n",
+                       lkdtm_kernel_info);
+       else if (IS_ENABLED(CONFIG_UBSAN_BOUNDS))
+               pr_expected_config(CONFIG_UBSAN_TRAP);
+       else
+               pr_expected_config(CONFIG_UBSAN_BOUNDS);
+}
+
 static void lkdtm_CORRUPT_LIST_ADD(void)
 {
        /*
@@ -616,6 +656,7 @@ static struct crashtype crashtypes[] = {
        CRASHTYPE(OVERFLOW_SIGNED),
        CRASHTYPE(OVERFLOW_UNSIGNED),
        CRASHTYPE(ARRAY_BOUNDS),
+       CRASHTYPE(FAM_BOUNDS),
        CRASHTYPE(CORRUPT_LIST_ADD),
        CRASHTYPE(CORRUPT_LIST_DEL),
        CRASHTYPE(STACK_GUARD_PAGE_LEADING),