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

lkdtm: tests for FORTIFY_SOURCE

Add code to test both:

- runtime detection of the overrun of a structure. This covers the
__builtin_object_size(x, 0) case. This test is called FORTIFY_OBJECT.

- runtime detection of the overrun of a char array within a structure.
This covers the __builtin_object_size(x, 1) case which can be used
for some string functions. This test is called FORTIFY_SUBOBJECT.

Link: https://lkml.kernel.org/r/20201122162451.27551-3-laniel_francis@privacyrequired.com
Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Francis Laniel <laniel_francis@privacyrequired.com>
Suggested-by: Kees Cook <keescook@chromium.org>
Reviewed-by: Kees Cook <keescook@chromium.org>
Cc: Daniel Micay <danielmicay@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Daniel Axtens and committed by
Linus Torvalds
d96938da 6a39e62a

+54
+50
drivers/misc/lkdtm/bugs.c
··· 482 482 pr_err("XFAIL: this test is arm64-only\n"); 483 483 #endif 484 484 } 485 + 486 + void lkdtm_FORTIFY_OBJECT(void) 487 + { 488 + struct target { 489 + char a[10]; 490 + } target[2] = {}; 491 + int result; 492 + 493 + /* 494 + * Using volatile prevents the compiler from determining the value of 495 + * 'size' at compile time. Without that, we would get a compile error 496 + * rather than a runtime error. 497 + */ 498 + volatile int size = 11; 499 + 500 + pr_info("trying to read past the end of a struct\n"); 501 + 502 + result = memcmp(&target[0], &target[1], size); 503 + 504 + /* Print result to prevent the code from being eliminated */ 505 + pr_err("FAIL: fortify did not catch an object overread!\n" 506 + "\"%d\" was the memcmp result.\n", result); 507 + } 508 + 509 + void lkdtm_FORTIFY_SUBOBJECT(void) 510 + { 511 + struct target { 512 + char a[10]; 513 + char b[10]; 514 + } target; 515 + char *src; 516 + 517 + src = kmalloc(20, GFP_KERNEL); 518 + strscpy(src, "over ten bytes", 20); 519 + 520 + pr_info("trying to strcpy past the end of a member of a struct\n"); 521 + 522 + /* 523 + * strncpy(target.a, src, 20); will hit a compile error because the 524 + * compiler knows at build time that target.a < 20 bytes. Use strcpy() 525 + * to force a runtime error. 526 + */ 527 + strcpy(target.a, src); 528 + 529 + /* Use target.a to prevent the code from being eliminated */ 530 + pr_err("FAIL: fortify did not catch an sub-object overrun!\n" 531 + "\"%s\" was copied.\n", target.a); 532 + 533 + kfree(src); 534 + }
+2
drivers/misc/lkdtm/core.c
··· 117 117 CRASHTYPE(UNSET_SMEP), 118 118 CRASHTYPE(CORRUPT_PAC), 119 119 CRASHTYPE(UNALIGNED_LOAD_STORE_WRITE), 120 + CRASHTYPE(FORTIFY_OBJECT), 121 + CRASHTYPE(FORTIFY_SUBOBJECT), 120 122 CRASHTYPE(OVERWRITE_ALLOCATION), 121 123 CRASHTYPE(WRITE_AFTER_FREE), 122 124 CRASHTYPE(READ_AFTER_FREE),
+2
drivers/misc/lkdtm/lkdtm.h
··· 32 32 void lkdtm_UNSET_SMEP(void); 33 33 void lkdtm_DOUBLE_FAULT(void); 34 34 void lkdtm_CORRUPT_PAC(void); 35 + void lkdtm_FORTIFY_OBJECT(void); 36 + void lkdtm_FORTIFY_SUBOBJECT(void); 35 37 36 38 /* lkdtm_heap.c */ 37 39 void __init lkdtm_heap_init(void);