All of lore.kernel.org
 help / color / mirror / Atom feed
From: Hans Liljestrand <liljestrandh@gmail.com>
To: kernel-hardening@lists.openwall.com
Cc: elena.reshetova@intel.com, dave.hansen@intel.com,
	keescook@chromium.org, hpa@zytor.com,
	Hans Liljestrand <LiljestrandH@gmail.com>
Subject: [kernel-hardening] [RFC PATCH 5/5] lkdtm: Add kernel MPX testing
Date: Mon, 24 Jul 2017 16:38:24 +0300	[thread overview]
Message-ID: <20170724133824.27223-6-LiljestrandH@gmail.com> (raw)
In-Reply-To: <20170724133824.27223-1-LiljestrandH@gmail.com>

Tests MPXK functionality via lkdtm test cases. Currently tests basic
bound propagation and instrumentation for memcpy and kmalloc.

Signed-off-by: Hans Liljestrand <LiljestrandH@gmail.com>
Signed-off-by: Elena Reshetova <elena.reshetova@intel.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

  parent reply	other threads:[~2017-07-24 13:38 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-07-24 13:38 [kernel-hardening] [RFC PATCH 0/5] MPXK: Intel MPX for in-kernel use Hans Liljestrand
2017-07-24 13:38 ` [kernel-hardening] [RFC PATCH 1/5] x86: add CONFIG_X86_INTEL_MPX_KERNEL to Kconfig Hans Liljestrand
2017-07-25  2:51   ` [kernel-hardening] " Kees Cook
2017-07-25  7:10     ` Hans Liljestrand
2017-07-24 13:38 ` [kernel-hardening] [RFC PATCH 2/5] gcc-plugins: adds MPXK gcc plugin Hans Liljestrand
2017-07-25  2:40   ` [kernel-hardening] " Kees Cook
2017-07-25  7:16     ` Hans Liljestrand
2017-07-24 13:38 ` [kernel-hardening] [RFC PATCH 3/5] x86: add mpxk-wrappers Hans Liljestrand
2017-07-25  2:45   ` [kernel-hardening] " Kees Cook
2017-07-25  7:52     ` Hans Liljestrand
2017-07-25 18:22       ` Kees Cook
2017-07-26  9:15         ` Hans Liljestrand
2017-07-24 13:38 ` [kernel-hardening] [RFC PATCH 4/5] x86: MPXK base Hans Liljestrand
2017-07-25  2:48   ` [kernel-hardening] " Kees Cook
2017-07-25  7:57     ` Hans Liljestrand
2017-07-24 13:38 ` Hans Liljestrand [this message]
2017-07-25  3:11   ` [kernel-hardening] Re: [RFC PATCH 5/5] lkdtm: Add kernel MPX testing Kees Cook
2017-07-25  8:17     ` Hans Liljestrand

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170724133824.27223-6-LiljestrandH@gmail.com \
    --to=liljestrandh@gmail.com \
    --cc=dave.hansen@intel.com \
    --cc=elena.reshetova@intel.com \
    --cc=hpa@zytor.com \
    --cc=keescook@chromium.org \
    --cc=kernel-hardening@lists.openwall.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.