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>
This commit is contained in:
parent
6a39e62abb
commit
d96938daae
|
@ -482,3 +482,53 @@ noinline void lkdtm_CORRUPT_PAC(void)
|
|||
pr_err("XFAIL: this test is arm64-only\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void lkdtm_FORTIFY_OBJECT(void)
|
||||
{
|
||||
struct target {
|
||||
char a[10];
|
||||
} target[2] = {};
|
||||
int result;
|
||||
|
||||
/*
|
||||
* Using volatile prevents the compiler from determining the value of
|
||||
* 'size' at compile time. Without that, we would get a compile error
|
||||
* rather than a runtime error.
|
||||
*/
|
||||
volatile int size = 11;
|
||||
|
||||
pr_info("trying to read past the end of a struct\n");
|
||||
|
||||
result = memcmp(&target[0], &target[1], size);
|
||||
|
||||
/* Print result to prevent the code from being eliminated */
|
||||
pr_err("FAIL: fortify did not catch an object overread!\n"
|
||||
"\"%d\" was the memcmp result.\n", result);
|
||||
}
|
||||
|
||||
void lkdtm_FORTIFY_SUBOBJECT(void)
|
||||
{
|
||||
struct target {
|
||||
char a[10];
|
||||
char b[10];
|
||||
} target;
|
||||
char *src;
|
||||
|
||||
src = kmalloc(20, GFP_KERNEL);
|
||||
strscpy(src, "over ten bytes", 20);
|
||||
|
||||
pr_info("trying to strcpy past the end of a member of a struct\n");
|
||||
|
||||
/*
|
||||
* strncpy(target.a, src, 20); will hit a compile error because the
|
||||
* compiler knows at build time that target.a < 20 bytes. Use strcpy()
|
||||
* to force a runtime error.
|
||||
*/
|
||||
strcpy(target.a, src);
|
||||
|
||||
/* Use target.a to prevent the code from being eliminated */
|
||||
pr_err("FAIL: fortify did not catch an sub-object overrun!\n"
|
||||
"\"%s\" was copied.\n", target.a);
|
||||
|
||||
kfree(src);
|
||||
}
|
||||
|
|
|
@ -117,6 +117,8 @@ static const struct crashtype crashtypes[] = {
|
|||
CRASHTYPE(UNSET_SMEP),
|
||||
CRASHTYPE(CORRUPT_PAC),
|
||||
CRASHTYPE(UNALIGNED_LOAD_STORE_WRITE),
|
||||
CRASHTYPE(FORTIFY_OBJECT),
|
||||
CRASHTYPE(FORTIFY_SUBOBJECT),
|
||||
CRASHTYPE(OVERWRITE_ALLOCATION),
|
||||
CRASHTYPE(WRITE_AFTER_FREE),
|
||||
CRASHTYPE(READ_AFTER_FREE),
|
||||
|
|
|
@ -32,6 +32,8 @@ void lkdtm_STACK_GUARD_PAGE_TRAILING(void);
|
|||
void lkdtm_UNSET_SMEP(void);
|
||||
void lkdtm_DOUBLE_FAULT(void);
|
||||
void lkdtm_CORRUPT_PAC(void);
|
||||
void lkdtm_FORTIFY_OBJECT(void);
|
||||
void lkdtm_FORTIFY_SUBOBJECT(void);
|
||||
|
||||
/* lkdtm_heap.c */
|
||||
void __init lkdtm_heap_init(void);
|
||||
|
|
Loading…
Reference in New Issue