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");
|
pr_err("XFAIL: this test is arm64-only\n");
|
||||||
#endif
|
#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(UNSET_SMEP),
|
||||||
CRASHTYPE(CORRUPT_PAC),
|
CRASHTYPE(CORRUPT_PAC),
|
||||||
CRASHTYPE(UNALIGNED_LOAD_STORE_WRITE),
|
CRASHTYPE(UNALIGNED_LOAD_STORE_WRITE),
|
||||||
|
CRASHTYPE(FORTIFY_OBJECT),
|
||||||
|
CRASHTYPE(FORTIFY_SUBOBJECT),
|
||||||
CRASHTYPE(OVERWRITE_ALLOCATION),
|
CRASHTYPE(OVERWRITE_ALLOCATION),
|
||||||
CRASHTYPE(WRITE_AFTER_FREE),
|
CRASHTYPE(WRITE_AFTER_FREE),
|
||||||
CRASHTYPE(READ_AFTER_FREE),
|
CRASHTYPE(READ_AFTER_FREE),
|
||||||
|
|
|
@ -32,6 +32,8 @@ void lkdtm_STACK_GUARD_PAGE_TRAILING(void);
|
||||||
void lkdtm_UNSET_SMEP(void);
|
void lkdtm_UNSET_SMEP(void);
|
||||||
void lkdtm_DOUBLE_FAULT(void);
|
void lkdtm_DOUBLE_FAULT(void);
|
||||||
void lkdtm_CORRUPT_PAC(void);
|
void lkdtm_CORRUPT_PAC(void);
|
||||||
|
void lkdtm_FORTIFY_OBJECT(void);
|
||||||
|
void lkdtm_FORTIFY_SUBOBJECT(void);
|
||||||
|
|
||||||
/* lkdtm_heap.c */
|
/* lkdtm_heap.c */
|
||||||
void __init lkdtm_heap_init(void);
|
void __init lkdtm_heap_init(void);
|
||||||
|
|
Loading…
Reference in New Issue