gcc-plugins: Add the randstruct plugin

This randstruct plugin is modified from Brad Spengler/PaX Team's code
in the last public patch of grsecurity/PaX based on my understanding
of the code. Changes or omissions from the original code are mine and
don't reflect the original grsecurity/PaX code.

The randstruct GCC plugin randomizes the layout of selected structures
at compile time, as a probabilistic defense against attacks that need to
know the layout of structures within the kernel. This is most useful for
"in-house" kernel builds where neither the randomization seed nor other
build artifacts are made available to an attacker. While less useful for
distribution kernels (where the randomization seed must be exposed for
third party kernel module builds), it still has some value there since now
all kernel builds would need to be tracked by an attacker.

In more performance sensitive scenarios, GCC_PLUGIN_RANDSTRUCT_PERFORMANCE
can be selected to make a best effort to restrict randomization to
cacheline-sized groups of elements, and will not randomize bitfields. This
comes at the cost of reduced randomization.

Two annotations are defined,__randomize_layout and __no_randomize_layout,
which respectively tell the plugin to either randomize or not to
randomize instances of the struct in question. Follow-on patches enable
the auto-detection logic for selecting structures for randomization
that contain only function pointers. It is disabled here to assist with
bisection.

Since any randomized structs must be initialized using designated
initializers, __randomize_layout includes the __designated_init annotation
even when the plugin is disabled so that all builds will require
the needed initialization. (With the plugin enabled, annotations for
automatically chosen structures are marked as well.)

The main differences between this implemenation and grsecurity are:
- disable automatic struct selection (to be enabled in follow-up patch)
- add designated_init attribute at runtime and for manual marking
- clarify debugging output to differentiate bad cast warnings
- add whitelisting infrastructure
- support gcc 7's DECL_ALIGN and DECL_MODE changes (Laura Abbott)
- raise minimum required GCC version to 4.7

Earlier versions of this patch series were ported by Michael Leibowitz.

Signed-off-by: Kees Cook <keescook@chromium.org>
This commit is contained in:
Kees Cook 2017-05-05 23:37:45 -07:00
parent 0aa5e49c68
commit 313dd1b629
11 changed files with 1108 additions and 1 deletions

View File

@ -207,6 +207,8 @@ r200_reg_safe.h
r300_reg_safe.h r300_reg_safe.h
r420_reg_safe.h r420_reg_safe.h
r600_reg_safe.h r600_reg_safe.h
randomize_layout_hash.h
randomize_layout_seed.h
recordmcount recordmcount
relocs relocs
rlim_names.h rlim_names.h

View File

