All of lore.kernel.org
 help / color / mirror / Atom feed
* [kernel-hardening] [PATCH 00/18] Introduce struct layout randomization plugin
@ 2017-04-06 21:18 Kees Cook
  2017-04-06 21:18 ` [kernel-hardening] [PATCH 01/18] gcc-plugins: Add the randstruct plugin Kees Cook
                   ` (20 more replies)
  0 siblings, 21 replies; 34+ messages in thread
From: Kees Cook @ 2017-04-06 21:18 UTC (permalink / raw)
  To: kernel-hardening; +Cc: Kees Cook, Michael Leibowitz

This series brings grsecurity's structure layout randomization plugin
to upstream. The 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. 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. It is
most useful to "in-house" kernel builds where the randomization seed
is not available to an attacker.
    
One requirement of the plugin is that randomized structures must use
designated initializers. Many of these have been landing already as
I've been sending them over the past couple months, but there are
still some stragglers, which are included here.

Another area to address are places where randomized structures are
cast to other structures, since there may be implicit positional
details that need to be addressed. Luckily, there are only a few
of these false positives, and they have been worked around either
by adjusting the source or whitelisting them in the plugin.

The plugin selects structures in two ways: manually marked with the
new __randomize_layout annotation, or automatically when a structure
is found to consist entirely of function pointers (which can be opted
out of with the new __no_randomize_layout annotation).

A structure that is especially sensitive and regularly abused in
exploits is task_struct, but randomizing it requires some special
handling due to some fields needing to be at the start and end. To
deal with this, an internal anonymous struct is used to mark the
portion that will be randomized. I'd love feedback on whether I
should bite the bullet and perform indenting or violate indenting
rules to avoid a massive white-space change.

As mentioned, the bulk of this feature is ported over from grsecurity.
The implementation is almost entirely identical to the original code
written by Brad Spengler and the PaX Team and Brad Spengler. The
changes are addition of improved designated initializer markings,
a whitelisting mechanism, and a different approach to handling the
task_struct randomization.

I've been doing boot tests with instrumentation showing successfully
changing offsets within the task_struct, which ran overnight without
problems. So far, the 0day builder hasn't alerted on anything, but
it's probably still a bit early.

This series is based on next-20170404.

Patches are:

[PATCH 01/18] gcc-plugins: Add the randstruct plugin
	The plugin itself, with struct auto-detection disabled.

[PATCH 02/18] compiler: Add __designated_init annotation
[PATCH 03/18] randstruct: Set designated_init attribute
	Adds marking of structures needing designated initialization.
	
[PATCH 04/18] randstruct: Differentiate bad cast warnings
	Minor clarifications to bad cast warning output.

[PATCH 05/18] af_unix: Use designated initializers
	Designated initializer fix for af_unix (taken for -next already)
	https://lkml.org/lkml/2017/4/6/846

[PATCH 06/18] NFS: Avoid cross-structure casting
	Avoids a false positive in casting (waiting for feedback)
	https://lkml.org/lkml/2017/4/5/530

[PATCH 07/18] randstruct: Whitelist struct security_hook_heads cast
[PATCH 08/18] randstruct: Whitelist UNIXCB cast
	Whitelist two more false positive cases where source-level
	fixes aren't obvious/possible.

[PATCH 09/18] randstruct: Mark various structs for randomization
	Adds the manual annotation for structures to randomize.

[PATCH 10/18] scsi/bfa: use designated initializers
[PATCH 11/18] scsi: qedi,qedf: Use designated initializers
[PATCH 12/18] ovl: Use designated initializers
	The remaining designated initializer fixes for automatic
	struct randomization.

[PATCH 13/18] randstruct: opt-out externally exposed function pointer
	Opt out of some externally-exposed structs that would be
	otherwise automatically randomized.

[PATCH 14/18] randstruct: Disable randomization of ACPICA structs
	Temporary disabling of automatic randomization of ACPICA struct.
	
[PATCH 15/18] randstruct: Enable function pointer struct detection
	Enables automatic struct randomization.

[PATCH 16/18] task_struct: Allow randomized layout
	Adds selected portion of task_struct to be randomized.

[PATCH 17/18] sgi-xp: Use designated initializers
	Enable randomization of sgi-xp struct, pending feedback.
	https://lkml.org/lkml/2017/3/29/808

[PATCH 18/18] ACPICA: Use designated initializers
	Enable randomization of ACPICA struct, pending feedback.
	https://github.com/acpica/acpica/pull/248/

Testing/feedback appreciated!

-Kees

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [kernel-hardening] [PATCH 01/18] gcc-plugins: Add the randstruct plugin
  2017-04-06 21:18 [kernel-hardening] [PATCH 00/18] Introduce struct layout randomization plugin Kees Cook
@ 2017-04-06 21:18 ` Kees Cook
  2017-04-12 22:12   ` [kernel-hardening] " Kees Cook
  2017-04-06 21:18 ` [kernel-hardening] [PATCH 02/18] compiler: Add __designated_init annotation Kees Cook
                   ` (19 subsequent siblings)
  20 siblings, 1 reply; 34+ messages in thread
From: Kees Cook @ 2017-04-06 21:18 UTC (permalink / raw)
  To: kernel-hardening; +Cc: Kees Cook, Michael Leibowitz

From: Michael Leibowitz <michael.leibowitz@intel.com>

This plugin randomizes the layout of selected structures at compile
time. This is a probabilistic defense against attacks that need to
know the layout of structures within the kernel. 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.

This introduces two defines __randomize_layout and __no_randomize_layout.
Which, in turn, tell the compiler to either randomize or not to randomize
the struct in question. Follow-on patches enable the auto-detection
logic for selecting structures that contain only function pointers.

This feature is ported over from grsecurity.  The implementation is
almost entirely identical to the original code written by the PaX Team
and Brad Spengler. To make integration simpler, this version has the
auto-detection logic temporarily disabled. Structures that are to be
randomized are required to use the C99 designated initializer form,
which will be in follow-on patches.

Signed-off-by: Michael Leibowitz <michael.leibowitz@intel.com>
[kees: refreshed plugin, disabled all-fptr-struct detection, update commit log]
Signed-off-by: Kees Cook <keescook@chromium.org>
---
 Documentation/dontdiff                        |   2 +
 arch/Kconfig                                  |  38 ++
 include/linux/compiler-gcc.h                  |   5 +
 include/linux/compiler.h                      |   8 +
 include/linux/vermagic.h                      |   9 +-
 kernel/module.c                               |  27 +-
 scripts/Makefile.gcc-plugins                  |   5 +
 scripts/gcc-plugins/.gitignore                |   1 +
 scripts/gcc-plugins/Makefile                  |   8 +
 scripts/gcc-plugins/gen-random-seed.sh        |   8 +
 scripts/gcc-plugins/randomize_layout_plugin.c | 943 ++++++++++++++++++++++++++
 11 files changed, 1052 insertions(+), 2 deletions(-)
 create mode 100644 scripts/gcc-plugins/.gitignore
 create mode 100644 scripts/gcc-plugins/gen-random-seed.sh
 create mode 100644 scripts/gcc-plugins/randomize_layout_plugin.c

diff --git a/Documentation/dontdiff b/Documentation/dontdiff
index 77b92221f951..e10a484629e4 100644
--- a/Documentation/dontdiff
+++ b/Documentation/dontdiff
@@ -207,6 +207,8 @@ r200_reg_safe.h
 r300_reg_safe.h
 r420_reg_safe.h
 r600_reg_safe.h
+randomize_layout_hash.h
+randomize_layout_seed.h
 recordmcount
 relocs
 rlim_names.h
diff --git a/arch/Kconfig b/arch/Kconfig
index feb78379f555..0097163327ac 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -483,6 +483,44 @@ config GCC_PLUGIN_STRUCTLEAK_VERBOSE
 	  initialized. Since not all existing initializers are detected
 	  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.6.4. 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
+	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
 	bool
 	help
diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h
index 8b013735dbdb..5f4d8f8b75da 100644
--- a/include/linux/compiler-gcc.h
+++ b/include/linux/compiler-gcc.h
@@ -245,6 +245,11 @@
 /* Mark a function definition as prohibited from being cloned. */
 #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 */
 
 #if GCC_VERSION >= 40600
diff --git a/include/linux/compiler.h b/include/linux/compiler.h
index 6e8e160b1e4b..b8642a3a1f4f 100644
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -444,6 +444,14 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s
 # define __latent_entropy
 #endif
 
+#ifndef __randomize_layout
+# define __randomize_layout
+#endif
+
+#ifndef __no_randomize_layout
+# define __no_randomize_layout
+#endif
+
 #ifndef __nocapture
 # define __nocapture(...)
 #endif
diff --git a/include/linux/vermagic.h b/include/linux/vermagic.h
index 6f8fbcf10dfb..af6c03f7f986 100644
--- a/include/linux/vermagic.h
+++ b/include/linux/vermagic.h
@@ -24,10 +24,17 @@
 #ifndef MODULE_ARCH_VERMAGIC
 #define MODULE_ARCH_VERMAGIC ""
 #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 						\
 	UTS_RELEASE " "							\
 	MODULE_VERMAGIC_SMP MODULE_VERMAGIC_PREEMPT 			\
 	MODULE_VERMAGIC_MODULE_UNLOAD MODULE_VERMAGIC_MODVERSIONS	\
-	MODULE_ARCH_VERMAGIC
+	MODULE_ARCH_VERMAGIC						\
+	MODULE_RANDSTRUCT_PLUGIN
 
diff --git a/kernel/module.c b/kernel/module.c
index f953df992a11..2887660b0e9c 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -1316,13 +1316,30 @@ static int check_version(Elf_Shdr *sechdrs,
 		goto bad_version;
 	}
 
+#ifdef CONFIG_GCC_PLUGIN_RANDSTRUCT
+	/*
+	 * avoid potentially printing jibberish on attempted load
+	 * of a module randomized with a different seed
+	 */
+	pr_warn("no symbol version for %s\n", symname);
+#else
 	/* Broken toolchain. Warn once, then let it go.. */
-	pr_warn_once("%s: no symbol version for %s\n", mod->name, symname);
+	pr_warn("%s: no symbol version for %s\n", mod->name, symname);
+#endif
 	return 1;
 
 bad_version:
+#ifdef CONFIG_GCC_PLUGIN_RANDSTRUCT
+	/*
+	 * avoid potentially printing jibberish on attempted load
+	 * of a module randomized with a different seed
+	 */
+	pr_warn("attempted module disagrees about version of symbol %s\n",
+	       symname);
+#else
 	pr_warn("%s: disagrees about version of symbol %s\n",
 	       mod->name, symname);
+#endif
 	return 0;
 }
 
@@ -2964,7 +2981,15 @@ static struct module *setup_load_info(struct load_info *info, int flags)
 	mod = (void *)info->sechdrs[info->index.mod].sh_addr;
 
 	if (info->index.sym == 0) {
+#ifdef CONFIG_GCC_PLUGIN_RANDSTRUCT
+		/*
+		 * avoid potentially printing jibberish on attempted load
+		 * of a module randomized with a different seed
+		 */
+		pr_warn("module has no symbols (stripped?)\n");
+#else
 		pr_warn("%s: module has no symbols (stripped?)\n", mod->name);
+#endif
 		return ERR_PTR(-ENOEXEC);
 	}
 
diff --git a/scripts/Makefile.gcc-plugins b/scripts/Makefile.gcc-plugins
index 9e89d744c6a3..2ef078f8bddb 100644
--- a/scripts/Makefile.gcc-plugins
+++ b/scripts/Makefile.gcc-plugins
@@ -42,11 +42,16 @@ ifdef CONFIG_GCC_PLUGINS
   gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK_VERBOSE)	+= -fplugin-arg-structleak_plugin-verbose
   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))
 
   export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGIN GCC_PLUGIN_SUBDIR
   export SANCOV_PLUGIN DISABLE_LATENT_ENTROPY_PLUGIN
   export INITIFY_DISABLE_VERIFIY_NOCAPTURE_FUNCTIONS
+  export RANDSTRUCT_PLUGIN
 
   ifneq ($(PLUGINCC),)
     # SANCOV_PLUGIN can be only in CFLAGS_KCOV because avoid duplication.
diff --git a/scripts/gcc-plugins/.gitignore b/scripts/gcc-plugins/.gitignore
new file mode 100644
index 000000000000..de92ed9e3d83
--- /dev/null
+++ b/scripts/gcc-plugins/.gitignore
@@ -0,0 +1 @@
+randomize_layout_seed.h
diff --git a/scripts/gcc-plugins/Makefile b/scripts/gcc-plugins/Makefile
index 8b29dc17c73c..214eb2335c31 100644
--- a/scripts/gcc-plugins/Makefile
+++ b/scripts/gcc-plugins/Makefile
@@ -18,6 +18,14 @@ endif
 
 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)))
 always := $($(HOSTLIBS)-y)
 
