From 42db2594e4cd4a3c29aad87f80b1c00bf7751afe Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 16 Feb 2022 10:20:47 -0800 Subject: lkdtm/heap: Note conditions for SLAB_LINEAR_OVERFLOW It wasn't clear when SLAB_LINEAR_OVERFLOW would be expected to trip. Explicitly describe it and include the CONFIGs in the kselftest. Cc: Muhammad Usama Anjum Cc: Arnd Bergmann Cc: Greg Kroah-Hartman Cc: Shuah Khan Cc: linux-kselftest@vger.kernel.org Signed-off-by: Kees Cook --- tools/testing/selftests/lkdtm/config | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tools') diff --git a/tools/testing/selftests/lkdtm/config b/tools/testing/selftests/lkdtm/config index 46f39ee76208..304123688739 100644 --- a/tools/testing/selftests/lkdtm/config +++ b/tools/testing/selftests/lkdtm/config @@ -9,3 +9,5 @@ CONFIG_UBSAN=y CONFIG_UBSAN_BOUNDS=y CONFIG_UBSAN_TRAP=y CONFIG_STACKPROTECTOR_STRONG=y +CONFIG_SLUB_DEBUG=y +CONFIG_SLUB_DEBUG_ON=y -- cgit v1.2.3 From 2e53b877dc1258d4ac3de98f496bb88ec3bf5e25 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 11 Mar 2022 12:00:42 -0800 Subject: lkdtm: Add CFI_BACKWARD to test ROP mitigations In order to test various backward-edge control flow integrity methods, add a test that manipulates the return address on the stack. Currently only arm64 Pointer Authentication and Shadow Call Stack is supported. $ echo CFI_BACKWARD | cat >/sys/kernel/debug/provoke-crash/DIRECT Under SCS, successful test of the mitigation is reported as: lkdtm: Performing direct entry CFI_BACKWARD lkdtm: Attempting unchecked stack return address redirection ... lkdtm: ok: redirected stack return address. lkdtm: Attempting checked stack return address redirection ... lkdtm: ok: control flow unchanged. Under PAC, successful test of the mitigation is reported by the PAC exception handler: lkdtm: Performing direct entry CFI_BACKWARD lkdtm: Attempting unchecked stack return address redirection ... lkdtm: ok: redirected stack return address. lkdtm: Attempting checked stack return address redirection ... Unable to handle kernel paging request at virtual address bfffffc0088d0514 Mem abort info: ESR = 0x86000004 EC = 0x21: IABT (current EL), IL = 32 bits SET = 0, FnV = 0 EA = 0, S1PTW = 0 FSC = 0x04: level 0 translation fault [bfffffc0088d0514] address between user and kernel address ranges ... If the CONFIGs are missing (or the mitigation isn't working), failure is reported as: lkdtm: Performing direct entry CFI_BACKWARD lkdtm: Attempting unchecked stack return address redirection ... lkdtm: ok: redirected stack return address. lkdtm: Attempting checked stack return address redirection ... lkdtm: FAIL: stack return address was redirected! lkdtm: This is probably expected, since this kernel was built *without* CONFIG_ARM64_PTR_AUTH_KERNEL=y nor CONFIG_SHADOW_CALL_STACK=y Co-developed-by: Dan Li Signed-off-by: Dan Li Cc: Arnd Bergmann Cc: Greg Kroah-Hartman Signed-off-by: Kees Cook Link: https://lore.kernel.org/lkml/20220416001103.1524653-1-keescook@chromium.org --- drivers/misc/lkdtm/cfi.c | 134 ++++++++++++++++++++++++++++++++ tools/testing/selftests/lkdtm/tests.txt | 1 + 2 files changed, 135 insertions(+) (limited to 'tools') diff --git a/drivers/misc/lkdtm/cfi.c b/drivers/misc/lkdtm/cfi.c index e88f778be0d5..804965a480b7 100644 --- a/drivers/misc/lkdtm/cfi.c +++ b/drivers/misc/lkdtm/cfi.c @@ -3,6 +3,7 @@ * This is for all the tests relating directly to Control Flow Integrity. */ #include "lkdtm.h" +#include static int called_count; @@ -42,8 +43,141 @@ static void lkdtm_CFI_FORWARD_PROTO(void) pr_expected_config(CONFIG_CFI_CLANG); } +/* + * This can stay local to LKDTM, as there should not be a production reason + * to disable PAC && SCS. + */ +#ifdef CONFIG_ARM64_PTR_AUTH_KERNEL +# ifdef CONFIG_ARM64_BTI_KERNEL +# define __no_pac "branch-protection=bti" +# else +# define __no_pac "branch-protection=none" +# endif +# define __no_ret_protection __noscs __attribute__((__target__(__no_pac))) +#else +# define __no_ret_protection __noscs +#endif + +#define no_pac_addr(addr) \ + ((__force __typeof__(addr))((__force u64)(addr) | PAGE_OFFSET)) + +/* The ultimate ROP gadget. */ +static noinline __no_ret_protection +void set_return_addr_unchecked(unsigned long *expected, unsigned long *addr) +{ + /* Use of volatile is to make sure final write isn't seen as a dead store. */ + unsigned long * volatile *ret_addr = (unsigned long **)__builtin_frame_address(0) + 1; + + /* Make sure we've found the right place on the stack before writing it. */ + if (no_pac_addr(*ret_addr) == expected) + *ret_addr = (addr); + else + /* Check architecture, stack layout, or compiler behavior... */ + pr_warn("Eek: return address mismatch! %px != %px\n", + *ret_addr, addr); +} + +static noinline +void set_return_addr(unsigned long *expected, unsigned long *addr) +{ + /* Use of volatile is to make sure final write isn't seen as a dead store. */ + unsigned long * volatile *ret_addr = (unsigned long **)__builtin_frame_address(0) + 1; + + /* Make sure we've found the right place on the stack before writing it. */ + if (no_pac_addr(*ret_addr) == expected) + *ret_addr = (addr); + else + /* Check architecture, stack layout, or compiler behavior... */ + pr_warn("Eek: return address mismatch! %px != %px\n", + *ret_addr, addr); +} + +static volatile int force_check; + +static void lkdtm_CFI_BACKWARD(void) +{ + /* Use calculated gotos to keep labels addressable. */ + void *labels[] = {0, &&normal, &&redirected, &&check_normal, &&check_redirected}; + + pr_info("Attempting unchecked stack return address redirection ...\n"); + + /* Always false */ + if (force_check) { + /* + * Prepare to call with NULLs to avoid parameters being treated as + * constants in -02. + */ + set_return_addr_unchecked(NULL, NULL); + set_return_addr(NULL, NULL); + if (force_check) + goto *labels[1]; + if (force_check) + goto *labels[2]; + if (force_check) + goto *labels[3]; + if (force_check) + goto *labels[4]; + return; + } + + /* + * Use fallthrough switch case to keep basic block ordering between + * set_return_addr*() and the label after it. + */ + switch (force_check) { + case 0: + set_return_addr_unchecked(&&normal, &&redirected); + fallthrough; + case 1: +normal: + /* Always true */ + if (!force_check) { + pr_err("FAIL: stack return address manipulation failed!\n"); + /* If we can't redirect "normally", we can't test mitigations. */ + return; + } + break; + default: +redirected: + pr_info("ok: redirected stack return address.\n"); + break; + } + + pr_info("Attempting checked stack return address redirection ...\n"); + + switch (force_check) { + case 0: + set_return_addr(&&check_normal, &&check_redirected); + fallthrough; + case 1: +check_normal: + /* Always true */ + if (!force_check) { + pr_info("ok: control flow unchanged.\n"); + return; + } + +check_redirected: + pr_err("FAIL: stack return address was redirected!\n"); + break; + } + + if (IS_ENABLED(CONFIG_ARM64_PTR_AUTH_KERNEL)) { + pr_expected_config(CONFIG_ARM64_PTR_AUTH_KERNEL); + return; + } + if (IS_ENABLED(CONFIG_SHADOW_CALL_STACK)) { + pr_expected_config(CONFIG_SHADOW_CALL_STACK); + return; + } + pr_warn("This is probably expected, since this %s was built *without* %s=y nor %s=y\n", + lkdtm_kernel_info, + "CONFIG_ARM64_PTR_AUTH_KERNEL", "CONFIG_SHADOW_CALL_STACK"); +} + static struct crashtype crashtypes[] = { CRASHTYPE(CFI_FORWARD_PROTO), + CRASHTYPE(CFI_BACKWARD), }; struct crashtype_category cfi_crashtypes = { diff --git a/tools/testing/selftests/lkdtm/tests.txt b/tools/testing/selftests/lkdtm/tests.txt index 243c781f0780..9dace01dbf15 100644 --- a/tools/testing/selftests/lkdtm/tests.txt +++ b/tools/testing/selftests/lkdtm/tests.txt @@ -74,6 +74,7 @@ USERCOPY_STACK_BEYOND USERCOPY_KERNEL STACKLEAK_ERASING OK: the rest of the thread stack is properly erased CFI_FORWARD_PROTO +CFI_BACKWARD call trace:|ok: control flow unchanged FORTIFIED_STRSCPY FORTIFIED_OBJECT FORTIFIED_SUBOBJECT -- cgit v1.2.3 From d23386ed7019d50164fa2066aae8656097a02425 Mon Sep 17 00:00:00 2001 From: Carlos Llamas Date: Fri, 29 Apr 2022 23:56:42 +0000 Subject: binderfs: add extended_error feature entry Add extended_error to the binderfs feature list, to help userspace determine whether the BINDER_GET_EXTENDED_ERROR ioctl is supported by the binder driver. Reviewed-by: Christian Brauner (Microsoft) Acked-by: Todd Kjos Signed-off-by: Carlos Llamas Link: https://lore.kernel.org/r/20220429235644.697372-4-cmllamas@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/android/binderfs.c | 8 ++++++++ tools/testing/selftests/filesystems/binderfs/binderfs_test.c | 1 + 2 files changed, 9 insertions(+) (limited to 'tools') diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index e3605cdd4335..6c5e94f6cb3a 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -60,6 +60,7 @@ enum binderfs_stats_mode { struct binder_features { bool oneway_spam_detection; + bool extended_error; }; static const struct constant_table binderfs_param_stats[] = { @@ -75,6 +76,7 @@ static const struct fs_parameter_spec binderfs_fs_parameters[] = { static struct binder_features binder_features = { .oneway_spam_detection = true, + .extended_error = true, }; static inline struct binderfs_info *BINDERFS_SB(const struct super_block *sb) @@ -615,6 +617,12 @@ static int init_binder_features(struct super_block *sb) if (IS_ERR(dentry)) return PTR_ERR(dentry); + dentry = binderfs_create_file(dir, "extended_error", + &binder_features_fops, + &binder_features.extended_error); + if (IS_ERR(dentry)) + return PTR_ERR(dentry); + return 0; } diff --git a/tools/testing/selftests/filesystems/binderfs/binderfs_test.c b/tools/testing/selftests/filesystems/binderfs/binderfs_test.c index 0315955ff0f4..9409bb136d95 100644 --- a/tools/testing/selftests/filesystems/binderfs/binderfs_test.c +++ b/tools/testing/selftests/filesystems/binderfs/binderfs_test.c @@ -64,6 +64,7 @@ static int __do_binderfs_test(struct __test_metadata *_metadata) device_path[sizeof(P_tmpdir "/binderfs_XXXXXX/") + BINDERFS_MAX_NAME]; static const char * const binder_features[] = { "oneway_spam_detection", + "extended_error", }; change_mountns(_metadata); -- cgit v1.2.3 From d2b8060f165105a68748a6d98ed548ca112ce4d3 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 11 May 2022 22:46:09 -0700 Subject: lkdtm/usercopy: Rename "heap" to "slab" To more clearly distinguish between the various heap types, rename the slab tests to "slab". Cc: Arnd Bergmann Cc: Greg Kroah-Hartman Cc: Shuah Khan Cc: linux-kselftest@vger.kernel.org Signed-off-by: Kees Cook --- drivers/misc/lkdtm/usercopy.c | 30 +++++++++++++++--------------- tools/testing/selftests/lkdtm/tests.txt | 8 ++++---- 2 files changed, 19 insertions(+), 19 deletions(-) (limited to 'tools') diff --git a/drivers/misc/lkdtm/usercopy.c b/drivers/misc/lkdtm/usercopy.c index 7852b9fc7c47..945806db2a13 100644 --- a/drivers/misc/lkdtm/usercopy.c +++ b/drivers/misc/lkdtm/usercopy.c @@ -130,7 +130,7 @@ free_user: * This checks for whole-object size validation with hardened usercopy, * with or without usercopy whitelisting. */ -static void do_usercopy_heap_size(bool to_user) +static void do_usercopy_slab_size(bool to_user) { unsigned long user_addr; unsigned char *one, *two; @@ -196,9 +196,9 @@ free_kernel: /* * This checks for the specific whitelist window within an object. If this - * test passes, then do_usercopy_heap_size() tests will pass too. + * test passes, then do_usercopy_slab_size() tests will pass too. */ -static void do_usercopy_heap_whitelist(bool to_user) +static void do_usercopy_slab_whitelist(bool to_user) { unsigned long user_alloc; unsigned char *buf = NULL; @@ -272,24 +272,24 @@ free_alloc: } /* Callable tests. */ -static void lkdtm_USERCOPY_HEAP_SIZE_TO(void) +static void lkdtm_USERCOPY_SLAB_SIZE_TO(void) { - do_usercopy_heap_size(true); + do_usercopy_slab_size(true); } -static void lkdtm_USERCOPY_HEAP_SIZE_FROM(void) +static void lkdtm_USERCOPY_SLAB_SIZE_FROM(void) { - do_usercopy_heap_size(false); + do_usercopy_slab_size(false); } -static void lkdtm_USERCOPY_HEAP_WHITELIST_TO(void) +static void lkdtm_USERCOPY_SLAB_WHITELIST_TO(void) { - do_usercopy_heap_whitelist(true); + do_usercopy_slab_whitelist(true); } -static void lkdtm_USERCOPY_HEAP_WHITELIST_FROM(void) +static void lkdtm_USERCOPY_SLAB_WHITELIST_FROM(void) { - do_usercopy_heap_whitelist(false); + do_usercopy_slab_whitelist(false); } static void lkdtm_USERCOPY_STACK_FRAME_TO(void) @@ -358,10 +358,10 @@ void __exit lkdtm_usercopy_exit(void) } static struct crashtype crashtypes[] = { - CRASHTYPE(USERCOPY_HEAP_SIZE_TO), - CRASHTYPE(USERCOPY_HEAP_SIZE_FROM), - CRASHTYPE(USERCOPY_HEAP_WHITELIST_TO), - CRASHTYPE(USERCOPY_HEAP_WHITELIST_FROM), + CRASHTYPE(USERCOPY_SLAB_SIZE_TO), + CRASHTYPE(USERCOPY_SLAB_SIZE_FROM), + CRASHTYPE(USERCOPY_SLAB_WHITELIST_TO), + CRASHTYPE(USERCOPY_SLAB_WHITELIST_FROM), CRASHTYPE(USERCOPY_STACK_FRAME_TO), CRASHTYPE(USERCOPY_STACK_FRAME_FROM), CRASHTYPE(USERCOPY_STACK_BEYOND), diff --git a/tools/testing/selftests/lkdtm/tests.txt b/tools/testing/selftests/lkdtm/tests.txt index 9dace01dbf15..65e53eb0840b 100644 --- a/tools/testing/selftests/lkdtm/tests.txt +++ b/tools/testing/selftests/lkdtm/tests.txt @@ -64,10 +64,10 @@ REFCOUNT_DEC_AND_TEST_SATURATED Saturation detected: still saturated REFCOUNT_SUB_AND_TEST_SATURATED Saturation detected: still saturated #REFCOUNT_TIMING timing only #ATOMIC_TIMING timing only -USERCOPY_HEAP_SIZE_TO -USERCOPY_HEAP_SIZE_FROM -USERCOPY_HEAP_WHITELIST_TO -USERCOPY_HEAP_WHITELIST_FROM +USERCOPY_SLAB_SIZE_TO +USERCOPY_SLAB_SIZE_FROM +USERCOPY_SLAB_WHITELIST_TO +USERCOPY_SLAB_WHITELIST_FROM USERCOPY_STACK_FRAME_TO USERCOPY_STACK_FRAME_FROM USERCOPY_STACK_BEYOND -- cgit v1.2.3 From 38c84c997d40f56273077af5f8ff3e6317d772b7 Mon Sep 17 00:00:00 2001 From: Muhammad Usama Anjum Date: Tue, 17 May 2022 18:29:31 +0500 Subject: selftests/lkdtm: Add configs for stackleak and "after free" tests Add config options which are needed for LKDTM sub-tests: STACKLEAK_ERASING test needs GCC_PLUGIN_STACKLEAK config. READ_AFTER_FREE and READ_BUDDY_AFTER_FREE tests need INIT_ON_FREE_DEFAULT_ON config. Signed-off-by: Muhammad Usama Anjum Signed-off-by: Kees Cook Link: https://lore.kernel.org/r/20220517132932.1484719-1-usama.anjum@collabora.com --- tools/testing/selftests/lkdtm/config | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tools') diff --git a/tools/testing/selftests/lkdtm/config b/tools/testing/selftests/lkdtm/config index 304123688739..5d52f64dfb43 100644 --- a/tools/testing/selftests/lkdtm/config +++ b/tools/testing/selftests/lkdtm/config @@ -2,8 +2,10 @@ CONFIG_LKDTM=y CONFIG_DEBUG_LIST=y CONFIG_SLAB_FREELIST_HARDENED=y CONFIG_FORTIFY_SOURCE=y +CONFIG_GCC_PLUGIN_STACKLEAK=y CONFIG_HARDENED_USERCOPY=y CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT=y +CONFIG_INIT_ON_FREE_DEFAULT_ON=y CONFIG_INIT_ON_ALLOC_DEFAULT_ON=y CONFIG_UBSAN=y CONFIG_UBSAN_BOUNDS=y -- cgit v1.2.3