Skip to contentSkip to conversation

gcc-plugins: Add initial x86_64 kernexec plugin

RFC New Kees Cook 1 participant 1 message Jan 14, 2017

Subsystems (3)
lore
Share & tools
lore

Kees Cook

author
#0 lore raw

RFC 1/1 gcc-plugins: Add initial x86_64 kernexec plugin

This plugin, ported from PaX, instruments C function call sites (and returns) to set the high bit of the instruction pointer to force any attempts to execute userspace memory into the faulting non-canonical address range. This can be thought of as a weak form of SMEP emulation.

For function pointer calls, the compiler attempts an optimization of "set high bit", which is an "or" when registers are available:

 3bf:   48 b8 00 00 00 00 00    movabs $0x8000000000000000,%rax
 3c6:   00 00 80 
 3c9:   48 09 d8                or     %rbx,%rax
 3cc:   ff d0                   callq  *%rax

And btsq for returns:

  36:   48 0f ba 2c 24 3f       btsq   $0x3f,(%rsp)
  3c:   c3                      retq   

Note: assembly instrumentation still needs to be ported from PaX. Without this, there is significant coverage missing.

---
 arch/Kconfig                          |  17 ++
 arch/x86/include/asm/module.h         |   9 +-
 scripts/Makefile.gcc-plugins          |  10 +-
 scripts/gcc-plugins/kernexec_plugin.c | 405 ++++++++++++++++++++++++++++++++++
 scripts/link-vmlinux.sh               |   2 +-
 5 files changed, 439 insertions(+), 4 deletions(-)
 create mode 100644 scripts/gcc-plugins/kernexec_plugin.c
arch/Kconfig +17 -0
index 99839c23d453..1181cb8b7154 100644
@@ -410,6 +410,23 @@ config GCC_PLUGIN_LATENT_ENTROPY
 	   * https://grsecurity.net/
 	   * https://pax.grsecurity.net/
 
+config GCC_PLUGIN_KERNEXEC
+	bool "Provide weak SMEP emulation by instrumenting function calls"
+	depends on GCC_PLUGINS && X86_64
+	help
+	  For x86_64 CPUs that lack Supervisor Mode Execute Prevention (SMEP),
+	  the kernel can be instrumented so that C call sites set the high
+	  bit on the target address. This means that attempts to execute
+	  userspace memory will force the execution to land in the
+	  non-canonical memory region and trigger a fault (instead of letting
+	  an attacker execute userspace memory).
+
+	  For systems with SMEP, select "n"; this option is redundant.
+
+	  This plugin was ported from grsecurity/PaX. More information at:
+	   * https://grsecurity.net/
+	   * https://pax.grsecurity.net/
+
 config HAVE_CC_STACKPROTECTOR
 	bool
 	help
arch/x86/include/asm/module.h +7 -2
index e3b7819caeef..87eee77daed3 100644
@@ -5,6 +5,7 @@
 
 #ifdef CONFIG_X86_64
 /* X86_64 does not define MODULE_PROC_FAMILY */
+#define MODULE_PROC_FAMILY ""
 #elif defined CONFIG_M486
 #define MODULE_PROC_FAMILY "486 "
 #elif defined CONFIG_M586
@@ -57,8 +58,12 @@
 #error unknown processor family
 #endif
 
-#ifdef CONFIG_X86_32
-# define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY
+#ifdef CONFIG_GCC_PLUGIN_KERNEXEC
+#define MODULE_GCC_PLUGIN_KERNEXEC "KERNEXEC_BTS "
+#else
+#define MODULE_GCC_PLUGIN_KERNEXEC ""
 #endif
 
+#define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY MODULE_GCC_PLUGIN_KERNEXEC
+
 #endif /* _ASM_X86_MODULE_H */
scripts/Makefile.gcc-plugins +9 -1
index 060d2cb373db..fd666cfd3ae3 100644
@@ -25,9 +25,16 @@ ifdef CONFIG_GCC_PLUGINS
     endif
   endif
 
+  gcc-plugin-$(CONFIG_GCC_PLUGIN_KERNEXEC)              += kernexec_plugin.so
+  gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_KERNEXEC)       += -DKERNEXEC_PLUGIN
+  gcc-plugin-aflags-$(CONFIG_GCC_PLUGIN_KERNEXEC)       += -fplugin=$(objtree)/scripts/gcc-plugins/kernexec_plugin.so
+  gcc-plugin-aflags-$(CONFIG_GCC_PLUGIN_KERNEXEC)       += -DKERNEXEC_PLUGIN
+
   GCC_PLUGINS_CFLAGS := $(strip $(addprefix -fplugin=$(objtree)/scripts/gcc-plugins/, $(gcc-plugin-y)) $(gcc-plugin-cflags-y))
+  GCC_PLUGINS_AFLAGS := $(gcc-plugin-aflags-y)
 
-  export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGIN GCC_PLUGIN_SUBDIR
+  export PLUGINCC GCC_PLUGIN GCC_PLUGIN_SUBDIR
+  export GCC_PLUGINS_CFLAGS GCC_PLUGINS_AFLAGS
   export SANCOV_PLUGIN DISABLE_LATENT_ENTROPY_PLUGIN
 
   ifneq ($(PLUGINCC),)
@@ -36,6 +43,7 @@ ifdef CONFIG_GCC_PLUGINS
   endif
 
   KBUILD_CFLAGS += $(GCC_PLUGINS_CFLAGS)
+  KBUILD_AFLAGS += $(GCC_PLUGINS_AFLAGS)
   GCC_PLUGIN := $(gcc-plugin-y)
   GCC_PLUGIN_SUBDIR := $(gcc-plugin-subdir-y)
 endif
scripts/gcc-plugins/kernexec_plugin.c new file +405 -0

405 lines not on this page · raw message

scripts/link-vmlinux.sh +1 -1
index c80291319cb2..716f8ca1b555 100755
@@ -220,7 +220,7 @@ else
 fi;
 
 # final build of init/
-${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init GCC_PLUGINS_CFLAGS="${GCC_PLUGINS_CFLAGS}"
+${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init GCC_PLUGINS_CFLAGS="${GCC_PLUGINS_CFLAGS}" GCC_PLUGINS_AFLAGS="${GCC_PLUGINS_AFLAGS}"
 
 archive_builtin
 
Signature · 6 lines
2.7.4


-- 
Kees Cook
Nexus Security