diff --git a/scripts/gcc-plugins/gen-random-seed.sh b/scripts/gcc-plugins/gen-random-seed.sh
new file mode 100644
index 000000000000..7514850f4815
--- /dev/null
+++ b/scripts/gcc-plugins/gen-random-seed.sh
@@ -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
diff --git a/scripts/gcc-plugins/randomize_layout_plugin.c b/scripts/gcc-plugins/randomize_layout_plugin.c
new file mode 100644
index 000000000000..eb8ac6cc315e
--- /dev/null
+++ b/scripts/gcc-plugins/randomize_layout_plugin.c
@@ -0,0 +1,943 @@
+/*
+ * Copyright 2014-2016 by Open Source Security, Inc., Brad Spengler <spender@grsecurity.net>
+ *                   and PaX Team <pageexec@freemail.hu>
+ * Licensed under the GPL v2
+ *
+ * Note: the choice of the license means that the compilation process is
+ *       NOT 'eligible' as defined by gcc's library exception to the GPL v3,
+ *       but for the kernel it doesn't matter since it doesn't link against
+ *       any of the gcc libraries
+ *
+ * Usage:
+ * $ # for 4.5/4.6/C based 4.7
+ * $ gcc -I`gcc -print-file-name=plugin`/include -I`gcc -print-file-name=plugin`/include/c-family -fPIC -shared -O2 -o randomize_layout_plugin.so randomize_layout_plugin.c
+ * $ # for C++ based 4.7/4.8+
+ * $ g++ -I`g++ -print-file-name=plugin`/include -I`g++ -print-file-name=plugin`/include/c-family -fPIC -shared -O2 -o randomize_layout_plugin.so randomize_layout_plugin.c
+ * $ gcc -fplugin=./randomize_layout_plugin.so test.c -O2
+ */
+
+#include "gcc-common.h"
+#include "randomize_layout_seed.h"
+
+#if BUILDING_GCC_MAJOR < 4 || (BUILDING_GCC_MAJOR == 4 && BUILDING_GCC_MINOR < 6) || \
+   (BUILDING_GCC_MAJOR == 4 && BUILDING_GCC_MINOR == 6 && BUILDING_GCC_PATCHLEVEL < 4)
+#error "The RANDSTRUCT plugin requires GCC 4.6.4 or newer."
+#endif
+
+#define ORIG_TYPE_NAME(node) \
+	(TYPE_NAME(TYPE_MAIN_VARIANT(node)) != NULL_TREE ? ((const unsigned char *)IDENTIFIER_POINTER(TYPE_NAME(TYPE_MAIN_VARIANT(node)))) : (const unsigned char *)"anonymous")
+
+__visible int plugin_is_GPL_compatible;
+
+static int performance_mode;
+
+static struct plugin_info randomize_layout_plugin_info = {
+	.version	= "201402201816vanilla",
+	.help		= "disable\t\t\tdo not activate plugin\n"
+			  "performance-mode\tenable cacheline-aware layout randomization\n"
+};
+
+/* from old Linux dcache.h */
+static inline unsigned long
+partial_name_hash(unsigned long c, unsigned long prevhash)
+{
+	return (prevhash + (c << 4) + (c >> 4)) * 11;
+}
+static inline unsigned int
+name_hash(const unsigned char *name)
+{
+	unsigned long hash = 0;
+	unsigned int len = strlen((const char *)name);
+	while (len--)
+		hash = partial_name_hash(*name++, hash);
+	return (unsigned int)hash;
+}
+
+static tree handle_randomize_layout_attr(tree *node, tree name, tree args, int flags, bool *no_add_attrs)
+{
+	tree type;
+
+	*no_add_attrs = true;
+	if (TREE_CODE(*node) == FUNCTION_DECL) {
+		error("%qE attribute does not apply to functions (%qF)", name, *node);
+		return NULL_TREE;
+	}
+
+	if (TREE_CODE(*node) == PARM_DECL) {
+		error("%qE attribute does not apply to function parameters (%qD)", name, *node);
+		return NULL_TREE;
+	}
+
+	if (TREE_CODE(*node) == VAR_DECL) {
+		error("%qE attribute does not apply to variables (%qD)", name, *node);
+		return NULL_TREE;
+	}
+
+	if (TYPE_P(*node)) {
+		type = *node;
+	} else {
+		gcc_assert(TREE_CODE(*node) == TYPE_DECL);
+		type = TREE_TYPE(*node);
+	}
+
+	if (TREE_CODE(type) != RECORD_TYPE) {
+		error("%qE attribute used on %qT applies to struct types only", name, type);
+		return NULL_TREE;
+	}
+
+	if (lookup_attribute(IDENTIFIER_POINTER(name), TYPE_ATTRIBUTES(type))) {
+		error("%qE attribute is already applied to the type %qT", name, type);
+		return NULL_TREE;
+	}
+
+	*no_add_attrs = false;
+
+	return NULL_TREE;
+}
+
+/* set on complete types that we don't need to inspect further at all */
+static tree handle_randomize_considered_attr(tree *node, tree name, tree args, int flags, bool *no_add_attrs)
+{
+	*no_add_attrs = false;
+	return NULL_TREE;
+}
+
+/*
+ * set on types that we've performed a shuffle on, to prevent re-shuffling
+ * this does not preclude us from inspecting its fields for potential shuffles
+ */
+static tree handle_randomize_performed_attr(tree *node, tree name, tree args, int flags, bool *no_add_attrs)
+{
+	*no_add_attrs = false;
+	return NULL_TREE;
+}
+
+/*
+ * 64bit variant of Bob Jenkins' public domain PRNG
+ * 256 bits of internal state
+ */
+
+typedef unsigned long long u64;
+
+typedef struct ranctx { u64 a; u64 b; u64 c; u64 d; } ranctx;
+
+#define rot(x,k) (((x)<<(k))|((x)>>(64-(k))))
+static u64 ranval(ranctx *x) {
+	u64 e = x->a - rot(x->b, 7);
+	x->a = x->b ^ rot(x->c, 13);
+	x->b = x->c + rot(x->d, 37);
+	x->c = x->d + e;
+	x->d = e + x->a;
+	return x->d;
+}
+
+static void raninit(ranctx *x, u64 *seed) {
+	int i;
+
+	x->a = seed[0];
+	x->b = seed[1];
+	x->c = seed[2];
+	x->d = seed[3];
+
+	for (i=0; i < 30; ++i)
+		(void)ranval(x);
+}
+
+static u64 shuffle_seed[4];
+
+struct partition_group {
+	tree tree_start;
+	unsigned long start;
+	unsigned long length;
+};
+
+static void partition_struct(tree *fields, unsigned long length, struct partition_group *size_groups, unsigned long *num_groups)
+{
+	unsigned long i;
+	unsigned long accum_size = 0;
+	unsigned long accum_length = 0;
+	unsigned long group_idx = 0;
+
+	gcc_assert(length < INT_MAX);
+
+	memset(size_groups, 0, sizeof(struct partition_group) * length);
+
+	for (i = 0; i < length; i++) {
+		if (size_groups[group_idx].tree_start == NULL_TREE) {
+			size_groups[group_idx].tree_start = fields[i];
+			size_groups[group_idx].start = i;
+			accum_length = 0;
+			accum_size = 0;
+		}
+		accum_size += (unsigned long)int_size_in_bytes(TREE_TYPE(fields[i]));
+		accum_length++;
+		if (accum_size >= 64) {
+			size_groups[group_idx].length = accum_length;
+			accum_length = 0;
+			group_idx++;
+		}
+	}
+
+	if (size_groups[group_idx].tree_start != NULL_TREE &&
+	    !size_groups[group_idx].length) {
+		size_groups[group_idx].length = accum_length;
+		group_idx++;
+	}
+
+	*num_groups = group_idx;
+}
+
+static void performance_shuffle(tree *newtree, unsigned long length, ranctx *prng_state)
+{
+	unsigned long i, x;
+	struct partition_group size_group[length];
+	unsigned long num_groups = 0;
+	unsigned long randnum;
+
+	partition_struct(newtree, length, (struct partition_group *)&size_group, &num_groups);
+	for (i = num_groups - 1; i > 0; i--) {
+		struct partition_group tmp;
+		randnum = ranval(prng_state) % (i + 1);
+		tmp = size_group[i];
+		size_group[i] = size_group[randnum];
+		size_group[randnum] = tmp;
+	}
+
+	for (x = 0; x < num_groups; x++) {
+		for (i = size_group[x].start + size_group[x].length - 1; i > size_group[x].start; i--) {
+			tree tmp;
+			if (DECL_BIT_FIELD_TYPE(newtree[i]))
+				continue;
+			randnum = ranval(prng_state) % (i + 1);
+			// we could handle this case differently if desired
+			if (DECL_BIT_FIELD_TYPE(newtree[randnum]))
+				continue;
+			tmp = newtree[i];
+			newtree[i] = newtree[randnum];
+			newtree[randnum] = tmp;
+		}
+	}
+}
+
+static void full_shuffle(tree *newtree, unsigned long length, ranctx *prng_state)
+{
+	unsigned long i, randnum;
+
+	for (i = length - 1; i > 0; i--) {
+		tree tmp;
+		randnum = ranval(prng_state) % (i + 1);
+		tmp = newtree[i];
+		newtree[i] = newtree[randnum];
+		newtree[randnum] = tmp;
+	}
+}
+
+/* modern in-place Fisher-Yates shuffle */
+static void shuffle(const_tree type, tree *newtree, unsigned long length)
+{
+	unsigned long i;
+	u64 seed[4];
+	ranctx prng_state;
+	const unsigned char *structname;
+
+	if (length == 0)
+		return;
+
+	gcc_assert(TREE_CODE(type) == RECORD_TYPE);
+
+	structname = ORIG_TYPE_NAME(type);
+
+#ifdef __DEBUG_PLUGIN
+	fprintf(stderr, "Shuffling struct %s %p\n", (const char *)structname, type);
+#ifdef __DEBUG_VERBOSE
+	debug_tree((tree)type);
+#endif
+#endif
+
+	for (i = 0; i < 4; i++) {
+		seed[i] = shuffle_seed[i];
+		seed[i] ^= name_hash(structname);
+	}
+
+	raninit(&prng_state, (u64 *)&seed);
+
+	if (performance_mode)
+		performance_shuffle(newtree, length, &prng_state);
+	else
+		full_shuffle(newtree, length, &prng_state);
+}
+
+static bool is_flexible_array(const_tree field)
+{
+	const_tree fieldtype;
+	const_tree typesize;
+	const_tree elemtype;
+	const_tree elemsize;
+
+	fieldtype = TREE_TYPE(field);
+	typesize = TYPE_SIZE(fieldtype);
+
+	if (TREE_CODE(fieldtype) != ARRAY_TYPE)
+		return false;
+
+	elemtype = TREE_TYPE(fieldtype);
+	elemsize = TYPE_SIZE(elemtype);
+
+	/* size of type is represented in bits */
+
+	if (typesize == NULL_TREE && TYPE_DOMAIN(fieldtype) != NULL_TREE &&
+	    TYPE_MAX_VALUE(TYPE_DOMAIN(fieldtype)) == NULL_TREE)
+		return true;
+
+	if (typesize != NULL_TREE && 
+	    (TREE_CONSTANT(typesize) && (!tree_to_uhwi(typesize) ||
+	     tree_to_uhwi(typesize) == tree_to_uhwi(elemsize))))
+		return true;
+
+	return false;
+}
+
+static int relayout_struct(tree type)
+{
+	unsigned long num_fields = (unsigned long)list_length(TYPE_FIELDS(type));
+	unsigned long shuffle_length = num_fields;
+	tree field;
+	tree newtree[num_fields];
+	unsigned long i;
+	tree list;
+	tree variant;
+	tree main_variant;
+	expanded_location xloc;
+	bool has_flexarray = false;
+
+	if (TYPE_FIELDS(type) == NULL_TREE)
+		return 0;
+
+	if (num_fields < 2)
+		return 0;
+
+	gcc_assert(TREE_CODE(type) == RECORD_TYPE);
+
+	gcc_assert(num_fields < INT_MAX);
+
+	if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(type)) ||
+	    lookup_attribute("no_randomize_layout", TYPE_ATTRIBUTES(TYPE_MAIN_VARIANT(type))))
+		return 0;
+
+	/* Workaround for 3rd-party VirtualBox source that we can't modify ourselves */
+	if (!strcmp((const char *)ORIG_TYPE_NAME(type), "INTNETTRUNKFACTORY") ||
+	    !strcmp((const char *)ORIG_TYPE_NAME(type), "RAWPCIFACTORY"))
+		return 0;
+
+	/* throw out any structs in uapi */
+	xloc = expand_location(DECL_SOURCE_LOCATION(TYPE_FIELDS(type)));
+
+	if (strstr(xloc.file, "/uapi/"))
+		error(G_("attempted to randomize userland API struct %s"), ORIG_TYPE_NAME(type));
+
+	for (field = TYPE_FIELDS(type), i = 0; field; field = TREE_CHAIN(field), i++) {
+		gcc_assert(TREE_CODE(field) == FIELD_DECL);
+		newtree[i] = field;
+	}
+
+	/*
+	 * enforce that we don't randomize the layout of the last
+	 * element of a struct if it's a 0 or 1-length array
+	 * or a proper flexible array
+	 */
+	if (is_flexible_array(newtree[num_fields - 1])) {
+		has_flexarray = true;
+		shuffle_length--;
+	}
+
+	shuffle(type, (tree *)newtree, shuffle_length);
+
+	/*
+	 * set up a bogus anonymous struct field designed to error out on unnamed struct initializers
+	 * as gcc provides no other way to detect such code
+	 */
+	list = make_node(FIELD_DECL);
+	TREE_CHAIN(list) = newtree[0];
+	TREE_TYPE(list) = void_type_node;
+	DECL_SIZE(list) = bitsize_zero_node;
+	DECL_NONADDRESSABLE_P(list) = 1;
+	DECL_FIELD_BIT_OFFSET(list) = bitsize_zero_node;
+	DECL_SIZE_UNIT(list) = size_zero_node;
+	DECL_FIELD_OFFSET(list) = size_zero_node;
+	DECL_CONTEXT(list) = type;
+	// to satisfy the constify plugin
+	TREE_READONLY(list) = 1;
+
+	for (i = 0; i < num_fields - 1; i++)
+		TREE_CHAIN(newtree[i]) = newtree[i+1];
+	TREE_CHAIN(newtree[num_fields - 1]) = NULL_TREE;
+
+	main_variant = TYPE_MAIN_VARIANT(type);
+	for (variant = main_variant; variant; variant = TYPE_NEXT_VARIANT(variant)) {
+		TYPE_FIELDS(variant) = list;
+		TYPE_ATTRIBUTES(variant) = copy_list(TYPE_ATTRIBUTES(variant));
+		TYPE_ATTRIBUTES(variant) = tree_cons(get_identifier("randomize_performed"), NULL_TREE, TYPE_ATTRIBUTES(variant));
+		if (has_flexarray)
+			TYPE_ATTRIBUTES(type) = tree_cons(get_identifier("has_flexarray"), NULL_TREE, TYPE_ATTRIBUTES(type));
+	}
+
+	/*
+	 * force a re-layout of the main variant
+	 * the TYPE_SIZE for all variants will be recomputed
+	 * by finalize_type_size()
+	 */
+	TYPE_SIZE(main_variant) = NULL_TREE;
+	layout_type(main_variant);
+	gcc_assert(TYPE_SIZE(main_variant) != NULL_TREE);
+
+	return 1;
+}
+
+/* from constify plugin */
+static const_tree get_field_type(const_tree field)
+{
+	return strip_array_types(TREE_TYPE(field));
+}
+
+/* from constify plugin */
+static bool is_fptr(const_tree fieldtype)
+{
+	if (TREE_CODE(fieldtype) != POINTER_TYPE)
+		return false;
+
+	return TREE_CODE(TREE_TYPE(fieldtype)) == FUNCTION_TYPE;
+}
+
+/* derived from constify plugin */
+static int is_pure_ops_struct(const_tree node)
+{
+	const_tree field;
+
+	gcc_assert(TREE_CODE(node) == RECORD_TYPE || TREE_CODE(node) == UNION_TYPE);
+
+	/* XXX: Do not apply randomization to all-ftpr structs yet. */
+	return 0;
+
+	for (field = TYPE_FIELDS(node); field; field = TREE_CHAIN(field)) {
+		const_tree fieldtype = get_field_type(field);
+		enum tree_code code = TREE_CODE(fieldtype);
+
+		if (node == fieldtype)
+			continue;
+
+		if (!is_fptr(fieldtype))
+			return 0;
+
+		if (code != RECORD_TYPE && code != UNION_TYPE)
+			continue;
+
+		if (!is_pure_ops_struct(fieldtype))
+			return 0;
+	}
+
+	return 1;
+}
+
+static void randomize_type(tree type)
+{
+	tree variant;
+
+	gcc_assert(TREE_CODE(type) == RECORD_TYPE);
+
+	if (lookup_attribute("randomize_considered", TYPE_ATTRIBUTES(type)))
+		return;
+
+	if (lookup_attribute("randomize_layout", TYPE_ATTRIBUTES(TYPE_MAIN_VARIANT(type))) || is_pure_ops_struct(type))
+		relayout_struct(type);
+
+	for (variant = TYPE_MAIN_VARIANT(type); variant; variant = TYPE_NEXT_VARIANT(variant)) {
+		TYPE_ATTRIBUTES(type) = copy_list(TYPE_ATTRIBUTES(type));
+		TYPE_ATTRIBUTES(type) = tree_cons(get_identifier("randomize_considered"), NULL_TREE, TYPE_ATTRIBUTES(type));
+	}
+#ifdef __DEBUG_PLUGIN
+	fprintf(stderr, "Marking randomize_considered on struct %s\n", ORIG_TYPE_NAME(type));
+#ifdef __DEBUG_VERBOSE
+	debug_tree(type);
+#endif
+#endif
+}
+
+static void update_decl_size(tree decl)
+{
+	tree lastval, lastidx, field, init, type, flexsize;
+	unsigned HOST_WIDE_INT len;
+
+	type = TREE_TYPE(decl);
+
+	if (!lookup_attribute("has_flexarray", TYPE_ATTRIBUTES(type)))
+		return;
+
+	init = DECL_INITIAL(decl);
+	if (init == NULL_TREE || init == error_mark_node)
+		return;
+
+	if (TREE_CODE(init) != CONSTRUCTOR)
+		return;
+
+	len = CONSTRUCTOR_NELTS(init);
+        if (!len)
+		return;
+
+	lastval = CONSTRUCTOR_ELT(init, CONSTRUCTOR_NELTS(init) - 1)->value;
+	lastidx = CONSTRUCTOR_ELT(init, CONSTRUCTOR_NELTS(init) - 1)->index;
+
+	for (field = TYPE_FIELDS(TREE_TYPE(decl)); TREE_CHAIN(field); field = TREE_CHAIN(field))
+		;
+
+	if (lastidx != field)
+		return;
+
+	if (TREE_CODE(lastval) != STRING_CST) {
+		error("Only string constants are supported as initializers "
+		      "for randomized structures with flexible arrays");
+		return;
+	}
+
+	flexsize = bitsize_int(TREE_STRING_LENGTH(lastval) *
+		tree_to_uhwi(TYPE_SIZE(TREE_TYPE(TREE_TYPE(lastval)))));
+
+	DECL_SIZE(decl) = size_binop(PLUS_EXPR, TYPE_SIZE(type), flexsize);
+
+	return;
+}
+
+
+static void randomize_layout_finish_decl(void *event_data, void *data)
+{
+	tree decl = (tree)event_data;
+	tree type;
+
+	if (decl == NULL_TREE || decl == error_mark_node)
+		return;
+
+	type = TREE_TYPE(decl);
+
+	if (TREE_CODE(decl) != VAR_DECL)
+		return;
+
+	if (TREE_CODE(type) != RECORD_TYPE && TREE_CODE(type) != UNION_TYPE)
+		return;
+
+	if (!lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(type)))
+		return;
+
+	DECL_SIZE(decl) = 0;
+	DECL_SIZE_UNIT(decl) = 0;
+	DECL_ALIGN(decl) = 0;
+	DECL_MODE (decl) = VOIDmode;
+	SET_DECL_RTL(decl, 0);
+	update_decl_size(decl);
+	layout_decl(decl, 0);
+}
+
+static void finish_type(void *event_data, void *data)
+{
+	tree type = (tree)event_data;
+
+	if (type == NULL_TREE || type == error_mark_node)
+		return;
+
+	if (TREE_CODE(type) != RECORD_TYPE)
+		return;
+
+	if (TYPE_FIELDS(type) == NULL_TREE)
+		return;
+
+	if (lookup_attribute("randomize_considered", TYPE_ATTRIBUTES(type)))
+		return;
+
+#ifdef __DEBUG_PLUGIN
+	fprintf(stderr, "Calling randomize_type on %s\n", ORIG_TYPE_NAME(type));
+#endif
+#ifdef __DEBUG_VERBOSE
+	debug_tree(type);
+#endif
+	randomize_type(type);
+
+	return;
+}
+
+static struct attribute_spec randomize_layout_attr = {
+	.name		= "randomize_layout",
+	// related to args
+	.min_length	= 0,
+	.max_length	= 0,
+	.decl_required	= false,
+	// need type declaration
+	.type_required	= true,
+	.function_type_required = false,
+	.handler		= handle_randomize_layout_attr,
+#if BUILDING_GCC_VERSION >= 4007
+	.affects_type_identity  = true
+#endif
+};
+
+static struct attribute_spec no_randomize_layout_attr = {
+	.name		= "no_randomize_layout",
+	// related to args
+	.min_length	= 0,
+	.max_length	= 0,
+	.decl_required	= false,
+	// need type declaration
+	.type_required	= true,
+	.function_type_required = false,
+	.handler		= handle_randomize_layout_attr,
+#if BUILDING_GCC_VERSION >= 4007
+	.affects_type_identity  = true
+#endif
+};
+
+static struct attribute_spec randomize_considered_attr = {
+	.name		= "randomize_considered",
+	// related to args
+	.min_length	= 0,
+	.max_length	= 0,
+	.decl_required	= false,
+	// need type declaration
+	.type_required	= true,
+	.function_type_required = false,
+	.handler		= handle_randomize_considered_attr,
+#if BUILDING_GCC_VERSION >= 4007
+	.affects_type_identity  = false
+#endif
+};
+
+static struct attribute_spec randomize_performed_attr = {
+	.name		= "randomize_performed",
+	// related to args
+	.min_length	= 0,
+	.max_length	= 0,
+	.decl_required	= false,
+	// need type declaration
+	.type_required	= true,
+	.function_type_required = false,
+	.handler		= handle_randomize_performed_attr,
+#if BUILDING_GCC_VERSION >= 4007
+	.affects_type_identity  = false
+#endif
+};
+
+static void register_attributes(void *event_data, void *data)
+{
+	register_attribute(&randomize_layout_attr);
+	register_attribute(&no_randomize_layout_attr);
+	register_attribute(&randomize_considered_attr);
+	register_attribute(&randomize_performed_attr);
+}
+
+static void check_bad_casts_in_constructor(tree var, tree init)
+{
+	unsigned HOST_WIDE_INT idx;
+	tree field, val;
+	tree field_type, val_type;
+
+	FOR_EACH_CONSTRUCTOR_ELT(CONSTRUCTOR_ELTS(init), idx, field, val) {
+		if (TREE_CODE(val) == CONSTRUCTOR) {
+			check_bad_casts_in_constructor(var, val);
+			continue;
+		}
+
+		/* pipacs' plugin creates franken-arrays that differ from those produced by
+		   normal code which all have valid 'field' trees. work around this */
+		if (field == NULL_TREE)
+			continue;
+		field_type = TREE_TYPE(field);
+		val_type = TREE_TYPE(val);
+
+		if (TREE_CODE(field_type) != POINTER_TYPE || TREE_CODE(val_type) != POINTER_TYPE)
+			continue;
+
+		if (field_type == val_type)
+			continue;
+
+		field_type = TYPE_MAIN_VARIANT(strip_array_types(TYPE_MAIN_VARIANT(TREE_TYPE(field_type))));
+		val_type = TYPE_MAIN_VARIANT(strip_array_types(TYPE_MAIN_VARIANT(TREE_TYPE(val_type))));
+
+		if (field_type == void_type_node)
+			continue;
+		if (field_type == val_type)
+			continue;
+		if (TREE_CODE(val_type) != RECORD_TYPE)
+			continue;
+
+		if (!lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(val_type)))
+			continue;
+		inform(DECL_SOURCE_LOCATION(var), "found mismatched struct pointer types: %qT and %qT\n", TYPE_MAIN_VARIANT(field_type), TYPE_MAIN_VARIANT(val_type));
+	}
+}
+
+/* derived from the constify plugin */
+static void check_global_variables(void *event_data, void *data)
+{
+	struct varpool_node *node;
+	tree init;
+
+	FOR_EACH_VARIABLE(node) {
+		tree var = NODE_DECL(node);
+		init = DECL_INITIAL(var);
+		if (init == NULL_TREE)
+			continue;
+
+		if (TREE_CODE(init) != CONSTRUCTOR)
+			continue;
+
+		check_bad_casts_in_constructor(var, init);
+	}
+}
+
+static bool dominated_by_is_err(const_tree rhs, basic_block bb)
+{
+	basic_block dom;
+	gimple dom_stmt;
+	gimple call_stmt;
+	const_tree dom_lhs;
+	const_tree poss_is_err_cond;
+	const_tree poss_is_err_func;
+	const_tree is_err_arg;
+
+	dom = get_immediate_dominator(CDI_DOMINATORS, bb);
+	if (!dom)
+		return false;
+
+	dom_stmt = last_stmt(dom);
+	if (!dom_stmt)
+		return false;
+
+	if (gimple_code(dom_stmt) != GIMPLE_COND)
+		return false;
+
+	if (gimple_cond_code(dom_stmt) != NE_EXPR)
+		return false;
+
+	if (!integer_zerop(gimple_cond_rhs(dom_stmt)))
+		return false;
+
+	poss_is_err_cond = gimple_cond_lhs(dom_stmt);
+
+	if (TREE_CODE(poss_is_err_cond) != SSA_NAME)
+		return false;
+
+	call_stmt = SSA_NAME_DEF_STMT(poss_is_err_cond);
+
+	if (gimple_code(call_stmt) != GIMPLE_CALL)
+		return false;
+
+	dom_lhs = gimple_get_lhs(call_stmt);
+	poss_is_err_func = gimple_call_fndecl(call_stmt);
+	if (!poss_is_err_func)
+		return false;
+	if (dom_lhs != poss_is_err_cond)
+		return false;
+	if (strcmp(DECL_NAME_POINTER(poss_is_err_func), "IS_ERR"))
+		return false;
+
+	is_err_arg = gimple_call_arg(call_stmt, 0);
+	if (!is_err_arg)
+		return false;
+
+	if (is_err_arg != rhs)
+		return false;
+
+	return true;
+}
+
+static void handle_local_var_initializers(void)
+{
+	tree var;
+	unsigned int i;
+
+	FOR_EACH_LOCAL_DECL(cfun, i, var) {
+		tree init = DECL_INITIAL(var);
+		if (!init)
+			continue;
+		if (TREE_CODE(init) != CONSTRUCTOR)
+			continue;
+		check_bad_casts_in_constructor(var, init);
+	}
+}
+
+/*
+ * iterate over all statements to find "bad" casts:
+ * those where the address of the start of a structure is cast
+ * to a pointer of a structure of a different type, or a
+ * structure pointer type is cast to a different structure pointer type
+ */
+static unsigned int find_bad_casts_execute(void)
+{
+	basic_block bb;
+
+	handle_local_var_initializers();
+
+	FOR_EACH_BB_FN(bb, cfun) {
+		gimple_stmt_iterator gsi;
+
+		for (gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) {
+			gimple stmt;
+			const_tree lhs;
+			const_tree lhs_type;
+			const_tree rhs1;
+			const_tree rhs_type;
+			const_tree ptr_lhs_type;
+			const_tree ptr_rhs_type;
+			const_tree op0;
+			const_tree op0_type;
+			enum tree_code rhs_code;
+
+			stmt = gsi_stmt(gsi);
+
+#ifdef __DEBUG_PLUGIN
+#ifdef __DEBUG_VERBOSE
+			debug_gimple_stmt(stmt);
+			debug_tree(gimple_get_lhs(stmt));
+#endif
+#endif
+
+			if (gimple_code(stmt) != GIMPLE_ASSIGN)
+				continue;
+
+#ifdef __DEBUG_PLUGIN
+#ifdef __DEBUG_VERBOSE
+			debug_tree(gimple_assign_rhs1(stmt));
+#endif
+#endif
+
+			rhs_code = gimple_assign_rhs_code(stmt);
+
+			if (rhs_code != ADDR_EXPR && rhs_code != SSA_NAME)
+				continue;
+
+			lhs = gimple_get_lhs(stmt);
+			lhs_type = TREE_TYPE(lhs);
+			rhs1 = gimple_assign_rhs1(stmt);
+			rhs_type = TREE_TYPE(rhs1);
+
+			if (TREE_CODE(rhs_type) != POINTER_TYPE ||
+			    TREE_CODE(lhs_type) != POINTER_TYPE)
+				continue;
+
+			ptr_lhs_type = TYPE_MAIN_VARIANT(strip_array_types(TYPE_MAIN_VARIANT(TREE_TYPE(lhs_type))));
+			ptr_rhs_type = TYPE_MAIN_VARIANT(strip_array_types(TYPE_MAIN_VARIANT(TREE_TYPE(rhs_type))));
+
+			if (ptr_rhs_type == void_type_node)
+				continue;
+
+			if (ptr_lhs_type == void_type_node)
+				continue;
+
+			if (dominated_by_is_err(rhs1, bb))
+				continue;
+
+			if (TREE_CODE(ptr_rhs_type) != RECORD_TYPE) {
+#ifndef __DEBUG_PLUGIN
+				if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(ptr_lhs_type)))
+#endif
+				inform(gimple_location(stmt), "found mismatched struct pointer types: %qT and %qT\n", ptr_lhs_type, ptr_rhs_type);
+				continue;
+			}
+
+			if (rhs_code == SSA_NAME && ptr_lhs_type == ptr_rhs_type)
+				continue;
+
+			if (rhs_code == ADDR_EXPR) {
+				op0 = TREE_OPERAND(rhs1, 0);
+
+				if (op0 == NULL_TREE)
+					continue;
+
+				if (TREE_CODE(op0) != VAR_DECL)
+					continue;
+
+				op0_type = TYPE_MAIN_VARIANT(strip_array_types(TYPE_MAIN_VARIANT(TREE_TYPE(op0))));
+				if (op0_type == ptr_lhs_type)
+					continue;
+
+#ifndef __DEBUG_PLUGIN
+				if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(op0_type)))
+#endif
+				inform(gimple_location(stmt), "found mismatched struct pointer types: %qT and %qT\n", ptr_lhs_type, op0_type);
+			} else {
+				const_tree ssa_name_var = SSA_NAME_VAR(rhs1);
+				/* skip bogus type casts introduced by container_of */
+				if (ssa_name_var != NULL_TREE && DECL_NAME(ssa_name_var) && 
+				    !strcmp((const char *)DECL_NAME_POINTER(ssa_name_var), "__mptr"))
+					continue;
+#ifndef __DEBUG_PLUGIN
+				if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(ptr_rhs_type)))
+#endif
+				inform(gimple_location(stmt), "found mismatched struct pointer types: %qT and %qT\n", ptr_lhs_type, ptr_rhs_type);
+			}
+
+		}
+	}
+	return 0;
+}
+
+#define PASS_NAME find_bad_casts
+#define NO_GATE
+#define TODO_FLAGS_FINISH TODO_dump_func
+#include "gcc-generate-gimple-pass.h"
+
+__visible int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version)
+{
+	int i;
+	const char * const plugin_name = plugin_info->base_name;
+	const int argc = plugin_info->argc;
+	const struct plugin_argument * const argv = plugin_info->argv;
+	bool enable = true;
+	int obtained_seed = 0;
+	struct register_pass_info find_bad_casts_pass_info;
+
+	find_bad_casts_pass_info.pass			= make_find_bad_casts_pass();
+	find_bad_casts_pass_info.reference_pass_name	= "ssa";
+	find_bad_casts_pass_info.ref_pass_instance_number	= 1;
+	find_bad_casts_pass_info.pos_op			= PASS_POS_INSERT_AFTER;
+
+	if (!plugin_default_version_check(version, &gcc_version)) {
+		error(G_("incompatible gcc/plugin versions"));
+		return 1;
+	}
+
+	if (strncmp(lang_hooks.name, "GNU C", 5) && !strncmp(lang_hooks.name, "GNU C+", 6)) {
+		inform(UNKNOWN_LOCATION, G_("%s supports C only, not %s"), plugin_name, lang_hooks.name);
+		enable = false;
+	}
+
+	for (i = 0; i < argc; ++i) {
+		if (!strcmp(argv[i].key, "disable")) {
+			enable = false;
+			continue;
+		}
+		if (!strcmp(argv[i].key, "performance-mode")) {
+			performance_mode = 1;
+			continue;
+		}
+		error(G_("unknown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key);
+	}
+
+	if (strlen(randstruct_seed) != 64) {
+		error(G_("invalid seed value supplied for %s plugin"), plugin_name);
+		return 1;
+	}
+	obtained_seed = sscanf(randstruct_seed, "%016llx%016llx%016llx%016llx",
+		&shuffle_seed[0], &shuffle_seed[1], &shuffle_seed[2], &shuffle_seed[3]);
+	if (obtained_seed != 4) {
+		error(G_("Invalid seed supplied for %s plugin"), plugin_name);
+		return 1;
+	}
+
+	register_callback(plugin_name, PLUGIN_INFO, NULL, &randomize_layout_plugin_info);
+	if (enable) {
+		register_callback(plugin_name, PLUGIN_ALL_IPA_PASSES_START, check_global_variables, NULL);
+		register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &find_bad_casts_pass_info);
+		register_callback(plugin_name, PLUGIN_FINISH_TYPE, finish_type, NULL);
+		register_callback(plugin_name, PLUGIN_FINISH_DECL, randomize_layout_finish_decl, NULL);
+	}
+	register_callback(plugin_name, PLUGIN_ATTRIBUTES, register_attributes, NULL);
+
+	return 0;
+}
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [kernel-hardening] [PATCH 02/18] compiler: Add __designated_init annotation
  2017-04-06 21:18 [kernel-hardening] [PATCH 00/18] Introduce struct layout randomization plugin Kees Cook
  2017-04-06 21:18 ` [kernel-hardening] [PATCH 01/18] gcc-plugins: Add the randstruct plugin Kees Cook
@ 2017-04-06 21:18 ` Kees Cook
  2017-04-06 21:18 ` [kernel-hardening] [PATCH 03/18] randstruct: Set designated_init attribute Kees Cook
                   ` (18 subsequent siblings)
  20 siblings, 0 replies; 34+ messages in thread
From: Kees Cook @ 2017-04-06 21:18 UTC (permalink / raw)
  To: kernel-hardening; +Cc: Kees Cook, Michael Leibowitz

This allows structure annotations for requiring designated initialization
in GCC 5.1.0 and later:
https://gcc.gnu.org/onlinedocs/gcc/Designated-Inits.html

The structure randomization layout plugin will be using this to help
identify structures that need this form of initialization.

Signed-off-by: Kees Cook <keescook@chromium.org>
---
 include/linux/compiler-gcc.h | 8 ++++++++
 include/linux/compiler.h     | 4 ++++
 2 files changed, 12 insertions(+)

diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h
index 5f4d8f8b75da..cf541e49841e 100644
--- a/include/linux/compiler-gcc.h
+++ b/include/linux/compiler-gcc.h
@@ -321,6 +321,14 @@
 #define __no_sanitize_address __attribute__((no_sanitize_address))
 #endif
 
+#if GCC_VERSION >= 50100
+/*
+ * Mark structures as requiring designated initializers.
+ * https://gcc.gnu.org/onlinedocs/gcc/Designated-Inits.html
+ */
+#define __designated_init __attribute__((designated_init))
+#endif
+
 #endif	/* gcc version >= 40000 specific checks */
 
 #if !defined(__noclone)
diff --git a/include/linux/compiler.h b/include/linux/compiler.h
index b8642a3a1f4f..40e584448605 100644
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -440,6 +440,10 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s
 # define __attribute_const__	/* unimplemented */
 #endif
 
+#ifndef __designated_init
+# define __designated_init
+#endif
+
 #ifndef __latent_entropy
 # define __latent_entropy
 #endif
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [kernel-hardening] [PATCH 03/18] randstruct: Set designated_init attribute
  2017-04-06 21:18 [kernel-hardening] [PATCH 00/18] Introduce struct layout randomization plugin Kees Cook
  2017-04-06 21:18 ` [kernel-hardening] [PATCH 01/18] gcc-plugins: Add the randstruct plugin Kees Cook
  2017-04-06 21:18 ` [kernel-hardening] [PATCH 02/18] compiler: Add __designated_init annotation Kees Cook
@ 2017-04-06 21:18 ` Kees Cook
  2017-04-06 21:18 ` [kernel-hardening] [PATCH 04/18] randstruct: Differentiate bad cast warnings Kees Cook
                   ` (17 subsequent siblings)
  20 siblings, 0 replies; 34+ messages in thread
From: Kees Cook @ 2017-04-06 21:18 UTC (permalink / raw)
  To: kernel-hardening; +Cc: Kees Cook, Michael Leibowitz

Since randomized structures need designated initializers, make
sure the designated_init attribute is set for GCC 5.1 and later's
-Werror=designated-init. Since this marking is needed for both manually
and automatically identified structures, have the plugin perform the
marking when active, otherwise fall back to just the manually marked
structures.

Signed-off-by: Kees Cook <keescook@chromium.org>
---
 include/linux/compiler.h                      | 2 +-
 scripts/gcc-plugins/randomize_layout_plugin.c | 1 +
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/include/linux/compiler.h b/include/linux/compiler.h
index 40e584448605..105410d776a6 100644
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -449,7 +449,7 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s
 #endif
 
 #ifndef __randomize_layout
-# define __randomize_layout
+# define __randomize_layout __designated_init
 #endif
 
 #ifndef __no_randomize_layout
diff --git a/scripts/gcc-plugins/randomize_layout_plugin.c b/scripts/gcc-plugins/randomize_layout_plugin.c
index eb8ac6cc315e..6e5dccc4f221 100644
--- a/scripts/gcc-plugins/randomize_layout_plugin.c
+++ b/scripts/gcc-plugins/randomize_layout_plugin.c
@@ -377,6 +377,7 @@ static int relayout_struct(tree type)
 		TYPE_FIELDS(variant) = list;
 		TYPE_ATTRIBUTES(variant) = copy_list(TYPE_ATTRIBUTES(variant));
 		TYPE_ATTRIBUTES(variant) = tree_cons(get_identifier("randomize_performed"), NULL_TREE, TYPE_ATTRIBUTES(variant));
+		TYPE_ATTRIBUTES(variant) = tree_cons(get_identifier("designated_init"), NULL_TREE, TYPE_ATTRIBUTES(variant));
 		if (has_flexarray)
 			TYPE_ATTRIBUTES(type) = tree_cons(get_identifier("has_flexarray"), NULL_TREE, TYPE_ATTRIBUTES(type));
 	}
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [kernel-hardening] [PATCH 04/18] randstruct: Differentiate bad cast warnings
  2017-04-06 21:18 [kernel-hardening] [PATCH 00/18] Introduce struct layout randomization plugin Kees Cook
                   ` (2 preceding siblings ...)
  2017-04-06 21:18 ` [kernel-hardening] [PATCH 03/18] randstruct: Set designated_init attribute Kees Cook
@ 2017-04-06 21:18 ` Kees Cook
  2017-04-06 21:18 ` [kernel-hardening] [PATCH 05/18] af_unix: Use designated initializers Kees Cook
                   ` (16 subsequent siblings)
  20 siblings, 0 replies; 34+ messages in thread
From: Kees Cook @ 2017-04-06 21:18 UTC (permalink / raw)
  To: kernel-hardening; +Cc: Kees Cook, Michael Leibowitz

This updates the bad cast warnings to be more specific about which kind
of comparison failed.

Signed-off-by: Kees Cook <keescook@chromium.org>
---
 scripts/gcc-plugins/randomize_layout_plugin.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/scripts/gcc-plugins/randomize_layout_plugin.c b/scripts/gcc-plugins/randomize_layout_plugin.c
index 6e5dccc4f221..dc03a6beb06b 100644
--- a/scripts/gcc-plugins/randomize_layout_plugin.c
+++ b/scripts/gcc-plugins/randomize_layout_plugin.c
@@ -668,7 +668,7 @@ static void check_bad_casts_in_constructor(tree var, tree init)
 
 		if (!lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(val_type)))
 			continue;
