2021-06-23 20:40:45

by Kees Cook

[permalink] [raw]
Subject: [PATCH 0/9] LKDTM: Improvements for kernelci.org

This is a bunch of LKDTM clean-ups to improve and expand testing,
given feedback from testing at kernelci.org. Adds a few new tests as
well.

(If a pull-request is preferred, please let me know.)

Thanks!

-Kees

Kees Cook (9):
selftests/lkdtm: Avoid needing explicit sub-shell
selftests/lkdtm: Fix expected text for CR4 pinning
selftests/lkdtm: Fix expected text for free poison
lkdtm/bugs: XFAIL UNALIGNED_LOAD_STORE_WRITE
lkdtm/heap: Add vmalloc linear overflow test
lkdtm: Enable DOUBLE_FAULT on all architectures
lkdtm: Add CONFIG hints in errors where possible
selftests/lkdtm: Enable various testable CONFIGs
lkdtm/heap: Add init_on_alloc tests

drivers/misc/lkdtm/bugs.c | 11 ++-
drivers/misc/lkdtm/cfi.c | 3 +-
drivers/misc/lkdtm/core.c | 58 ++++++++++-
drivers/misc/lkdtm/fortify.c | 3 +-
drivers/misc/lkdtm/heap.c | 97 ++++++++++++++++++-
drivers/misc/lkdtm/lkdtm.h | 46 ++++++++-
drivers/misc/lkdtm/stackleak.c | 4 +-
drivers/misc/lkdtm/usercopy.c | 7 +-
tools/testing/selftests/lkdtm/config | 7 ++
tools/testing/selftests/lkdtm/run.sh | 12 ++-
.../testing/selftests/lkdtm/stack-entropy.sh | 1 +
tools/testing/selftests/lkdtm/tests.txt | 11 ++-
12 files changed, 236 insertions(+), 24 deletions(-)

--
2.30.2


2021-06-23 20:40:48

by Kees Cook

[permalink] [raw]
Subject: [PATCH 1/9] selftests/lkdtm: Avoid needing explicit sub-shell

Some environments do not set $SHELL when running tests. There's no
need to use $SHELL here anyway, since "cat" can be used to receive any
delivered signals from the kernel. Additionally avoid using bash-isms
in the command, and record stderr for posterity.

Suggested-by: Guillaume Tucker <[email protected]>
Suggested-by: David Laight <[email protected]>
Fixes: 46d1a0f03d66 ("selftests/lkdtm: Add tests for LKDTM targets")
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
tools/testing/selftests/lkdtm/run.sh | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/tools/testing/selftests/lkdtm/run.sh b/tools/testing/selftests/lkdtm/run.sh
index bb7a1775307b..e95e79bd3126 100755
--- a/tools/testing/selftests/lkdtm/run.sh
+++ b/tools/testing/selftests/lkdtm/run.sh
@@ -76,10 +76,14 @@ fi
# Save existing dmesg so we can detect new content below
dmesg > "$DMESG"

-# Most shells yell about signals and we're expecting the "cat" process
-# to usually be killed by the kernel. So we have to run it in a sub-shell
-# and silence errors.
-($SHELL -c 'cat <(echo '"$test"') >'"$TRIGGER" 2>/dev/null) || true
+# Since the kernel is likely killing the process writing to the trigger
+# file, it must not be the script's shell itself. i.e. we cannot do:
+# echo "$test" >"$TRIGGER"
+# Instead, use "cat" to take the signal. Since the shell will yell about
+# the signal that killed the subprocess, we must ignore the failure and
+# continue. However we don't silence stderr since there might be other
+# useful details reported there in the case of other unexpected conditions.
+echo "$test" | cat >"$TRIGGER" || true

# Record and dump the results
dmesg | comm --nocheck-order -13 "$DMESG" - > "$LOG" || true
--
2.30.2

2021-06-23 20:40:50

by Kees Cook

[permalink] [raw]
Subject: [PATCH 4/9] lkdtm/bugs: XFAIL UNALIGNED_LOAD_STORE_WRITE

When built under CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS, this test is
expected to fail (i.e. not trip an exception).

Fixes: 46d1a0f03d66 ("selftests/lkdtm: Add tests for LKDTM targets")
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
drivers/misc/lkdtm/bugs.c | 3 +++
1 file changed, 3 insertions(+)

diff --git a/drivers/misc/lkdtm/bugs.c b/drivers/misc/lkdtm/bugs.c
index 0e8254d0cf0b..9ff02bdf3153 100644
--- a/drivers/misc/lkdtm/bugs.c
+++ b/drivers/misc/lkdtm/bugs.c
@@ -161,6 +161,9 @@ void lkdtm_UNALIGNED_LOAD_STORE_WRITE(void)
if (*p == 0)
val = 0x87654321;
*p = val;
+
+ if (IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS))
+ pr_err("XFAIL: arch has CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS\n");
}

