Skip to content

Commit

Permalink
lkdtm: tests for FORTIFY_SOURCE
Browse files Browse the repository at this point in the history
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/[email protected]
Signed-off-by: Daniel Axtens <[email protected]>
Signed-off-by: Francis Laniel <[email protected]>
Suggested-by: Kees Cook <[email protected]>
Reviewed-by: Kees Cook <[email protected]>
Cc: Daniel Micay <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
daxtens authored and torvalds committed Dec 16, 2020
1 parent 6a39e62 commit d96938d
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 0 deletions.
50 changes: 50 additions & 0 deletions drivers/misc/lkdtm/bugs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
2 changes: 2 additions & 0 deletions drivers/misc/lkdtm/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
2 changes: 2 additions & 0 deletions drivers/misc/lkdtm/lkdtm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit d96938d

Please sign in to comment.