-		inform(DECL_SOURCE_LOCATION(var), "found mismatched struct pointer types: %qT and %qT\n", TYPE_MAIN_VARIANT(field_type), TYPE_MAIN_VARIANT(val_type));
+		inform(DECL_SOURCE_LOCATION(var), "found mismatched constructor struct pointer types: %qT and %qT\n", TYPE_MAIN_VARIANT(field_type), TYPE_MAIN_VARIANT(val_type));
 	}
 }
 
@@ -837,7 +837,7 @@ static unsigned int find_bad_casts_execute(void)
 #ifndef __DEBUG_PLUGIN
 				if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(ptr_lhs_type)))
 #endif
-				inform(gimple_location(stmt), "found mismatched struct pointer types: %qT and %qT\n", ptr_lhs_type, ptr_rhs_type);
+				inform(gimple_location(stmt), "found mismatched rhs struct pointer types: %qT and %qT\n", ptr_lhs_type, ptr_rhs_type);
 				continue;
 			}
 
@@ -860,7 +860,7 @@ static unsigned int find_bad_casts_execute(void)
 #ifndef __DEBUG_PLUGIN
 				if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(op0_type)))
 #endif
-				inform(gimple_location(stmt), "found mismatched struct pointer types: %qT and %qT\n", ptr_lhs_type, op0_type);
+				inform(gimple_location(stmt), "found mismatched op0 struct pointer types: %qT and %qT\n", ptr_lhs_type, op0_type);
 			} else {
 				const_tree ssa_name_var = SSA_NAME_VAR(rhs1);
 				/* skip bogus type casts introduced by container_of */
@@ -870,7 +870,7 @@ static unsigned int find_bad_casts_execute(void)
 #ifndef __DEBUG_PLUGIN
 				if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(ptr_rhs_type)))
 #endif
-				inform(gimple_location(stmt), "found mismatched struct pointer types: %qT and %qT\n", ptr_lhs_type, ptr_rhs_type);
+				inform(gimple_location(stmt), "found mismatched ssa struct pointer types: %qT and %qT\n", ptr_lhs_type, ptr_rhs_type);
 			}
 
 		}
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [kernel-hardening] [PATCH 05/18] af_unix: Use designated initializers
  2017-04-06 21:18 [kernel-hardening] [PATCH 00/18] Introduce struct layout randomization plugin Kees Cook
                   ` (3 preceding siblings ...)
  2017-04-06 21:18 ` [kernel-hardening] [PATCH 04/18] randstruct: Differentiate bad cast warnings Kees Cook
@ 2017-04-06 21:18 ` Kees Cook
  2017-04-06 21:18 ` [kernel-hardening] [PATCH 06/18] NFS: Avoid cross-structure casting Kees Cook
                   ` (15 subsequent siblings)
  20 siblings, 0 replies; 34+ messages in thread
From: Kees Cook @ 2017-04-06 21:18 UTC (permalink / raw)
  To: kernel-hardening; +Cc: Kees Cook, Michael Leibowitz

Prepare to mark sensitive kernel structures for randomization by making
sure they're using designated initializers. These were identified during
allyesconfig builds of x86, arm, and arm64, and the initializer fixes
were extracted from grsecurity. In this case, NULL initialize with { }
instead of undesignated NULLs.

Signed-off-by: Kees Cook <keescook@chromium.org>
---
 net/unix/af_unix.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 928691c43408..6a7fe7660551 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -996,7 +996,7 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 	unsigned int hash;
 	struct unix_address *addr;
 	struct hlist_head *list;
-	struct path path = { NULL, NULL };
+	struct path path = { };
 
 	err = -EINVAL;
 	if (sunaddr->sun_family != AF_UNIX)
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [kernel-hardening] [PATCH 06/18] NFS: Avoid cross-structure casting
  2017-04-06 21:18 [kernel-hardening] [PATCH 00/18] Introduce struct layout randomization plugin Kees Cook
                   ` (4 preceding siblings ...)
  2017-04-06 21:18 ` [kernel-hardening] [PATCH 05/18] af_unix: Use designated initializers Kees Cook
@ 2017-04-06 21:18 ` Kees Cook
  2017-04-06 21:18 ` [kernel-hardening] [PATCH 07/18] randstruct: Whitelist struct security_hook_heads cast Kees Cook
                   ` (14 subsequent siblings)
  20 siblings, 0 replies; 34+ messages in thread
From: Kees Cook @ 2017-04-06 21:18 UTC (permalink / raw)
  To: kernel-hardening; +Cc: Kees Cook, Michael Leibowitz

When the call to nfs_devname() fails, the error path attempts to retain
the error via the mnt variable, but this requires a cast across very
different types (char * to struct vfsmount *), which the upcoming
structure layout randomization plugin flags as being potentially
dangerous in the face of randomization. This is a false positive, but
what this code actually wants to do is retain the error value, so this
patch explicitly sets it, instead of using what seems to be an
unexpected cast.

Signed-off-by: Kees Cook <keescook@chromium.org>
---
 fs/nfs/namespace.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
index 786f17580582..8ca5d147124d 100644
--- a/fs/nfs/namespace.c
+++ b/fs/nfs/namespace.c
@@ -259,9 +259,10 @@ struct vfsmount *nfs_do_submount(struct dentry *dentry, struct nfs_fh *fh,
 	if (page == NULL)
 		goto out;
 	devname = nfs_devname(dentry, page, PAGE_SIZE);
-	mnt = (struct vfsmount *)devname;
-	if (IS_ERR(devname))
+	if (IS_ERR(devname)) {
+		mnt = ERR_CAST(devname);
 		goto free_page;
+	}
 	mnt = nfs_do_clone_mount(NFS_SB(dentry->d_sb), devname, &mountdata);
 free_page:
 	free_page((unsigned long)page);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [kernel-hardening] [PATCH 07/18] randstruct: Whitelist struct security_hook_heads cast
  2017-04-06 21:18 [kernel-hardening] [PATCH 00/18] Introduce struct layout randomization plugin Kees Cook
                   ` (5 preceding siblings ...)
  2017-04-06 21:18 ` [kernel-hardening] [PATCH 06/18] NFS: Avoid cross-structure casting Kees Cook
@ 2017-04-06 21:18 ` Kees Cook
  2017-04-06 21:18 ` [kernel-hardening] [PATCH 08/18] randstruct: Whitelist UNIXCB cast Kees Cook
                   ` (13 subsequent siblings)
  20 siblings, 0 replies; 34+ messages in thread
From: Kees Cook @ 2017-04-06 21:18 UTC (permalink / raw)
  To: kernel-hardening; +Cc: Kees Cook, Michael Leibowitz

The LSM initialization routines walk security_hook_heads as an array
of struct list_head instead of via names to avoid a ton of needless
source. Whitelist this to avoid the false positive warning from the
plugin:

security/security.c: In function ‘security_init’:
security/security.c:59:20: note: found mismatched op0 struct pointer types: ‘struct list_head’ and ‘struct security_hook_heads’

  struct list_head *list = (struct list_head *) &security_hook_heads;
                    ^

Signed-off-by: Kees Cook <keescook@chromium.org>
---
 scripts/gcc-plugins/randomize_layout_plugin.c | 38 ++++++++++++++++++++++++++-
 1 file changed, 37 insertions(+), 1 deletion(-)

diff --git a/scripts/gcc-plugins/randomize_layout_plugin.c b/scripts/gcc-plugins/randomize_layout_plugin.c
index dc03a6beb06b..63c654a00249 100644
--- a/scripts/gcc-plugins/randomize_layout_plugin.c
+++ b/scripts/gcc-plugins/randomize_layout_plugin.c
@@ -762,6 +762,33 @@ static void handle_local_var_initializers(void)
 	}
 }
 
+static bool type_name_eq(gimple stmt, const_tree type_tree, const char *wanted_name)
+{
+	const char *type_name;
+
+	if (type_tree == NULL_TREE)
+		return false;
+
+	switch (TREE_CODE(type_tree)) {
+	case RECORD_TYPE:
+		type_name = TYPE_NAME_POINTER(type_tree);
+		break;
+	default:
+		inform(gimple_location(stmt), "unhandled cast comparison: %qT\n", type_tree);
+		debug_tree(type_tree);
+		return false;
+	}
+
+	return strcmp(type_name, wanted_name) == 0;
+}
+
+static bool whitelisted_cast(gimple stmt,
+			     const_tree lhs_tree, const_tree rhs_tree,
+			     const char *lhs, const char *rhs)
+{
+	return type_name_eq(stmt, lhs_tree, lhs) && type_name_eq(stmt, rhs_tree, rhs);
+}
+
 /*
  * iterate over all statements to find "bad" casts:
  * those where the address of the start of a structure is cast
@@ -859,8 +886,17 @@ static unsigned int find_bad_casts_execute(void)
 
 #ifndef __DEBUG_PLUGIN
 				if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(op0_type)))
+				{
 #endif
-				inform(gimple_location(stmt), "found mismatched op0 struct pointer types: %qT and %qT\n", ptr_lhs_type, op0_type);
+					/*
+					 * Whitelist walking struct security_hook_heads
+					 * as an array of struct list_head.
+					 */
+					if (whitelisted_cast(stmt, ptr_lhs_type, op0_type, "list_head", "security_hook_heads"))
+						continue;
+
+					inform(gimple_location(stmt), "found mismatched op0 struct pointer types: %qT and %qT\n", ptr_lhs_type, op0_type);
+				}
 			} else {
 				const_tree ssa_name_var = SSA_NAME_VAR(rhs1);
 				/* skip bogus type casts introduced by container_of */
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [kernel-hardening] [PATCH 08/18] randstruct: Whitelist UNIXCB cast
  2017-04-06 21:18 [kernel-hardening] [PATCH 00/18] Introduce struct layout randomization plugin Kees Cook
                   ` (6 preceding siblings ...)
  2017-04-06 21:18 ` [kernel-hardening] [PATCH 07/18] randstruct: Whitelist struct security_hook_heads cast Kees Cook
@ 2017-04-06 21:18 ` Kees Cook
  2017-04-06 21:18 ` [kernel-hardening] [PATCH 09/18] randstruct: Mark various structs for randomization Kees Cook
                   ` (12 subsequent siblings)
  20 siblings, 0 replies; 34+ messages in thread
From: Kees Cook @ 2017-04-06 21:18 UTC (permalink / raw)
  To: kernel-hardening; +Cc: Kees Cook, Michael Leibowitz

This is another false positive in bad cast detection:

net/unix/af_unix.c: In function ‘unix_skb_scm_eq’:
net/unix/af_unix.c:1621:31: note: found mismatched rhs struct pointer types: ‘struct unix_skb_parms’ and ‘char’

  const struct unix_skb_parms *u = &UNIXCB(skb);
                               ^

UNIXCB is:

	#define UNIXCB(skb)     (*(struct unix_skb_parms *)&((skb)->cb))

And ->cb is:

	char                    cb[48] __aligned(8);

This is a rather crazy cast, but appears to be safe in the face of
randomization, so whitelist it in the plugin.

Signed-off-by: Kees Cook <keescook@chromium.org>
---
 scripts/gcc-plugins/randomize_layout_plugin.c | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/scripts/gcc-plugins/randomize_layout_plugin.c b/scripts/gcc-plugins/randomize_layout_plugin.c
index 63c654a00249..a2d7e933c33f 100644
--- a/scripts/gcc-plugins/randomize_layout_plugin.c
+++ b/scripts/gcc-plugins/randomize_layout_plugin.c
@@ -773,6 +773,15 @@ static bool type_name_eq(gimple stmt, const_tree type_tree, const char *wanted_n
 	case RECORD_TYPE:
 		type_name = TYPE_NAME_POINTER(type_tree);
 		break;
+	case INTEGER_TYPE:
+		if (TYPE_PRECISION(type_tree) == CHAR_TYPE_SIZE)
+			type_name = "char";
+		else {
+			inform(gimple_location(stmt), "found non-char INTEGER_TYPE cast comparison: %qT\n", type_tree);
+			debug_tree(type_tree);
+			return false;
+		}
+		break;
 	default:
 		inform(gimple_location(stmt), "unhandled cast comparison: %qT\n", type_tree);
 		debug_tree(type_tree);
@@ -864,7 +873,13 @@ static unsigned int find_bad_casts_execute(void)
 #ifndef __DEBUG_PLUGIN
 				if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(ptr_lhs_type)))
 #endif
