History

Merge branch 'merge/randstruct' into for-next/gcc-plugins

Kees Cook committed 9 years ago

Commit d1185a82 parents 6f7da29 03232e014 files · +1146 −9Browse files

Showing the changes to scripts (6 of 14 files). Show all

Unified · Split

6 files
  1. scripts/Makefile.gcc-plugins +4 −0
  2. scripts/gcc-plugins/.gitignore +1 −0
  3. scripts/gcc-plugins/Makefile +8 −0
  4. scripts/gcc-plugins/gcc-common.h +12 −0
  5. scripts/gcc-plugins/gen-random-seed.sh +8 −0
  6. scripts/gcc-plugins/randomize_layout_plugin.c +1028 −0
scripts/Makefile.gcc-plugins+4−0
@@ -29,6 +29,10 @@ ifdef CONFIG_GCC_PLUGINS · 28 unmodified lines
2929 gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK_VERBOSE) += -fplugin-arg-structleak_plugin-verbose
3030 gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK) += -DSTRUCTLEAK_PLUGIN
3131
32+ gcc-plugin-$(CONFIG_GCC_PLUGIN_RANDSTRUCT) += randomize_layout_plugin.so
33+ gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_RANDSTRUCT) += -DRANDSTRUCT_PLUGIN
34+ gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_RANDSTRUCT_PERFORMANCE) += -fplugin-arg-randomize_layout_plugin-performance-mode
35+
3236 GCC_PLUGINS_CFLAGS := $(strip $(addprefix -fplugin=$(objtree)/scripts/gcc-plugins/, $(gcc-plugin-y)) $(gcc-plugin-cflags-y))
3337
3438 export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGIN GCC_PLUGIN_SUBDIR
scripts/gcc-plugins/.gitignore+1−0
@@ -0,0 +1 @@
1+randomize_layout_seed.h
scripts/gcc-plugins/Makefile+8−0
@@ -18,6 +18,14 @@ endif · 17 unmodified lines
1818
1919 export HOSTLIBS
2020
21+$(obj)/randomize_layout_plugin.o: $(objtree)/$(obj)/randomize_layout_seed.h
22+quiet_cmd_create_randomize_layout_seed = GENSEED $@
23+cmd_create_randomize_layout_seed = \
24+ $(CONFIG_SHELL) $(srctree)/$(src)/gen-random-seed.sh $@ $(objtree)/include/generated/randomize_layout_hash.h
25+$(objtree)/$(obj)/randomize_layout_seed.h: FORCE
26+ $(call if_changed,create_randomize_layout_seed)
27+targets = randomize_layout_seed.h randomize_layout_hash.h
28+
2129 $(HOSTLIBS)-y := $(foreach p,$(GCC_PLUGIN),$(if $(findstring /,$(p)),,$(p)))
2230 always := $($(HOSTLIBS)-y)
2331
scripts/gcc-plugins/gcc-common.h+12−0
@@ -63,6 +63,13 @@ · 62 unmodified lines
6363 #endif
6464
6565 #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+ */
6673 #include "c-family/c-common.h"
6774 #else
6875 #include "c-common.h"
@@ -946,4 +953,9 @@ static inline void debug_gimple_stmt(const_gimple s) · 877 unmodified lines
946953 get_inner_reference(exp, pbitsize, pbitpos, poffset, pmode, punsignedp, preversep, pvolatilep)
947954 #endif
948955
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+
949961 #endif
scripts/gcc-plugins/gen-random-seed.sh+8−0
@@ -0,0 +1,8 @@
1+#!/bin/sh
2+
3+if [ ! -f "$1" ]; then
4+ SEED=`od -A n -t x8 -N 32 /dev/urandom | tr -d ' \n'`
5+ echo "const char *randstruct_seed = \"$SEED\";" > "$1"
6+ HASH=`echo -n "$SEED" | sha256sum | cut -d" " -f1 | tr -d ' \n'`
7+ echo "#define RANDSTRUCT_HASHED_SEED \"$HASH\"" > "$2"
8+fi
scripts/gcc-plugins/randomize_layout_plugin.c+1028−0
@@ -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+
34+static int performance_mode;
35+
36+static 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+
42+struct whitelist_entry {
43+ const char *pathname;
44+ const char *lhs;
45+ const char *rhs;
46+};
47+
48+static 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 */
61+static inline unsigned long
62+partial_name_hash(unsigned long c, unsigned long prevhash)
63+{
64+ return (prevhash + (c << 4) + (c >> 4)) * 11;
65+}
66+static inline unsigned int
67+name_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+
76+static 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 */
119+static 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+ */
129+static 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+
140+typedef unsigned long long u64;
141+
142+typedef struct ranctx { u64 a; u64 b; u64 c; u64 d; } ranctx;
143+
144+#define rot(x,k) (((x)<<(k))|((x)>>(64-(k))))
145+static 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+
154+static 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+
166+static u64 shuffle_seed[4];
167+
168+struct partition_group {
169+ tree tree_start;
170+ unsigned long start;
171+ unsigned long length;
172+};
173+
174+static 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+
210+static 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+
242+static 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 */
256+static 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+
290+static 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+
320+static 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 */
418+static const_tree get_field_type(const_tree field)
419+{
420+ return strip_array_types(TREE_TYPE(field));
421+}
422+
423+/* from constify plugin */
424+static 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 */
433+static 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+
462+static 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+
486+static 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+
531+static 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+
559+static 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+
586+static 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+
601+static 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+
616+static 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+
631+static 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+
646+static 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+
654+static 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 */
696+static 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+
714+static 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+
770+static 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+
785+static 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+
823+static 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+ */
845+static 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+}