Skip to content

Commit 313dd1b

Browse files
committed
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 <[email protected]>
1 parent 0aa5e49 commit 313dd1b

File tree

11 files changed

+1108
-1
lines changed

11 files changed

+1108
-1
lines changed

Documentation/dontdiff

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,8 @@ r200_reg_safe.h
207207
r300_reg_safe.h
208208
r420_reg_safe.h
209209
r600_reg_safe.h
210+
randomize_layout_hash.h
211+
randomize_layout_seed.h
210212
recordmcount
211213
relocs
212214
rlim_names.h

arch/Kconfig

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,45 @@ config GCC_PLUGIN_STRUCTLEAK_VERBOSE
443443
initialized. Since not all existing initializers are detected
444444
by the plugin, this can produce false positive warnings.
445445

446+
config GCC_PLUGIN_RANDSTRUCT
447+
bool "Randomize layout of sensitive kernel structures"
448+
depends on GCC_PLUGINS
449+
select MODVERSIONS if MODULES
450+
help
451+
If you say Y here, the layouts of structures explicitly
452+
marked by __randomize_layout will be randomized at
453+
compile-time. This can introduce the requirement of an
454+
additional information exposure vulnerability for exploits
455+
targeting these structure types.
456+
457+
Enabling this feature will introduce some performance impact,
458+
slightly increase memory usage, and prevent the use of forensic
459+
tools like Volatility against the system (unless the kernel
460+
source tree isn't cleaned after kernel installation).
461+
462+
The seed used for compilation is located at
463+
scripts/gcc-plgins/randomize_layout_seed.h. It remains after
464+
a make clean to allow for external modules to be compiled with
465+
the existing seed and will be removed by a make mrproper or
466+
make distclean.
467+
468+
Note that the implementation requires gcc 4.7 or newer.
469+
470+
This plugin was ported from grsecurity/PaX. More information at:
471+
* https://grsecurity.net/
472+
* https://pax.grsecurity.net/
473+
474+
config GCC_PLUGIN_RANDSTRUCT_PERFORMANCE
475+
bool "Use cacheline-aware structure randomization"
476+
depends on GCC_PLUGIN_RANDSTRUCT
477+
depends on !COMPILE_TEST
478+
help
479+
If you say Y here, the RANDSTRUCT randomization will make a
480+
best effort at restricting randomization to cacheline-sized
481+
groups of elements. It will further not randomize bitfields
482+
in structures. This reduces the performance hit of RANDSTRUCT
483+
at the cost of weakened randomization.
484+
446485
config HAVE_CC_STACKPROTECTOR
447486
bool
448487
help

include/linux/compiler-gcc.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,11 @@
223223
/* Mark a function definition as prohibited from being cloned. */
224224
#define __noclone __attribute__((__noclone__, __optimize__("no-tracer")))
225225

226+
#ifdef RANDSTRUCT_PLUGIN
227+
#define __randomize_layout __attribute__((randomize_layout))
228+
#define __no_randomize_layout __attribute__((no_randomize_layout))
229+
#endif
230+
226231
#endif /* GCC_VERSION >= 40500 */
227232

228233
#if GCC_VERSION >= 40600

include/linux/compiler.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,14 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s
448448
# define __latent_entropy
449449
#endif
450450

451+
#ifndef __randomize_layout
452+
# define __randomize_layout __designated_init
453+
#endif
454+
455+
#ifndef __no_randomize_layout
456+
# define __no_randomize_layout
457+
#endif
458+
451459
/*
452460
* Tell gcc if a function is cold. The compiler will assume any path
453461
* directly leading to the call is unlikely.

include/linux/vermagic.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,17 @@
2424
#ifndef MODULE_ARCH_VERMAGIC
2525
#define MODULE_ARCH_VERMAGIC ""
2626
#endif
27+
#ifdef RANDSTRUCT_PLUGIN
28+
#include <generated/randomize_layout_hash.h>
29+
#define MODULE_RANDSTRUCT_PLUGIN "RANDSTRUCT_PLUGIN_" RANDSTRUCT_HASHED_SEED
30+
#else
31+
#define MODULE_RANDSTRUCT_PLUGIN
32+
#endif
2733

2834
#define VERMAGIC_STRING \
2935
UTS_RELEASE " " \
3036
MODULE_VERMAGIC_SMP MODULE_VERMAGIC_PREEMPT \
3137
MODULE_VERMAGIC_MODULE_UNLOAD MODULE_VERMAGIC_MODVERSIONS \
32-
MODULE_ARCH_VERMAGIC
38+
MODULE_ARCH_VERMAGIC \
39+
MODULE_RANDSTRUCT_PLUGIN
3340

scripts/Makefile.gcc-plugins

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ ifdef CONFIG_GCC_PLUGINS
2929
gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK_VERBOSE) += -fplugin-arg-structleak_plugin-verbose
3030
gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK) += -DSTRUCTLEAK_PLUGIN
3131

32+
gcc-plugin-$(CONFIG_GCC_PLUGIN_RANDSTRUCT) += randomize_layout_plugin.so
33+
gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_RANDSTRUCT) += -DRANDSTRUCT_PLUGIN
34+
gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_RANDSTRUCT_PERFORMANCE) += -fplugin-arg-randomize_layout_plugin-performance-mode
35+
3236
GCC_PLUGINS_CFLAGS := $(strip $(addprefix -fplugin=$(objtree)/scripts/gcc-plugins/, $(gcc-plugin-y)) $(gcc-plugin-cflags-y))
3337

3438
export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGIN GCC_PLUGIN_SUBDIR

scripts/gcc-plugins/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
randomize_layout_seed.h

scripts/gcc-plugins/Makefile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@ endif
1818

1919
export HOSTLIBS
2020

21+
$(obj)/randomize_layout_plugin.o: $(objtree)/$(obj)/randomize_layout_seed.h
22+
quiet_cmd_create_randomize_layout_seed = GENSEED $@
23+
cmd_create_randomize_layout_seed = \
24+
$(CONFIG_SHELL) $(srctree)/$(src)/gen-random-seed.sh $@ $(objtree)/include/generated/randomize_layout_hash.h
25+
$(objtree)/$(obj)/randomize_layout_seed.h: FORCE
26+
$(call if_changed,create_randomize_layout_seed)
27+
targets = randomize_layout_seed.h randomize_layout_hash.h
28+
2129
$(HOSTLIBS)-y := $(foreach p,$(GCC_PLUGIN),$(if $(findstring /,$(p)),,$(p)))
2230
always := $($(HOSTLIBS)-y)
2331

scripts/gcc-plugins/gcc-common.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -953,4 +953,9 @@ static inline void debug_gimple_stmt(const_gimple s)
953953
get_inner_reference(exp, pbitsize, pbitpos, poffset, pmode, punsignedp, preversep, pvolatilep)
954954
#endif
955955

956+
#if BUILDING_GCC_VERSION < 7000
957+
#define SET_DECL_ALIGN(decl, align) DECL_ALIGN(decl) = (align)
958+
#define SET_DECL_MODE(decl, mode) DECL_MODE(decl) = (mode)
959+
#endif
960+
956961
#endif
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#!/bin/sh
2+
3+
if [ ! -f "$1" ]; then
4+
SEED=`od -A n -t x8 -N 32 /dev/urandom | tr -d ' \n'`
5+
echo "const char *randstruct_seed = \"$SEED\";" > "$1"
6+
HASH=`echo -n "$SEED" | sha256sum | cut -d" " -f1 | tr -d ' \n'`
7+
echo "#define RANDSTRUCT_HASHED_SEED \"$HASH\"" > "$2"
8+
fi

0 commit comments

Comments
 (0)