-				inform(gimple_location(stmt), "found mismatched rhs struct pointer types: %qT and %qT\n", ptr_lhs_type, ptr_rhs_type);
+				{
+					/* Whitelist unix_skb_parms via UNIXCB() */
+					if (whitelisted_cast(stmt, ptr_lhs_type, ptr_rhs_type, "unix_skb_parms", "char"))
+						continue;
+
+					inform(gimple_location(stmt), "found mismatched rhs struct pointer types: %qT and %qT\n", ptr_lhs_type, ptr_rhs_type);
+				}
 				continue;
 			}
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [kernel-hardening] [PATCH 09/18] randstruct: Mark various structs for randomization
  2017-04-06 21:18 [kernel-hardening] [PATCH 00/18] Introduce struct layout randomization plugin Kees Cook
                   ` (7 preceding siblings ...)
  2017-04-06 21:18 ` [kernel-hardening] [PATCH 08/18] randstruct: Whitelist UNIXCB cast Kees Cook
@ 2017-04-06 21:18 ` Kees Cook
  2017-04-06 21:18 ` [kernel-hardening] [PATCH 10/18] scsi/bfa: use designated initializers Kees Cook
                   ` (11 subsequent siblings)
  20 siblings, 0 replies; 34+ messages in thread
From: Kees Cook @ 2017-04-06 21:18 UTC (permalink / raw)
  To: kernel-hardening; +Cc: Kees Cook, Michael Leibowitz

This marks many critical kernel structures for randomization. These
are structures that have been targeted in the past in security
exploits, or contain functions pointers, pointers to function pointer
tables, lists, workqueues, ref-counters, credentials, or are otherwise
sensitive. This initial list was extracted from grsecurity.

Let out of this list is task_struct, which requires special handling
to avoid breaking certain fields that have positional requirements,
and is covered in a subsequent patch.

Signed-off-by: Kees Cook <keescook@chromium.org>
---
 arch/x86/include/asm/processor.h |  2 +-
 fs/mount.h                       |  4 ++--
 fs/namei.c                       |  2 +-
 fs/proc/internal.h               |  6 +++---
 include/linux/binfmts.h          |  4 ++--
 include/linux/cdev.h             |  2 +-
 include/linux/cred.h             |  4 ++--
 include/linux/dcache.h           |  2 +-
 include/linux/fs.h               | 17 +++++++++--------
 include/linux/fs_struct.h        |  2 +-
 include/linux/ipc.h              |  2 +-
 include/linux/ipc_namespace.h    |  2 +-
 include/linux/key-type.h         |  4 ++--
 include/linux/kmod.h             |  2 +-
 include/linux/kobject.h          |  2 +-
 include/linux/lsm_hooks.h        |  4 ++--
 include/linux/mm_types.h         |  4 ++--
 include/linux/module.h           |  4 ++--
 include/linux/mount.h            |  2 +-
 include/linux/msg.h              |  2 +-
 include/linux/path.h             |  2 +-
 include/linux/pid_namespace.h    |  2 +-
 include/linux/proc_ns.h          |  2 +-
 include/linux/sched.h            |  2 +-
 include/linux/sched/signal.h     |  2 +-
 include/linux/sem.h              |  2 +-
 include/linux/shm.h              |  2 +-
 include/linux/sysctl.h           |  2 +-
 include/linux/tty.h              |  2 +-
 include/linux/tty_driver.h       |  4 ++--
 include/linux/user_namespace.h   |  2 +-
 include/linux/utsname.h          |  2 +-
 include/net/af_unix.h            |  2 +-
 include/net/neighbour.h          |  2 +-
 include/net/net_namespace.h      |  2 +-
 include/net/sock.h               |  2 +-
 kernel/futex.c                   |  4 ++--
 security/keys/internal.h         |  2 +-
 38 files changed, 57 insertions(+), 56 deletions(-)

diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index 3cada998a402..e2335edb9fc5 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -129,7 +129,7 @@ struct cpuinfo_x86 {
 	/* Index into per_cpu list: */
 	u16			cpu_index;
 	u32			microcode;
-};
+} __randomize_layout;
 
 struct cpuid_regs {
 	u32 eax, ebx, ecx, edx;
diff --git a/fs/mount.h b/fs/mount.h
index 2826543a131d..b1763a8d07c8 100644
--- a/fs/mount.h
+++ b/fs/mount.h
@@ -16,7 +16,7 @@ struct mnt_namespace {
 	u64 event;
 	unsigned int		mounts; /* # of mounts in the namespace */
 	unsigned int		pending_mounts;
-};
+} __randomize_layout;
 
 struct mnt_pcp {
 	int mnt_count;
@@ -68,7 +68,7 @@ struct mount {
 	struct hlist_head mnt_pins;
 	struct fs_pin mnt_umount;
 	struct dentry *mnt_ex_mountpoint;
-};
+} __randomize_layout;
 
 #define MNT_NS_INTERNAL ERR_PTR(-EINVAL) /* distinct from any mnt_namespace */
 
diff --git a/fs/namei.c b/fs/namei.c
index 482414aa558b..48895f8cdb2b 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -524,7 +524,7 @@ struct nameidata {
 	struct inode	*link_inode;
 	unsigned	root_seq;
 	int		dfd;
-};
+} __randomize_layout;
 
 static void set_nameidata(struct nameidata *p, int dfd, struct filename *name)
 {
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index c5ae09b6c726..07b16318223f 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -51,7 +51,7 @@ struct proc_dir_entry {
 	spinlock_t pde_unload_lock; /* proc_fops checks and pde_users bumps */
 	u8 namelen;
 	char name[];
-};
+} __randomize_layout;
 
 union proc_op {
 	int (*proc_get_link)(struct dentry *, struct path *);
@@ -70,7 +70,7 @@ struct proc_inode {
 	struct list_head sysctl_inodes;
 	const struct proc_ns_operations *ns_ops;
 	struct inode vfs_inode;
-};
+} __randomize_layout;
 
 /*
  * General functions
@@ -279,7 +279,7 @@ struct proc_maps_private {
 #ifdef CONFIG_NUMA
 	struct mempolicy *task_mempolicy;
 #endif
-};
+} __randomize_layout;
 
 struct mm_struct *proc_mem_open(struct inode *inode, unsigned int mode);
 
diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
index 05488da3aee9..3ae9013eeaaa 100644
--- a/include/linux/binfmts.h
+++ b/include/linux/binfmts.h
@@ -46,7 +46,7 @@ struct linux_binprm {
 	unsigned interp_flags;
 	unsigned interp_data;
 	unsigned long loader, exec;
-};
+} __randomize_layout;
 
 #define BINPRM_FLAGS_ENFORCE_NONDUMP_BIT 0
 #define BINPRM_FLAGS_ENFORCE_NONDUMP (1 << BINPRM_FLAGS_ENFORCE_NONDUMP_BIT)
@@ -81,7 +81,7 @@ struct linux_binfmt {
 	int (*load_shlib)(struct file *);
 	int (*core_dump)(struct coredump_params *cprm);
 	unsigned long min_coredump;	/* minimal dump size */
-};
+} __randomize_layout;
 
 extern void __register_binfmt(struct linux_binfmt *fmt, int insert);
 
diff --git a/include/linux/cdev.h b/include/linux/cdev.h
index 408bc09ce497..cb28eb21e3ca 100644
--- a/include/linux/cdev.h
+++ b/include/linux/cdev.h
@@ -17,7 +17,7 @@ struct cdev {
 	struct list_head list;
 	dev_t dev;
 	unsigned int count;
-};
+} __randomize_layout;
 
 void cdev_init(struct cdev *, const struct file_operations *);
 
diff --git a/include/linux/cred.h b/include/linux/cred.h
index b03e7d049a64..82c8a9e1aabb 100644
--- a/include/linux/cred.h
+++ b/include/linux/cred.h
@@ -31,7 +31,7 @@ struct group_info {
 	atomic_t	usage;
 	int		ngroups;
 	kgid_t		gid[0];
-};
+} __randomize_layout;
 
 /**
  * get_group_info - Get a reference to a group info structure
@@ -145,7 +145,7 @@ struct cred {
 	struct user_namespace *user_ns; /* user_ns the caps and keyrings are relative to. */
 	struct group_info *group_info;	/* supplementary groups for euid/fsgid */
 	struct rcu_head	rcu;		/* RCU deletion hook */
-};
+} __randomize_layout;
 
 extern void __put_cred(struct cred *);
 extern void exit_creds(struct task_struct *);
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index d2e38dc6172c..7eb262e13d3c 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -113,7 +113,7 @@ struct dentry {
 		struct hlist_bl_node d_in_lookup_hash;	/* only for in-lookup ones */
 	 	struct rcu_head d_rcu;
 	} d_u;
-};
+} __randomize_layout;
 
 /*
  * dentry->d_lock spinlock nesting subclasses:
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 3928a5517702..d530da806a5e 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -277,7 +277,7 @@ struct kiocb {
 	void (*ki_complete)(struct kiocb *iocb, long ret, long ret2);
 	void			*private;
 	int			ki_flags;
-};
+} __randomize_layout;
 
 static inline bool is_sync_kiocb(struct kiocb *kiocb)
 {
@@ -394,7 +394,7 @@ struct address_space {
 	gfp_t			gfp_mask;	/* implicit gfp mask for allocations */
 	struct list_head	private_list;	/* ditto */
 	void			*private_data;	/* ditto */
-} __attribute__((aligned(sizeof(long))));
+} __attribute__((aligned(sizeof(long)))) __randomize_layout;
 	/*
 	 * On most architectures that alignment is already the case; but
 	 * must be enforced here for CRIS, to let the least significant bit
@@ -437,7 +437,7 @@ struct block_device {
 	int			bd_fsfreeze_count;
 	/* Mutex for freeze */
 	struct mutex		bd_fsfreeze_mutex;
-};
+} __randomize_layout;
 
 /*
  * Radix-tree tags, for tagging dirty and writeback pages within the pagecache
@@ -653,7 +653,7 @@ struct inode {
 #endif
 
 	void			*i_private; /* fs or device private pointer */
-};
+} __randomize_layout;
 
 static inline unsigned int i_blocksize(const struct inode *node)
 {
@@ -868,7 +868,8 @@ struct file {
 	struct list_head	f_tfile_llink;
 #endif /* #ifdef CONFIG_EPOLL */
 	struct address_space	*f_mapping;
-} __attribute__((aligned(4)));	/* lest something weird decides that 2 is OK */
+} __randomize_layout
+  __attribute__((aligned(4)));	/* lest something weird decides that 2 is OK */
 
 struct file_handle {
 	__u32 handle_bytes;
@@ -1003,7 +1004,7 @@ struct file_lock {
 			int state;		/* state of grant or error if -ve */
 		} afs;
 	} fl_u;
-};
+} __randomize_layout;
 
 struct file_lock_context {
 	spinlock_t		flc_lock;
@@ -1402,7 +1403,7 @@ struct super_block {
 
 	spinlock_t		s_inode_wblist_lock;
 	struct list_head	s_inodes_wb;	/* writeback inodes */
-};
+} __randomize_layout;
 
 /* Helper functions so that in most cases filesystems will
  * not need to deal directly with kuid_t and kgid_t and can
@@ -1689,7 +1690,7 @@ struct file_operations {
 			u64);
 	ssize_t (*dedupe_file_range)(struct file *, u64, u64, struct file *,
 			u64);
-};
+} __randomize_layout;
 
 struct inode_operations {
 	struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
diff --git a/include/linux/fs_struct.h b/include/linux/fs_struct.h
index 0efc3e62843a..7a026240cbb1 100644
--- a/include/linux/fs_struct.h
+++ b/include/linux/fs_struct.h
@@ -12,7 +12,7 @@ struct fs_struct {
 	int umask;
 	int in_exec;
 	struct path root, pwd;
-};
+} __randomize_layout;
 
 extern struct kmem_cache *fs_cachep;
 
diff --git a/include/linux/ipc.h b/include/linux/ipc.h
index 9d84942ae2e5..9ac8d568f5eb 100644
--- a/include/linux/ipc.h
+++ b/include/linux/ipc.h
@@ -21,6 +21,6 @@ struct kern_ipc_perm
 	umode_t		mode; 
 	unsigned long	seq;
 	void		*security;
-};
+} __randomize_layout;
 
 #endif /* _LINUX_IPC_H */
diff --git a/include/linux/ipc_namespace.h b/include/linux/ipc_namespace.h
index 848e5796400e..65327ee0936b 100644
--- a/include/linux/ipc_namespace.h
+++ b/include/linux/ipc_namespace.h
@@ -61,7 +61,7 @@ struct ipc_namespace {
 	struct ucounts *ucounts;
 
 	struct ns_common ns;
-};
+} __randomize_layout;
 
 extern struct ipc_namespace init_ipc_ns;
 extern spinlock_t mq_lock;
diff --git a/include/linux/key-type.h b/include/linux/key-type.h
index 63b2a92c2085..549a16ffc860 100644
--- a/include/linux/key-type.h
+++ b/include/linux/key-type.h
@@ -48,7 +48,7 @@ struct key_preparsed_payload {
 	size_t		datalen;	/* Raw datalen */
 	size_t		quotalen;	/* Quota length for proposed payload */
 	time_t		expiry;		/* Expiry time of key */
-};
+} __randomize_layout;
 
 typedef int (*request_key_actor_t)(struct key_construction *key,
 				   const char *op, void *aux);
@@ -161,7 +161,7 @@ struct key_type {
 	/* internal fields */
 	struct list_head	link;		/* link in types list */
 	struct lock_class_key	lock_class;	/* key->sem lock class */
-};
+} __randomize_layout;
 
 extern struct key_type key_type_keyring;
 
diff --git a/include/linux/kmod.h b/include/linux/kmod.h
index c4e441e00db5..655082c88fd9 100644
--- a/include/linux/kmod.h
+++ b/include/linux/kmod.h
@@ -64,7 +64,7 @@ struct subprocess_info {
 	int (*init)(struct subprocess_info *info, struct cred *new);
 	void (*cleanup)(struct subprocess_info *info);
 	void *data;
-};
+} __randomize_layout;
 
 extern int
 call_usermodehelper(const char *path, char **argv, char **envp, int wait);
diff --git a/include/linux/kobject.h b/include/linux/kobject.h
index ca85cb80e99a..084513350317 100644
--- a/include/linux/kobject.h
+++ b/include/linux/kobject.h
@@ -172,7 +172,7 @@ struct kset {
 	spinlock_t list_lock;
 	struct kobject kobj;
 	const struct kset_uevent_ops *uevent_ops;
-};
+} __randomize_layout;
 
 extern void kset_init(struct kset *kset);
 extern int __must_check kset_register(struct kset *kset);
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 080f34e66017..565163fc9ad4 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1876,7 +1876,7 @@ struct security_hook_heads {
 	struct list_head audit_rule_match;
 	struct list_head audit_rule_free;
 #endif /* CONFIG_AUDIT */
-};
+} __randomize_layout;
 
 /*
  * Security module hook list structure.
@@ -1887,7 +1887,7 @@ struct security_hook_list {
 	struct list_head		*head;
 	union security_list_options	hook;
 	char				*lsm;
-};
+} __randomize_layout;
 
 /*
  * Initializing a security_hook_list structure takes
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 45cdb27791a3..ff151814a02d 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -342,7 +342,7 @@ struct vm_area_struct {
 	struct mempolicy *vm_policy;	/* NUMA policy for the VMA */
 #endif
 	struct vm_userfaultfd_ctx vm_userfaultfd_ctx;
-};
+} __randomize_layout;
 
 struct core_thread {
 	struct task_struct *task;
@@ -500,7 +500,7 @@ struct mm_struct {
 	atomic_long_t hugetlb_usage;
 #endif
 	struct work_struct async_put_work;
-};
+} __randomize_layout;
 
 extern struct mm_struct init_mm;
 
diff --git a/include/linux/module.h b/include/linux/module.h
index 9ad68561d8c2..c3ca8154f618 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -45,7 +45,7 @@ struct module_kobject {
 	struct kobject *drivers_dir;
 	struct module_param_attrs *mp;
 	struct completion *kobj_completion;
-};
+} __randomize_layout;
 
 struct module_attribute {
 	struct attribute attr;
@@ -475,7 +475,7 @@ struct module {
 	ctor_fn_t *ctors;
 	unsigned int num_ctors;
 #endif
-} ____cacheline_aligned;
+} ____cacheline_aligned __randomize_layout;
 #ifndef MODULE_ARCH_INIT
 #define MODULE_ARCH_INIT {}
 #endif
diff --git a/include/linux/mount.h b/include/linux/mount.h
index 8e0352af06b7..1ce85e6fd95f 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -67,7 +67,7 @@ struct vfsmount {
 	struct dentry *mnt_root;	/* root of the mounted tree */
 	struct super_block *mnt_sb;	/* pointer to superblock */
 	int mnt_flags;
-};
+} __randomize_layout;
 
 struct file; /* forward dec */
 struct path;
diff --git a/include/linux/msg.h b/include/linux/msg.h
index f3f302f9c197..a001305f5a79 100644
--- a/include/linux/msg.h
+++ b/include/linux/msg.h
@@ -29,7 +29,7 @@ struct msg_queue {
 	struct list_head q_messages;
 	struct list_head q_receivers;
 	struct list_head q_senders;
-};
+} __randomize_layout;
 
 /* Helper routines for sys_msgsnd and sys_msgrcv */
 extern long do_msgsnd(int msqid, long mtype, void __user *mtext,
diff --git a/include/linux/path.h b/include/linux/path.h
index d1372186f431..cde895cc4af4 100644
--- a/include/linux/path.h
+++ b/include/linux/path.h
@@ -7,7 +7,7 @@ struct vfsmount;
 struct path {
 	struct vfsmount *mnt;
 	struct dentry *dentry;
-};
+} __randomize_layout;
 
 extern void path_get(const struct path *);
 extern void path_put(const struct path *);
diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h
index c2a989dee876..b09136f88cf4 100644
--- a/include/linux/pid_namespace.h
+++ b/include/linux/pid_namespace.h
@@ -52,7 +52,7 @@ struct pid_namespace {
 	int hide_pid;
 	int reboot;	/* group exit code if this pidns was rebooted */
 	struct ns_common ns;
-};
+} __randomize_layout;
 
 extern struct pid_namespace init_pid_ns;
 
diff --git a/include/linux/proc_ns.h b/include/linux/proc_ns.h
index 58ab28d81fc2..06844b54dfc1 100644
--- a/include/linux/proc_ns.h
+++ b/include/linux/proc_ns.h
@@ -21,7 +21,7 @@ struct proc_ns_operations {
 	int (*install)(struct nsproxy *nsproxy, struct ns_common *ns);
 	struct user_namespace *(*owner)(struct ns_common *ns);
 	struct ns_common *(*get_parent)(struct ns_common *ns);
-};
+} __randomize_layout;
 
 extern const struct proc_ns_operations netns_operations;
 extern const struct proc_ns_operations utsns_operations;
diff --git a/include/linux/sched.h b/include/linux/sched.h
index f0f085416adf..91f3ea399e0c 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -408,7 +408,7 @@ struct sched_rt_entity {
 	/* rq "owned" by this entity/group: */
 	struct rt_rq			*my_q;
 #endif
-};
+} __randomize_layout;
 
 struct sched_dl_entity {
 	struct rb_node			rb_node;
diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h
index 2cf446704cd4..0e28c63bba29 100644
--- a/include/linux/sched/signal.h
+++ b/include/linux/sched/signal.h
@@ -222,7 +222,7 @@ struct signal_struct {
 	struct mutex cred_guard_mutex;	/* guard against foreign influences on
 					 * credential calculations
 					 * (notably. ptrace) */
-};
+} __randomize_layout;
 
 /*
  * Bits in flags field of signal_struct.
diff --git a/include/linux/sem.h b/include/linux/sem.h
index 4fc222f8755d..a59674981a57 100644
--- a/include/linux/sem.h
+++ b/include/linux/sem.h
@@ -22,7 +22,7 @@ struct sem_array {
 	int			sem_nsems;	/* no. of semaphores in array */
 	int			complex_count;	/* pending complex operations */
 	unsigned int		use_global_lock;/* >0: global lock required */
-};
+} __randomize_layout;
 
 #ifdef CONFIG_SYSVIPC
 
diff --git a/include/linux/shm.h b/include/linux/shm.h
index 04e881829625..0fb7061ec54c 100644
--- a/include/linux/shm.h
+++ b/include/linux/shm.h
@@ -22,7 +22,7 @@ struct shmid_kernel /* private to the kernel */
 	/* The task created the shm object.  NULL if the task is dead. */
 	struct task_struct	*shm_creator;
 	struct list_head	shm_clist;	/* list by creator */
-};
+} __randomize_layout;
 
 /* shm_mode upper byte flags */
 #define	SHM_DEST	01000	/* segment will be destroyed on last detach */
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index b7e82049fec7..efb6c0e886f9 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -117,7 +117,7 @@ struct ctl_table
 	struct ctl_table_poll *poll;
 	void *extra1;
 	void *extra2;
-};
+} __randomize_layout;
 
 struct ctl_node {
 	struct rb_node node;
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 1017e904c0a3..c4b003d17cae 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -333,7 +333,7 @@ struct tty_struct {
 	/* If the tty has a pending do_SAK, queue it here - akpm */
 	struct work_struct SAK_work;
 	struct tty_port *port;
-};
+} __randomize_layout;
 
 /* Each of a tty's open files has private_data pointing to tty_file_private */
 struct tty_file_private {
diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
index b742b5e47cc2..00b2213f6a35 100644
--- a/include/linux/tty_driver.h
+++ b/include/linux/tty_driver.h
@@ -291,7 +291,7 @@ struct tty_operations {
 	void (*poll_put_char)(struct tty_driver *driver, int line, char ch);
 #endif
 	const struct file_operations *proc_fops;
-};
+} __randomize_layout;
 
 struct tty_driver {
 	int	magic;		/* magic number for this structure */
@@ -325,7 +325,7 @@ struct tty_driver {
 
 	const struct tty_operations *ops;
 	struct list_head tty_drivers;
-};
+} __randomize_layout;
 
 extern struct list_head tty_drivers;
 
diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h
index 32354b4b4b2b..b3575ce29148 100644
--- a/include/linux/user_namespace.h
+++ b/include/linux/user_namespace.h
@@ -66,7 +66,7 @@ struct user_namespace {
 #endif
 	struct ucounts		*ucounts;
 	int ucount_max[UCOUNT_COUNTS];
-};
+} __randomize_layout;
 
 struct ucounts {
 	struct hlist_node node;
diff --git a/include/linux/utsname.h b/include/linux/utsname.h
index 60f0bb83b313..da826ed059cf 100644
--- a/include/linux/utsname.h
+++ b/include/linux/utsname.h
@@ -26,7 +26,7 @@ struct uts_namespace {
 	struct user_namespace *user_ns;
 	struct ucounts *ucounts;
 	struct ns_common ns;
-};
+} __randomize_layout;
 extern struct uts_namespace init_uts_ns;
 
 #ifdef CONFIG_UTS_NS
diff --git a/include/net/af_unix.h b/include/net/af_unix.h
index fd60eccb59a6..64e2a1e24a2c 100644
--- a/include/net/af_unix.h
+++ b/include/net/af_unix.h
@@ -36,7 +36,7 @@ struct unix_skb_parms {
 	u32			secid;		/* Security ID		*/
 #endif
 	u32			consumed;
-};
+} __randomize_layout;
 
 #define UNIXCB(skb) 	(*(struct unix_skb_parms *)&((skb)->cb))
 
diff --git a/include/net/neighbour.h b/include/net/neighbour.h
index 9496179c7b4e..2a37bc506388 100644
--- a/include/net/neighbour.h
+++ b/include/net/neighbour.h
@@ -155,7 +155,7 @@ struct neighbour {
 	struct rcu_head		rcu;
 	struct net_device	*dev;
 	u8			primary_key[0];
-};
+} __randomize_layout;
 
 struct neigh_ops {
 	int			family;
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index af8fe8a909dc..f5615b9b5b8d 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -143,7 +143,7 @@ struct net {
 #endif
 	struct sock		*diag_nlsk;
 	atomic_t		fnhe_genid;
-};
+} __randomize_layout;
 
 #include <linux/seq_file_net.h>
 
diff --git a/include/net/sock.h b/include/net/sock.h
index f33e3d134e0b..d349297db9e9 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -1113,7 +1113,7 @@ struct proto {
 	atomic_t		socks;
 #endif
 	int			(*diag_destroy)(struct sock *sk, int err);
-};
+} __randomize_layout;
 
 int proto_register(struct proto *prot, int alloc_slab);
 void proto_unregister(struct proto *prot);
diff --git a/kernel/futex.c b/kernel/futex.c
index 628be42296eb..ff797a3ca1d2 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -212,7 +212,7 @@ struct futex_pi_state {
 	atomic_t refcount;
 
 	union futex_key key;
-};
+} __randomize_layout;
 
 /**
  * struct futex_q - The hashed futex queue entry, one per waiting task
@@ -246,7 +246,7 @@ struct futex_q {
 	struct rt_mutex_waiter *rt_waiter;
 	union futex_key *requeue_pi_key;
 	u32 bitset;
-};
+} __randomize_layout;
 
 static const struct futex_q futex_q_init = {
 	/* list gets initialized in queue_me()*/
diff --git a/security/keys/internal.h b/security/keys/internal.h
index 298439b1f087..edde0237c6b6 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -194,7 +194,7 @@ struct request_key_auth {
 	void			*callout_info;
 	size_t			callout_len;
 	pid_t			pid;
-};
+} __randomize_layout;
 
 extern struct key_type key_type_request_key_auth;
 extern struct key *request_key_auth_new(struct key *target,
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [kernel-hardening] [PATCH 10/18] scsi/bfa: use designated initializers
  2017-04-06 21:18 [kernel-hardening] [PATCH 00/18] Introduce struct layout randomization plugin Kees Cook
                   ` (8 preceding siblings ...)
  2017-04-06 21:18 ` [kernel-hardening] [PATCH 09/18] randstruct: Mark various structs for randomization Kees Cook
@ 2017-04-06 21:18 ` Kees Cook
  2017-04-06 21:18 ` [kernel-hardening] [PATCH 11/18] scsi: qedi,qedf: Use " Kees Cook
                   ` (10 subsequent siblings)
  20 siblings, 0 replies; 34+ messages in thread