void lkdtm_SOFTLOCKUP(void)
--
2.30.2

2021-06-23 20:40:54

by Kees Cook

[permalink] [raw]
Subject: [PATCH 5/9] lkdtm/heap: Add vmalloc linear overflow test

Similar to the existing slab overflow and stack exhaustion tests, add
VMALLOC_LINEAR_OVERFLOW (and rename the slab test SLAB_LINEAR_OVERFLOW).
Additionally unmarks the test as destructive. (It should be safe in the
face of misbehavior.)

Signed-off-by: Kees Cook <[email protected]>
---
drivers/misc/lkdtm/core.c | 3 ++-
drivers/misc/lkdtm/heap.c | 22 +++++++++++++++++++++-
drivers/misc/lkdtm/lkdtm.h | 3 ++-
tools/testing/selftests/lkdtm/tests.txt | 3 ++-
4 files changed, 27 insertions(+), 4 deletions(-)

diff --git a/drivers/misc/lkdtm/core.c b/drivers/misc/lkdtm/core.c
index 8024b6a5cc7f..645b31e98c77 100644
--- a/drivers/misc/lkdtm/core.c
+++ b/drivers/misc/lkdtm/core.c
@@ -120,7 +120,8 @@ static const struct crashtype crashtypes[] = {
CRASHTYPE(UNALIGNED_LOAD_STORE_WRITE),
CRASHTYPE(FORTIFY_OBJECT),
CRASHTYPE(FORTIFY_SUBOBJECT),
- CRASHTYPE(OVERWRITE_ALLOCATION),
+ CRASHTYPE(SLAB_LINEAR_OVERFLOW),
+ CRASHTYPE(VMALLOC_LINEAR_OVERFLOW),
CRASHTYPE(WRITE_AFTER_FREE),
CRASHTYPE(READ_AFTER_FREE),
CRASHTYPE(WRITE_BUDDY_AFTER_FREE),
diff --git a/drivers/misc/lkdtm/heap.c b/drivers/misc/lkdtm/heap.c
index 1323bc16f113..36be5e353cd0 100644
--- a/drivers/misc/lkdtm/heap.c
+++ b/drivers/misc/lkdtm/heap.c
@@ -5,24 +5,44 @@
*/
#include "lkdtm.h"
#include <linux/slab.h>
+#include <linux/vmalloc.h>
#include <linux/sched.h>

static struct kmem_cache *double_free_cache;
static struct kmem_cache *a_cache;
static struct kmem_cache *b_cache;

+/*
+ * If there aren't guard pages, it's likely that a consecutive allocation will
+ * let us overflow into the second allocation without overwriting something real.
+ */
+void lkdtm_VMALLOC_LINEAR_OVERFLOW(void)
+{
+ char *one, *two;
+
+ one = vzalloc(PAGE_SIZE);
+ two = vzalloc(PAGE_SIZE);
+
+ pr_info("Attempting vmalloc linear overflow ...\n");
+ memset(one, 0xAA, PAGE_SIZE + 1);
+
+ vfree(two);
+ vfree(one);
+}
+
/*
* This tries to stay within the next largest power-of-2 kmalloc cache
* to avoid actually overwriting anything important if it's not detected
* correctly.
*/
-void lkdtm_OVERWRITE_ALLOCATION(void)
+void lkdtm_SLAB_LINEAR_OVERFLOW(void)
{
size_t len = 1020;
u32 *data = kmalloc(len, GFP_KERNEL);
if (!data)
return;

+ pr_info("Attempting slab linear overflow ...\n");
data[1024 / sizeof(u32)] = 0x12345678;
kfree(data);
}
diff --git a/drivers/misc/lkdtm/lkdtm.h b/drivers/misc/lkdtm/lkdtm.h
index 99f90d3e5e9c..c6baf4f1e1db 100644
--- a/drivers/misc/lkdtm/lkdtm.h
+++ b/drivers/misc/lkdtm/lkdtm.h
@@ -39,7 +39,8 @@ void lkdtm_FORTIFY_SUBOBJECT(void);
/* heap.c */
void __init lkdtm_heap_init(void);
void __exit lkdtm_heap_exit(void);
-void lkdtm_OVERWRITE_ALLOCATION(void);
+void lkdtm_VMALLOC_LINEAR_OVERFLOW(void);
+void lkdtm_SLAB_LINEAR_OVERFLOW(void);
void lkdtm_WRITE_AFTER_FREE(void);
void lkdtm_READ_AFTER_FREE(void);
void lkdtm_WRITE_BUDDY_AFTER_FREE(void);
diff --git a/tools/testing/selftests/lkdtm/tests.txt b/tools/testing/selftests/lkdtm/tests.txt
index a94d4d8eeb5c..30080cc15623 100644
--- a/tools/testing/selftests/lkdtm/tests.txt
+++ b/tools/testing/selftests/lkdtm/tests.txt
@@ -15,7 +15,8 @@ UNSET_SMEP pinned CR4 bits changed:
DOUBLE_FAULT
CORRUPT_PAC
UNALIGNED_LOAD_STORE_WRITE
-#OVERWRITE_ALLOCATION Corrupts memory on failure
+SLAB_LINEAR_OVERFLOW
+VMALLOC_LINEAR_OVERFLOW
#WRITE_AFTER_FREE Corrupts memory on failure
READ_AFTER_FREE call trace:|Memory correctly poisoned
#WRITE_BUDDY_AFTER_FREE Corrupts memory on failure
--
2.30.2

2021-06-23 20:40:56

by Kees Cook

[permalink] [raw]
Subject: [PATCH 3/9] selftests/lkdtm: Fix expected text for free poison

Freed memory poisoning can be tested a few ways, so update the expected
text to reflect the non-Oopsing alternative.

Signed-off-by: Kees Cook <[email protected]>
---
tools/testing/selftests/lkdtm/tests.txt | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/tools/testing/selftests/lkdtm/tests.txt b/tools/testing/selftests/lkdtm/tests.txt
index a5fce7fd4520..a94d4d8eeb5c 100644
--- a/tools/testing/selftests/lkdtm/tests.txt
+++ b/tools/testing/selftests/lkdtm/tests.txt
@@ -17,9 +17,9 @@ CORRUPT_PAC
UNALIGNED_LOAD_STORE_WRITE
#OVERWRITE_ALLOCATION Corrupts memory on failure
#WRITE_AFTER_FREE Corrupts memory on failure
-READ_AFTER_FREE
+READ_AFTER_FREE call trace:|Memory correctly poisoned
#WRITE_BUDDY_AFTER_FREE Corrupts memory on failure
-READ_BUDDY_AFTER_FREE
+READ_BUDDY_AFTER_FREE call trace:|Memory correctly poisoned
SLAB_FREE_DOUBLE
SLAB_FREE_CROSS
SLAB_FREE_PAGE
--
2.30.2

2021-06-23 20:40:59

by Kees Cook

[permalink] [raw]
Subject: [PATCH 8/9] selftests/lkdtm: Enable various testable CONFIGs

Add a handful of LKDTM-testable features that depend on certain CONFIGs
so that they are visible in logs for CI systems that run the selftests.
Others could be added, but may be seen as having too high a trade-off
for general testing.

Cc: [email protected]
Suggested-by: Guillaume Tucker <[email protected]>
Signed-off-by: Kees Cook <[email protected]>
---
tools/testing/selftests/lkdtm/config | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/tools/testing/selftests/lkdtm/config b/tools/testing/selftests/lkdtm/config
index d874990e442b..849799bcfa95 100644
--- a/tools/testing/selftests/lkdtm/config
+++ b/tools/testing/selftests/lkdtm/config
@@ -1 +1,7 @@
CONFIG_LKDTM=y
+CONFIG_DEBUG_LIST=y
+CONFIG_SLAB_FREELIST_HARDENED=y
+CONFIG_FORTIFY_SOURCE=y
+CONFIG_HARDENED_USERCOPY=y
+# CONFIG_HARDENED_USERCOPY_FALLBACK is not set
+CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT=y
--
2.30.2

2021-06-23 20:41:21

by Kees Cook

[permalink] [raw]
Subject: [PATCH 6/9] lkdtm: Enable DOUBLE_FAULT on all architectures

Where feasible, I prefer to have all tests visible on all architectures,
but to have them wired to XFAIL. DOUBLE_FAIL was set up to XFAIL, but
wasn't actually being added to the test list.

Fixes: cea23efb4de2 ("lkdtm/bugs: Make double-fault test always available")
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
drivers/misc/lkdtm/core.c | 2 --
1 file changed, 2 deletions(-)

diff --git a/drivers/misc/lkdtm/core.c b/drivers/misc/lkdtm/core.c
index 645b31e98c77..2c89fc18669f 100644
--- a/drivers/misc/lkdtm/core.c
+++ b/drivers/misc/lkdtm/core.c
@@ -178,9 +178,7 @@ static const struct crashtype crashtypes[] = {
CRASHTYPE(STACKLEAK_ERASING),
CRASHTYPE(CFI_FORWARD_PROTO),
CRASHTYPE(FORTIFIED_STRSCPY),
-#ifdef CONFIG_X86_32
CRASHTYPE(DOUBLE_FAULT),
-#endif
#ifdef CONFIG_PPC_BOOK3S_64
CRASHTYPE(PPC_SLB_MULTIHIT),
#endif
--
2.30.2

2021-06-23 20:42:00

by Kees Cook

[permalink] [raw]
Subject: [PATCH 9/9] lkdtm/heap: Add init_on_alloc tests

Add SLAB and page allocator tests for init_on_alloc. Testing for
init_on_free was already happening via the poisoning tests.

Signed-off-by: Kees Cook <[email protected]>
---
drivers/misc/lkdtm/core.c | 2 +
drivers/misc/lkdtm/heap.c | 65 +++++++++++++++++++++++++
drivers/misc/lkdtm/lkdtm.h | 2 +
tools/testing/selftests/lkdtm/config | 1 +
tools/testing/selftests/lkdtm/tests.txt | 2 +
5 files changed, 72 insertions(+)

diff --git a/drivers/misc/lkdtm/core.c b/drivers/misc/lkdtm/core.c
index c185ae4719c3..9dda87c6b54a 100644
--- a/drivers/misc/lkdtm/core.c
+++ b/drivers/misc/lkdtm/core.c
@@ -127,6 +127,8 @@ static const struct crashtype crashtypes[] = {
CRASHTYPE(READ_AFTER_FREE),
CRASHTYPE(WRITE_BUDDY_AFTER_FREE),
CRASHTYPE(READ_BUDDY_AFTER_FREE),
+ CRASHTYPE(SLAB_INIT_ON_ALLOC),
+ CRASHTYPE(BUDDY_INIT_ON_ALLOC),
CRASHTYPE(SLAB_FREE_DOUBLE),
CRASHTYPE(SLAB_FREE_CROSS),
CRASHTYPE(SLAB_FREE_PAGE),
diff --git a/drivers/misc/lkdtm/heap.c b/drivers/misc/lkdtm/heap.c
index a3bb0577ed8b..3d9aae5821a0 100644
--- a/drivers/misc/lkdtm/heap.c
+++ b/drivers/misc/lkdtm/heap.c
@@ -174,6 +174,71 @@ void lkdtm_READ_BUDDY_AFTER_FREE(void)
kfree(val);
}

+void lkdtm_SLAB_INIT_ON_ALLOC(void)
+{
+ u8 *first;
+ u8 *val;
+
+ first = kmalloc(512, GFP_KERNEL);
+ if (!first) {
+ pr_info("Unable to allocate 512 bytes the first time.\n");
+ return;
+ }
+
+ memset(first, 0xAB, 512);
+ kfree(first);
+
+ val = kmalloc(512, GFP_KERNEL);
+ if (!val) {
+ pr_info("Unable to allocate 512 bytes the second time.\n");
+ return;
+ }
+ if (val != first) {
+ pr_warn("Reallocation missed clobbered memory.\n");
+ }
+
+ if (memchr(val, 0xAB, 512) == NULL) {
+ pr_info("Memory appears initialized (%x, no earlier values)\n", *val);
+ } else {
+ pr_err("FAIL: Slab was not initialized\n");
+ pr_expected_config_param(CONFIG_INIT_ON_ALLOC_DEFAULT_ON, "init_on_alloc");
+ }
+ kfree(val);
+}
+
+void lkdtm_BUDDY_INIT_ON_ALLOC(void)
+{
+ u8 *first;
+ u8 *val;
+
+ first = (u8 *)__get_free_page(GFP_KERNEL);
+ if (!first) {
+ pr_info("Unable to allocate first free page\n");
+ return;
+ }
+
+ memset(first, 0xAB, PAGE_SIZE);
+ free_page((unsigned long)first);
+
+ val = (u8 *)__get_free_page(GFP_KERNEL);
+ if (!val) {
+ pr_info("Unable to allocate second free page\n");
+ return;
+ }
+
+ if (val != first) {
+ pr_warn("Reallocation missed clobbered memory.\n");
+ }
+
+ if (memchr(val, 0xAB, PAGE_SIZE) == NULL) {
+ pr_info("Memory appears initialized (%x, no earlier values)\n", *val);
+ } else {
+ pr_err("FAIL: Slab was not initialized\n");
+ pr_expected_config_param(CONFIG_INIT_ON_ALLOC_DEFAULT_ON, "init_on_alloc");
+ }
+ free_page((unsigned long)val);
+}
+
void lkdtm_SLAB_FREE_DOUBLE(void)
{
int *val;
diff --git a/drivers/misc/lkdtm/lkdtm.h b/drivers/misc/lkdtm/lkdtm.h
index e491bc571808..6a30b60519f3 100644
--- a/drivers/misc/lkdtm/lkdtm.h
+++ b/drivers/misc/lkdtm/lkdtm.h
@@ -86,6 +86,8 @@ void lkdtm_WRITE_AFTER_FREE(void);
void lkdtm_READ_AFTER_FREE(void);
void lkdtm_WRITE_BUDDY_AFTER_FREE(void);
void lkdtm_READ_BUDDY_AFTER_FREE(void);
+void lkdtm_SLAB_INIT_ON_ALLOC(void);
+void lkdtm_BUDDY_INIT_ON_ALLOC(void);
void lkdtm_SLAB_FREE_DOUBLE(void);
void lkdtm_SLAB_FREE_CROSS(void);
void lkdtm_SLAB_FREE_PAGE(void);
diff --git a/tools/testing/selftests/lkdtm/config b/tools/testing/selftests/lkdtm/config
index 849799bcfa95..013446e87f1f 100644
--- a/tools/testing/selftests/lkdtm/config
+++ b/tools/testing/selftests/lkdtm/config
@@ -5,3 +5,4 @@ CONFIG_FORTIFY_SOURCE=y
CONFIG_HARDENED_USERCOPY=y
# CONFIG_HARDENED_USERCOPY_FALLBACK is not set
CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT=y
+CONFIG_INIT_ON_ALLOC_DEFAULT_ON=y
diff --git a/tools/testing/selftests/lkdtm/tests.txt b/tools/testing/selftests/lkdtm/tests.txt
index 30080cc15623..846cfd508d3c 100644
--- a/tools/testing/selftests/lkdtm/tests.txt
+++ b/tools/testing/selftests/lkdtm/tests.txt
@@ -21,6 +21,8 @@ VMALLOC_LINEAR_OVERFLOW
READ_AFTER_FREE call trace:|Memory correctly poisoned
#WRITE_BUDDY_AFTER_FREE Corrupts memory on failure
READ_BUDDY_AFTER_FREE call trace:|Memory correctly poisoned
+SLAB_INIT_ON_ALLOC Memory appears initialized
+BUDDY_INIT_ON_ALLOC Memory appears initialized
SLAB_FREE_DOUBLE
SLAB_FREE_CROSS
SLAB_FREE_PAGE
--
2.30.2

2021-06-23 20:42:38

by Kees Cook

[permalink] [raw]
Subject: [PATCH 7/9] lkdtm: Add CONFIG hints in errors where possible

For various failure conditions, try to include some details about where
to look for reasons about the failure.

Signed-off-by: Kees Cook <[email protected]>
---
drivers/misc/lkdtm/bugs.c | 8 ++-
drivers/misc/lkdtm/cfi.c | 3 +-
drivers/misc/lkdtm/core.c | 51 +++++++++++++++++++
drivers/misc/lkdtm/fortify.c | 3 +-
drivers/misc/lkdtm/heap.c | 10 ++--
drivers/misc/lkdtm/lkdtm.h | 41 +++++++++++++++
drivers/misc/lkdtm/stackleak.c | 4 +-
drivers/misc/lkdtm/usercopy.c | 7 ++-
.../testing/selftests/lkdtm/stack-entropy.sh | 1 +
9 files changed, 117 insertions(+), 11 deletions(-)

diff --git a/drivers/misc/lkdtm/bugs.c b/drivers/misc/lkdtm/bugs.c
index 9ff02bdf3153..7c7335506c45 100644
--- a/drivers/misc/lkdtm/bugs.c
+++ b/drivers/misc/lkdtm/bugs.c
@@ -303,8 +303,10 @@ void lkdtm_CORRUPT_LIST_ADD(void)

if (target[0] == NULL && target[1] == NULL)
pr_err("Overwrite did not happen, but no BUG?!\n");
- else
+ else {
pr_err("list_add() corruption not detected!\n");
+ pr_expected_config(CONFIG_DEBUG_LIST);
+ }
}

void lkdtm_CORRUPT_LIST_DEL(void)
@@ -328,8 +330,10 @@ void lkdtm_CORRUPT_LIST_DEL(void)

if (target[0] == NULL && target[1] == NULL)
pr_err("Overwrite did not happen, but no BUG?!\n");
- else
+ else {
pr_err("list_del() corruption not detected!\n");
+ pr_expected_config(CONFIG_DEBUG_LIST);
+ }
}

/* Test that VMAP_STACK is actually allocating with a leading guard page */
diff --git a/drivers/misc/lkdtm/cfi.c b/drivers/misc/lkdtm/cfi.c
index e73ebdbfa806..c9aeddef1044 100644
--- a/drivers/misc/lkdtm/cfi.c
+++ b/drivers/misc/lkdtm/cfi.c
@@ -38,5 +38,6 @@ void lkdtm_CFI_FORWARD_PROTO(void)
func = (void *)lkdtm_increment_int;
func(&called_count);

- pr_info("Fail: survived mismatched prototype function call!\n");
+ pr_err("FAIL: survived mismatched prototype function call!\n");
+ pr_expected_config(CONFIG_CFI_CLANG);
}
diff --git a/drivers/misc/lkdtm/core.c b/drivers/misc/lkdtm/core.c
index 2c89fc18669f..c185ae4719c3 100644
--- a/drivers/misc/lkdtm/core.c
+++ b/drivers/misc/lkdtm/core.c
@@ -26,6 +26,7 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/debugfs.h>
+#include <linux/init.h>

