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:
parent
0aa5e49c68
commit
313dd1b629
|
@ -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
|
||||||
|
|
39
arch/Kconfig
39
arch/Kconfig
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
randomize_layout_seed.h
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
Loading…
Reference in New Issue