Skip to content

Commit

Permalink
drivers/misc/lkdtm: add new file in LKDTM to test fortified strscpy
Browse files Browse the repository at this point in the history
This new test ensures that fortified strscpy has the same behavior than
vanilla strscpy (e.g.  returning -E2BIG when src content is truncated).
Finally, it generates a crash at runtime because there is a write overflow
in destination string.

Link: https://lkml.kernel.org/r/20201122162451.27551-5-laniel_francis@privacyrequired.com
Signed-off-by: Francis Laniel <laniel_francis@privacyrequired.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
Cc: Daniel Axtens <dja@axtens.net>
Cc: Daniel Micay <danielmicay@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
Francis Laniel authored and Linus Torvalds committed Dec 16, 2020
1 parent 33e56a5 commit febebaf
Showing 5 changed files with 88 additions and 0 deletions.
1 change: 1 addition & 0 deletions drivers/misc/lkdtm/Makefile
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@ lkdtm-$(CONFIG_LKDTM) += rodata_objcopy.o
lkdtm-$(CONFIG_LKDTM) += usercopy.o
lkdtm-$(CONFIG_LKDTM) += stackleak.o
lkdtm-$(CONFIG_LKDTM) += cfi.o
lkdtm-$(CONFIG_LKDTM) += fortify.o

KASAN_SANITIZE_rodata.o := n
KASAN_SANITIZE_stackleak.o := n
1 change: 1 addition & 0 deletions drivers/misc/lkdtm/core.c
Original file line number Diff line number Diff line change
@@ -175,6 +175,7 @@ static const struct crashtype crashtypes[] = {
CRASHTYPE(USERCOPY_KERNEL),
CRASHTYPE(STACKLEAK_ERASING),
CRASHTYPE(CFI_FORWARD_PROTO),
CRASHTYPE(FORTIFIED_STRSCPY),
#ifdef CONFIG_X86_32
CRASHTYPE(DOUBLE_FAULT),
#endif
82 changes: 82 additions & 0 deletions drivers/misc/lkdtm/fortify.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2020 Francis Laniel <laniel_francis@privacyrequired.com>
*
* Add tests related to fortified functions in this file.
*/
#include "lkdtm.h"
#include <linux/string.h>
#include <linux/slab.h>


/*
* Calls fortified strscpy to test that it returns the same result as vanilla
* strscpy and generate a panic because there is a write overflow (i.e. src
* length is greater than dst length).
*/
void lkdtm_FORTIFIED_STRSCPY(void)
{
char *src;
char dst[5];

struct {
union {
char big[10];
char src[5];
};
} weird = { .big = "hello!" };
char weird_dst[sizeof(weird.src) + 1];

src = kstrdup("foobar", GFP_KERNEL);

if (src == NULL)
return;

/* Vanilla strscpy returns -E2BIG if size is 0. */
if (strscpy(dst, src, 0) != -E2BIG)
pr_warn("FAIL: strscpy() of 0 length did not return -E2BIG\n");

/* Vanilla strscpy returns -E2BIG if src is truncated. */
if (strscpy(dst, src, sizeof(dst)) != -E2BIG)
pr_warn("FAIL: strscpy() did not return -E2BIG while src is truncated\n");

/* After above call, dst must contain "foob" because src was truncated. */
if (strncmp(dst, "foob", sizeof(dst)) != 0)
pr_warn("FAIL: after strscpy() dst does not contain \"foob\" but \"%s\"\n",
dst);

/* Shrink src so the strscpy() below succeeds. */
src[3] = '\0';

/*
* Vanilla strscpy returns number of character copied if everything goes
* well.
*/
if (strscpy(dst, src, sizeof(dst)) != 3)
pr_warn("FAIL: strscpy() did not return 3 while src was copied entirely truncated\n");

/* After above call, dst must contain "foo" because src was copied. */
if (strncmp(dst, "foo", sizeof(dst)) != 0)
pr_warn("FAIL: after strscpy() dst does not contain \"foo\" but \"%s\"\n",
dst);

/* Test when src is embedded inside a union. */
strscpy(weird_dst, weird.src, sizeof(weird_dst));

if (strcmp(weird_dst, "hello") != 0)
pr_warn("FAIL: after strscpy() weird_dst does not contain \"hello\" but \"%s\"\n",
weird_dst);

/* Restore src to its initial value. */
src[3] = 'b';

/*
* Use strlen here so size cannot be known at compile time and there is
* a runtime write overflow.
*/
strscpy(dst, src, strlen(src));

pr_warn("FAIL: No overflow in above strscpy()\n");

kfree(src);
}
3 changes: 3 additions & 0 deletions drivers/misc/lkdtm/lkdtm.h
Original file line number Diff line number Diff line change
@@ -104,4 +104,7 @@ void lkdtm_STACKLEAK_ERASING(void);
/* cfi.c */
void lkdtm_CFI_FORWARD_PROTO(void);

/* fortify.c */
void lkdtm_FORTIFIED_STRSCPY(void);

#endif
1 change: 1 addition & 0 deletions tools/testing/selftests/lkdtm/tests.txt
Original file line number Diff line number Diff line change
@@ -68,3 +68,4 @@ USERCOPY_STACK_BEYOND
USERCOPY_KERNEL
STACKLEAK_ERASING OK: the rest of the thread stack is properly erased
CFI_FORWARD_PROTO
FORTIFIED_STRSCPY

0 comments on commit febebaf

Please sign in to comment.