aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/dontdiff2
-rw-r--r--arch/Kconfig41
-rw-r--r--arch/arm/include/asm/assembler.h2
-rw-r--r--arch/arm/kernel/entry-armv.S5
-rw-r--r--arch/arm/mm/proc-macros.S10
-rw-r--r--include/linux/compiler-gcc.h13
-rw-r--r--include/linux/compiler.h12
-rw-r--r--include/linux/vermagic.h9
-rw-r--r--scripts/Makefile.gcc-plugins4
-rw-r--r--scripts/gcc-plugins/.gitignore1
-rw-r--r--scripts/gcc-plugins/Makefile8
-rw-r--r--scripts/gcc-plugins/gcc-common.h12
-rw-r--r--scripts/gcc-plugins/gen-random-seed.sh8
-rw-r--r--scripts/gcc-plugins/randomize_layout_plugin.c1028
14 files changed, 1146 insertions, 9 deletions
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
207r300_reg_safe.h 207r300_reg_safe.h
208r420_reg_safe.h 208r420_reg_safe.h
209r600_reg_safe.h 209r600_reg_safe.h
210randomize_layout_hash.h
211randomize_layout_seed.h
210recordmcount 212recordmcount
211relocs 213relocs
212rlim_names.h 214rlim_names.h
diff --git a/arch/Kconfig b/arch/Kconfig
index 6c00e5b00f8b..3eac97a4c7b3 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -425,7 +425,7 @@ config GCC_PLUGIN_STRUCTLEAK
425 bool "Force initialization of variables containing userspace addresses" 425 bool "Force initialization of variables containing userspace addresses"
426 depends on GCC_PLUGINS 426 depends on GCC_PLUGINS
427 help 427 help
428 This plugin zero-initializes any structures that containing a 428 This plugin zero-initializes any structures containing a
429 __user attribute. This can prevent some classes of information 429 __user attribute. This can prevent some classes of information
430 exposures. 430 exposures.
431 431
@@ -443,6 +443,45 @@ config GCC_PLUGIN_STRUCTLEAK_VERBOSE
443 initialized. Since not all existing initializers are detected 443 initialized. Since not all existing initializers are detected
444 by the plugin, this can produce false positive warnings. 444 by the plugin, this can produce false positive warnings.
445 445
446config GCC_PLUGIN_RANDSTRUCT
447 bool "Randomize layout of sensitive kernel structures"
448 depends on GCC_PLUGINS
449 select MODVERSIONS if MODULES
450 help
451 If you say Y here, the layouts of structures explicitly
452 marked by __randomize_layout will be randomized at
453 compile-time. This can introduce the requirement of an
454 additional information exposure vulnerability for exploits
455 targeting these structure types.
456
457 Enabling this feature will introduce some performance impact,
458 slightly increase memory usage, and prevent the use of forensic
459 tools like Volatility against the system (unless the kernel
460 source tree isn't cleaned after kernel installation).
461
462 The seed used for compilation is located at
463 scripts/gcc-plgins/randomize_layout_seed.h. It remains after
464 a make clean to allow for external modules to be compiled with
465 the existing seed and will be removed by a make mrproper or
466 make distclean.
467
468 Note that the implementation requires gcc 4.7 or newer.
469
470 This plugin was ported from grsecurity/PaX. More information at:
471 * https://grsecurity.net/
472 * https://pax.grsecurity.net/
473
474config GCC_PLUGIN_RANDSTRUCT_PERFORMANCE
475 bool "Use cacheline-aware structure randomization"
476 depends on GCC_PLUGIN_RANDSTRUCT
477 depends on !COMPILE_TEST
478 help
479 If you say Y here, the RANDSTRUCT randomization will make a
480 best effort at restricting randomization to cacheline-sized
481 groups of elements. It will further not randomize bitfields
482 in structures. This reduces the performance hit of RANDSTRUCT
483 at the cost of weakened randomization.
484
446config HAVE_CC_STACKPROTECTOR 485config HAVE_CC_STACKPROTECTOR
447 bool 486 bool
448 help 487 help
diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h
index 68b06f9c65de..ad301f107dd2 100644
--- a/arch/arm/include/asm/assembler.h
+++ b/arch/arm/include/asm/assembler.h
@@ -87,6 +87,8 @@
87#define CALGN(code...) 87#define CALGN(code...)
88#endif 88#endif
89 89
90#define IMM12_MASK 0xfff
91
90/* 92/*
91 * Enable and disable interrupts 93 * Enable and disable interrupts
92 */ 94 */
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 9f157e7c51e7..c731f0d2b2af 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -797,7 +797,10 @@ ENTRY(__switch_to)
797#if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP) 797#if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)
798 ldr r7, [r2, #TI_TASK] 798 ldr r7, [r2, #TI_TASK]
799 ldr r8, =__stack_chk_guard 799 ldr r8, =__stack_chk_guard
800 ldr r7, [r7, #TSK_STACK_CANARY] 800 .if (TSK_STACK_CANARY > IMM12_MASK)
801 add r7, r7, #TSK_STACK_CANARY & ~IMM12_MASK
802 .endif
803 ldr r7, [r7, #TSK_STACK_CANARY & IMM12_MASK]
801#endif 804#endif
802#ifdef CONFIG_CPU_USE_DOMAINS 805#ifdef CONFIG_CPU_USE_DOMAINS
803 mcr p15, 0, r6, c3, c0, 0 @ Set domain register 806 mcr p15, 0, r6, c3, c0, 0 @ Set domain register
diff --git a/arch/arm/mm/proc-macros.S b/arch/arm/mm/proc-macros.S
index 0d40c285bd86..f944836da8a2 100644
--- a/arch/arm/mm/proc-macros.S
+++ b/arch/arm/mm/proc-macros.S
@@ -25,11 +25,6 @@
25 ldr \rd, [\rn, #VMA_VM_FLAGS] 25 ldr \rd, [\rn, #VMA_VM_FLAGS]
26 .endm 26 .endm
27 27
28 .macro tsk_mm, rd, rn
29 ldr \rd, [\rn, #TI_TASK]
30 ldr \rd, [\rd, #TSK_ACTIVE_MM]
31 .endm
32
33/* 28/*
34 * act_mm - get current->active_mm 29 * act_mm - get current->active_mm
35 */ 30 */
@@ -37,7 +32,10 @@
37 bic \rd, sp, #8128 32 bic \rd, sp, #8128
38 bic \rd, \rd, #63 33 bic \rd, \rd, #63
39 ldr \rd, [\rd, #TI_TASK] 34 ldr \rd, [\rd, #TI_TASK]
40 ldr \rd, [\rd, #TSK_ACTIVE_MM] 35 .if (TSK_ACTIVE_MM > IMM12_MASK)
36 add \rd, \rd, #TSK_ACTIVE_MM & ~IMM12_MASK
37 .endif
38 ldr \rd, [\rd, #TSK_ACTIVE_MM & IMM12_MASK]
41 .endm 39 .endm
42 40
43/* 41/*
diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h
index 0efef9cf014f..7deaae3dc87d 100644
--- a/include/linux/compiler-gcc.h
+++ b/include/linux/compiler-gcc.h
@@ -223,6 +223,11 @@
223/* Mark a function definition as prohibited from being cloned. */ 223/* Mark a function definition as prohibited from being cloned. */
224#define __noclone __attribute__((__noclone__, __optimize__("no-tracer"))) 224#define __noclone __attribute__((__noclone__, __optimize__("no-tracer")))
225 225
226#ifdef RANDSTRUCT_PLUGIN
227#define __randomize_layout __attribute__((randomize_layout))
228#define __no_randomize_layout __attribute__((no_randomize_layout))
229#endif
230
226#endif /* GCC_VERSION >= 40500 */ 231#endif /* GCC_VERSION >= 40500 */
227 232
228#if GCC_VERSION >= 40600 233#if GCC_VERSION >= 40600
@@ -294,6 +299,14 @@
294#define __no_sanitize_address __attribute__((no_sanitize_address)) 299#define __no_sanitize_address __attribute__((no_sanitize_address))
295#endif 300#endif
296 301
302#if GCC_VERSION >= 50100
303/*
304 * Mark structures as requiring designated initializers.
305 * https://gcc.gnu.org/onlinedocs/gcc/Designated-Inits.html
306 */
307#define __designated_init __attribute__((designated_init))
308#endif
309
297#endif /* gcc version >= 40000 specific checks */ 310#endif /* gcc version >= 40000 specific checks */
298 311
299#if !defined(__noclone) 312#if !defined(__noclone)
diff --git a/include/linux/compiler.h b/include/linux/compiler.h
index f8110051188f..55ee9ee814f8 100644
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -440,10 +440,22 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s
440# define __attribute_const__ /* unimplemented */ 440# define __attribute_const__ /* unimplemented */
441#endif 441#endif
442 442
443#ifndef __designated_init
444# define __designated_init
445#endif
446
443#ifndef __latent_entropy 447#ifndef __latent_entropy
444# define __latent_entropy 448# define __latent_entropy
445#endif 449#endif
446 450
451#ifndef __randomize_layout
452# define __randomize_layout __designated_init
453#endif
454
455#ifndef __no_randomize_layout
456# define __no_randomize_layout
457#endif
458
447/* 459/*
448 * Tell gcc if a function is cold. The compiler will assume any path 460 * Tell gcc if a function is cold. The compiler will assume any path
449 * directly leading to the call is unlikely. 461 * directly leading to the call is unlikely.
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 @@
24#ifndef MODULE_ARCH_VERMAGIC 24#ifndef MODULE_ARCH_VERMAGIC
25#define MODULE_ARCH_VERMAGIC "" 25#define MODULE_ARCH_VERMAGIC ""
26#endif 26#endif
27#ifdef RANDSTRUCT_PLUGIN
28#include <generated/randomize_layout_hash.h>
29#define MODULE_RANDSTRUCT_PLUGIN "RANDSTRUCT_PLUGIN_" RANDSTRUCT_HASHED_SEED
30#else
31#define MODULE_RANDSTRUCT_PLUGIN
32#endif
27 33
28#define VERMAGIC_STRING \ 34#define VERMAGIC_STRING \
29 UTS_RELEASE " " \ 35 UTS_RELEASE " " \
30 MODULE_VERMAGIC_SMP MODULE_VERMAGIC_PREEMPT \ 36 MODULE_VERMAGIC_SMP MODULE_VERMAGIC_PREEMPT \
31 MODULE_VERMAGIC_MODULE_UNLOAD MODULE_VERMAGIC_MODVERSIONS \ 37 MODULE_VERMAGIC_MODULE_UNLOAD MODULE_VERMAGIC_MODVERSIONS \
32 MODULE_ARCH_VERMAGIC 38 MODULE_ARCH_VERMAGIC \
39 MODULE_RANDSTRUCT_PLUGIN
33 40
diff --git a/scripts/Makefile.gcc-plugins b/scripts/Makefile.gcc-plugins
index 82335533620e..2e0e2eaa397f 100644
--- a/scripts/Makefile.gcc-plugins
+++ b/scripts/Makefile.gcc-plugins
@@ -29,6 +29,10 @@ ifdef CONFIG_GCC_PLUGINS
29 gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK_VERBOSE) += -fplugin-arg-structleak_plugin-verbose 29 gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK_VERBOSE) += -fplugin-arg-structleak_plugin-verbose
30 gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK) += -DSTRUCTLEAK_PLUGIN 30 gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK) += -DSTRUCTLEAK_PLUGIN
31 31
32 gcc-plugin-$(CONFIG_GCC_PLUGIN_RANDSTRUCT) += randomize_layout_plugin.so
33 gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_RANDSTRUCT) += -DRANDSTRUCT_PLUGIN
34 gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_RANDSTRUCT_PERFORMANCE) += -fplugin-arg-randomize_layout_plugin-performance-mode
35
32 GCC_PLUGINS_CFLAGS := $(strip $(addprefix -fplugin=$(objtree)/scripts/gcc-plugins/, $(gcc-plugin-y)) $(gcc-plugin-cflags-y)) 36 GCC_PLUGINS_CFLAGS := $(strip $(addprefix -fplugin=$(objtree)/scripts/gcc-plugins/, $(gcc-plugin-y)) $(gcc-plugin-cflags-y))
33 37
34 export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGIN GCC_PLUGIN_SUBDIR 38 export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGIN GCC_PLUGIN_SUBDIR
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
18 18
19export HOSTLIBS 19export HOSTLIBS
20 20
21$(obj)/randomize_layout_plugin.o: $(objtree)/$(obj)/randomize_layout_seed.h
22quiet_cmd_create_randomize_layout_seed = GENSEED $@
23cmd_create_randomize_layout_seed = \
24 $(CONFIG_SHELL) $(srctree)/$(src)/gen-random-seed.sh $@ $(objtree)/include/generated/randomize_layout_hash.h
25$(objtree)/$(obj)/randomize_layout_seed.h: FORCE
26 $(call if_changed,create_randomize_layout_seed)
27targets = randomize_layout_seed.h randomize_layout_hash.h
28
21$(HOSTLIBS)-y := $(foreach p,$(GCC_PLUGIN),$(if $(findstring /,$(p)),,$(p))) 29$(HOSTLIBS)-y := $(foreach p,$(GCC_PLUGIN),$(if $(findstring /,$(p)),,$(p)))
22always := $($(HOSTLIBS)-y) 30always := $($(HOSTLIBS)-y)
23 31
diff --git a/scripts/gcc-plugins/gcc-common.h b/scripts/gcc-plugins/gcc-common.h
index b232ab15624c..6948898b3cdf 100644
--- a/scripts/gcc-plugins/gcc-common.h
+++ b/scripts/gcc-plugins/gcc-common.h
@@ -63,6 +63,13 @@
63#endif 63#endif
64 64
65#if BUILDING_GCC_VERSION >= 4006 65#if BUILDING_GCC_VERSION >= 4006
66/*
67 * The c-family headers were moved into a subdirectory in GCC version
68 * 4.7, but most plugin-building users of GCC 4.6 are using the Debian
69 * or Ubuntu package, which has an out-of-tree patch to move this to the
70 * same location as found in 4.7 and later:
71 * https://sources.debian.net/src/gcc-4.6/4.6.3-14/debian/patches/pr45078.diff/
72 */
66#include "c-family/c-common.h" 73#include "c-family/c-common.h"
67#else 74#else
68#include "c-common.h" 75#include "c-common.h"
@@ -946,4 +953,9 @@ static inline void debug_gimple_stmt(const_gimple s)
946 get_inner_reference(exp, pbitsize, pbitpos, poffset, pmode, punsignedp, preversep, pvolatilep) 953 get_inner_reference(exp, pbitsize, pbitpos, poffset, pmode, punsignedp, preversep, pvolatilep)
947#endif 954#endif
948 955
956#if BUILDING_GCC_VERSION < 7000
957#define SET_DECL_ALIGN(decl, align) DECL_ALIGN(decl) = (align)
958#define SET_DECL_MODE(decl, mode) DECL_MODE(decl) = (mode)
959#endif
960
949#endif 961#endif
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 @@
1#!/bin/sh
2
3if [ ! -f "$1" ]; then
4 SEED=`od -A n -t x8 -N 32 /dev/urandom | tr -d ' \n'`
5 echo "const char *randstruct_seed = \"$SEED\";" > "$1"
6 HASH=`echo -n "$SEED" | sha256sum | cut -d" " -f1 | tr -d ' \n'`
7 echo "#define RANDSTRUCT_HASHED_SEED \"$HASH\"" > "$2"
8fi
diff --git a/scripts/gcc-plugins/randomize_layout_plugin.c b/scripts/gcc-plugins/randomize_layout_plugin.c
new file mode 100644
index 000000000000..cdaac8c66734
--- /dev/null
+++ b/scripts/gcc-plugins/randomize_layout_plugin.c
@@ -0,0 +1,1028 @@
1/*
2 * Copyright 2014-2016 by Open Source Security, Inc., Brad Spengler <spender@grsecurity.net>
3 * and PaX Team <pageexec@freemail.hu>
4 * Licensed under the GPL v2
5 *
6 * Note: the choice of the license means that the compilation process is
7 * NOT 'eligible' as defined by gcc's library exception to the GPL v3,
8 * but for the kernel it doesn't matter since it doesn't link against
9 * any of the gcc libraries
10 *
11 * Usage:
12 * $ # for 4.5/4.6/C based 4.7
13 * $ 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
14 * $ # for C++ based 4.7/4.8+
15 * $ 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
16 * $ gcc -fplugin=./randomize_layout_plugin.so test.c -O2
17 */
18
19#include "gcc-common.h"
20#include "randomize_layout_seed.h"
21
22#if BUILDING_GCC_MAJOR < 4 || (BUILDING_GCC_MAJOR == 4 && BUILDING_GCC_MINOR < 7)
23#error "The RANDSTRUCT plugin requires GCC 4.7 or newer."
24#endif
25
26#define ORIG_TYPE_NAME(node) \
27 (TYPE_NAME(TYPE_MAIN_VARIANT(node)) != NULL_TREE ? ((const unsigned char *)IDENTIFIER_POINTER(TYPE_NAME(TYPE_MAIN_VARIANT(node)))) : (const unsigned char *)"anonymous")
28
29#define INFORM(loc, msg, ...) inform(loc, "randstruct: " msg, ##__VA_ARGS__)
30#define MISMATCH(loc, how, ...) INFORM(loc, "casting between randomized structure pointer types (" how "): %qT and %qT\n", __VA_ARGS__)
31
32__visible int plugin_is_GPL_compatible;
33
34static int performance_mode;
35
36static struct plugin_info randomize_layout_plugin_info = {
37 .version = "201402201816vanilla",
38 .help = "disable\t\t\tdo not activate plugin\n"
39 "performance-mode\tenable cacheline-aware layout randomization\n"
40};
41
42struct whitelist_entry {
43 const char *pathname;
44 const char *lhs;
45 const char *rhs;
46};
47
48static const struct whitelist_entry whitelist[] = {
49 /* NIU overloads mapping with page struct */
50 { "drivers/net/ethernet/sun/niu.c", "page", "address_space" },
51 /* unix_skb_parms via UNIXCB() buffer */
52 { "net/unix/af_unix.c", "unix_skb_parms", "char" },
53 /* big_key payload.data struct splashing */
54 { "security/keys/big_key.c", "path", "void *" },
55 /* walk struct security_hook_heads as an array of struct list_head */
56 { "security/security.c", "list_head", "security_hook_heads" },
57 { }
58};
59
60/* from old Linux dcache.h */
61static inline unsigned long
62partial_name_hash(unsigned long c, unsigned long prevhash)
63{
64 return (prevhash + (c << 4) + (c >> 4)) * 11;
65}
66static inline unsigned int
67name_hash(const unsigned char *name)
68{
69 unsigned long hash = 0;
70 unsigned int len = strlen((const char *)name);
71 while (len--)
72 hash = partial_name_hash(*name++, hash);
73 return (unsigned int)hash;
74}
75
76static tree handle_randomize_layout_attr(tree *node, tree name, tree args, int flags, bool *no_add_attrs)
77{
78 tree type;
79
80 *no_add_attrs = true;
81 if (TREE_CODE(*node) == FUNCTION_DECL) {
82 error("%qE attribute does not apply to functions (%qF)", name, *node);
83 return NULL_TREE;
84 }
85
86 if (TREE_CODE(*node) == PARM_DECL) {
87 error("%qE attribute does not apply to function parameters (%qD)", name, *node);
88 return NULL_TREE;
89 }
90
91 if (TREE_CODE(*node) == VAR_DECL) {
92 error("%qE attribute does not apply to variables (%qD)", name, *node);
93 return NULL_TREE;
94 }
95
96 if (TYPE_P(*node)) {
97 type = *node;
98 } else {
99 gcc_assert(TREE_CODE(*node) == TYPE_DECL);
100 type = TREE_TYPE(*node);
101 }
102
103 if (TREE_CODE(type) != RECORD_TYPE) {
104 error("%qE attribute used on %qT applies to struct types only", name, type);
105 return NULL_TREE;
106 }
107
108 if (lookup_attribute(IDENTIFIER_POINTER(name), TYPE_ATTRIBUTES(type))) {
109 error("%qE attribute is already applied to the type %qT", name, type);
110 return NULL_TREE;
111 }
112
113 *no_add_attrs = false;
114
115 return NULL_TREE;
116}
117
118/* set on complete types that we don't need to inspect further at all */
119static tree handle_randomize_considered_attr(tree *node, tree name, tree args, int flags, bool *no_add_attrs)
120{
121 *no_add_attrs = false;
122 return NULL_TREE;
123}
124
125/*
126 * set on types that we've performed a shuffle on, to prevent re-shuffling
127 * this does not preclude us from inspecting its fields for potential shuffles
128 */
129static tree handle_randomize_performed_attr(tree *node, tree name, tree args, int flags, bool *no_add_attrs)
130{
131 *no_add_attrs = false;
132 return NULL_TREE;
133}
134
135/*
136 * 64bit variant of Bob Jenkins' public domain PRNG
137 * 256 bits of internal state
138 */
139
140typedef unsigned long long u64;
141
142typedef struct ranctx { u64 a; u64 b; u64 c; u64 d; } ranctx;
143
144#define rot(x,k) (((x)<<(k))|((x)>>(64-(k))))
145static u64 ranval(ranctx *x) {
146 u64 e = x->a - rot(x->b, 7);
147 x->a = x->b ^ rot(x->c, 13);
148 x->b = x->c + rot(x->d, 37);
149 x->c = x->d + e;
150 x->d = e + x->a;
151 return x->d;
152}
153
154static void raninit(ranctx *x, u64 *seed) {
155 int i;
156
157 x->a = seed[0];
158 x->b = seed[1];
159 x->c = seed[2];
160 x->d = seed[3];
161
162 for (i=0; i < 30; ++i)
163 (void)ranval(x);
164}
165
166static u64 shuffle_seed[4];
167
168struct partition_group {
169 tree tree_start;
170 unsigned long start;
171 unsigned long length;
172};
173
174static void partition_struct(tree *fields, unsigned long length, struct partition_group *size_groups, unsigned long *num_groups)
175{
176 unsigned long i;
177 unsigned long accum_size = 0;
178 unsigned long accum_length = 0;
179 unsigned long group_idx = 0;
180
181 gcc_assert(length < INT_MAX);
182
183 memset(size_groups, 0, sizeof(struct partition_group) * length);
184
185 for (i = 0; i < length; i++) {
186 if (size_groups[group_idx].tree_start == NULL_TREE) {
187 size_groups[group_idx].tree_start = fields[i];
188 size_groups[group_idx].start = i;
189 accum_length = 0;
190 accum_size = 0;
191 }
192 accum_size += (unsigned long)int_size_in_bytes(TREE_TYPE(fields[i]));
193 accum_length++;
194 if (accum_size >= 64) {
195 size_groups[group_idx].length = accum_length;
196 accum_length = 0;
197 group_idx++;
198 }
199 }
200
201 if (size_groups[group_idx].tree_start != NULL_TREE &&
202 !size_groups[group_idx].length) {
203 size_groups[group_idx].length = accum_length;
204 group_idx++;
205 }
206
207 *num_groups = group_idx;
208}
209
210static void performance_shuffle(tree *newtree, unsigned long length, ranctx *prng_state)
211{
212 unsigned long i, x;
213 struct partition_group size_group[length];
214 unsigned long num_groups = 0;
215 unsigned long randnum;
216
217 partition_struct(newtree, length, (struct partition_group *)&size_group, &num_groups);
218 for (i = num_groups - 1; i > 0; i--) {
219 struct partition_group tmp;
220 randnum = ranval(prng_state) % (i + 1);
221 tmp = size_group[i];
222 size_group[i] = size_group[randnum];
223 size_group[randnum] = tmp;
224 }
225
226 for (x = 0; x < num_groups; x++) {
227 for (i = size_group[x].start + size_group[x].length - 1; i > size_group[x].start; i--) {
228 tree tmp;
229 if (DECL_BIT_FIELD_TYPE(newtree[i]))
230 continue;
231 randnum = ranval(prng_state) % (i + 1);
232 // we could handle this case differently if desired
233 if (DECL_BIT_FIELD_TYPE(newtree[randnum]))
234 continue;
235 tmp = newtree[i];
236 newtree[i] = newtree[randnum];
237 newtree[randnum] = tmp;
238 }
239 }
240}
241
242static void full_shuffle(tree *newtree, unsigned long length, ranctx *prng_state)
243{
244 unsigned long i, randnum;
245
246 for (i = length - 1; i > 0; i--) {
247 tree tmp;
248 randnum = ranval(prng_state) % (i + 1);
249 tmp = newtree[i];
250 newtree[i] = newtree[randnum];
251 newtree[randnum] = tmp;
252 }
253}
254
255/* modern in-place Fisher-Yates shuffle */
256static void shuffle(const_tree type, tree *newtree, unsigned long length)
257{
258 unsigned long i;
259 u64 seed[4];
260 ranctx prng_state;
261 const unsigned char *structname;
262
263 if (length == 0)
264 return;
265
266 gcc_assert(TREE_CODE(type) == RECORD_TYPE);
267
268 structname = ORIG_TYPE_NAME(type);
269
270#ifdef __DEBUG_PLUGIN
271 fprintf(stderr, "Shuffling struct %s %p\n", (const char *)structname, type);
272#ifdef __DEBUG_VERBOSE
273 debug_tree((tree)type);
274#endif
275#endif
276
277 for (i = 0; i < 4; i++) {
278 seed[i] = shuffle_seed[i];
279 seed[i] ^= name_hash(structname);
280 }
281
282 raninit(&prng_state, (u64 *)&seed);
283
284 if (performance_mode)
285 performance_shuffle(newtree, length, &prng_state);
286 else
287 full_shuffle(newtree, length, &prng_state);
288}
289
290static bool is_flexible_array(const_tree field)
291{
292 const_tree fieldtype;
293 const_tree typesize;
294 const_tree elemtype;
295 const_tree elemsize;
296
297 fieldtype = TREE_TYPE(field);
298 typesize = TYPE_SIZE(fieldtype);
299
300 if (TREE_CODE(fieldtype) != ARRAY_TYPE)
301 return false;
302
303 elemtype = TREE_TYPE(fieldtype);
304 elemsize = TYPE_SIZE(elemtype);
305
306 /* size of type is represented in bits */
307
308 if (typesize == NULL_TREE && TYPE_DOMAIN(fieldtype) != NULL_TREE &&
309 TYPE_MAX_VALUE(TYPE_DOMAIN(fieldtype)) == NULL_TREE)
310 return true;
311
312 if (typesize != NULL_TREE &&
313 (TREE_CONSTANT(typesize) && (!tree_to_uhwi(typesize) ||
314 tree_to_uhwi(typesize) == tree_to_uhwi(elemsize))))
315 return true;
316
317 return false;
318}
319
320static int relayout_struct(tree type)
321{
322 unsigned long num_fields = (unsigned long)list_length(TYPE_FIELDS(type));
323 unsigned long shuffle_length = num_fields;
324 tree field;
325 tree newtree[num_fields];
326 unsigned long i;
327 tree list;
328 tree variant;
329 tree main_variant;
330 expanded_location xloc;
331 bool has_flexarray = false;
332
333 if (TYPE_FIELDS(type) == NULL_TREE)
334 return 0;
335
336 if (num_fields < 2)
337 return 0;
338
339 gcc_assert(TREE_CODE(type) == RECORD_TYPE);
340
341 gcc_assert(num_fields < INT_MAX);
342
343 if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(type)) ||
344 lookup_attribute("no_randomize_layout", TYPE_ATTRIBUTES(TYPE_MAIN_VARIANT(type))))
345 return 0;
346
347 /* Workaround for 3rd-party VirtualBox source that we can't modify ourselves */
348 if (!strcmp((const char *)ORIG_TYPE_NAME(type), "INTNETTRUNKFACTORY") ||
349 !strcmp((const char *)ORIG_TYPE_NAME(type), "RAWPCIFACTORY"))
350 return 0;
351
352 /* throw out any structs in uapi */
353 xloc = expand_location(DECL_SOURCE_LOCATION(TYPE_FIELDS(type)));
354
355 if (strstr(xloc.file, "/uapi/"))
356 error(G_("attempted to randomize userland API struct %s"), ORIG_TYPE_NAME(type));
357
358 for (field = TYPE_FIELDS(type), i = 0; field; field = TREE_CHAIN(field), i++) {
359 gcc_assert(TREE_CODE(field) == FIELD_DECL);
360 newtree[i] = field;
361 }
362
363 /*
364 * enforce that we don't randomize the layout of the last
365 * element of a struct if it's a 0 or 1-length array
366 * or a proper flexible array
367 */
368 if (is_flexible_array(newtree[num_fields - 1])) {
369 has_flexarray = true;
370 shuffle_length--;
371 }
372
373 shuffle(type, (tree *)newtree, shuffle_length);
374
375 /*
376 * set up a bogus anonymous struct field designed to error out on unnamed struct initializers
377 * as gcc provides no other way to detect such code
378 */
379 list = make_node(FIELD_DECL);
380 TREE_CHAIN(list) = newtree[0];
381 TREE_TYPE(list) = void_type_node;
382 DECL_SIZE(list) = bitsize_zero_node;
383 DECL_NONADDRESSABLE_P(list) = 1;
384 DECL_FIELD_BIT_OFFSET(list) = bitsize_zero_node;
385 DECL_SIZE_UNIT(list) = size_zero_node;
386 DECL_FIELD_OFFSET(list) = size_zero_node;
387 DECL_CONTEXT(list) = type;
388 // to satisfy the constify plugin
389 TREE_READONLY(list) = 1;
390
391 for (i = 0; i < num_fields - 1; i++)
392 TREE_CHAIN(newtree[i]) = newtree[i+1];
393 TREE_CHAIN(newtree[num_fields - 1]) = NULL_TREE;
394
395 main_variant = TYPE_MAIN_VARIANT(type);
396 for (variant = main_variant; variant; variant = TYPE_NEXT_VARIANT(variant)) {
397 TYPE_FIELDS(variant) = list;
398 TYPE_ATTRIBUTES(variant) = copy_list(TYPE_ATTRIBUTES(variant));
399 TYPE_ATTRIBUTES(variant) = tree_cons(get_identifier("randomize_performed"), NULL_TREE, TYPE_ATTRIBUTES(variant));
400 TYPE_ATTRIBUTES(variant) = tree_cons(get_identifier("designated_init"), NULL_TREE, TYPE_ATTRIBUTES(variant));
401 if (has_flexarray)
402 TYPE_ATTRIBUTES(type) = tree_cons(get_identifier("has_flexarray"), NULL_TREE, TYPE_ATTRIBUTES(type));
403 }
404
405 /*
406 * force a re-layout of the main variant
407 * the TYPE_SIZE for all variants will be recomputed
408 * by finalize_type_size()
409 */
410 TYPE_SIZE(main_variant) = NULL_TREE;
411 layout_type(main_variant);
412 gcc_assert(TYPE_SIZE(main_variant) != NULL_TREE);
413
414 return 1;
415}
416
417/* from constify plugin */
418static const_tree get_field_type(const_tree field)
419{
420 return strip_array_types(TREE_TYPE(field));
421}
422
423/* from constify plugin */
424static bool is_fptr(const_tree fieldtype)
425{
426 if (TREE_CODE(fieldtype) != POINTER_TYPE)
427 return false;
428
429 return TREE_CODE(TREE_TYPE(fieldtype)) == FUNCTION_TYPE;
430}
431
432/* derived from constify plugin */
433static int is_pure_ops_struct(const_tree node)
434{
435 const_tree field;
436
437 gcc_assert(TREE_CODE(node) == RECORD_TYPE || TREE_CODE(node) == UNION_TYPE);
438
439 /* XXX: Do not apply randomization to all-ftpr structs yet. */
440 return 0;
441
442 for (field = TYPE_FIELDS(node); field; field = TREE_CHAIN(field)) {
443 const_tree fieldtype = get_field_type(field);
444 enum tree_code code = TREE_CODE(fieldtype);
445
446 if (node == fieldtype)
447 continue;
448
449 if (!is_fptr(fieldtype))
450 return 0;
451
452 if (code != RECORD_TYPE && code != UNION_TYPE)
453 continue;
454
455 if (!is_pure_ops_struct(fieldtype))
456 return 0;
457 }
458
459 return 1;
460}
461
462static void randomize_type(tree type)
463{
464 tree variant;
465
466 gcc_assert(TREE_CODE(type) == RECORD_TYPE);
467
468 if (lookup_attribute("randomize_considered", TYPE_ATTRIBUTES(type)))
469 return;
470
471 if (lookup_attribute("randomize_layout", TYPE_ATTRIBUTES(TYPE_MAIN_VARIANT(type))) || is_pure_ops_struct(type))
472 relayout_struct(type);
473
474 for (variant = TYPE_MAIN_VARIANT(type); variant; variant = TYPE_NEXT_VARIANT(variant)) {
475 TYPE_ATTRIBUTES(type) = copy_list(TYPE_ATTRIBUTES(type));
476 TYPE_ATTRIBUTES(type) = tree_cons(get_identifier("randomize_considered"), NULL_TREE, TYPE_ATTRIBUTES(type));
477 }
478#ifdef __DEBUG_PLUGIN
479 fprintf(stderr, "Marking randomize_considered on struct %s\n", ORIG_TYPE_NAME(type));
480#ifdef __DEBUG_VERBOSE
481 debug_tree(type);
482#endif
483#endif
484}
485
486static void update_decl_size(tree decl)
487{
488 tree lastval, lastidx, field, init, type, flexsize;
489 unsigned HOST_WIDE_INT len;
490
491 type = TREE_TYPE(decl);
492
493 if (!lookup_attribute("has_flexarray", TYPE_ATTRIBUTES(type)))
494 return;
495
496 init = DECL_INITIAL(decl);
497 if (init == NULL_TREE || init == error_mark_node)
498 return;
499
500 if (TREE_CODE(init) != CONSTRUCTOR)
501 return;
502
503 len = CONSTRUCTOR_NELTS(init);
504 if (!len)
505 return;
506
507 lastval = CONSTRUCTOR_ELT(init, CONSTRUCTOR_NELTS(init) - 1)->value;
508 lastidx = CONSTRUCTOR_ELT(init, CONSTRUCTOR_NELTS(init) - 1)->index;
509
510 for (field = TYPE_FIELDS(TREE_TYPE(decl)); TREE_CHAIN(field); field = TREE_CHAIN(field))
511 ;
512
513 if (lastidx != field)
514 return;
515
516 if (TREE_CODE(lastval) != STRING_CST) {
517 error("Only string constants are supported as initializers "
518 "for randomized structures with flexible arrays");
519 return;
520 }
521
522 flexsize = bitsize_int(TREE_STRING_LENGTH(lastval) *
523 tree_to_uhwi(TYPE_SIZE(TREE_TYPE(TREE_TYPE(lastval)))));
524
525 DECL_SIZE(decl) = size_binop(PLUS_EXPR, TYPE_SIZE(type), flexsize);
526
527 return;
528}
529
530
531static void randomize_layout_finish_decl(void *event_data, void *data)
532{
533 tree decl = (tree)event_data;
534 tree type;
535
536 if (decl == NULL_TREE || decl == error_mark_node)
537 return;
538
539 type = TREE_TYPE(decl);
540
541 if (TREE_CODE(decl) != VAR_DECL)
542 return;
543
544 if (TREE_CODE(type) != RECORD_TYPE && TREE_CODE(type) != UNION_TYPE)
545 return;
546
547 if (!lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(type)))
548 return;
549
550 DECL_SIZE(decl) = 0;
551 DECL_SIZE_UNIT(decl) = 0;
552 SET_DECL_ALIGN(decl, 0);
553 SET_DECL_MODE (decl, VOIDmode);
554 SET_DECL_RTL(decl, 0);
555 update_decl_size(decl);
556 layout_decl(decl, 0);
557}
558
559static void finish_type(void *event_data, void *data)
560{
561 tree type = (tree)event_data;
562
563 if (type == NULL_TREE || type == error_mark_node)
564 return;
565
566 if (TREE_CODE(type) != RECORD_TYPE)
567 return;
568
569 if (TYPE_FIELDS(type) == NULL_TREE)
570 return;
571
572 if (lookup_attribute("randomize_considered", TYPE_ATTRIBUTES(type)))
573 return;
574
575#ifdef __DEBUG_PLUGIN
576 fprintf(stderr, "Calling randomize_type on %s\n", ORIG_TYPE_NAME(type));
577#endif
578#ifdef __DEBUG_VERBOSE
579 debug_tree(type);
580#endif
581 randomize_type(type);
582
583 return;
584}
585
586static struct attribute_spec randomize_layout_attr = {
587 .name = "randomize_layout",
588 // related to args
589 .min_length = 0,
590 .max_length = 0,
591 .decl_required = false,
592 // need type declaration
593 .type_required = true,
594 .function_type_required = false,
595 .handler = handle_randomize_layout_attr,
596#if BUILDING_GCC_VERSION >= 4007
597 .affects_type_identity = true
598#endif
599};
600
601static struct attribute_spec no_randomize_layout_attr = {
602 .name = "no_randomize_layout",
603 // related to args
604 .min_length = 0,
605 .max_length = 0,
606 .decl_required = false,
607 // need type declaration
608 .type_required = true,
609 .function_type_required = false,
610 .handler = handle_randomize_layout_attr,
611#if BUILDING_GCC_VERSION >= 4007
612 .affects_type_identity = true
613#endif
614};
615
616static struct attribute_spec randomize_considered_attr = {
617 .name = "randomize_considered",
618 // related to args
619 .min_length = 0,
620 .max_length = 0,
621 .decl_required = false,
622 // need type declaration
623 .type_required = true,
624 .function_type_required = false,
625 .handler = handle_randomize_considered_attr,
626#if BUILDING_GCC_VERSION >= 4007
627 .affects_type_identity = false
628#endif
629};
630
631static struct attribute_spec randomize_performed_attr = {
632 .name = "randomize_performed",
633 // related to args
634 .min_length = 0,
635 .max_length = 0,
636 .decl_required = false,
637 // need type declaration
638 .type_required = true,
639 .function_type_required = false,
640 .handler = handle_randomize_performed_attr,
641#if BUILDING_GCC_VERSION >= 4007
642 .affects_type_identity = false
643#endif
644};
645
646static void register_attributes(void *event_data, void *data)
647{
648 register_attribute(&randomize_layout_attr);
649 register_attribute(&no_randomize_layout_attr);
650 register_attribute(&randomize_considered_attr);
651 register_attribute(&randomize_performed_attr);
652}
653
654static void check_bad_casts_in_constructor(tree var, tree init)
655{
656 unsigned HOST_WIDE_INT idx;
657 tree field, val;
658 tree field_type, val_type;
659
660 FOR_EACH_CONSTRUCTOR_ELT(CONSTRUCTOR_ELTS(init), idx, field, val) {
661 if (TREE_CODE(val) == CONSTRUCTOR) {
662 check_bad_casts_in_constructor(var, val);
663 continue;
664 }
665
666 /* pipacs' plugin creates franken-arrays that differ from those produced by
667 normal code which all have valid 'field' trees. work around this */
668 if (field == NULL_TREE)
669 continue;
670 field_type = TREE_TYPE(field);
671 val_type = TREE_TYPE(val);
672
673 if (TREE_CODE(field_type) != POINTER_TYPE || TREE_CODE(val_type) != POINTER_TYPE)
674 continue;
675
676 if (field_type == val_type)
677 continue;
678
679 field_type = TYPE_MAIN_VARIANT(strip_array_types(TYPE_MAIN_VARIANT(TREE_TYPE(field_type))));
680 val_type = TYPE_MAIN_VARIANT(strip_array_types(TYPE_MAIN_VARIANT(TREE_TYPE(val_type))));
681
682 if (field_type == void_type_node)
683 continue;
684 if (field_type == val_type)
685 continue;
686 if (TREE_CODE(val_type) != RECORD_TYPE)
687 continue;
688
689 if (!lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(val_type)))
690 continue;
691 MISMATCH(DECL_SOURCE_LOCATION(var), "constructor\n", TYPE_MAIN_VARIANT(field_type), TYPE_MAIN_VARIANT(val_type));
692 }
693}
694
695/* derived from the constify plugin */
696static void check_global_variables(void *event_data, void *data)
697{
698 struct varpool_node *node;
699 tree init;
700
701 FOR_EACH_VARIABLE(node) {
702 tree var = NODE_DECL(node);
703 init = DECL_INITIAL(var);
704 if (init == NULL_TREE)
705 continue;
706
707 if (TREE_CODE(init) != CONSTRUCTOR)
708 continue;
709
710 check_bad_casts_in_constructor(var, init);
711 }
712}
713
714static bool dominated_by_is_err(const_tree rhs, basic_block bb)
715{
716 basic_block dom;
717 gimple dom_stmt;
718 gimple call_stmt;
719 const_tree dom_lhs;
720 const_tree poss_is_err_cond;
721 const_tree poss_is_err_func;
722 const_tree is_err_arg;
723
724 dom = get_immediate_dominator(CDI_DOMINATORS, bb);
725 if (!dom)
726 return false;
727
728 dom_stmt = last_stmt(dom);
729 if (!dom_stmt)
730 return false;
731
732 if (gimple_code(dom_stmt) != GIMPLE_COND)
733 return false;
734
735 if (gimple_cond_code(dom_stmt) != NE_EXPR)
736 return false;
737
738 if (!integer_zerop(gimple_cond_rhs(dom_stmt)))
739 return false;
740
741 poss_is_err_cond = gimple_cond_lhs(dom_stmt);
742
743 if (TREE_CODE(poss_is_err_cond) != SSA_NAME)
744 return false;
745
746 call_stmt = SSA_NAME_DEF_STMT(poss_is_err_cond);
747
748 if (gimple_code(call_stmt) != GIMPLE_CALL)
749 return false;
750
751 dom_lhs = gimple_get_lhs(call_stmt);
752 poss_is_err_func = gimple_call_fndecl(call_stmt);
753 if (!poss_is_err_func)
754 return false;
755 if (dom_lhs != poss_is_err_cond)
756 return false;
757 if (strcmp(DECL_NAME_POINTER(poss_is_err_func), "IS_ERR"))
758 return false;
759
760 is_err_arg = gimple_call_arg(call_stmt, 0);
761 if (!is_err_arg)
762 return false;
763
764 if (is_err_arg != rhs)
765 return false;
766
767 return true;
768}
769
770static void handle_local_var_initializers(void)
771{
772 tree var;
773 unsigned int i;
774
775 FOR_EACH_LOCAL_DECL(cfun, i, var) {
776 tree init = DECL_INITIAL(var);
777 if (!init)
778 continue;
779 if (TREE_CODE(init) != CONSTRUCTOR)
780 continue;
781 check_bad_casts_in_constructor(var, init);
782 }
783}
784
785static bool type_name_eq(gimple stmt, const_tree type_tree, const char *wanted_name)
786{
787 const char *type_name;
788
789 if (type_tree == NULL_TREE)
790 return false;
791
792 switch (TREE_CODE(type_tree)) {
793 case RECORD_TYPE:
794 type_name = TYPE_NAME_POINTER(type_tree);
795 break;
796 case INTEGER_TYPE:
797 if (TYPE_PRECISION(type_tree) == CHAR_TYPE_SIZE)
798 type_name = "char";
799 else {
800 INFORM(gimple_location(stmt), "found non-char INTEGER_TYPE cast comparison: %qT\n", type_tree);
801 debug_tree(type_tree);
802 return false;
803 }
804 break;
805 case POINTER_TYPE:
806 if (TREE_CODE(TREE_TYPE(type_tree)) == VOID_TYPE) {
807 type_name = "void *";
808 break;
809 } else {
810 INFORM(gimple_location(stmt), "found non-void POINTER_TYPE cast comparison %qT\n", type_tree);
811 debug_tree(type_tree);
812 return false;
813 }
814 default:
815 INFORM(gimple_location(stmt), "unhandled cast comparison: %qT\n", type_tree);
816 debug_tree(type_tree);
817 return false;
818 }
819
820 return strcmp(type_name, wanted_name) == 0;
821}
822
823static bool whitelisted_cast(gimple stmt, const_tree lhs_tree, const_tree rhs_tree)
824{
825 const struct whitelist_entry *entry;
826 expanded_location xloc = expand_location(gimple_location(stmt));
827
828 for (entry = whitelist; entry->pathname; entry++) {
829 if (!strstr(xloc.file, entry->pathname))
830 continue;
831
832 if (type_name_eq(stmt, lhs_tree, entry->lhs) && type_name_eq(stmt, rhs_tree, entry->rhs))
833 return true;
834 }
835
836 return false;
837}
838
839/*
840 * iterate over all statements to find "bad" casts:
841 * those where the address of the start of a structure is cast
842 * to a pointer of a structure of a different type, or a
843 * structure pointer type is cast to a different structure pointer type
844 */
845static unsigned int find_bad_casts_execute(void)
846{
847 basic_block bb;
848
849 handle_local_var_initializers();
850
851 FOR_EACH_BB_FN(bb, cfun) {
852 gimple_stmt_iterator gsi;
853
854 for (gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) {
855 gimple stmt;
856 const_tree lhs;
857 const_tree lhs_type;
858 const_tree rhs1;
859 const_tree rhs_type;
860 const_tree ptr_lhs_type;
861 const_tree ptr_rhs_type;
862 const_tree op0;
863 const_tree op0_type;
864 enum tree_code rhs_code;
865
866 stmt = gsi_stmt(gsi);
867
868#ifdef __DEBUG_PLUGIN
869#ifdef __DEBUG_VERBOSE
870 debug_gimple_stmt(stmt);
871 debug_tree(gimple_get_lhs(stmt));
872#endif
873#endif
874
875 if (gimple_code(stmt) != GIMPLE_ASSIGN)
876 continue;
877
878#ifdef __DEBUG_PLUGIN
879#ifdef __DEBUG_VERBOSE
880 debug_tree(gimple_assign_rhs1(stmt));
881#endif
882#endif
883
884
885 rhs_code = gimple_assign_rhs_code(stmt);
886
887 if (rhs_code != ADDR_EXPR && rhs_code != SSA_NAME)
888 continue;
889
890 lhs = gimple_get_lhs(stmt);
891 lhs_type = TREE_TYPE(lhs);
892 rhs1 = gimple_assign_rhs1(stmt);
893 rhs_type = TREE_TYPE(rhs1);
894
895 if (TREE_CODE(rhs_type) != POINTER_TYPE ||
896 TREE_CODE(lhs_type) != POINTER_TYPE)
897 continue;
898
899 ptr_lhs_type = TYPE_MAIN_VARIANT(strip_array_types(TYPE_MAIN_VARIANT(TREE_TYPE(lhs_type))));
900 ptr_rhs_type = TYPE_MAIN_VARIANT(strip_array_types(TYPE_MAIN_VARIANT(TREE_TYPE(rhs_type))));
901
902 if (ptr_rhs_type == void_type_node)
903 continue;
904
905 if (ptr_lhs_type == void_type_node)
906 continue;
907
908 if (dominated_by_is_err(rhs1, bb))
909 continue;
910
911 if (TREE_CODE(ptr_rhs_type) != RECORD_TYPE) {
912#ifndef __DEBUG_PLUGIN
913 if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(ptr_lhs_type)))
914#endif
915 {
916 if (!whitelisted_cast(stmt, ptr_lhs_type, ptr_rhs_type))
917 MISMATCH(gimple_location(stmt), "rhs", ptr_lhs_type, ptr_rhs_type);
918 }
919 continue;
920 }
921
922 if (rhs_code == SSA_NAME && ptr_lhs_type == ptr_rhs_type)
923 continue;
924
925 if (rhs_code == ADDR_EXPR) {
926 op0 = TREE_OPERAND(rhs1, 0);
927
928 if (op0 == NULL_TREE)
929 continue;
930
931 if (TREE_CODE(op0) != VAR_DECL)
932 continue;
933
934 op0_type = TYPE_MAIN_VARIANT(strip_array_types(TYPE_MAIN_VARIANT(TREE_TYPE(op0))));
935 if (op0_type == ptr_lhs_type)
936 continue;
937
938#ifndef __DEBUG_PLUGIN
939 if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(op0_type)))
940#endif
941 {
942 if (!whitelisted_cast(stmt, ptr_lhs_type, op0_type))
943 MISMATCH(gimple_location(stmt), "op0", ptr_lhs_type, op0_type);
944 }
945 } else {
946 const_tree ssa_name_var = SSA_NAME_VAR(rhs1);
947 /* skip bogus type casts introduced by container_of */
948 if (ssa_name_var != NULL_TREE && DECL_NAME(ssa_name_var) &&
949 !strcmp((const char *)DECL_NAME_POINTER(ssa_name_var), "__mptr"))
950 continue;
951#ifndef __DEBUG_PLUGIN
952 if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(ptr_rhs_type)))
953#endif
954 {
955 if (!whitelisted_cast(stmt, ptr_lhs_type, ptr_rhs_type))
956 MISMATCH(gimple_location(stmt), "ssa", ptr_lhs_type, ptr_rhs_type);
957 }
958 }
959
960 }
961 }
962 return 0;
963}
964
965#define PASS_NAME find_bad_casts
966#define NO_GATE
967#define TODO_FLAGS_FINISH TODO_dump_func
968#include "gcc-generate-gimple-pass.h"
969
970__visible int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version)
971{
972 int i;
973 const char * const plugin_name = plugin_info->base_name;
974 const int argc = plugin_info->argc;
975 const struct plugin_argument * const argv = plugin_info->argv;
976 bool enable = true;
977 int obtained_seed = 0;
978 struct register_pass_info find_bad_casts_pass_info;
979
980 find_bad_casts_pass_info.pass = make_find_bad_casts_pass();
981 find_bad_casts_pass_info.reference_pass_name = "ssa";
982 find_bad_casts_pass_info.ref_pass_instance_number = 1;
983 find_bad_casts_pass_info.pos_op = PASS_POS_INSERT_AFTER;
984
985 if (!plugin_default_version_check(version, &gcc_version)) {
986 error(G_("incompatible gcc/plugin versions"));
987 return 1;
988 }
989
990 if (strncmp(lang_hooks.name, "GNU C", 5) && !strncmp(lang_hooks.name, "GNU C+", 6)) {
991 inform(UNKNOWN_LOCATION, G_("%s supports C only, not %s"), plugin_name, lang_hooks.name);
992 enable = false;
993 }
994
995 for (i = 0; i < argc; ++i) {
996 if (!strcmp(argv[i].key, "disable")) {
997 enable = false;
998 continue;
999 }
1000 if (!strcmp(argv[i].key, "performance-mode")) {
1001 performance_mode = 1;
1002 continue;
1003 }
1004 error(G_("unknown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key);
1005 }
1006
1007 if (strlen(randstruct_seed) != 64) {
1008 error(G_("invalid seed value supplied for %s plugin"), plugin_name);
1009 return 1;
1010 }
1011 obtained_seed = sscanf(randstruct_seed, "%016llx%016llx%016llx%016llx",
1012 &shuffle_seed[0], &shuffle_seed[1], &shuffle_seed[2], &shuffle_seed[3]);
1013 if (obtained_seed != 4) {
1014 error(G_("Invalid seed supplied for %s plugin"), plugin_name);
1015 return 1;
1016 }
1017
1018 register_callback(plugin_name, PLUGIN_INFO, NULL, &randomize_layout_plugin_info);
1019 if (enable) {
1020 register_callback(plugin_name, PLUGIN_ALL_IPA_PASSES_START, check_global_variables, NULL);
1021 register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &find_bad_casts_pass_info);
1022 register_callback(plugin_name, PLUGIN_FINISH_TYPE, finish_type, NULL);
1023 register_callback(plugin_name, PLUGIN_FINISH_DECL, randomize_layout_finish_decl, NULL);
1024 }
1025 register_callback(plugin_name, PLUGIN_ATTRIBUTES, register_attributes, NULL);
1026
1027 return 0;
1028}