From: Kees Cook @ 2017-04-06 21:18 UTC (permalink / raw)
  To: kernel-hardening; +Cc: Kees Cook, Michael Leibowitz

Prepare to mark sensitive kernel structures for randomization by making
sure they're using designated initializers. These were identified during
allyesconfig builds of x86, arm, and arm64, with most initializer fixes
extracted from grsecurity.

Signed-off-by: Kees Cook <keescook@chromium.org>
---
 drivers/scsi/bfa/bfa_fcs_lport.c | 29 ++++++++++++++++++++---------
 drivers/scsi/bfa/bfa_modules.h   | 12 ++++++------
 2 files changed, 26 insertions(+), 15 deletions(-)

diff --git a/drivers/scsi/bfa/bfa_fcs_lport.c b/drivers/scsi/bfa/bfa_fcs_lport.c
index 4ddda72f60e6..64860c730ec9 100644
--- a/drivers/scsi/bfa/bfa_fcs_lport.c
+++ b/drivers/scsi/bfa/bfa_fcs_lport.c
@@ -90,15 +90,26 @@ static struct {
 	void		(*offline) (struct bfa_fcs_lport_s *port);
 } __port_action[] = {
 	{
-	bfa_fcs_lport_unknown_init, bfa_fcs_lport_unknown_online,
-			bfa_fcs_lport_unknown_offline}, {
-	bfa_fcs_lport_fab_init, bfa_fcs_lport_fab_online,
-			bfa_fcs_lport_fab_offline}, {
-	bfa_fcs_lport_n2n_init, bfa_fcs_lport_n2n_online,
-			bfa_fcs_lport_n2n_offline}, {
-	bfa_fcs_lport_loop_init, bfa_fcs_lport_loop_online,
-			bfa_fcs_lport_loop_offline},
-	};
+		.init = bfa_fcs_lport_unknown_init,
+		.online = bfa_fcs_lport_unknown_online,
+		.offline = bfa_fcs_lport_unknown_offline
+	},
+	{
+		.init = bfa_fcs_lport_fab_init,
+		.online = bfa_fcs_lport_fab_online,
+		.offline = bfa_fcs_lport_fab_offline
+	},
+	{
+		.init = bfa_fcs_lport_n2n_init,
+		.online = bfa_fcs_lport_n2n_online,
+		.offline = bfa_fcs_lport_n2n_offline
+	},
+	{
+		.init = bfa_fcs_lport_loop_init,
+		.online = bfa_fcs_lport_loop_online,
+		.offline = bfa_fcs_lport_loop_offline
+	},
+};
 
 /*
  *  fcs_port_sm FCS logical port state machine
diff --git a/drivers/scsi/bfa/bfa_modules.h b/drivers/scsi/bfa/bfa_modules.h
index 53135f21fa0e..640621b4c3da 100644
--- a/drivers/scsi/bfa/bfa_modules.h
+++ b/drivers/scsi/bfa/bfa_modules.h
@@ -79,12 +79,12 @@ enum {
 									\
 	extern struct bfa_module_s hal_mod_ ## __mod;			\
 	struct bfa_module_s hal_mod_ ## __mod = {			\
-		bfa_ ## __mod ## _meminfo,				\
-		bfa_ ## __mod ## _attach,				\
-		bfa_ ## __mod ## _detach,				\
-		bfa_ ## __mod ## _start,				\
-		bfa_ ## __mod ## _stop,					\
-		bfa_ ## __mod ## _iocdisable,				\
+		.meminfo = bfa_ ## __mod ## _meminfo,			\
+		.attach = bfa_ ## __mod ## _attach,			\
+		.detach = bfa_ ## __mod ## _detach,			\
+		.start = bfa_ ## __mod ## _start,			\
+		.stop = bfa_ ## __mod ## _stop,				\
+		.iocdisable = bfa_ ## __mod ## _iocdisable,		\
 	}
 
 #define BFA_CACHELINE_SZ	(256)
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [kernel-hardening] [PATCH 11/18] scsi: qedi,qedf: Use designated initializers
  2017-04-06 21:18 [kernel-hardening] [PATCH 00/18] Introduce struct layout randomization plugin Kees Cook
                   ` (9 preceding siblings ...)
  2017-04-06 21:18 ` [kernel-hardening] [PATCH 10/18] scsi/bfa: use designated initializers Kees Cook
@ 2017-04-06 21:18 ` Kees Cook
  2017-04-06 21:18 ` [kernel-hardening] [PATCH 12/18] ovl: " Kees Cook
                   ` (9 subsequent siblings)
  20 siblings, 0 replies; 34+ messages in thread
From: Kees Cook @ 2017-04-06 21:18 UTC (permalink / raw)
  To: kernel-hardening; +Cc: Kees Cook, Michael Leibowitz

Prepare to mark sensitive kernel structures for randomization by making
sure they're using designated initializers. These were identified during
allyesconfig builds of x86, arm, and arm64, with most initializer fixes
extracted from grsecurity.

For these cases, terminate the list with { }, which will be zero-filled,
instead of undesignated NULLs.

Signed-off-by: Kees Cook <keescook@chromium.org>
---
 drivers/scsi/qedf/qedf_debugfs.c | 2 +-
 drivers/scsi/qedi/qedi_debugfs.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/qedf/qedf_debugfs.c b/drivers/scsi/qedf/qedf_debugfs.c
index cb08b625c594..00a1d6405ebe 100644
--- a/drivers/scsi/qedf/qedf_debugfs.c
+++ b/drivers/scsi/qedf/qedf_debugfs.c
@@ -449,7 +449,7 @@ const struct file_operations qedf_dbg_fops[] = {
 	qedf_dbg_fileops(qedf, clear_stats),
 	qedf_dbg_fileops_seq(qedf, offload_stats),
 	/* This must be last */
-	{ NULL, NULL },
+	{ },
 };
 
 #else /* CONFIG_DEBUG_FS */
diff --git a/drivers/scsi/qedi/qedi_debugfs.c b/drivers/scsi/qedi/qedi_debugfs.c
index 59417199bf36..39d77818a677 100644
--- a/drivers/scsi/qedi/qedi_debugfs.c
+++ b/drivers/scsi/qedi/qedi_debugfs.c
@@ -240,5 +240,5 @@ const struct file_operations qedi_dbg_fops[] = {
 	qedi_dbg_fileops_seq(qedi, gbl_ctx),
 	qedi_dbg_fileops(qedi, do_not_recover),
 	qedi_dbg_fileops_seq(qedi, io_trace),
-	{ NULL, NULL },
+	{ },
 };
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [kernel-hardening] [PATCH 12/18] ovl: Use designated initializers
  2017-04-06 21:18 [kernel-hardening] [PATCH 00/18] Introduce struct layout randomization plugin Kees Cook
                   ` (10 preceding siblings ...)
  2017-04-06 21:18 ` [kernel-hardening] [PATCH 11/18] scsi: qedi,qedf: Use " Kees Cook
@ 2017-04-06 21:18 ` Kees Cook
  2017-04-06 21:18 ` [kernel-hardening] [PATCH 13/18] randstruct: opt-out externally exposed function pointer structs Kees Cook
                   ` (8 subsequent siblings)
  20 siblings, 0 replies; 34+ messages in thread
From: Kees Cook @ 2017-04-06 21:18 UTC (permalink / raw)
  To: kernel-hardening; +Cc: Kees Cook, Michael Leibowitz

Prepare to mark sensitive kernel structures for randomization by making
sure they're using designated initializers. These were identified during
allyesconfig builds of x86, arm, and arm64, with most initializer fixes
extracted from grsecurity.

For these cases, terminate the list with { }, which will be zero-filled,
instead of undesignated NULLs.

Signed-off-by: Kees Cook <keescook@chromium.org>
---
 fs/overlayfs/super.c | 4 ++--
 fs/overlayfs/util.c  | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index c9e70d39c1ea..07c8793efb1d 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -709,8 +709,8 @@ static const struct xattr_handler *ovl_xattr_handlers[] = {
 
 static int ovl_fill_super(struct super_block *sb, void *data, int silent)
 {
-	struct path upperpath = { NULL, NULL };
-	struct path workpath = { NULL, NULL };
+	struct path upperpath = { };
+	struct path workpath = { };
 	struct dentry *root_dentry;
 	struct inode *realinode;
 	struct ovl_entry *oe;
diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c
index 6e610a205e15..590fb098f763 100644
--- a/fs/overlayfs/util.c
+++ b/fs/overlayfs/util.c
@@ -100,7 +100,7 @@ void ovl_path_lower(struct dentry *dentry, struct path *path)
 {
 	struct ovl_entry *oe = dentry->d_fsdata;
 
-	*path = oe->numlower ? oe->lowerstack[0] : (struct path) { NULL, NULL };
+	*path = oe->numlower ? oe->lowerstack[0] : (struct path) { };
 }
 
 enum ovl_path_type ovl_path_real(struct dentry *dentry, struct path *path)
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [kernel-hardening] [PATCH 13/18] randstruct: opt-out externally exposed function pointer structs
  2017-04-06 21:18 [kernel-hardening] [PATCH 00/18] Introduce struct layout randomization plugin Kees Cook
                   ` (11 preceding siblings ...)
  2017-04-06 21:18 ` [kernel-hardening] [PATCH 12/18] ovl: " Kees Cook
@ 2017-04-06 21:18 ` Kees Cook
  2017-04-06 21:18 ` [kernel-hardening] [PATCH 14/18] randstruct: Disable randomization of ACPICA structs Kees Cook
                   ` (7 subsequent siblings)
  20 siblings, 0 replies; 34+ messages in thread
From: Kees Cook @ 2017-04-06 21:18 UTC (permalink / raw)
  To: kernel-hardening; +Cc: Kees Cook, Michael Leibowitz

Some function pointer structures are used externally to the kernel, like
the paravirt structures. These should never be randomized, so mark them as
such. This set was extracted from grsecurity.

One difference from grsecurity is the opting out of sgi-xp, until
maintainers can decide if randomization is actually safe there.

Signed-off-by: Kees Cook <keescook@chromium.org>
---
 arch/arm/include/asm/cacheflush.h     |  2 +-
 arch/x86/include/asm/paravirt_types.h | 16 ++++++++--------
 drivers/misc/sgi-xp/xp.h              |  2 +-
 3 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
index d69bebf697e7..74504b154256 100644
--- a/arch/arm/include/asm/cacheflush.h
+++ b/arch/arm/include/asm/cacheflush.h
@@ -116,7 +116,7 @@ struct cpu_cache_fns {
 	void (*dma_unmap_area)(const void *, size_t, int);
 
 	void (*dma_flush_range)(const void *, const void *);
-};
+} __no_randomize_layout;
 
 /*
  * Select the calling method
diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h
index 93c49cf09b63..82f7d92b9232 100644
--- a/arch/x86/include/asm/paravirt_types.h
+++ b/arch/x86/include/asm/paravirt_types.h
@@ -83,7 +83,7 @@ struct pv_init_ops {
 	 */
 	unsigned (*patch)(u8 type, u16 clobber, void *insnbuf,
 			  unsigned long addr, unsigned len);
-};
+} __no_randomize_layout;
 
 
 struct pv_lazy_ops {
@@ -91,12 +91,12 @@ struct pv_lazy_ops {
 	void (*enter)(void);
 	void (*leave)(void);
 	void (*flush)(void);
-};
+} __no_randomize_layout;
 
 struct pv_time_ops {
 	unsigned long long (*sched_clock)(void);
 	unsigned long long (*steal_clock)(int cpu);
-};
+} __no_randomize_layout;
 
 struct pv_cpu_ops {
 	/* hooks for various privileged instructions */
@@ -175,7 +175,7 @@ struct pv_cpu_ops {
 
 	void (*start_context_switch)(struct task_struct *prev);
 	void (*end_context_switch)(struct task_struct *next);
-};
+} __no_randomize_layout;
 
 struct pv_irq_ops {
 	/*
@@ -198,7 +198,7 @@ struct pv_irq_ops {
 #ifdef CONFIG_X86_64
 	void (*adjust_exception_frame)(void);
 #endif
-};
+} __no_randomize_layout;
 
 struct pv_mmu_ops {
 	unsigned long (*read_cr2)(void);
@@ -301,7 +301,7 @@ struct pv_mmu_ops {
 	   an mfn.  We can tell which is which from the index. */
 	void (*set_fixmap)(unsigned /* enum fixed_addresses */ idx,
 			   phys_addr_t phys, pgprot_t flags);
-};
+} __no_randomize_layout;
 
 struct arch_spinlock;
 #ifdef CONFIG_SMP
