|
Message-Id: <20170724133824.27223-6-LiljestrandH@gmail.com> Date: Mon, 24 Jul 2017 16:38:24 +0300 From: Hans Liljestrand <liljestrandh@...il.com> To: kernel-hardening@...ts.openwall.com Cc: elena.reshetova@...el.com, dave.hansen@...el.com, keescook@...omium.org, hpa@...or.com, Hans Liljestrand <LiljestrandH@...il.com> Subject: [RFC PATCH 5/5] lkdtm: Add kernel MPX testing Tests MPXK functionality via lkdtm test cases. Currently tests basic bound propagation and instrumentation for memcpy and kmalloc. Signed-off-by: Hans Liljestrand <LiljestrandH@...il.com> Signed-off-by: Elena Reshetova <elena.reshetova@...el.com> --- drivers/misc/Makefile | 7 +++ drivers/misc/lkdtm.h | 7 +++ drivers/misc/lkdtm_core.c | 6 +++ drivers/misc/lkdtm_mpxk.c | 115 +++++++++++++++++++++++++++++++++++++++++ drivers/misc/lkdtm_mpxk.h | 11 ++++ drivers/misc/lkdtm_mpxk_base.c | 65 +++++++++++++++++++++++ 6 files changed, 211 insertions(+) create mode 100644 drivers/misc/lkdtm_mpxk.c create mode 100644 drivers/misc/lkdtm_mpxk.h create mode 100644 drivers/misc/lkdtm_mpxk_base.c diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 81ef3e67acc9..58d9ba43e081 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -64,6 +64,13 @@ lkdtm-$(CONFIG_LKDTM) += lkdtm_usercopy.o KCOV_INSTRUMENT_lkdtm_rodata.o := n +ifdef CONFIG_X86_INTEL_MPX_KERNEL + lkdtm-$(CONFIG_LKDTM) += lkdtm_mpxk.o + lkdtm-$(CONFIG_LKDTM) += lkdtm_mpxk_base.o + CFLAGS_lkdtm_mpxk.o += $(MPXK_CFLAGS) + CFLAGS_lkdtm_mpxk_base.o += $(MPXK_CFLAGS) +endif + OBJCOPYFLAGS := OBJCOPYFLAGS_lkdtm_rodata_objcopy.o := \ --set-section-flags .text=alloc,readonly \ diff --git a/drivers/misc/lkdtm.h b/drivers/misc/lkdtm.h index 3b4976396ec4..46cecd01db92 100644 --- a/drivers/misc/lkdtm.h +++ b/drivers/misc/lkdtm.h @@ -29,6 +29,13 @@ void lkdtm_CORRUPT_LIST_ADD(void); void lkdtm_CORRUPT_LIST_DEL(void); void lkdtm_CORRUPT_USER_DS(void); +#ifdef CONFIG_X86_INTEL_MPX_KERNEL +void lkdtm_MPXK_LOAD_BOUNDS(void); +void lkdtm_MPXK_FUNCTION_ARGS(void); +void lkdtm_MPXK_KMALLOC(void); +void lkdtm_MPXK_MEMCPY(void); +#endif + /* lkdtm_heap.c */ void lkdtm_OVERWRITE_ALLOCATION(void); void lkdtm_WRITE_AFTER_FREE(void); diff --git a/drivers/misc/lkdtm_core.c b/drivers/misc/lkdtm_core.c index 42d2b8e31e6b..74e258ddc5fe 100644 --- a/drivers/misc/lkdtm_core.c +++ b/drivers/misc/lkdtm_core.c @@ -235,6 +235,12 @@ struct crashtype crashtypes[] = { CRASHTYPE(USERCOPY_STACK_FRAME_FROM), CRASHTYPE(USERCOPY_STACK_BEYOND), CRASHTYPE(USERCOPY_KERNEL), +#ifdef CONFIG_X86_INTEL_MPX_KERNEL + CRASHTYPE(MPXK_LOAD_BOUNDS), + CRASHTYPE(MPXK_FUNCTION_ARGS), + CRASHTYPE(MPXK_KMALLOC), + CRASHTYPE(MPXK_MEMCPY) +#endif }; diff --git a/drivers/misc/lkdtm_mpxk.c b/drivers/misc/lkdtm_mpxk.c new file mode 100644 index 000000000000..b957d3641378 --- /dev/null +++ b/drivers/misc/lkdtm_mpxk.c @@ -0,0 +1,115 @@ +#undef pr_fmt +#include "lkdtm_mpxk.h" +#include <linux/list.h> +#include <linux/sched.h> +#include <linux/time.h> +#include <linux/slab.h> +#include <linux/printk.h> +#include <asm/mpxk.h> + +/** lkdtm_MPXK_LOAD_BOUNDS - test mpxk_bound_load + * + * Tests mpxk_load_bounds function by passing pointers into function via an + * array. The bounds for the array itself are passed via the bnd0 register, but + * MPX cannot do that for the internal pointers, hence it uses BNDSTX+BNDLDX. + * MPXK therefore must use mpxk_load_bounds to retrieve the bounds inside the + * called function. + */ +void lkdtm_MPXK_LOAD_BOUNDS(void) +{ + int i; + char *arr[10]; + + for (i = 0; i < 10; i++) + arr[i] = kmalloc(16, GFP_KERNEL); + + pr_info("attempting good ptr write\n"); + mpxk_write_arr_i(arr, 2, 0); + + /* This could succeed because mpxk_load_bounds retrieved the size based + * on the pointer value via ksize, which in turn doesn't necessarily + * return the exact size that was passed into kmalloc. The size is none + * the less guaranteed to be "safe" in that it will not be reserved + * elsewhere. + */ + pr_info("attempting exact (+1) bad ptr write (can succeed)"); + mpxk_write_arr_i(arr, 4, 16); + + pr_info("attempting real bad ptr write (should be caught)\n"); + mpxk_write_arr_i(arr, 5, 1024); + + for (i = 0; i < 10; i++) + kfree(arr[i]); +} + +/** lkdtm_MPXK_FUNCTION_ARGS - test function argument bound propagation + * + * Note that the four first pointers will have their bounds passed into the + * function via the bnd0-bnd3 registers. The rest are in vanilla MPX passed in + * via BNDSTX+BNDLDX, but in the case of MPXK they are simply loaded inside the + * called function using mpxk_load_bounds. + */ +void lkdtm_MPXK_FUNCTION_ARGS(void) +{ + int i; + char *arr[10]; + + for (i = 0; i < 10; i++) + arr[i] = kmalloc(16, GFP_KERNEL); + + pr_info("attempting good ptr write\n"); + mpxk_write_10_i(8, 0, + arr[0], arr[1], arr[2], arr[3], arr[4], + arr[5], arr[6], arr[7], arr[8], arr[9]); + + pr_info("attempting exact bad ptr write\n"); + mpxk_write_10_i(9, 2, + arr[0], arr[1], arr[2], arr[3], arr[4], + arr[5], arr[6], arr[7], arr[8], arr[9]); + + pr_info("attempting real bad ptr write\n"); + mpxk_write_10_i(7, 1024, + arr[0], arr[1], arr[2], arr[3], arr[4], + arr[5], arr[6], arr[7], arr[8], arr[9]); + + for (i = 0; i < 10; i++) + kfree(arr[i]); +} + +/** lkdtm_MPXK_KMALLOC + * + * Make suer kmalloc is properly instrumented, i.e. it returns proper pointer + * bounds on allocation. + */ +void lkdtm_MPXK_KMALLOC(void) +{ + void *ptr = kmalloc(10, GFP_KERNEL); + + pr_info("attempting good write\n"); + try_write(ptr, 1); + + pr_info("attempting bad write\n"); + try_write(ptr, 11); + + kfree(ptr); +} + + +/** lkdtm_MPXK_MEMCPY - test memcpy instrumentation + * + * Test memcpy instrumentation, which should check that both target and source + * are within bounds (this exercises only destination bounds). + */ +void lkdtm_MPXK_MEMCPY(void) +{ + char *s = "123456789"; + char *s_big = "12345678901234567890123456789012"; + char *d = kmalloc(4 * sizeof(char), GFP_KERNEL); + + pr_info("performing okay memcpy\n"); + memcpy(d, s, 1); + + /* The source is okay, but target is too small. */ + pr_info("performing bad memcpy\n"); + memcpy(d, s_big, 32 * sizeof(char)); +} diff --git a/drivers/misc/lkdtm_mpxk.h b/drivers/misc/lkdtm_mpxk.h new file mode 100644 index 000000000000..197bdca2c10c --- /dev/null +++ b/drivers/misc/lkdtm_mpxk.h @@ -0,0 +1,11 @@ +#undef pr_fmt +#include "lkdtm.h" +#include <asm/mpxk.h> + +/* #define SOFT_TEST */ + +void try_write(void *ptr, int i); +void mpxk_write_arr_i(char **arr, int i, int j); +noinline void mpxk_write_10_i(int i, int j, + void *s0, void *s1, void *s2, void *s3, void *s4, + void *s5, void *s6, void *s7, void *s8, void *s9); diff --git a/drivers/misc/lkdtm_mpxk_base.c b/drivers/misc/lkdtm_mpxk_base.c new file mode 100644 index 000000000000..938aa5c78211 --- /dev/null +++ b/drivers/misc/lkdtm_mpxk_base.c @@ -0,0 +1,65 @@ +#undef pr_fmt +#include "lkdtm_mpxk.h" +#include <linux/printk.h> + +/** + * try_write - Attempt write at pointed memory + * + * On bad writes this will either cause a bound violation, or + * when SOFT_TEST is set pritn out "fail". + */ +noinline void try_write(void *ptr, int i) +{ +#ifdef SOFT_TEST + const void *ubound = __bnd_get_ptr_ubound(ptr); + const void *lbound = __bnd_get_ptr_lbound(ptr); + + if (ptr < lbound || (ptr+i) > ubound) + pr_info("fail\n"); + else + pr_info("ok\n"); +#else + ((char *)ptr)[i] = '\0'; +#endif /* SOFT_TEST */ +} + +/** + * mpxk_write_arr_i - Test function that writes to array. + * + * The boudns for the inner array cannot be passed in via stack/registers and + * are therefore loaded with mpxk_load_bounds (and would have been passed in + * vanilla MPX with BNDSTX+BNDLDX). + */ +noinline void mpxk_write_arr_i(char **arr, int i, int j) +{ + try_write(arr[i], j); +} + + +/** + * mpxk_write_10_i - Test function that writes to function arg strings. + * + * Because bounds cannot be passed beyond the sixth argument (or the fourth + * bound) this forces MPXK to use mpxk_load_bounds for the latter pointers. + */ +noinline void mpxk_write_10_i(int i, int j, + void *s0, void *s1, void *s2, void *s3, void *s4, + void *s5, void *s6, void *s7, void *s8, void *s9) +{ + +#define mpxk_func_case(x) do { \ + if (i == x) \ + try_write(s##x, j); \ +} while (0) + mpxk_func_case(0); + mpxk_func_case(1); + mpxk_func_case(2); + mpxk_func_case(3); + mpxk_func_case(4); + mpxk_func_case(5); + mpxk_func_case(6); + mpxk_func_case(7); + mpxk_func_case(8); + mpxk_func_case(9); +#undef mpxk_func_case +} -- 2.11.0
Powered by blists - more mailing lists
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.