|
|
Message-ID: <CAGXu5j+nu2V1Uy0qAbXxN1QzsnZwarA6ddPN5ORBkEQXQKa=+g@mail.gmail.com>
Date: Mon, 24 Jul 2017 20:11:15 -0700
From: Kees Cook <keescook@...omium.org>
To: Hans Liljestrand <liljestrandh@...il.com>
Cc: "kernel-hardening@...ts.openwall.com" <kernel-hardening@...ts.openwall.com>,
"Reshetova, Elena" <elena.reshetova@...el.com>, Dave Hansen <dave.hansen@...el.com>,
"H. Peter Anvin" <hpa@...or.com>
Subject: Re: [RFC PATCH 5/5] lkdtm: Add kernel MPX testing
On Mon, Jul 24, 2017 at 6:38 AM, Hans Liljestrand
<liljestrandh@...il.com> wrote:
> 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 +++++++++++++++++++++++
Organizationally speaking, I'd prefer this was all in one file: lkdtm_mpxk.c
> 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
Operationally, I'd like to find a way for these tests to be added
unconditionally (i.e. built with either CONFIG_X86_INTEL_MPX_KERNEL
enabled or disabled.) They would, obviously, all fail without MPXK.
> +
> 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
> +
It would allow dropping all these ifdefs too.
> /* 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]);
> +}
Instead of these mpxk_write_arr_i() wrappers, I'd prefer just seeing a
direct use of the standard kernel APIs or memory accesses. The "SOFT
TEST" stuff doesn't make sense to me here -- lkdtm should either pass
loudly (with WARN, BUG, etc) or fail quietly.
-Kees
--
Kees Cook
Pixel Security
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.