@ -443,6 +443,45 @@ config GCC_PLUGIN_STRUCTLEAK_VERBOSE
initialized. Since not all existing initializers are detected initialized. Since not all existing initializers are detected
by the plugin, this can produce false positive warnings. by the plugin, this can produce false positive warnings.
config GCC_PLUGIN_RANDSTRUCT
bool "Randomize layout of sensitive kernel structures"
depends on GCC_PLUGINS
select MODVERSIONS if MODULES
help
If you say Y here, the layouts of structures explicitly
marked by __randomize_layout will be randomized at
compile-time. This can introduce the requirement of an
additional information exposure vulnerability for exploits
targeting these structure types.
Enabling this feature will introduce some performance impact,
slightly increase memory usage, and prevent the use of forensic
tools like Volatility against the system (unless the kernel
source tree isn't cleaned after kernel installation).
The seed used for compilation is located at
scripts/gcc-plgins/randomize_layout_seed.h. It remains after
a make clean to allow for external modules to be compiled with
the existing seed and will be removed by a make mrproper or
make distclean.
Note that the implementation requires gcc 4.7 or newer.
This plugin was ported from grsecurity/PaX. More information at:
* https://grsecurity.net/
* https://pax.grsecurity.net/
config GCC_PLUGIN_RANDSTRUCT_PERFORMANCE
bool "Use cacheline-aware structure randomization"
depends on GCC_PLUGIN_RANDSTRUCT
depends on !COMPILE_TEST
help
If you say Y here, the RANDSTRUCT randomization will make a
best effort at restricting randomization to cacheline-sized
groups of elements. It will further not randomize bitfields
in structures. This reduces the performance hit of RANDSTRUCT
at the cost of weakened randomization.
config HAVE_CC_STACKPROTECTOR config HAVE_CC_STACKPROTECTOR
bool bool
help help

View File

@ -223,6 +223,11 @@
/* Mark a function definition as prohibited from being cloned. */ /* Mark a function definition as prohibited from being cloned. */
#define __noclone __attribute__((__noclone__, __optimize__("no-tracer"))) #define __noclone __attribute__((__noclone__, __optimize__("no-tracer")))
#ifdef RANDSTRUCT_PLUGIN
#define __randomize_layout __attribute__((randomize_layout))
#define __no_randomize_layout __attribute__((no_randomize_layout))
#endif
#endif /* GCC_VERSION >= 40500 */ #endif /* GCC_VERSION >= 40500 */
#if GCC_VERSION >= 40600 #if GCC_VERSION >= 40600

View File

@ -448,6 +448,14 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s
# define __latent_entropy # define __latent_entropy
#endif #endif
#ifndef __randomize_layout
# define __randomize_layout __designated_init
#endif
#ifndef __no_randomize_layout
# define __no_randomize_layout
#endif
/* /*
* Tell gcc if a function is cold. The compiler will assume any path * Tell gcc if a function is cold. The compiler will assume any path
* directly leading to the call is unlikely. * directly leading to the call is unlikely.

View File

@ -24,10 +24,17 @@
#ifndef MODULE_ARCH_VERMAGIC #ifndef MODULE_ARCH_VERMAGIC
#define MODULE_ARCH_VERMAGIC "" #define MODULE_ARCH_VERMAGIC ""
#endif #endif
#ifdef RANDSTRUCT_PLUGIN
#include <generated/randomize_layout_hash.h>
#define MODULE_RANDSTRUCT_PLUGIN "RANDSTRUCT_PLUGIN_" RANDSTRUCT_HASHED_SEED
#else
#define MODULE_RANDSTRUCT_PLUGIN
#endif
#define VERMAGIC_STRING \ #define VERMAGIC_STRING \
UTS_RELEASE " " \ UTS_RELEASE " " \
MODULE_VERMAGIC_SMP MODULE_VERMAGIC_PREEMPT \ MODULE_VERMAGIC_SMP MODULE_VERMAGIC_PREEMPT \
MODULE_VERMAGIC_MODULE_UNLOAD MODULE_VERMAGIC_MODVERSIONS \ MODULE_VERMAGIC_MODULE_UNLOAD MODULE_VERMAGIC_MODVERSIONS \
MODULE_ARCH_VERMAGIC MODULE_ARCH_VERMAGIC \
MODULE_RANDSTRUCT_PLUGIN

View File

@ -29,6 +29,10 @@ ifdef CONFIG_GCC_PLUGINS
gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK_VERBOSE) += -fplugin-arg-structleak_plugin-verbose gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK_VERBOSE) += -fplugin-arg-structleak_plugin-verbose
gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK) += -DSTRUCTLEAK_PLUGIN gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK) += -DSTRUCTLEAK_PLUGIN
gcc-plugin-$(CONFIG_GCC_PLUGIN_RANDSTRUCT) += randomize_layout_plugin.so
gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_RANDSTRUCT) += -DRANDSTRUCT_PLUGIN
gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_RANDSTRUCT_PERFORMANCE) += -fplugin-arg-randomize_layout_plugin-performance-mode
GCC_PLUGINS_CFLAGS := $(strip $(addprefix -fplugin=$(objtree)/scripts/gcc-plugins/, $(gcc-plugin-y)) $(gcc-plugin-cflags-y)) GCC_PLUGINS_CFLAGS := $(strip $(addprefix -fplugin=$(objtree)/scripts/gcc-plugins/, $(gcc-plugin-y)) $(gcc-plugin-cflags-y))
export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGIN GCC_PLUGIN_SUBDIR export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGIN GCC_PLUGIN_SUBDIR

1
scripts/gcc-plugins/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
randomize_layout_seed.h

View File

@ -18,6 +18,14 @@ endif
export HOSTLIBS export HOSTLIBS
$(obj)/randomize_layout_plugin.o: $(objtree)/$(obj)/randomize_layout_seed.h
quiet_cmd_create_randomize_layout_seed = GENSEED $@
cmd_create_randomize_layout_seed = \
$(CONFIG_SHELL) $(srctree)/$(src)/gen-random-seed.sh $@ $(objtree)/include/generated/randomize_layout_hash.h
$(objtree)/$(obj)/randomize_layout_seed.h: FORCE
$(call if_changed,create_randomize_layout_seed)
targets = randomize_layout_seed.h randomize_layout_hash.h
$(HOSTLIBS)-y := $(foreach p,$(GCC_PLUGIN),$(if $(findstring /,$(p)),,$(p))) $(HOSTLIBS)-y := $(foreach p,$(GCC_PLUGIN),$(if $(findstring /,$(p)),,$(p)))
always := $($(HOSTLIBS)-y) always := $($(HOSTLIBS)-y)

View File

@ -953,4 +953,9 @@ static inline void debug_gimple_stmt(const_gimple s)
get_inner_reference(exp, pbitsize, pbitpos, poffset, pmode, punsignedp, preversep, pvolatilep) get_inner_reference(exp, pbitsize, pbitpos, poffset, pmode, punsignedp, preversep, pvolatilep)
#endif #endif
#if BUILDING_GCC_VERSION < 7000
#define SET_DECL_ALIGN(decl, align) DECL_ALIGN(decl) = (align)
#define SET_DECL_MODE(decl, mode) DECL_MODE(decl) = (mode)
#endif
#endif #endif

View File

@ -0,0 +1,8 @@
#!/bin/sh
if [ ! -f "$1" ]; then
SEED=`od -A n -t x8 -N 32 /dev/urandom | tr -d ' \n'`
echo "const char *randstruct_seed = \"$SEED\";" > "$1"
HASH=`echo -n "$SEED" | sha256sum | cut -d" " -f1 | tr -d ' \n'`
echo "#define RANDSTRUCT_HASHED_SEED \"$HASH\"" > "$2"
fi

File diff suppressed because it is too large Load Diff