Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

lkdtm/fortify: Consolidate FORTIFY_SOURCE tests

The FORTIFY_SOURCE tests were split between bugs.c and fortify.c. Move
tests into fortify.c, standardize their naming, add CONFIG hints, and
add them to the lkdtm selftests.

Cc: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Kees Cook <keescook@chromium.org>
Link: https://lore.kernel.org/r/20210818174855.2307828-3-keescook@chromium.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Kees Cook and committed by
Greg Kroah-Hartman
fe8e353b c75be56e

+59 -54
-50
drivers/misc/lkdtm/bugs.c
··· 507 507 pr_err("XFAIL: this test is arm64-only\n"); 508 508 #endif 509 509 } 510 - 511 - void lkdtm_FORTIFY_OBJECT(void) 512 - { 513 - struct target { 514 - char a[10]; 515 - } target[2] = {}; 516 - int result; 517 - 518 - /* 519 - * Using volatile prevents the compiler from determining the value of 520 - * 'size' at compile time. Without that, we would get a compile error 521 - * rather than a runtime error. 522 - */ 523 - volatile int size = 11; 524 - 525 - pr_info("trying to read past the end of a struct\n"); 526 - 527 - result = memcmp(&target[0], &target[1], size); 528 - 529 - /* Print result to prevent the code from being eliminated */ 530 - pr_err("FAIL: fortify did not catch an object overread!\n" 531 - "\"%d\" was the memcmp result.\n", result); 532 - } 533 - 534 - void lkdtm_FORTIFY_SUBOBJECT(void) 535 - { 536 - struct target { 537 - char a[10]; 538 - char b[10]; 539 - } target; 540 - char *src; 541 - 542 - src = kmalloc(20, GFP_KERNEL); 543 - strscpy(src, "over ten bytes", 20); 544 - 545 - pr_info("trying to strcpy past the end of a member of a struct\n"); 546 - 547 - /* 548 - * strncpy(target.a, src, 20); will hit a compile error because the 549 - * compiler knows at build time that target.a < 20 bytes. Use strcpy() 550 - * to force a runtime error. 551 - */ 552 - strcpy(target.a, src); 553 - 554 - /* Use target.a to prevent the code from being eliminated */ 555 - pr_err("FAIL: fortify did not catch an sub-object overrun!\n" 556 - "\"%s\" was copied.\n", target.a); 557 - 558 - kfree(src); 559 - }
+2 -2
drivers/misc/lkdtm/core.c
··· 118 118 CRASHTYPE(UNSET_SMEP), 119 119 CRASHTYPE(CORRUPT_PAC), 120 120 CRASHTYPE(UNALIGNED_LOAD_STORE_WRITE), 121 - CRASHTYPE(FORTIFY_OBJECT), 122 - CRASHTYPE(FORTIFY_SUBOBJECT), 123 121 CRASHTYPE(SLAB_LINEAR_OVERFLOW), 124 122 CRASHTYPE(VMALLOC_LINEAR_OVERFLOW), 125 123 CRASHTYPE(WRITE_AFTER_FREE), ··· 177 179 CRASHTYPE(USERCOPY_KERNEL), 178 180 CRASHTYPE(STACKLEAK_ERASING), 179 181 CRASHTYPE(CFI_FORWARD_PROTO), 182 + CRASHTYPE(FORTIFIED_OBJECT), 183 + CRASHTYPE(FORTIFIED_SUBOBJECT), 180 184 CRASHTYPE(FORTIFIED_STRSCPY), 181 185 CRASHTYPE(DOUBLE_FAULT), 182 186 #ifdef CONFIG_PPC_BOOK3S_64
+53
drivers/misc/lkdtm/fortify.c
··· 8 8 #include <linux/string.h> 9 9 #include <linux/slab.h> 10 10 11 + static volatile int fortify_scratch_space; 12 + 13 + void lkdtm_FORTIFIED_OBJECT(void) 14 + { 15 + struct target { 16 + char a[10]; 17 + } target[2] = {}; 18 + /* 19 + * Using volatile prevents the compiler from determining the value of 20 + * 'size' at compile time. Without that, we would get a compile error 21 + * rather than a runtime error. 22 + */ 23 + volatile int size = 11; 24 + 25 + pr_info("trying to read past the end of a struct\n"); 26 + 27 + /* Store result to global to prevent the code from being eliminated */ 28 + fortify_scratch_space = memcmp(&target[0], &target[1], size); 29 + 30 + pr_err("FAIL: fortify did not block an object overread!\n"); 31 + pr_expected_config(CONFIG_FORTIFY_SOURCE); 32 + } 33 + 34 + void lkdtm_FORTIFIED_SUBOBJECT(void) 35 + { 36 + struct target { 37 + char a[10]; 38 + char b[10]; 39 + } target; 40 + volatile int size = 20; 41 + char *src; 42 + 43 + src = kmalloc(size, GFP_KERNEL); 44 + strscpy(src, "over ten bytes", size); 45 + size = strlen(src) + 1; 46 + 47 + pr_info("trying to strcpy past the end of a member of a struct\n"); 48 + 49 + /* 50 + * memcpy(target.a, src, 20); will hit a compile error because the 51 + * compiler knows at build time that target.a < 20 bytes. Use a 52 + * volatile to force a runtime error. 53 + */ 54 + memcpy(target.a, src, size); 55 + 56 + /* Store result to global to prevent the code from being eliminated */ 57 + fortify_scratch_space = target.a[3]; 58 + 59 + pr_err("FAIL: fortify did not block an sub-object overrun!\n"); 60 + pr_expected_config(CONFIG_FORTIFY_SOURCE); 61 + 62 + kfree(src); 63 + } 11 64 12 65 /* 13 66 * Calls fortified strscpy to test that it returns the same result as vanilla
+2 -2
drivers/misc/lkdtm/lkdtm.h
··· 74 74 void lkdtm_UNSET_SMEP(void); 75 75 void lkdtm_DOUBLE_FAULT(void); 76 76 void lkdtm_CORRUPT_PAC(void); 77 - void lkdtm_FORTIFY_OBJECT(void); 78 - void lkdtm_FORTIFY_SUBOBJECT(void); 79 77 80 78 /* heap.c */ 81 79 void __init lkdtm_heap_init(void); ··· 148 150 void lkdtm_CFI_FORWARD_PROTO(void); 149 151 150 152 /* fortify.c */ 153 + void lkdtm_FORTIFIED_OBJECT(void); 154 + void lkdtm_FORTIFIED_SUBOBJECT(void); 151 155 void lkdtm_FORTIFIED_STRSCPY(void); 152 156 153 157 /* powerpc.c */
+2
tools/testing/selftests/lkdtm/tests.txt
··· 73 73 STACKLEAK_ERASING OK: the rest of the thread stack is properly erased 74 74 CFI_FORWARD_PROTO 75 75 FORTIFIED_STRSCPY 76 + FORTIFIED_OBJECT 77 + FORTIFIED_SUBOBJECT 76 78 PPC_SLB_MULTIHIT Recovered