@@ -318,7 +318,7 @@ struct pv_lock_ops {
 	void (*kick)(int cpu);
 
 	struct paravirt_callee_save vcpu_is_preempted;
-};
+} __no_randomize_layout;
 
 /* This contains all the paravirt structures: we get a convenient
  * number for each function using the offset which we use to indicate
@@ -330,7 +330,7 @@ struct paravirt_patch_template {
 	struct pv_irq_ops pv_irq_ops;
 	struct pv_mmu_ops pv_mmu_ops;
 	struct pv_lock_ops pv_lock_ops;
-};
+} __no_randomize_layout;
 
 extern struct pv_info pv_info;
 extern struct pv_init_ops pv_init_ops;
diff --git a/drivers/misc/sgi-xp/xp.h b/drivers/misc/sgi-xp/xp.h
index c862cd4583cc..a23a373d8707 100644
--- a/drivers/misc/sgi-xp/xp.h
+++ b/drivers/misc/sgi-xp/xp.h
@@ -288,7 +288,7 @@ struct xpc_interface {
 					xpc_notify_func, void *);
 	void (*received) (short, int, void *);
 	enum xp_retval (*partid_to_nasids) (short, void *);
-};
+} __no_randomize_layout;
 
 extern struct xpc_interface xpc_interface;
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [kernel-hardening] [PATCH 14/18] randstruct: Disable randomization of ACPICA structs
  2017-04-06 21:18 [kernel-hardening] [PATCH 00/18] Introduce struct layout randomization plugin Kees Cook
                   ` (12 preceding siblings ...)
  2017-04-06 21:18 ` [kernel-hardening] [PATCH 13/18] randstruct: opt-out externally exposed function pointer structs Kees Cook
@ 2017-04-06 21:18 ` Kees Cook
  2017-04-06 21:18 ` [kernel-hardening] [PATCH 15/18] randstruct: Enable function pointer struct detection Kees Cook
                   ` (6 subsequent siblings)
  20 siblings, 0 replies; 34+ messages in thread
From: Kees Cook @ 2017-04-06 21:18 UTC (permalink / raw)
  To: kernel-hardening; +Cc: Kees Cook, Michael Leibowitz

Since the ACPICA source is maintained externally to the kernel, we can
neither switch it to designated initializers nor mark it
__no_randomize_layout. Until ACPICA-upstream changes land to handle the
designated initialization, explicitly skip it in the plugin.

Signed-off-by: Kees Cook <keescook@chromium.org>
---
 scripts/gcc-plugins/randomize_layout_plugin.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/scripts/gcc-plugins/randomize_layout_plugin.c b/scripts/gcc-plugins/randomize_layout_plugin.c
index a2d7e933c33f..cbde695e392a 100644
--- a/scripts/gcc-plugins/randomize_layout_plugin.c
+++ b/scripts/gcc-plugins/randomize_layout_plugin.c
@@ -329,6 +329,10 @@ static int relayout_struct(tree type)
 	    !strcmp((const char *)ORIG_TYPE_NAME(type), "RAWPCIFACTORY"))
 		return 0;
 
+	/* Skip ACPICA structs until refreshed with designated_init. */
+	if (!strcmp((const char *)ORIG_TYPE_NAME(type), "acpi_sleep_functions"))
+		return 0;
+
 	/* throw out any structs in uapi */
 	xloc = expand_location(DECL_SOURCE_LOCATION(TYPE_FIELDS(type)));
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [kernel-hardening] [PATCH 15/18] randstruct: Enable function pointer struct detection
  2017-04-06 21:18 [kernel-hardening] [PATCH 00/18] Introduce struct layout randomization plugin Kees Cook
                   ` (13 preceding siblings ...)
  2017-04-06 21:18 ` [kernel-hardening] [PATCH 14/18] randstruct: Disable randomization of ACPICA structs Kees Cook
@ 2017-04-06 21:18 ` Kees Cook
  2017-04-06 21:18 ` [kernel-hardening] [PATCH 16/18] task_struct: Allow randomized layout Kees Cook
                   ` (5 subsequent siblings)
  20 siblings, 0 replies; 34+ messages in thread
From: Kees Cook @ 2017-04-06 21:18 UTC (permalink / raw)
  To: kernel-hardening; +Cc: Kees Cook, Michael Leibowitz

With prior patches landed that clean up structure initialization, it is
now possible to enable CONFIG_GCC_PLUGIN_RANDSTRUCT's detection and
randomization of structures that contain only function pointers.

Signed-off-by: Kees Cook <keescook@chromium.org>
---
 scripts/gcc-plugins/randomize_layout_plugin.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/scripts/gcc-plugins/randomize_layout_plugin.c b/scripts/gcc-plugins/randomize_layout_plugin.c
index cbde695e392a..716bb877b3fd 100644
--- a/scripts/gcc-plugins/randomize_layout_plugin.c
+++ b/scripts/gcc-plugins/randomize_layout_plugin.c
@@ -420,9 +420,6 @@ static int is_pure_ops_struct(const_tree node)
 
 	gcc_assert(TREE_CODE(node) == RECORD_TYPE || TREE_CODE(node) == UNION_TYPE);
 
-	/* XXX: Do not apply randomization to all-ftpr structs yet. */
-	return 0;
-
 	for (field = TYPE_FIELDS(node); field; field = TREE_CHAIN(field)) {
 		const_tree fieldtype = get_field_type(field);
 		enum tree_code code = TREE_CODE(fieldtype);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [kernel-hardening] [PATCH 16/18] task_struct: Allow randomized layout
  2017-04-06 21:18 [kernel-hardening] [PATCH 00/18] Introduce struct layout randomization plugin Kees Cook
                   ` (14 preceding siblings ...)
  2017-04-06 21:18 ` [kernel-hardening] [PATCH 15/18] randstruct: Enable function pointer struct detection Kees Cook
@ 2017-04-06 21:18 ` Kees Cook
  2017-04-07 16:25   ` Rik van Riel
  2017-04-06 21:18 ` [kernel-hardening] [PATCH 17/18] sgi-xp: Use designated initializers Kees Cook
                   ` (4 subsequent siblings)
  20 siblings, 1 reply; 34+ messages in thread
From: Kees Cook @ 2017-04-06 21:18 UTC (permalink / raw)
  To: kernel-hardening; +Cc: Kees Cook, Michael Leibowitz

This marks most of the layout of task_struct as randomizable, but leaves
thread_info and scheduler state untouched at the start, and thread_struct
untouched at the end.

Additionally, this keeps the blocked and saved sigset_t fields
unrandomized relative to each other, as found in grsecurity. I tried
to find a rationale for this, but so far I haven't been able to find
instances, but it seems like a nasty enough corner case to have to debug
that I've left it in.

One question about formatting remains: should this patch indent all the
randomized fields, due to the added anonymous struct, which would make
this patch white-space huge, or should I leave the indentation level
alone, to avoid massive churn? I opted for making the patch more
readable, but can easily do the indentation...

Signed-off-by: Kees Cook <keescook@chromium.org>
---
 include/linux/sched.h | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/include/linux/sched.h b/include/linux/sched.h
index 91f3ea399e0c..96903286b5dc 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -490,6 +490,10 @@ struct task_struct {
 #endif
 	/* -1 unrunnable, 0 runnable, >0 stopped: */
 	volatile long			state;
+
+	/* This begins the randomizable portion of task_struct... */
+	struct {
+
 	void				*stack;
 	atomic_t			usage;
 	/* Per task flags (PF_*), defined further below: */
@@ -745,10 +749,13 @@ struct task_struct {
 	/* Signal handlers: */
 	struct signal_struct		*signal;
 	struct sighand_struct		*sighand;
-	sigset_t			blocked;
 	sigset_t			real_blocked;
-	/* Restored if set_restore_sigmask() was used: */
-	sigset_t			saved_sigmask;
+	/* These need to stay unrandomized, relative to each other. */
+	struct {
+		sigset_t			blocked;
+		/* Restored if set_restore_sigmask() was used: */
+		sigset_t			saved_sigmask;
+	};
 	struct sigpending		pending;
 	unsigned long			sas_ss_sp;
 	size_t				sas_ss_size;
@@ -1050,6 +1057,8 @@ struct task_struct {
 #ifdef CONFIG_LIVEPATCH
 	int patch_state;
 #endif
+	} __randomize_layout;
+
 	/* CPU-specific state of this task: */
 	struct thread_struct		thread;
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [kernel-hardening] [PATCH 17/18] sgi-xp: Use designated initializers
  2017-04-06 21:18 [kernel-hardening] [PATCH 00/18] Introduce struct layout randomization plugin Kees Cook
                   ` (15 preceding siblings ...)
  2017-04-06 21:18 ` [kernel-hardening] [PATCH 16/18] task_struct: Allow randomized layout Kees Cook
@ 2017-04-06 21:18 ` Kees Cook
  2017-04-06 21:18 ` [kernel-hardening] [PATCH 18/18] ACPICA: " Kees Cook
                   ` (3 subsequent siblings)
  20 siblings, 0 replies; 34+ messages in thread
From: Kees Cook @ 2017-04-06 21:18 UTC (permalink / raw)
  To: kernel-hardening; +Cc: Kees Cook, Michael Leibowitz

Prepare to mark sensitive kernel structures for randomization by making
sure they're using designated initializers. These were identified during
allyesconfig builds of x86, arm, and arm64, with most initializer fixes
extracted from grsecurity.

To avoid casting, this implements dummy functions with full function
prototypes.

Signed-off-by: Kees Cook <keescook@chromium.org>
---
 drivers/misc/sgi-xp/xp.h      |  2 +-
 drivers/misc/sgi-xp/xp_main.c | 59 ++++++++++++++++++++++++++++---------------
 2 files changed, 40 insertions(+), 21 deletions(-)

diff --git a/drivers/misc/sgi-xp/xp.h b/drivers/misc/sgi-xp/xp.h
index a23a373d8707..c862cd4583cc 100644
--- a/drivers/misc/sgi-xp/xp.h
+++ b/drivers/misc/sgi-xp/xp.h
@@ -288,7 +288,7 @@ struct xpc_interface {
 					xpc_notify_func, void *);
 	void (*received) (short, int, void *);
 	enum xp_retval (*partid_to_nasids) (short, void *);
-} __no_randomize_layout;
+};
 
 extern struct xpc_interface xpc_interface;
 
diff --git a/drivers/misc/sgi-xp/xp_main.c b/drivers/misc/sgi-xp/xp_main.c
index 01be66d02ca8..bb47f9d9b68a 100644
--- a/drivers/misc/sgi-xp/xp_main.c
+++ b/drivers/misc/sgi-xp/xp_main.c
@@ -71,20 +71,44 @@ EXPORT_SYMBOL_GPL(xpc_registrations);
 /*
  * Initialize the XPC interface to indicate that XPC isn't loaded.
  */
-static enum xp_retval
-xpc_notloaded(void)
+static void xpc_notloaded_connect(int ch_number)
+{ }
+
+static void xpc_notloaded_disconnect(int ch_number)
+{ }
+
+static enum xp_retval xpc_notloaded_send(short partid, int ch_number,
+					 u32 flags, void *payload,
+					 u16 payload_size)
+{
+	return xpNotLoaded;
+}
+
+static enum xp_retval xpc_notloaded_send_notify(short partid, int ch_number,
+						u32 flags, void *payload,
+						u16 payload_size,
+						xpc_notify_func func,
+						void *key)
+{
+	return xpNotLoaded;
+}
+
+static void xpc_notloaded_received(short partid, int ch_number, void *payload)
+{ }
+
+static enum xp_retval xpc_notloaded_partid_to_nasids(short partid,
+						     void *nasid_mask)
 {
 	return xpNotLoaded;
 }
 
 struct xpc_interface xpc_interface = {
-	(void (*)(int))xpc_notloaded,
-	(void (*)(int))xpc_notloaded,
-	(enum xp_retval(*)(short, int, u32, void *, u16))xpc_notloaded,
-	(enum xp_retval(*)(short, int, u32, void *, u16, xpc_notify_func,
-			   void *))xpc_notloaded,
-	(void (*)(short, int, void *))xpc_notloaded,
-	(enum xp_retval(*)(short, void *))xpc_notloaded
+	.connect = xpc_notloaded_connect,
+	.disconnect = xpc_notloaded_disconnect,
+	.send = xpc_notloaded_send,
+	.send_notify = xpc_notloaded_send_notify,
+	.received = xpc_notloaded_received,
+	.partid_to_nasids = xpc_notloaded_partid_to_nasids
 };
 EXPORT_SYMBOL_GPL(xpc_interface);
 
@@ -115,17 +139,12 @@ EXPORT_SYMBOL_GPL(xpc_set_interface);
 void
 xpc_clear_interface(void)
 {
-	xpc_interface.connect = (void (*)(int))xpc_notloaded;
-	xpc_interface.disconnect = (void (*)(int))xpc_notloaded;
-	xpc_interface.send = (enum xp_retval(*)(short, int, u32, void *, u16))
-	    xpc_notloaded;
-	xpc_interface.send_notify = (enum xp_retval(*)(short, int, u32, void *,
-						       u16, xpc_notify_func,
-						       void *))xpc_notloaded;
-	xpc_interface.received = (void (*)(short, int, void *))
-	    xpc_notloaded;
-	xpc_interface.partid_to_nasids = (enum xp_retval(*)(short, void *))
-	    xpc_notloaded;
+	xpc_interface.connect = xpc_notloaded_connect;
+	xpc_interface.disconnect = xpc_notloaded_disconnect;
+	xpc_interface.send = xpc_notloaded_send;
+	xpc_interface.send_notify = xpc_notloaded_send_notify;
+	xpc_interface.received = xpc_notloaded_received;
+	xpc_interface.partid_to_nasids = xpc_notloaded_partid_to_nasids;
 }
 EXPORT_SYMBOL_GPL(xpc_clear_interface);
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [kernel-hardening] [PATCH 18/18] ACPICA: Use designated initializers
  2017-04-06 21:18 [kernel-hardening] [PATCH 00/18] Introduce struct layout randomization plugin Kees Cook
                   ` (16 preceding siblings ...)
  2017-04-06 21:18 ` [kernel-hardening] [PATCH 17/18] sgi-xp: Use designated initializers Kees Cook
@ 2017-04-06 21:18 ` Kees Cook
  2017-04-06 21:54 ` [kernel-hardening] [PATCH 00/18] Introduce struct layout randomization plugin James Morris
                   ` (2 subsequent siblings)
  20 siblings, 0 replies; 34+ messages in thread
From: Kees Cook @ 2017-04-06 21:18 UTC (permalink / raw)
  To: kernel-hardening; +Cc: Kees Cook, Michael Leibowitz

The struct layout randomization plugin detects and randomizes any structs
that contain only function pointers. Once layout is randomized, all
initialization must be designated or the compiler will misalign the
assignments. This switches all the ACPICA function pointer struct to
use designated initializers, using the proposed upstream ACPICA macro.

Signed-off-by: Kees Cook <keescook@chromium.org>
---
 drivers/acpi/acpica/hwxfsleep.c               | 17 ++++++++++++-----
 include/acpi/platform/acenv.h                 |  4 ++++
 include/acpi/platform/aclinux.h               |  2 ++
 scripts/gcc-plugins/randomize_layout_plugin.c |  4 ----
 4 files changed, 18 insertions(+), 9 deletions(-)

diff --git a/drivers/acpi/acpica/hwxfsleep.c b/drivers/acpi/acpica/hwxfsleep.c
index 5733b1167e46..f737e54412f6 100644
--- a/drivers/acpi/acpica/hwxfsleep.c
+++ b/drivers/acpi/acpica/hwxfsleep.c
@@ -70,11 +70,18 @@ static acpi_status acpi_hw_sleep_dispatch(u8 sleep_state, u32 function_id);
 /* Legacy functions are optional, based upon ACPI_REDUCED_HARDWARE */
 
 static struct acpi_sleep_functions acpi_sleep_dispatch[] = {
-	{ACPI_HW_OPTIONAL_FUNCTION(acpi_hw_legacy_sleep),
-	 acpi_hw_extended_sleep},
-	{ACPI_HW_OPTIONAL_FUNCTION(acpi_hw_legacy_wake_prep),
-	 acpi_hw_extended_wake_prep},
-	{ACPI_HW_OPTIONAL_FUNCTION(acpi_hw_legacy_wake), acpi_hw_extended_wake}
+    {ACPI_STRUCT_INIT (legacy_function,
+                       ACPI_HW_OPTIONAL_FUNCTION (acpi_hw_legacy_sleep)),
+     ACPI_STRUCT_INIT (extended_function,
+                       acpi_hw_extended_sleep) },
+    {ACPI_STRUCT_INIT (legacy_function,
+                       ACPI_HW_OPTIONAL_FUNCTION (acpi_hw_legacy_wake_prep)),
+     ACPI_STRUCT_INIT (extended_function,
+                       acpi_hw_extended_wake_prep) },
+    {ACPI_STRUCT_INIT (legacy_function,
+                       ACPI_HW_OPTIONAL_FUNCTION (acpi_hw_legacy_wake)),
+     ACPI_STRUCT_INIT (extended_function,
+                       acpi_hw_extended_wake) }
 };
 
 /*
diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h
index 09994b063243..912563c66948 100644
--- a/include/acpi/platform/acenv.h
+++ b/include/acpi/platform/acenv.h
@@ -382,4 +382,8 @@
 #define ACPI_INIT_FUNCTION
 #endif
 
+#ifndef ACPI_STRUCT_INIT
+#define ACPI_STRUCT_INIT(field, value) value
+#endif
+
 #endif				/* __ACENV_H__ */
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index a39e3f67616f..047f13865608 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -178,6 +178,8 @@
 #define ACPI_MSG_BIOS_ERROR     KERN_ERR "ACPI BIOS Error (bug): "
 #define ACPI_MSG_BIOS_WARNING   KERN_WARNING "ACPI BIOS Warning (bug): "
 
+#define ACPI_STRUCT_INIT(field, value)	.field = value
+
 #else				/* !__KERNEL__ */
 
 #define ACPI_USE_STANDARD_HEADERS
diff --git a/scripts/gcc-plugins/randomize_layout_plugin.c b/scripts/gcc-plugins/randomize_layout_plugin.c
index 716bb877b3fd..3d4366996b2f 100644
--- a/scripts/gcc-plugins/randomize_layout_plugin.c
+++ b/scripts/gcc-plugins/randomize_layout_plugin.c
@@ -329,10 +329,6 @@ static int relayout_struct(tree type)
 	    !strcmp((const char *)ORIG_TYPE_NAME(type), "RAWPCIFACTORY"))
 		return 0;
 
-	/* Skip ACPICA structs until refreshed with designated_init. */
-	if (!strcmp((const char *)ORIG_TYPE_NAME(type), "acpi_sleep_functions"))
-		return 0;
-
 	/* throw out any structs in uapi */
 	xloc = expand_location(DECL_SOURCE_LOCATION(TYPE_FIELDS(type)));
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* Re: [kernel-hardening] [PATCH 00/18] Introduce struct layout randomization plugin
  2017-04-06 21:18 [kernel-hardening] [PATCH 00/18] Introduce struct layout randomization plugin Kees Cook
                   ` (17 preceding siblings ...)
  2017-04-06 21:18 ` [kernel-hardening] [PATCH 18/18] ACPICA: " Kees Cook
@ 2017-04-06 21:54 ` James Morris
  2017-04-06 22:32   ` Rik van Riel
  2017-04-13 23:39 ` Laura Abbott
  2017-04-18 16:54 ` Laura Abbott
  20 siblings, 1 reply; 34+ messages in thread
From: James Morris @ 2017-04-06 21:54 UTC (permalink / raw)
  To: Kees Cook; +Cc: kernel-hardening, Michael Leibowitz

On Thu, 6 Apr 2017, Kees Cook wrote:

> third party kernel module builds), it still has some value there since
> now all kernel builds would need to be tracked by an attacker.

I don't see this case as providing any value.  Tracking a bunch of known 
seed values seems like a pretty low bar for an attacker.



- James
-- 
James Morris
<jmorris@namei.org>

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [kernel-hardening] [PATCH 00/18] Introduce struct layout randomization plugin
  2017-04-06 21:54 ` [kernel-hardening] [PATCH 00/18] Introduce struct layout randomization plugin James Morris
@ 2017-04-06 22:32   ` Rik van Riel
  2017-04-06 22:51     ` Kees Cook
  0 siblings, 1 reply; 34+ messages in thread
From: Rik van Riel @ 2017-04-06 22:32 UTC (permalink / raw)
  To: James Morris, Kees Cook; +Cc: kernel-hardening, Michael Leibowitz

On Fri, 2017-04-07 at 07:54 +1000, James Morris wrote:
> On Thu, 6 Apr 2017, Kees Cook wrote:
> 
> > third party kernel module builds), it still has some value there
> > since
> > now all kernel builds would need to be tracked by an attacker.
> 
> I don't see this case as providing any value.  Tracking a bunch of
> known 
> seed values seems like a pretty low bar for an attacker.

I agree this is not likely to provide much value for users
of distribution kernels.

One possible exception might be if Google started distributing
dozens, or hundreds, of kernel variants randomly to users of
Nexus devices, and nobody knew which variant each device was
running.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [kernel-hardening] [PATCH 00/18] Introduce struct layout randomization plugin
  2017-04-06 22:32   ` Rik van Riel
@ 2017-04-06 22:51     ` Kees Cook
  0 siblings, 0 replies; 34+ messages in thread
From: Kees Cook @ 2017-04-06 22:51 UTC (permalink / raw)
  To: Rik van Riel; +Cc: James Morris, kernel-hardening, Michael Leibowitz

On Thu, Apr 6, 2017 at 3:32 PM, Rik van Riel <riel@redhat.com> wrote:
> On Fri, 2017-04-07 at 07:54 +1000, James Morris wrote:
>> On Thu, 6 Apr 2017, Kees Cook wrote:
>>
>> > third party kernel module builds), it still has some value there
>> > since
>> > now all kernel builds would need to be tracked by an attacker.
>>
>> I don't see this case as providing any value.  Tracking a bunch of
>> known
>> seed values seems like a pretty low bar for an attacker.
>
> I agree this is not likely to provide much value for users
> of distribution kernels.
>
> One possible exception might be if Google started distributing
> dozens, or hundreds, of kernel variants randomly to users of
> Nexus devices, and nobody knew which variant each device was
> running.