#define DEFAULT_COUNT 10

@@ -398,6 +399,56 @@ static ssize_t direct_entry(struct file *f, const char __user *user_buf,
return count;
}

+#ifndef MODULE
+/*
+ * To avoid needing to export parse_args(), just don't use this code
+ * when LKDTM is built as a module.
+ */
+struct check_cmdline_args {
+ const char *param;
+ int value;
+};
+
+static int lkdtm_parse_one(char *param, char *val,
+ const char *unused, void *arg)
+{
+ struct check_cmdline_args *args = arg;
+
+ /* short circuit if we already found a value. */
+ if (args->value != -ESRCH)
+ return 0;
+ if (strncmp(param, args->param, strlen(args->param)) == 0) {
+ bool bool_result;
+ int ret;
+
+ ret = kstrtobool(val, &bool_result);
+ if (ret == 0)
+ args->value = bool_result;
+ }
+ return 0;
+}
+
+int lkdtm_check_bool_cmdline(const char *param)
+{
+ char *command_line;
+ struct check_cmdline_args args = {
+ .param = param,
+ .value = -ESRCH,
+ };
+
+ command_line = kstrdup(saved_command_line, GFP_KERNEL);
+ if (!command_line)
+ return -ENOMEM;
+
+ parse_args("Setting sysctl args", command_line,
+ NULL, 0, -1, -1, &args, lkdtm_parse_one);
+
+ kfree(command_line);
+
+ return args.value;
+}
+#endif
+
static struct dentry *lkdtm_debugfs_root;

static int __init lkdtm_module_init(void)
diff --git a/drivers/misc/lkdtm/fortify.c b/drivers/misc/lkdtm/fortify.c
index faf29cf04baa..0f51d31b57ca 100644
--- a/drivers/misc/lkdtm/fortify.c
+++ b/drivers/misc/lkdtm/fortify.c
@@ -76,7 +76,8 @@ void lkdtm_FORTIFIED_STRSCPY(void)
*/
strscpy(dst, src, strlen(src));

- pr_warn("FAIL: No overflow in above strscpy()\n");
+ pr_err("FAIL: strscpy() overflow not detected!\n");
+ pr_expected_config(CONFIG_FORTIFY_SOURCE);

kfree(src);
}
diff --git a/drivers/misc/lkdtm/heap.c b/drivers/misc/lkdtm/heap.c
index 36be5e353cd0..a3bb0577ed8b 100644
--- a/drivers/misc/lkdtm/heap.c
+++ b/drivers/misc/lkdtm/heap.c
@@ -109,9 +109,10 @@ void lkdtm_READ_AFTER_FREE(void)
if (saw != *val) {
/* Good! Poisoning happened, so declare a win. */
pr_info("Memory correctly poisoned (%x)\n", saw);
- BUG();
+ } else {
+ pr_err("FAIL: Memory was not poisoned!\n");
+ pr_expected_config_param(CONFIG_INIT_ON_FREE_DEFAULT_ON, "init_on_free");
}
- pr_info("Memory was not poisoned\n");