Right, or in the distribution case, rebuilding distro kernels instead
of using the binary packages.

-Kees

-- 
Kees Cook
Pixel Security

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [kernel-hardening] [PATCH 16/18] task_struct: Allow randomized layout
  2017-04-06 21:18 ` [kernel-hardening] [PATCH 16/18] task_struct: Allow randomized layout Kees Cook
@ 2017-04-07 16:25   ` Rik van Riel
  2017-04-07 20:43     ` Kees Cook
  0 siblings, 1 reply; 34+ messages in thread
From: Rik van Riel @ 2017-04-07 16:25 UTC (permalink / raw)
  To: Kees Cook, kernel-hardening; +Cc: Michael Leibowitz

On Thu, 2017-04-06 at 14:18 -0700, Kees Cook wrote:

> One question about formatting remains: should this patch indent all
> the
> randomized fields, due to the added anonymous struct, which would
> make
> this patch white-space huge, or should I leave the indentation level
> alone, to avoid massive churn? I opted for making the patch more
> readable, but can easily do the indentation...

It may make sense to do the indentation in a separate
patch, for readability reasons.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [kernel-hardening] [PATCH 16/18] task_struct: Allow randomized layout
  2017-04-07 16:25   ` Rik van Riel
@ 2017-04-07 20:43     ` Kees Cook
  0 siblings, 0 replies; 34+ messages in thread
From: Kees Cook @ 2017-04-07 20:43 UTC (permalink / raw)
  To: Rik van Riel; +Cc: kernel-hardening, Michael Leibowitz

On Fri, Apr 7, 2017 at 9:25 AM, Rik van Riel <riel@redhat.com> wrote:
> On Thu, 2017-04-06 at 14:18 -0700, Kees Cook wrote:
>
>> One question about formatting remains: should this patch indent all
>> the
>> randomized fields, due to the added anonymous struct, which would
>> make
>> this patch white-space huge, or should I leave the indentation level
>> alone, to avoid massive churn? I opted for making the patch more
>> readable, but can easily do the indentation...
>
> It may make sense to do the indentation in a separate
> patch, for readability reasons.

Ah, yeah, that makes sense. I'll do three phases: the sigset_t
anonymous struct, then the non-indent-changing randomizable anon
struct, then all the whitespace...

-Kees

-- 
Kees Cook
Pixel Security

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [kernel-hardening] Re: [PATCH 01/18] gcc-plugins: Add the randstruct plugin
  2017-04-06 21:18 ` [kernel-hardening] [PATCH 01/18] gcc-plugins: Add the randstruct plugin Kees Cook
@ 2017-04-12 22:12   ` Kees Cook
  2017-04-17  5:30     ` Jessica Yu
  0 siblings, 1 reply; 34+ messages in thread
From: Kees Cook @ 2017-04-12 22:12 UTC (permalink / raw)
  To: Jessica Yu; +Cc: Michael Leibowitz, kernel-hardening

On Thu, Apr 6, 2017 at 2:18 PM, Kees Cook <keescook@chromium.org> wrote:
> From: Michael Leibowitz <michael.leibowitz@intel.com>
>
> This plugin randomizes the layout of selected structures at compile
> time. This is a probabilistic defense against attacks that need to
> know the layout of structures within the kernel. 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.
>
> This introduces two defines __randomize_layout and __no_randomize_layout.
> Which, in turn, tell the compiler to either randomize or not to randomize
> the struct in question. Follow-on patches enable the auto-detection
> logic for selecting structures that contain only function pointers.
>
> This feature is ported over from grsecurity.  The implementation is
> almost entirely identical to the original code written by the PaX Team
> and Brad Spengler. To make integration simpler, this version has the
> auto-detection logic temporarily disabled. Structures that are to be
> randomized are required to use the C99 designated initializer form,
> which will be in follow-on patches.
>
> Signed-off-by: Michael Leibowitz <michael.leibowitz@intel.com>
> [kees: refreshed plugin, disabled all-fptr-struct detection, update commit log]
> Signed-off-by: Kees Cook <keescook@chromium.org>
> ---
>  Documentation/dontdiff                        |   2 +
>  arch/Kconfig                                  |  38 ++
>  include/linux/compiler-gcc.h                  |   5 +
>  include/linux/compiler.h                      |   8 +
>  include/linux/vermagic.h                      |   9 +-
>  kernel/module.c                               |  27 +-
>  scripts/Makefile.gcc-plugins                  |   5 +
>  scripts/gcc-plugins/.gitignore                |   1 +
>  scripts/gcc-plugins/Makefile                  |   8 +
>  scripts/gcc-plugins/gen-random-seed.sh        |   8 +
>  scripts/gcc-plugins/randomize_layout_plugin.c | 943 ++++++++++++++++++++++++++
>  11 files changed, 1052 insertions(+), 2 deletions(-)
>  create mode 100644 scripts/gcc-plugins/.gitignore
>  create mode 100644 scripts/gcc-plugins/gen-random-seed.sh
>  create mode 100644 scripts/gcc-plugins/randomize_layout_plugin.c
>
> [...]
> diff --git a/include/linux/vermagic.h b/include/linux/vermagic.h
> index 6f8fbcf10dfb..af6c03f7f986 100644
> --- a/include/linux/vermagic.h
> +++ b/include/linux/vermagic.h
> @@ -24,10 +24,17 @@
>  #ifndef MODULE_ARCH_VERMAGIC
>  #define MODULE_ARCH_VERMAGIC ""
>  #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                                                \
>         UTS_RELEASE " "                                                 \
>         MODULE_VERMAGIC_SMP MODULE_VERMAGIC_PREEMPT                     \
>         MODULE_VERMAGIC_MODULE_UNLOAD MODULE_VERMAGIC_MODVERSIONS       \
> -       MODULE_ARCH_VERMAGIC
> +       MODULE_ARCH_VERMAGIC                                            \
> +       MODULE_RANDSTRUCT_PLUGIN
>
> diff --git a/kernel/module.c b/kernel/module.c
> index f953df992a11..2887660b0e9c 100644
> --- a/kernel/module.c
> +++ b/kernel/module.c
> @@ -1316,13 +1316,30 @@ static int check_version(Elf_Shdr *sechdrs,
>                 goto bad_version;
>         }
>
> +#ifdef CONFIG_GCC_PLUGIN_RANDSTRUCT
> +       /*
> +        * avoid potentially printing jibberish on attempted load
> +        * of a module randomized with a different seed
> +        */
> +       pr_warn("no symbol version for %s\n", symname);
> +#else
>         /* Broken toolchain. Warn once, then let it go.. */
>         pr_warn_once("%s: no symbol version for %s\n", mod->name, symname);
> +#endif
>         return 1;
>
>  bad_version:
> +#ifdef CONFIG_GCC_PLUGIN_RANDSTRUCT
> +       /*
> +        * avoid potentially printing jibberish on attempted load
> +        * of a module randomized with a different seed
> +        */
> +       pr_warn("attempted module disagrees about version of symbol %s\n",
> +              symname);
> +#else
>         pr_warn("%s: disagrees about version of symbol %s\n",
>                mod->name, symname);
> +#endif
>         return 0;
>  }
>
> @@ -2964,7 +2981,15 @@ static struct module *setup_load_info(struct load_info *info, int flags)
>         mod = (void *)info->sechdrs[info->index.mod].sh_addr;
>
>         if (info->index.sym == 0) {
> +#ifdef CONFIG_GCC_PLUGIN_RANDSTRUCT
> +               /*
> +                * avoid potentially printing jibberish on attempted load
> +                * of a module randomized with a different seed
> +                */
> +               pr_warn("module has no symbols (stripped?)\n");
> +#else
>                 pr_warn("%s: module has no symbols (stripped?)\n", mod->name);
> +#endif
>                 return ERR_PTR(-ENOEXEC);
>         }
>

Hi Jessica,

I was curious to get your input on these module-related changes that
are needed to support structure layout randomization. In the face of a
vermagic failure on a kernel built with randstruct, the module errors
can't dereference the from-disk module structure name field since it
may not be in the place it's expected.

I was thinking, instead of these explicit #ifdef chunks, maybe making
a helper macro/function would be better?

Also, can we get the module filename from somewhere, and use that
instead of the name field?

-Kees

-- 
Kees Cook
Pixel Security

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [kernel-hardening] [PATCH 00/18] Introduce struct layout randomization plugin
  2017-04-06 21:18 [kernel-hardening] [PATCH 00/18] Introduce struct layout randomization plugin Kees Cook
                   ` (18 preceding siblings ...)
  2017-04-06 21:54 ` [kernel-hardening] [PATCH 00/18] Introduce struct layout randomization plugin James Morris
@ 2017-04-13 23:39 ` Laura Abbott
  2017-04-15 18:50   ` Kees Cook
  2017-04-18 16:54 ` Laura Abbott
  20 siblings, 1 reply; 34+ messages in thread
From: Laura Abbott @ 2017-04-13 23:39 UTC (permalink / raw)
  To: Kees Cook, kernel-hardening; +Cc: Michael Leibowitz

On 04/06/2017 02:18 PM, Kees Cook wrote:
> This series brings grsecurity's structure layout randomization plugin
> to upstream. The 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. 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. It is
> most useful to "in-house" kernel builds where the randomization seed
> is not available to an attacker.
>     
> One requirement of the plugin is that randomized structures must use
> designated initializers. Many of these have been landing already as
> I've been sending them over the past couple months, but there are
> still some stragglers, which are included here.
> 
> Another area to address are places where randomized structures are
> cast to other structures, since there may be implicit positional
> details that need to be addressed. Luckily, there are only a few
> of these false positives, and they have been worked around either
> by adjusting the source or whitelisting them in the plugin.
> 
> The plugin selects structures in two ways: manually marked with the
> new __randomize_layout annotation, or automatically when a structure
> is found to consist entirely of function pointers (which can be opted
> out of with the new __no_randomize_layout annotation).
> 
> A structure that is especially sensitive and regularly abused in
> exploits is task_struct, but randomizing it requires some special
> handling due to some fields needing to be at the start and end. To
> deal with this, an internal anonymous struct is used to mark the
> portion that will be randomized. I'd love feedback on whether I
> should bite the bullet and perform indenting or violate indenting
> rules to avoid a massive white-space change.
> 
> As mentioned, the bulk of this feature is ported over from grsecurity.
> The implementation is almost entirely identical to the original code
> written by Brad Spengler and the PaX Team and Brad Spengler. The
> changes are addition of improved designated initializer markings,
> a whitelisting mechanism, and a different approach to handling the
> task_struct randomization.
> 
> I've been doing boot tests with instrumentation showing successfully
> changing offsets within the task_struct, which ran overnight without
> problems. So far, the 0day builder hasn't alerted on anything, but
> it's probably still a bit early.
> 
> This series is based on next-20170404.
> 
> Patches are:
> 
> [PATCH 01/18] gcc-plugins: Add the randstruct plugin
> 	The plugin itself, with struct auto-detection disabled.
> 
> [PATCH 02/18] compiler: Add __designated_init annotation
> [PATCH 03/18] randstruct: Set designated_init attribute
> 	Adds marking of structures needing designated initialization.
> 	
> [PATCH 04/18] randstruct: Differentiate bad cast warnings
> 	Minor clarifications to bad cast warning output.
> 
> [PATCH 05/18] af_unix: Use designated initializers
> 	Designated initializer fix for af_unix (taken for -next already)
> 	https://lkml.org/lkml/2017/4/6/846
> 
> [PATCH 06/18] NFS: Avoid cross-structure casting
> 	Avoids a false positive in casting (waiting for feedback)
> 	https://lkml.org/lkml/2017/4/5/530
> 
> [PATCH 07/18] randstruct: Whitelist struct security_hook_heads cast
> [PATCH 08/18] randstruct: Whitelist UNIXCB cast
> 	Whitelist two more false positive cases where source-level
> 	fixes aren't obvious/possible.
> 
> [PATCH 09/18] randstruct: Mark various structs for randomization
> 	Adds the manual annotation for structures to randomize.
> 
> [PATCH 10/18] scsi/bfa: use designated initializers
> [PATCH 11/18] scsi: qedi,qedf: Use designated initializers
> [PATCH 12/18] ovl: Use designated initializers
> 	The remaining designated initializer fixes for automatic
> 	struct randomization.
> 
> [PATCH 13/18] randstruct: opt-out externally exposed function pointer
> 	Opt out of some externally-exposed structs that would be
> 	otherwise automatically randomized.
> 
> [PATCH 14/18] randstruct: Disable randomization of ACPICA structs
> 	Temporary disabling of automatic randomization of ACPICA struct.
> 	
> [PATCH 15/18] randstruct: Enable function pointer struct detection
> 	Enables automatic struct randomization.
> 
> [PATCH 16/18] task_struct: Allow randomized layout
> 	Adds selected portion of task_struct to be randomized.
> 
> [PATCH 17/18] sgi-xp: Use designated initializers
> 	Enable randomization of sgi-xp struct, pending feedback.
> 	https://lkml.org/lkml/2017/3/29/808
> 
> [PATCH 18/18] ACPICA: Use designated initializers
> 	Enable randomization of ACPICA struct, pending feedback.
> 	https://github.com/acpica/acpica/pull/248/
> 
> Testing/feedback appreciated!
> 
> -Kees
> 

I gave this a quick spin on my aarch64 Rawhide machine. I needed to
change the following to work with gcc7

diff --git a/scripts/gcc-plugins/randomize_layout_plugin.c b/scripts/gcc-plugins/randomize_layout_plugin.c
index a2d7e933c33f..8dd5134f161a 100644
--- a/scripts/gcc-plugins/randomize_layout_plugin.c
+++ b/scripts/gcc-plugins/randomize_layout_plugin.c
@@ -529,8 +529,8 @@ static void randomize_layout_finish_decl(void *event_data, void *data)
 
        DECL_SIZE(decl) = 0;
        DECL_SIZE_UNIT(decl) = 0;
-       DECL_ALIGN(decl) = 0;
-       DECL_MODE (decl) = VOIDmode;
+       SET_DECL_ALIGN(decl, 0);
+       SET_DECL_MODE(decl, VOIDmode);
        SET_DECL_RTL(decl, 0);
        update_decl_size(decl);
        layout_decl(decl, 0);

It boots but dies with a bunch of kernel faults somewhere after reaching
userspace. I'll pick up the debugging next week.

Thanks,
Laura

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* Re: [kernel-hardening] [PATCH 00/18] Introduce struct layout randomization plugin
  2017-04-13 23:39 ` Laura Abbott
@ 2017-04-15 18:50   ` Kees Cook
  2017-04-18 17:15     ` Laura Abbott
  0 siblings, 1 reply; 34+ messages in thread
From: Kees Cook @ 2017-04-15 18:50 UTC (permalink / raw)
  To: Laura Abbott; +Cc: kernel-hardening, Michael Leibowitz

On Thu, Apr 13, 2017 at 4:39 PM, Laura Abbott <labbott@redhat.com> wrote:
> I gave this a quick spin on my aarch64 Rawhide machine. I needed to
> change the following to work with gcc7
>
> diff --git a/scripts/gcc-plugins/randomize_layout_plugin.c b/scripts/gcc-plugins/randomize_layout_plugin.c
> index a2d7e933c33f..8dd5134f161a 100644
> --- a/scripts/gcc-plugins/randomize_layout_plugin.c
> +++ b/scripts/gcc-plugins/randomize_layout_plugin.c
> @@ -529,8 +529,8 @@ static void randomize_layout_finish_decl(void *event_data, void *data)
>
>         DECL_SIZE(decl) = 0;
>         DECL_SIZE_UNIT(decl) = 0;
> -       DECL_ALIGN(decl) = 0;
> -       DECL_MODE (decl) = VOIDmode;
> +       SET_DECL_ALIGN(decl, 0);
> +       SET_DECL_MODE(decl, VOIDmode);
>         SET_DECL_RTL(decl, 0);
>         update_decl_size(decl);
>         layout_decl(decl, 0);

Very cool, thanks! I'll adjust the common header file to provide these
macros for gcc pre-7 builds and update the series.

> It boots but dies with a bunch of kernel faults somewhere after reaching
> userspace. I'll pick up the debugging next week.

I've been thinking about splitting up the structure marking patch into
per-structure markings to make failure bisection easier. I assume
there's a specific structure that is misbehaving on aarch64 (my first
guess is always task_struct).

-Kees

-- 
Kees Cook
Pixel Security

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [kernel-hardening] Re: [PATCH 01/18] gcc-plugins: Add the randstruct plugin
  2017-04-12 22:12   ` [kernel-hardening] " Kees Cook
@ 2017-04-17  5:30     ` Jessica Yu
  2017-04-17 15:23       ` Kees Cook
  0 siblings, 1 reply; 34+ messages in thread
From: Jessica Yu @ 2017-04-17  5:30 UTC (permalink / raw)
  To: Kees Cook; +Cc: Michael Leibowitz, kernel-hardening

+++ Kees Cook [12/04/17 15:12 -0700]:
>On Thu, Apr 6, 2017 at 2:18 PM, Kees Cook <keescook@chromium.org> wrote:
>> From: Michael Leibowitz <michael.leibowitz@intel.com>
>>
>> This plugin randomizes the layout of selected structures at compile
>> time. This is a probabilistic defense against attacks that need to
>> know the layout of structures within the kernel. 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.
>>
>> This introduces two defines __randomize_layout and __no_randomize_layout.
>> Which, in turn, tell the compiler to either randomize or not to randomize
>> the struct in question. Follow-on patches enable the auto-detection
>> logic for selecting structures that contain only function pointers.
>>
>> This feature is ported over from grsecurity.  The implementation is
>> almost entirely identical to the original code written by the PaX Team
>> and Brad Spengler. To make integration simpler, this version has the
>> auto-detection logic temporarily disabled. Structures that are to be
>> randomized are required to use the C99 designated initializer form,
>> which will be in follow-on patches.
>>
>> Signed-off-by: Michael Leibowitz <michael.leibowitz@intel.com>
>> [kees: refreshed plugin, disabled all-fptr-struct detection, update commit log]
>> Signed-off-by: Kees Cook <keescook@chromium.org>
>> ---
>>  Documentation/dontdiff                        |   2 +
>>  arch/Kconfig                                  |  38 ++
>>  include/linux/compiler-gcc.h                  |   5 +
>>  include/linux/compiler.h                      |   8 +
>>  include/linux/vermagic.h                      |   9 +-
>>  kernel/module.c                               |  27 +-
>>  scripts/Makefile.gcc-plugins                  |   5 +
>>  scripts/gcc-plugins/.gitignore                |   1 +
>>  scripts/gcc-plugins/Makefile                  |   8 +
>>  scripts/gcc-plugins/gen-random-seed.sh        |   8 +
>>  scripts/gcc-plugins/randomize_layout_plugin.c | 943 ++++++++++++++++++++++++++
>>  11 files changed, 1052 insertions(+), 2 deletions(-)
>>  create mode 100644 scripts/gcc-plugins/.gitignore
>>  create mode 100644 scripts/gcc-plugins/gen-random-seed.sh
>>  create mode 100644 scripts/gcc-plugins/randomize_layout_plugin.c
>>
>> [...]
>> diff --git a/include/linux/vermagic.h b/include/linux/vermagic.h
>> index 6f8fbcf10dfb..af6c03f7f986 100644
>> --- a/include/linux/vermagic.h
>> +++ b/include/linux/vermagic.h
>> @@ -24,10 +24,17 @@
>>  #ifndef MODULE_ARCH_VERMAGIC
>>  #define MODULE_ARCH_VERMAGIC ""
>>  #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                                                \
>>         UTS_RELEASE " "                                                 \
>>         MODULE_VERMAGIC_SMP MODULE_VERMAGIC_PREEMPT                     \
>>         MODULE_VERMAGIC_MODULE_UNLOAD MODULE_VERMAGIC_MODVERSIONS       \
>> -       MODULE_ARCH_VERMAGIC
>> +       MODULE_ARCH_VERMAGIC                                            \
>> +       MODULE_RANDSTRUCT_PLUGIN
>>
>> diff --git a/kernel/module.c b/kernel/module.c
>> index f953df992a11..2887660b0e9c 100644
>> --- a/kernel/module.c
>> +++ b/kernel/module.c
>> @@ -1316,13 +1316,30 @@ static int check_version(Elf_Shdr *sechdrs,
>>                 goto bad_version;
>>         }
>>
>> +#ifdef CONFIG_GCC_PLUGIN_RANDSTRUCT
>> +       /*
>> +        * avoid potentially printing jibberish on attempted load
>> +        * of a module randomized with a different seed
>> +        */
>> +       pr_warn("no symbol version for %s\n", symname);
>> +#else
>>         /* Broken toolchain. Warn once, then let it go.. */
>>         pr_warn_once("%s: no symbol version for %s\n", mod->name, symname);
>> +#endif
>>         return 1;
>>
>>  bad_version:
>> +#ifdef CONFIG_GCC_PLUGIN_RANDSTRUCT
>> +       /*
>> +        * avoid potentially printing jibberish on attempted load
>> +        * of a module randomized with a different seed
>> +        */
>> +       pr_warn("attempted module disagrees about version of symbol %s\n",
>> +              symname);
>> +#else
>>         pr_warn("%s: disagrees about version of symbol %s\n",
>>                mod->name, symname);
>> +#endif
>>         return 0;
>>  }
>>
>> @@ -2964,7 +2981,15 @@ static struct module *setup_load_info(struct load_info *info, int flags)
>>         mod = (void *)info->sechdrs[info->index.mod].sh_addr;
>>
>>         if (info->index.sym == 0) {
>> +#ifdef CONFIG_GCC_PLUGIN_RANDSTRUCT
>> +               /*
>> +                * avoid potentially printing jibberish on attempted load
>> +                * of a module randomized with a different seed
>> +                */
>> +               pr_warn("module has no symbols (stripped?)\n");
>> +#else
>>                 pr_warn("%s: module has no symbols (stripped?)\n", mod->name);
>> +#endif
>>                 return ERR_PTR(-ENOEXEC);
>>         }
>>
>
>Hi Jessica,
>
>I was curious to get your input on these module-related changes that
>are needed to support structure layout randomization. In the face of a
>vermagic failure on a kernel built with randstruct, the module errors
>can't dereference the from-disk module structure name field since it
>may not be in the place it's expected.
>
>I was thinking, instead of these explicit #ifdef chunks, maybe making
>a helper macro/function would be better?

Hi Kees,

Yes, that would be preferable to using the repeated #ifdef blocks.
IMO your other patchset which adds name to .modinfo is a cleaner
solution.

(PS, I'm still on PTO, but I'll be able to give that a proper look
after Tues.)

>Also, can we get the module filename from somewhere, and use that
>instead of the name field?

AFAIK, we don't store or keep track of that anywhere in-kernel.

Thanks,

Jessica

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [kernel-hardening] Re: [PATCH 01/18] gcc-plugins: Add the randstruct plugin
  2017-04-17  5:30     ` Jessica Yu