kfree(val);
}
@@ -165,9 +166,10 @@ void lkdtm_READ_BUDDY_AFTER_FREE(void)
if (saw != *val) {
/* Good! Poisoning happened, so declare a win. */
pr_info("Memory correctly poisoned (%x)\n", saw);
- BUG();
+ } else {
+ pr_err("FAIL: Buddy page was not poisoned!\n");
+ pr_expected_config_param(CONFIG_INIT_ON_FREE_DEFAULT_ON, "init_on_free");
}
- pr_info("Buddy page was not poisoned\n");

kfree(val);
}
diff --git a/drivers/misc/lkdtm/lkdtm.h b/drivers/misc/lkdtm/lkdtm.h
index c6baf4f1e1db..e491bc571808 100644
--- a/drivers/misc/lkdtm/lkdtm.h
+++ b/drivers/misc/lkdtm/lkdtm.h
@@ -6,6 +6,47 @@

#include <linux/kernel.h>

+#define pr_expected_config(kconfig) \
+{ \
+ if (IS_ENABLED(kconfig)) \
+ pr_err("Unexpected! This kernel was built with " #kconfig "=y\n"); \
+ else \
+ pr_warn("This is probably expected, since this kernel was built *without* " #kconfig "=y\n"); \
+}
+
+#ifndef MODULE
+int lkdtm_check_bool_cmdline(const char *param);
+#define pr_expected_config_param(kconfig, param) \
+{ \
+ if (IS_ENABLED(kconfig)) { \
+ switch (lkdtm_check_bool_cmdline(param)) { \
+ case 0: \
+ pr_warn("This is probably expected, since this kernel was built with " #kconfig "=y but booted with '" param "=N'\n"); \
+ break; \
+ case 1: \
+ pr_err("Unexpected! This kernel was built with " #kconfig "=y and booted with '" param "=Y'\n"); \
+ break; \
+ default: \
+ pr_err("Unexpected! This kernel was built with " #kconfig "=y (and booted without '" param "' specified)\n"); \
+ } \
+ } else { \
+ switch (lkdtm_check_bool_cmdline(param)) { \
+ case 0: \
+ pr_warn("This is probably expected, as kernel was built *without* " #kconfig "=y and booted with '" param "=N'\n"); \
+ break; \
+ case 1: \
+ pr_err("Unexpected! This kernel was built *without* " #kconfig "=y but booted with '" param "=Y'\n"); \
+ break; \
+ default: \
+ pr_err("This is probably expected, since this kernel was built *without* " #kconfig "=y (and booted without '" param "' specified)\n"); \
+ break; \
+ } \
+ } \
+}
+#else
+#define pr_expected_config_param(kconfig, param) pr_expected_config(kconfig)
+#endif
+
/* bugs.c */
void __init lkdtm_bugs_init(int *recur_param);
void lkdtm_PANIC(void);
diff --git a/drivers/misc/lkdtm/stackleak.c b/drivers/misc/lkdtm/stackleak.c
index d1a5c0705be3..00db21ff115e 100644
--- a/drivers/misc/lkdtm/stackleak.c
+++ b/drivers/misc/lkdtm/stackleak.c
@@ -74,8 +74,8 @@ void lkdtm_STACKLEAK_ERASING(void)

end:
if (test_failed) {
- pr_err("FAIL: the thread stack is NOT properly erased\n");
- dump_stack();
+ pr_err("FAIL: the thread stack is NOT properly erased!\n");
+ pr_expected_config(CONFIG_GCC_PLUGIN_STACKLEAK);
} else {
pr_info("OK: the rest of the thread stack is properly erased\n");
}
diff --git a/drivers/misc/lkdtm/usercopy.c b/drivers/misc/lkdtm/usercopy.c
index 15d220ef35a5..9161ce7ed47a 100644
--- a/drivers/misc/lkdtm/usercopy.c
+++ b/drivers/misc/lkdtm/usercopy.c
@@ -173,6 +173,8 @@ static void do_usercopy_heap_size(bool to_user)
goto free_user;
}
}
+ pr_err("FAIL: bad usercopy not detected!\n");
+ pr_expected_config_param(CONFIG_HARDENED_USERCOPY, "hardened_usercopy");

free_user:
vm_munmap(user_addr, PAGE_SIZE);
@@ -248,6 +250,8 @@ static void do_usercopy_heap_whitelist(bool to_user)
goto free_user;
}
}
+ pr_err("FAIL: bad usercopy not detected!\n");
+ pr_expected_config_param(CONFIG_HARDENED_USERCOPY, "hardened_usercopy");

free_user:
vm_munmap(user_alloc, PAGE_SIZE);
@@ -319,7 +323,8 @@ void lkdtm_USERCOPY_KERNEL(void)
pr_warn("copy_to_user failed, but lacked Oops\n");
goto free_user;
}
- pr_err("FAIL: survived bad copy_to_user()\n");
+ pr_err("FAIL: bad copy_to_user() not detected!\n");
+ pr_expected_config_param(CONFIG_HARDENED_USERCOPY, "hardened_usercopy");

free_user:
vm_munmap(user_addr, PAGE_SIZE);
diff --git a/tools/testing/selftests/lkdtm/stack-entropy.sh b/tools/testing/selftests/lkdtm/stack-entropy.sh
index b1b8a5097cbb..1b4d95d575f8 100755
--- a/tools/testing/selftests/lkdtm/stack-entropy.sh
+++ b/tools/testing/selftests/lkdtm/stack-entropy.sh
@@ -30,6 +30,7 @@ rm -f "$log"

# We would expect any functional stack randomization to be at least 5 bits.
if [ "$bits" -lt 5 ]; then
+ echo "Stack entropy is low! Booted without 'randomize_kstack_offset=y'?"
exit 1
else
exit 0
--
2.30.2

2021-06-24 13:34:45

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH 0/9] LKDTM: Improvements for kernelci.org

On Wed, Jun 23, 2021 at 01:39:27PM -0700, Kees Cook wrote:
> This is a bunch of LKDTM clean-ups to improve and expand testing,
> given feedback from testing at kernelci.org. Adds a few new tests as
> well.
>
> (If a pull-request is preferred, please let me know.)

This works, thanks!

greg k-h

2021-06-25 06:23:19

by Guillaume Tucker

[permalink] [raw]
Subject: Re: [PATCH 0/9] LKDTM: Improvements for kernelci.org

On 23/06/2021 21:39, Kees Cook wrote:
> This is a bunch of LKDTM clean-ups to improve and expand testing,
> given feedback from testing at kernelci.org. Adds a few new tests as
> well.
>
> (If a pull-request is preferred, please let me know.)
>
> Thanks!
>
> -Kees
>
> Kees Cook (9):
> selftests/lkdtm: Avoid needing explicit sub-shell
> selftests/lkdtm: Fix expected text for CR4 pinning
> selftests/lkdtm: Fix expected text for free poison
> lkdtm/bugs: XFAIL UNALIGNED_LOAD_STORE_WRITE
> lkdtm/heap: Add vmalloc linear overflow test
> lkdtm: Enable DOUBLE_FAULT on all architectures
> lkdtm: Add CONFIG hints in errors where possible
> selftests/lkdtm: Enable various testable CONFIGs
> lkdtm/heap: Add init_on_alloc tests

Tested-by: "kernelci.org bot" <[email protected]>


This whole series was tested on top of next-20210623, here are a
couple of sample results from KernelCI staging:

Clang 13 on AMD x86_64:
https://staging.kernelci.org/test/plan/id/60d4a5ce3d2bc535d924bf25/

GCC 8 on Intel x86_64:
https://staging.kernelci.org/test/plan/id/60d570711a3d6beefe24bf26/

And this is where the series was applied:
https://github.com/kernelci/linux/commits/a9f4387015268e426c77fd51ed846c9756938828


Thanks,
Guillaume

2021-06-26 06:14:52

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH 0/9] LKDTM: Improvements for kernelci.org

On Fri, Jun 25, 2021 at 07:22:01AM +0100, Guillaume Tucker wrote:
> On 23/06/2021 21:39, Kees Cook wrote:
> > This is a bunch of LKDTM clean-ups to improve and expand testing,
> > given feedback from testing at kernelci.org. Adds a few new tests as
> > well.
> >
> > (If a pull-request is preferred, please let me know.)
> >
> > Thanks!
> >
> > -Kees
> >
> > Kees Cook (9):
> > selftests/lkdtm: Avoid needing explicit sub-shell
> > selftests/lkdtm: Fix expected text for CR4 pinning
> > selftests/lkdtm: Fix expected text for free poison
> > lkdtm/bugs: XFAIL UNALIGNED_LOAD_STORE_WRITE
> > lkdtm/heap: Add vmalloc linear overflow test
> > lkdtm: Enable DOUBLE_FAULT on all architectures
> > lkdtm: Add CONFIG hints in errors where possible
> > selftests/lkdtm: Enable various testable CONFIGs
> > lkdtm/heap: Add init_on_alloc tests
>
> Tested-by: "kernelci.org bot" <[email protected]>
>
>
> This whole series was tested on top of next-20210623, here are a
> couple of sample results from KernelCI staging:
>
> Clang 13 on AMD x86_64:
> https://staging.kernelci.org/test/plan/id/60d4a5ce3d2bc535d924bf25/
>
> GCC 8 on Intel x86_64:
> https://staging.kernelci.org/test/plan/id/60d570711a3d6beefe24bf26/
>
> And this is where the series was applied:
> https://github.com/kernelci/linux/commits/a9f4387015268e426c77fd51ed846c9756938828

Fantastic! Thanks; this looks great. :)

--
Kees Cook