@ 2017-04-17 15:23       ` Kees Cook
  2017-05-12  6:37         ` Loganaden Velvindron
  0 siblings, 1 reply; 34+ messages in thread
From: Kees Cook @ 2017-04-17 15:23 UTC (permalink / raw)
  To: Jessica Yu; +Cc: Michael Leibowitz, kernel-hardening

On Sun, Apr 16, 2017 at 10:30 PM, Jessica Yu <jeyu@redhat.com> wrote:
> Yes, that would be preferable to using the repeated #ifdef blocks.
> IMO your other patchset which adds name to .modinfo is a cleaner
> solution.

Sounds good. Yeah, after I sent this email I went looking for another
way to find the module name and realized that we probably needed a
general solution. :)

> (PS, I'm still on PTO, but I'll be able to give that a proper look
> after Tues.)

Awesome, thanks!

-Kees

-- 
Kees Cook
Pixel Security

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [kernel-hardening] [PATCH 00/18] Introduce struct layout randomization plugin
  2017-04-06 21:18 [kernel-hardening] [PATCH 00/18] Introduce struct layout randomization plugin Kees Cook
                   ` (19 preceding siblings ...)
  2017-04-13 23:39 ` Laura Abbott
@ 2017-04-18 16:54 ` Laura Abbott
  20 siblings, 0 replies; 34+ messages in thread
From: Laura Abbott @ 2017-04-18 16:54 UTC (permalink / raw)
  To: Kees Cook, kernel-hardening; +Cc: Michael Leibowitz

On 04/06/2017 02:18 PM, Kees Cook wrote:
> This series brings grsecurity's structure layout randomization plugin
> to upstream. The 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. 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. It is
> most useful to "in-house" kernel builds where the randomization seed
> is not available to an attacker.
>      
> One requirement of the plugin is that randomized structures must use
> designated initializers. Many of these have been landing already as
> I've been sending them over the past couple months, but there are
> still some stragglers, which are included here.
> 
> Another area to address are places where randomized structures are
> cast to other structures, since there may be implicit positional
> details that need to be addressed. Luckily, there are only a few
> of these false positives, and they have been worked around either
> by adjusting the source or whitelisting them in the plugin.
> 
> The plugin selects structures in two ways: manually marked with the
> new __randomize_layout annotation, or automatically when a structure
> is found to consist entirely of function pointers (which can be opted
> out of with the new __no_randomize_layout annotation).
> 
> A structure that is especially sensitive and regularly abused in
> exploits is task_struct, but randomizing it requires some special
> handling due to some fields needing to be at the start and end. To
> deal with this, an internal anonymous struct is used to mark the
> portion that will be randomized. I'd love feedback on whether I
> should bite the bullet and perform indenting or violate indenting
> rules to avoid a massive white-space change.
> 
> As mentioned, the bulk of this feature is ported over from grsecurity.
> The implementation is almost entirely identical to the original code
> written by Brad Spengler and the PaX Team and Brad Spengler. The
> changes are addition of improved designated initializer markings,
> a whitelisting mechanism, and a different approach to handling the
> task_struct randomization.
> 
> I've been doing boot tests with instrumentation showing successfully
> changing offsets within the task_struct, which ran overnight without
> problems. So far, the 0day builder hasn't alerted on anything, but
> it's probably still a bit early.
> 
> This series is based on next-20170404.
> 
> Patches are:
> 
> [PATCH 01/18] gcc-plugins: Add the randstruct plugin
> 	The plugin itself, with struct auto-detection disabled.
> 
> [PATCH 02/18] compiler: Add __designated_init annotation
> [PATCH 03/18] randstruct: Set designated_init attribute
> 	Adds marking of structures needing designated initialization.
> 	
> [PATCH 04/18] randstruct: Differentiate bad cast warnings
> 	Minor clarifications to bad cast warning output.
> 
> [PATCH 05/18] af_unix: Use designated initializers
> 	Designated initializer fix for af_unix (taken for -next already)
> 	https://lkml.org/lkml/2017/4/6/846
> 
> [PATCH 06/18] NFS: Avoid cross-structure casting
> 	Avoids a false positive in casting (waiting for feedback)
> 	https://lkml.org/lkml/2017/4/5/530
> 
> [PATCH 07/18] randstruct: Whitelist struct security_hook_heads cast
> [PATCH 08/18] randstruct: Whitelist UNIXCB cast
> 	Whitelist two more false positive cases where source-level
> 	fixes aren't obvious/possible.
> 
> [PATCH 09/18] randstruct: Mark various structs for randomization
> 	Adds the manual annotation for structures to randomize.
> 
> [PATCH 10/18] scsi/bfa: use designated initializers
> [PATCH 11/18] scsi: qedi,qedf: Use designated initializers
> [PATCH 12/18] ovl: Use designated initializers
> 	The remaining designated initializer fixes for automatic
> 	struct randomization.
> 
> [PATCH 13/18] randstruct: opt-out externally exposed function pointer
> 	Opt out of some externally-exposed structs that would be
> 	otherwise automatically randomized.
> 
> [PATCH 14/18] randstruct: Disable randomization of ACPICA structs
> 	Temporary disabling of automatic randomization of ACPICA struct.
> 	
> [PATCH 15/18] randstruct: Enable function pointer struct detection
> 	Enables automatic struct randomization.
> 
> [PATCH 16/18] task_struct: Allow randomized layout
> 	Adds selected portion of task_struct to be randomized.
> 
> [PATCH 17/18] sgi-xp: Use designated initializers
> 	Enable randomization of sgi-xp struct, pending feedback.
> 	https://lkml.org/lkml/2017/3/29/808
> 
> [PATCH 18/18] ACPICA: Use designated initializers
> 	Enable randomization of ACPICA struct, pending feedback.
> 	https://github.com/acpica/acpica/pull/248/
> 
> Testing/feedback appreciated!
> 
> -Kees
> 

A few more reports from the Fedora config

ipc/sem.c: In function ‘newary’:
ipc/sem.c:507:16: note: found mismatched ssa struct pointer types: 
‘struct sem’ and ‘struct sem_array’

   sma->sem_base = (struct sem *) &sma[1];
   ~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~

This looks like a false positive

security/keys/big_key.c:126:15: note: found mismatched rhs struct 
pointer types: ‘struct path’ and ‘void *’

   struct path *path = (struct path *)&prep->payload.data[big_key_path];
                ^~~~
security/keys/big_key.c: In function ‘big_key_free_preparse’:
security/keys/big_key.c:225:16: note: found mismatched rhs struct 
pointer types: ‘struct path’ and ‘void *’

    struct path *path = (struct path *)&prep->payload.data[big_key_path];
                 ^~~~
security/keys/big_key.c: In function ‘big_key_destroy’:
security/keys/big_key.c:255:16: note: found mismatched rhs struct 
pointer types: ‘struct path’ and ‘void *’

    struct path *path = (struct path *)&key->payload.data[big_key_path];
                 ^~~~
security/keys/big_key.c: In function ‘big_key_revoke’:
security/keys/big_key.c:238:15: note: found mismatched rhs struct 
pointer types: ‘struct path’ and ‘void *’

   struct path *path = (struct path *)&key->payload.data[big_key_path];
                ^~~~
security/keys/big_key.c: In function ‘big_key_read’:
security/keys/big_key.c:293:16: note: found mismatched rhs struct 
pointer types: ‘struct path’ and ‘void *’

    struct path *path = (struct path *)&key->payload.data[big_key_path];

I'm not quite sure what's going on here, I think it might be
another false positive?


fs/ocfs2/export.c: In function ‘ocfs2_get_dentry’:
fs/ocfs2/export.c:122:10: note: found mismatched ssa struct pointer 
types: ‘struct dentry’ and ‘struct inode’

    result = (void *)inode;
    ~~~~~~~^~~~~~~~~~~~~~~

This looks similar to the NFS issue

drivers/net/ethernet/sun/niu.c: In function ‘niu_rx_pkt_ignore’:
drivers/net/ethernet/sun/niu.c:3402:10: note: found mismatched ssa 
struct pointer types: ‘struct page’ and ‘struct address_space’

     *link = (struct page *) page->mapping;
     ~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
drivers/net/ethernet/sun/niu.c: In function ‘niu_process_rx_pkt’:
drivers/net/ethernet/sun/niu.c:3472:10: note: found mismatched ssa 
struct pointer types: ‘struct page’ and ‘struct address_space’

     *link = (struct page *) page->mapping;
     ~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

This driver appears to be doing something unique with storing
a page in page->mapping?

The AMD GPU driver has a bunch of warnings about needing to use
explicit initializers.

Thanks,
Laura

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [kernel-hardening] [PATCH 00/18] Introduce struct layout randomization plugin
  2017-04-15 18:50   ` Kees Cook
@ 2017-04-18 17:15     ` Laura Abbott
  2017-04-18 17:20       ` Kees Cook
  0 siblings, 1 reply; 34+ messages in thread
From: Laura Abbott @ 2017-04-18 17:15 UTC (permalink / raw)
  To: Kees Cook; +Cc: kernel-hardening, Michael Leibowitz

On 04/15/2017 11:50 AM, Kees Cook wrote:
> On Thu, Apr 13, 2017 at 4:39 PM, Laura Abbott <labbott@redhat.com> wrote:
>> I gave this a quick spin on my aarch64 Rawhide machine. I needed to
>> change the following to work with gcc7
>>
>> diff --git a/scripts/gcc-plugins/randomize_layout_plugin.c b/scripts/gcc-plugins/randomize_layout_plugin.c
>> index a2d7e933c33f..8dd5134f161a 100644
>> --- a/scripts/gcc-plugins/randomize_layout_plugin.c
>> +++ b/scripts/gcc-plugins/randomize_layout_plugin.c
>> @@ -529,8 +529,8 @@ static void randomize_layout_finish_decl(void *event_data, void *data)
>>
>>         DECL_SIZE(decl) = 0;
>>         DECL_SIZE_UNIT(decl) = 0;
>> -       DECL_ALIGN(decl) = 0;
>> -       DECL_MODE (decl) = VOIDmode;
>> +       SET_DECL_ALIGN(decl, 0);
>> +       SET_DECL_MODE(decl, VOIDmode);
>>         SET_DECL_RTL(decl, 0);
>>         update_decl_size(decl);
>>         layout_decl(decl, 0);
> 
> Very cool, thanks! I'll adjust the common header file to provide these
> macros for gcc pre-7 builds and update the series.
> 
>> It boots but dies with a bunch of kernel faults somewhere after reaching
>> userspace. I'll pick up the debugging next week.
> 
> I've been thinking about splitting up the structure marking patch into
> per-structure markings to make failure bisection easier. I assume
> there's a specific structure that is misbehaving on aarch64 (my first
> guess is always task_struct).
> 
> -Kees
> 

I think this was a build error on my side. I thought I tested with your
-next branch but it was apparently based on -rc2. Several builds with
your -next branch work fine. I'll test again with your v2 and see
what happens.

Thanks,
Laura

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [kernel-hardening] [PATCH 00/18] Introduce struct layout randomization plugin
  2017-04-18 17:15     ` Laura Abbott
@ 2017-04-18 17:20       ` Kees Cook
  0 siblings, 0 replies; 34+ messages in thread
From: Kees Cook @ 2017-04-18 17:20 UTC (permalink / raw)
  To: Laura Abbott; +Cc: kernel-hardening, Michael Leibowitz

On Tue, Apr 18, 2017 at 10:15 AM, Laura Abbott <labbott@redhat.com> wrote:
> On 04/15/2017 11:50 AM, Kees Cook wrote:
>> On Thu, Apr 13, 2017 at 4:39 PM, Laura Abbott <labbott@redhat.com> wrote:
>>> I gave this a quick spin on my aarch64 Rawhide machine. I needed to
>>> change the following to work with gcc7
>>>
>>> diff --git a/scripts/gcc-plugins/randomize_layout_plugin.c b/scripts/gcc-plugins/randomize_layout_plugin.c
>>> index a2d7e933c33f..8dd5134f161a 100644
>>> --- a/scripts/gcc-plugins/randomize_layout_plugin.c
>>> +++ b/scripts/gcc-plugins/randomize_layout_plugin.c
>>> @@ -529,8 +529,8 @@ static void randomize_layout_finish_decl(void *event_data, void *data)
>>>
>>>         DECL_SIZE(decl) = 0;
>>>         DECL_SIZE_UNIT(decl) = 0;
>>> -       DECL_ALIGN(decl) = 0;
>>> -       DECL_MODE (decl) = VOIDmode;
>>> +       SET_DECL_ALIGN(decl, 0);
>>> +       SET_DECL_MODE(decl, VOIDmode);
>>>         SET_DECL_RTL(decl, 0);
>>>         update_decl_size(decl);
>>>         layout_decl(decl, 0);
>>
>> Very cool, thanks! I'll adjust the common header file to provide these
>> macros for gcc pre-7 builds and update the series.
>>
>>> It boots but dies with a bunch of kernel faults somewhere after reaching
>>> userspace. I'll pick up the debugging next week.
>>
>> I've been thinking about splitting up the structure marking patch into
>> per-structure markings to make failure bisection easier. I assume
>> there's a specific structure that is misbehaving on aarch64 (my first
>> guess is always task_struct).
>>
>> -Kees
>>
>
> I think this was a build error on my side. I thought I tested with your
> -next branch but it was apparently based on -rc2. Several builds with
> your -next branch work fine. I'll test again with your v2 and see
> what happens.

This branch isn't quite ready, it was me trying to find the right
"first step" for getting things in, and only had some manually
annotated structs:

https://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git/log/?h=for-next/gcc-plugin/randstruct

This is where I've been staging fixes, but I need to update it to a
more recent -next tree:

https://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git/log/?h=kspp/gcc-plugin/randstruct-next-20170404

-Kees

-- 
Kees Cook
Pixel Security

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [kernel-hardening] Re: [PATCH 01/18] gcc-plugins: Add the randstruct plugin
  2017-04-17 15:23       ` Kees Cook
@ 2017-05-12  6:37         ` Loganaden Velvindron
  2017-05-12 19:36           ` Kees Cook
  0 siblings, 1 reply; 34+ messages in thread
From: Loganaden Velvindron @ 2017-05-12  6:37 UTC (permalink / raw)
  To: Kees Cook; +Cc: Jessica Yu, Michael Leibowitz, kernel-hardening

I often see drivers for android phones have all kinds of security
issues. Does this help to make it harder to exploit vulnerabilities
and RCEs in wifi drivers for example ?

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [kernel-hardening] Re: [PATCH 01/18] gcc-plugins: Add the randstruct plugin
  2017-05-12  6:37         ` Loganaden Velvindron
@ 2017-05-12 19:36           ` Kees Cook
  0 siblings, 0 replies; 34+ messages in thread
From: Kees Cook @ 2017-05-12 19:36 UTC (permalink / raw)
  To: Loganaden Velvindron; +Cc: Jessica Yu, Michael Leibowitz, kernel-hardening

On Thu, May 11, 2017 at 11:37 PM, Loganaden Velvindron
<loganaden@gmail.com> wrote:
> I often see drivers for android phones have all kinds of security
> issues. Does this help to make it harder to exploit vulnerabilities
> and RCEs in wifi drivers for example ?

Depends on the flaw (some of the recent wifi attacks have been against
the wifi firmware itself). As documented in the changelog:

... [randstruct is a] probabilistic defense against attacks that need
to know the layout of structures within the kernel ...

And overwriting function pointers in structures is a common way to
perform attacks, which this plugin would complicate. See "executing
code" in: https://googleprojectzero.blogspot.com/2017/05/exploiting-linux-kernel-via-packet.html

-Kees

-- 
Kees Cook
Pixel Security

^ permalink raw reply	[flat|nested] 34+ messages in thread

end of thread, other threads:[~2017-05-12 19:36 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-04-06 21:18 [kernel-hardening] [PATCH 00/18] Introduce struct layout randomization plugin Kees Cook
2017-04-06 21:18 ` [kernel-hardening] [PATCH 01/18] gcc-plugins: Add the randstruct plugin Kees Cook
2017-04-12 22:12   ` [kernel-hardening] " Kees Cook
2017-04-17  5:30     ` Jessica Yu
2017-04-17 15:23       ` Kees Cook
2017-05-12  6:37         ` Loganaden Velvindron
2017-05-12 19:36           ` Kees Cook
2017-04-06 21:18 ` [kernel-hardening] [PATCH 02/18] compiler: Add __designated_init annotation Kees Cook
2017-04-06 21:18 ` [kernel-hardening] [PATCH 03/18] randstruct: Set designated_init attribute Kees Cook
2017-04-06 21:18 ` [kernel-hardening] [PATCH 04/18] randstruct: Differentiate bad cast warnings Kees Cook
2017-04-06 21:18 ` [kernel-hardening] [PATCH 05/18] af_unix: Use designated initializers Kees Cook
2017-04-06 21:18 ` [kernel-hardening] [PATCH 06/18] NFS: Avoid cross-structure casting Kees Cook
2017-04-06 21:18 ` [kernel-hardening] [PATCH 07/18] randstruct: Whitelist struct security_hook_heads cast Kees Cook
2017-04-06 21:18 ` [kernel-hardening] [PATCH 08/18] randstruct: Whitelist UNIXCB cast Kees Cook
2017-04-06 21:18 ` [kernel-hardening] [PATCH 09/18] randstruct: Mark various structs for randomization Kees Cook
2017-04-06 21:18 ` [kernel-hardening] [PATCH 10/18] scsi/bfa: use designated initializers Kees Cook
2017-04-06 21:18 ` [kernel-hardening] [PATCH 11/18] scsi: qedi,qedf: Use " Kees Cook
2017-04-06 21:18 ` [kernel-hardening] [PATCH 12/18] ovl: " Kees Cook
2017-04-06 21:18 ` [kernel-hardening] [PATCH 13/18] randstruct: opt-out externally exposed function pointer structs Kees Cook
2017-04-06 21:18 ` [kernel-hardening] [PATCH 14/18] randstruct: Disable randomization of ACPICA structs Kees Cook
2017-04-06 21:18 ` [kernel-hardening] [PATCH 15/18] randstruct: Enable function pointer struct detection Kees Cook
2017-04-06 21:18 ` [kernel-hardening] [PATCH 16/18] task_struct: Allow randomized layout Kees Cook
2017-04-07 16:25   ` Rik van Riel
2017-04-07 20:43     ` Kees Cook
2017-04-06 21:18 ` [kernel-hardening] [PATCH 17/18] sgi-xp: Use designated initializers Kees Cook
2017-04-06 21:18 ` [kernel-hardening] [PATCH 18/18] ACPICA: " Kees Cook
2017-04-06 21:54 ` [kernel-hardening] [PATCH 00/18] Introduce struct layout randomization plugin James Morris
2017-04-06 22:32   ` Rik van Riel
2017-04-06 22:51     ` Kees Cook
2017-04-13 23:39 ` Laura Abbott
2017-04-15 18:50   ` Kees Cook
2017-04-18 17:15     ` Laura Abbott
2017-04-18 17:20       ` Kees Cook
2017-04-18 16:54 ` Laura Abbott

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.