xref: /linux/scripts/gcc-plugins/randomize_layout_plugin.c (revision 9931be2cfca35be7040f35a272a7b82b31ec1c71)
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	= PLUGIN_VERSION,
38  	.help		= "disable\t\t\tdo not activate plugin\n"
39  			  "performance-mode\tenable cacheline-aware layout randomization\n"
40  };
41  
42  /* from old Linux dcache.h */
43  static inline unsigned long
44  partial_name_hash(unsigned long c, unsigned long prevhash)
45  {
46  	return (prevhash + (c << 4) + (c >> 4)) * 11;
47  }
48  static inline unsigned int
49  name_hash(const unsigned char *name)
50  {
51  	unsigned long hash = 0;
52  	unsigned int len = strlen((const char *)name);
53  	while (len--)
54  		hash = partial_name_hash(*name++, hash);
55  	return (unsigned int)hash;
56  }
57  
58  static tree handle_randomize_layout_attr(tree *node, tree name, tree args, int flags, bool *no_add_attrs)
59  {
60  	tree type;
61  
62  	*no_add_attrs = true;
63  	if (TREE_CODE(*node) == FUNCTION_DECL) {
64  		error("%qE attribute does not apply to functions (%qF)", name, *node);
65  		return NULL_TREE;
66  	}
67  
68  	if (TREE_CODE(*node) == PARM_DECL) {
69  		error("%qE attribute does not apply to function parameters (%qD)", name, *node);
70  		return NULL_TREE;
71  	}
72  
73  	if (TREE_CODE(*node) == VAR_DECL) {
74  		error("%qE attribute does not apply to variables (%qD)", name, *node);
75  		return NULL_TREE;
76  	}
77  
78  	if (TYPE_P(*node)) {
79  		type = *node;
80  	} else {
81  		gcc_assert(TREE_CODE(*node) == TYPE_DECL);
82  		type = TREE_TYPE(*node);
83  	}
84  
85  	if (TREE_CODE(type) != RECORD_TYPE) {
86  		error("%qE attribute used on %qT applies to struct types only", name, type);
87  		return NULL_TREE;
88  	}
89  
90  	if (lookup_attribute(IDENTIFIER_POINTER(name), TYPE_ATTRIBUTES(type))) {
91  		error("%qE attribute is already applied to the type %qT", name, type);
92  		return NULL_TREE;
93  	}
94  
95  	*no_add_attrs = false;
96  
97  	return NULL_TREE;
98  }
99  
100  /* set on complete types that we don't need to inspect further at all */
101  static tree handle_randomize_considered_attr(tree *node, tree name, tree args, int flags, bool *no_add_attrs)
102  {
103  	*no_add_attrs = false;
104  	return NULL_TREE;
105  }
106  
107  /*
108   * set on types that we've performed a shuffle on, to prevent re-shuffling
109   * this does not preclude us from inspecting its fields for potential shuffles
110   */
111  static tree handle_randomize_performed_attr(tree *node, tree name, tree args, int flags, bool *no_add_attrs)
112  {
113  	*no_add_attrs = false;
114  	return NULL_TREE;
115  }
116  
117  /*
118   * 64bit variant of Bob Jenkins' public domain PRNG
119   * 256 bits of internal state
120   */
121  
122  typedef unsigned long long u64;
123  
124  typedef struct ranctx { u64 a; u64 b; u64 c; u64 d; } ranctx;
125  
126  #define rot(x,k) (((x)<<(k))|((x)>>(64-(k))))
127  static u64 ranval(ranctx *x) {
128  	u64 e = x->a - rot(x->b, 7);
129  	x->a = x->b ^ rot(x->c, 13);
130  	x->b = x->c + rot(x->d, 37);
131  	x->c = x->d + e;
132  	x->d = e + x->a;
133  	return x->d;
134  }
135  
136  static void raninit(ranctx *x, u64 *seed) {
137  	int i;
138  
139  	x->a = seed[0];
140  	x->b = seed[1];
141  	x->c = seed[2];
142  	x->d = seed[3];
143  
144  	for (i=0; i < 30; ++i)
145  		(void)ranval(x);
146  }
147  
148  static u64 shuffle_seed[4];
149  
150  struct partition_group {
151  	tree tree_start;
152  	unsigned long start;
153  	unsigned long length;
154  };
155  
156  static void partition_struct(tree *fields, unsigned long length, struct partition_group *size_groups, unsigned long *num_groups)
157  {
158  	unsigned long i;
159  	unsigned long accum_size = 0;
160  	unsigned long accum_length = 0;
161  	unsigned long group_idx = 0;
162  
163  	gcc_assert(length < INT_MAX);
164  
165  	memset(size_groups, 0, sizeof(struct partition_group) * length);
166  
167  	for (i = 0; i < length; i++) {
168  		if (size_groups[group_idx].tree_start == NULL_TREE) {
169  			size_groups[group_idx].tree_start = fields[i];
170  			size_groups[group_idx].start = i;
171  			accum_length = 0;
172  			accum_size = 0;
173  		}
174  		accum_size += (unsigned long)int_size_in_bytes(TREE_TYPE(fields[i]));
175  		accum_length++;
176  		if (accum_size >= 64) {
177  			size_groups[group_idx].length = accum_length;
178  			accum_length = 0;
179  			group_idx++;
180  		}
181  	}
182  
183  	if (size_groups[group_idx].tree_start != NULL_TREE &&
184  	    !size_groups[group_idx].length) {
185  		size_groups[group_idx].length = accum_length;
186  		group_idx++;
187  	}
188  
189  	*num_groups = group_idx;
190  }
191  
192  static void performance_shuffle(tree *newtree, unsigned long length, ranctx *prng_state)
193  {
194  	unsigned long i, x;
195  	struct partition_group size_group[length];
196  	unsigned long num_groups = 0;
197  	unsigned long randnum;
198  
199  	partition_struct(newtree, length, (struct partition_group *)&size_group, &num_groups);
200  	for (i = num_groups - 1; i > 0; i--) {
201  		struct partition_group tmp;
202  		randnum = ranval(prng_state) % (i + 1);
203  		tmp = size_group[i];
204  		size_group[i] = size_group[randnum];
205  		size_group[randnum] = tmp;
206  	}
207  
208  	for (x = 0; x < num_groups; x++) {
209  		for (i = size_group[x].start + size_group[x].length - 1; i > size_group[x].start; i--) {
210  			tree tmp;
211  			if (DECL_BIT_FIELD_TYPE(newtree[i]))
212  				continue;
213  			randnum = ranval(prng_state) % (i + 1);
214  			// we could handle this case differently if desired
215  			if (DECL_BIT_FIELD_TYPE(newtree[randnum]))
216  				continue;
217  			tmp = newtree[i];
218  			newtree[i] = newtree[randnum];
219  			newtree[randnum] = tmp;
220  		}
221  	}
222  }
223  
224  static void full_shuffle(tree *newtree, unsigned long length, ranctx *prng_state)
225  {
226  	unsigned long i, randnum;
227  
228  	for (i = length - 1; i > 0; i--) {
229  		tree tmp;
230  		randnum = ranval(prng_state) % (i + 1);
231  		tmp = newtree[i];
232  		newtree[i] = newtree[randnum];
233  		newtree[randnum] = tmp;
234  	}
235  }
236  
237  /* modern in-place Fisher-Yates shuffle */
238  static void shuffle(const_tree type, tree *newtree, unsigned long length)
239  {
240  	unsigned long i;
241  	u64 seed[4];
242  	ranctx prng_state;
243  	const unsigned char *structname;
244  
245  	if (length == 0)
246  		return;
247  
248  	gcc_assert(TREE_CODE(type) == RECORD_TYPE);
249  
250  	structname = ORIG_TYPE_NAME(type);
251  
252  #ifdef __DEBUG_PLUGIN
253  	fprintf(stderr, "Shuffling struct %s %p\n", (const char *)structname, type);
254  #ifdef __DEBUG_VERBOSE
255  	debug_tree((tree)type);
256  #endif
257  #endif
258  
259  	for (i = 0; i < 4; i++) {
260  		seed[i] = shuffle_seed[i];
261  		seed[i] ^= name_hash(structname);
262  	}
263  
264  	raninit(&prng_state, (u64 *)&seed);
265  
266  	if (performance_mode)
267  		performance_shuffle(newtree, length, &prng_state);
268  	else
269  		full_shuffle(newtree, length, &prng_state);
270  }
271  
272  static bool is_flexible_array(const_tree field)
273  {
274  	const_tree fieldtype;
275  	const_tree typesize;
276  	const_tree elemtype;
277  	const_tree elemsize;
278  
279  	fieldtype = TREE_TYPE(field);
280  	typesize = TYPE_SIZE(fieldtype);
281  
282  	if (TREE_CODE(fieldtype) != ARRAY_TYPE)
283  		return false;
284  
285  	elemtype = TREE_TYPE(fieldtype);
286  	elemsize = TYPE_SIZE(elemtype);
287  
288  	/* size of type is represented in bits */
289  
290  	if (typesize == NULL_TREE && TYPE_DOMAIN(fieldtype) != NULL_TREE &&
291  	    TYPE_MAX_VALUE(TYPE_DOMAIN(fieldtype)) == NULL_TREE)
292  		return true;
293  
294  	if (typesize != NULL_TREE &&
295  	    (TREE_CONSTANT(typesize) && (!tree_to_uhwi(typesize) ||
296  	     tree_to_uhwi(typesize) == tree_to_uhwi(elemsize))))
297  		return true;
298  
299  	return false;
300  }
301  
302  static int relayout_struct(tree type)
303  {
304  	unsigned long num_fields = (unsigned long)list_length(TYPE_FIELDS(type));
305  	unsigned long shuffle_length = num_fields;
306  	tree field;
307  	tree newtree[num_fields];
308  	unsigned long i;
309  	tree list;
310  	tree variant;
311  	tree main_variant;
312  	expanded_location xloc;
313  	bool has_flexarray = false;
314  
315  	if (TYPE_FIELDS(type) == NULL_TREE)
316  		return 0;
317  
318  	if (num_fields < 2)
319  		return 0;
320  
321  	gcc_assert(TREE_CODE(type) == RECORD_TYPE);
322  
323  	gcc_assert(num_fields < INT_MAX);
324  
325  	if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(type)) ||
326  	    lookup_attribute("no_randomize_layout", TYPE_ATTRIBUTES(TYPE_MAIN_VARIANT(type))))
327  		return 0;
328  
329  	/* Workaround for 3rd-party VirtualBox source that we can't modify ourselves */
330  	if (!strcmp((const char *)ORIG_TYPE_NAME(type), "INTNETTRUNKFACTORY") ||
331  	    !strcmp((const char *)ORIG_TYPE_NAME(type), "RAWPCIFACTORY"))
332  		return 0;
333  
334  	/* throw out any structs in uapi */
335  	xloc = expand_location(DECL_SOURCE_LOCATION(TYPE_FIELDS(type)));
336  
337  	if (strstr(xloc.file, "/uapi/"))
338  		error(G_("attempted to randomize userland API struct %s"), ORIG_TYPE_NAME(type));
339  
340  	for (field = TYPE_FIELDS(type), i = 0; field; field = TREE_CHAIN(field), i++) {
341  		gcc_assert(TREE_CODE(field) == FIELD_DECL);
342  		newtree[i] = field;
343  	}
344  
345  	/*
346  	 * enforce that we don't randomize the layout of the last
347  	 * element of a struct if it's a 0 or 1-length array
348  	 * or a proper flexible array
349  	 */
350  	if (is_flexible_array(newtree[num_fields - 1])) {
351  		has_flexarray = true;
352  		shuffle_length--;
353  	}
354  
355  	shuffle(type, (tree *)newtree, shuffle_length);
356  
357  	/*
358  	 * set up a bogus anonymous struct field designed to error out on unnamed struct initializers
359  	 * as gcc provides no other way to detect such code
360  	 */
361  	list = make_node(FIELD_DECL);
362  	TREE_CHAIN(list) = newtree[0];
363  	TREE_TYPE(list) = void_type_node;
364  	DECL_SIZE(list) = bitsize_zero_node;
365  	DECL_NONADDRESSABLE_P(list) = 1;
366  	DECL_FIELD_BIT_OFFSET(list) = bitsize_zero_node;
367  	DECL_SIZE_UNIT(list) = size_zero_node;
368  	DECL_FIELD_OFFSET(list) = size_zero_node;
369  	DECL_CONTEXT(list) = type;
370  	// to satisfy the constify plugin
371  	TREE_READONLY(list) = 1;
372  
373  	for (i = 0; i < num_fields - 1; i++)
374  		TREE_CHAIN(newtree[i]) = newtree[i+1];
375  	TREE_CHAIN(newtree[num_fields - 1]) = NULL_TREE;
376  
377  	main_variant = TYPE_MAIN_VARIANT(type);
378  	for (variant = main_variant; variant; variant = TYPE_NEXT_VARIANT(variant)) {
379  		TYPE_FIELDS(variant) = list;
380  		TYPE_ATTRIBUTES(variant) = copy_list(TYPE_ATTRIBUTES(variant));
381  		TYPE_ATTRIBUTES(variant) = tree_cons(get_identifier("randomize_performed"), NULL_TREE, TYPE_ATTRIBUTES(variant));
382  		TYPE_ATTRIBUTES(variant) = tree_cons(get_identifier("designated_init"), NULL_TREE, TYPE_ATTRIBUTES(variant));
383  		if (has_flexarray)
384  			TYPE_ATTRIBUTES(type) = tree_cons(get_identifier("has_flexarray"), NULL_TREE, TYPE_ATTRIBUTES(type));
385  	}
386  
387  	/*
388  	 * force a re-layout of the main variant
389  	 * the TYPE_SIZE for all variants will be recomputed
390  	 * by finalize_type_size()
391  	 */
392  	TYPE_SIZE(main_variant) = NULL_TREE;
393  	layout_type(main_variant);
394  	gcc_assert(TYPE_SIZE(main_variant) != NULL_TREE);
395  
396  	return 1;
397  }
398  
399  /* from constify plugin */
400  static const_tree get_field_type(const_tree field)
401  {
402  	return strip_array_types(TREE_TYPE(field));
403  }
404  
405  /* from constify plugin */
406  static bool is_fptr(const_tree fieldtype)
407  {
408  	if (TREE_CODE(fieldtype) != POINTER_TYPE)
409  		return false;
410  
411  	return TREE_CODE(TREE_TYPE(fieldtype)) == FUNCTION_TYPE;
412  }
413  
414  /* derived from constify plugin */
415  static int is_pure_ops_struct(const_tree node)
416  {
417  	const_tree field;
418  
419  	gcc_assert(TREE_CODE(node) == RECORD_TYPE || TREE_CODE(node) == UNION_TYPE);
420  
421  	for (field = TYPE_FIELDS(node); field; field = TREE_CHAIN(field)) {
422  		const_tree fieldtype = get_field_type(field);
423  		enum tree_code code = TREE_CODE(fieldtype);
424  
425  		if (node == fieldtype)
426  			continue;
427  
428  		if (code == RECORD_TYPE || code == UNION_TYPE) {
429  			if (!is_pure_ops_struct(fieldtype))
430  				return 0;
431  			continue;
432  		}
433  
434  		if (!is_fptr(fieldtype))
435  			return 0;
436  	}
437  
438  	return 1;
439  }
440  
441  static void randomize_type(tree type)
442  {
443  	tree variant;
444  
445  	gcc_assert(TREE_CODE(type) == RECORD_TYPE);
446  
447  	if (lookup_attribute("randomize_considered", TYPE_ATTRIBUTES(type)))
448  		return;
449  
450  	if (lookup_attribute("randomize_layout", TYPE_ATTRIBUTES(TYPE_MAIN_VARIANT(type))) || is_pure_ops_struct(type))
451  		relayout_struct(type);
452  
453  	for (variant = TYPE_MAIN_VARIANT(type); variant; variant = TYPE_NEXT_VARIANT(variant)) {
454  		TYPE_ATTRIBUTES(type) = copy_list(TYPE_ATTRIBUTES(type));
455  		TYPE_ATTRIBUTES(type) = tree_cons(get_identifier("randomize_considered"), NULL_TREE, TYPE_ATTRIBUTES(type));
456  	}
457  #ifdef __DEBUG_PLUGIN
458  	fprintf(stderr, "Marking randomize_considered on struct %s\n", ORIG_TYPE_NAME(type));
459  #ifdef __DEBUG_VERBOSE
460  	debug_tree(type);
461  #endif
462  #endif
463  }
464  
465  static void update_decl_size(tree decl)
466  {
467  	tree lastval, lastidx, field, init, type, flexsize;
468  	unsigned HOST_WIDE_INT len;
469  
470  	type = TREE_TYPE(decl);
471  
472  	if (!lookup_attribute("has_flexarray", TYPE_ATTRIBUTES(type)))
473  		return;
474  
475  	init = DECL_INITIAL(decl);
476  	if (init == NULL_TREE || init == error_mark_node)
477  		return;
478  
479  	if (TREE_CODE(init) != CONSTRUCTOR)
480  		return;
481  
482  	len = CONSTRUCTOR_NELTS(init);
483          if (!len)
484  		return;
485  
486  	lastval = CONSTRUCTOR_ELT(init, CONSTRUCTOR_NELTS(init) - 1)->value;
487  	lastidx = CONSTRUCTOR_ELT(init, CONSTRUCTOR_NELTS(init) - 1)->index;
488  
489  	for (field = TYPE_FIELDS(TREE_TYPE(decl)); TREE_CHAIN(field); field = TREE_CHAIN(field))
490  		;
491  
492  	if (lastidx != field)
493  		return;
494  
495  	if (TREE_CODE(lastval) != STRING_CST) {
496  		error("Only string constants are supported as initializers "
497  		      "for randomized structures with flexible arrays");
498  		return;
499  	}
500  
501  	flexsize = bitsize_int(TREE_STRING_LENGTH(lastval) *
502  		tree_to_uhwi(TYPE_SIZE(TREE_TYPE(TREE_TYPE(lastval)))));
503  
504  	DECL_SIZE(decl) = size_binop(PLUS_EXPR, TYPE_SIZE(type), flexsize);
505  
506  	return;
507  }
508  
509  
510  static void randomize_layout_finish_decl(void *event_data, void *data)
511  {
512  	tree decl = (tree)event_data;
513  	tree type;
514  
515  	if (decl == NULL_TREE || decl == error_mark_node)
516  		return;
517  
518  	type = TREE_TYPE(decl);
519  
520  	if (TREE_CODE(decl) != VAR_DECL)
521  		return;
522  
523  	if (TREE_CODE(type) != RECORD_TYPE && TREE_CODE(type) != UNION_TYPE)
524  		return;
525  
526  	if (!lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(type)))
527  		return;
528  
529  	DECL_SIZE(decl) = 0;
530  	DECL_SIZE_UNIT(decl) = 0;
531  	SET_DECL_ALIGN(decl, 0);
532  	SET_DECL_MODE (decl, VOIDmode);
533  	SET_DECL_RTL(decl, 0);
534  	update_decl_size(decl);
535  	layout_decl(decl, 0);
536  }
537  
538  static void finish_type(void *event_data, void *data)
539  {
540  	tree type = (tree)event_data;
541  
542  	if (type == NULL_TREE || type == error_mark_node)
543  		return;
544  
545  	if (TREE_CODE(type) != RECORD_TYPE)
546  		return;
547  
548  	if (TYPE_FIELDS(type) == NULL_TREE)
549  		return;
550  
551  	if (lookup_attribute("randomize_considered", TYPE_ATTRIBUTES(type)))
552  		return;
553  
554  #ifdef __DEBUG_PLUGIN
555  	fprintf(stderr, "Calling randomize_type on %s\n", ORIG_TYPE_NAME(type));
556  #endif
557  #ifdef __DEBUG_VERBOSE
558  	debug_tree(type);
559  #endif
560  	randomize_type(type);
561  
562  	return;
563  }
564  
565  static struct attribute_spec randomize_layout_attr = { };
566  static struct attribute_spec no_randomize_layout_attr = { };
567  static struct attribute_spec randomize_considered_attr = { };
568  static struct attribute_spec randomize_performed_attr = { };
569  
570  static void register_attributes(void *event_data, void *data)
571  {
572  	randomize_layout_attr.name		= "randomize_layout";
573  	randomize_layout_attr.type_required	= true;
574  	randomize_layout_attr.handler		= handle_randomize_layout_attr;
575  	randomize_layout_attr.affects_type_identity = true;
576  
577  	no_randomize_layout_attr.name		= "no_randomize_layout";
578  	no_randomize_layout_attr.type_required	= true;
579  	no_randomize_layout_attr.handler	= handle_randomize_layout_attr;
580  	no_randomize_layout_attr.affects_type_identity = true;
581  
582  	randomize_considered_attr.name		= "randomize_considered";
583  	randomize_considered_attr.type_required	= true;
584  	randomize_considered_attr.handler	= handle_randomize_considered_attr;
585  
586  	randomize_performed_attr.name		= "randomize_performed";
587  	randomize_performed_attr.type_required	= true;
588  	randomize_performed_attr.handler	= handle_randomize_performed_attr;
589  
590  	register_attribute(&randomize_layout_attr);
591  	register_attribute(&no_randomize_layout_attr);
592  	register_attribute(&randomize_considered_attr);
593  	register_attribute(&randomize_performed_attr);
594  }
595  
596  static void check_bad_casts_in_constructor(tree var, tree init)
597  {
598  	unsigned HOST_WIDE_INT idx;
599  	tree field, val;
600  	tree field_type, val_type;
601  
602  	FOR_EACH_CONSTRUCTOR_ELT(CONSTRUCTOR_ELTS(init), idx, field, val) {
603  		if (TREE_CODE(val) == CONSTRUCTOR) {
604  			check_bad_casts_in_constructor(var, val);
605  			continue;
606  		}
607  
608  		/* pipacs' plugin creates franken-arrays that differ from those produced by
609  		   normal code which all have valid 'field' trees. work around this */
610  		if (field == NULL_TREE)
611  			continue;
612  		field_type = TREE_TYPE(field);
613  		val_type = TREE_TYPE(val);
614  
615  		if (TREE_CODE(field_type) != POINTER_TYPE || TREE_CODE(val_type) != POINTER_TYPE)
616  			continue;
617  
618  		if (field_type == val_type)
619  			continue;
620  
621  		field_type = TYPE_MAIN_VARIANT(strip_array_types(TYPE_MAIN_VARIANT(TREE_TYPE(field_type))));
622  		val_type = TYPE_MAIN_VARIANT(strip_array_types(TYPE_MAIN_VARIANT(TREE_TYPE(val_type))));
623  
624  		if (field_type == void_type_node)
625  			continue;
626  		if (field_type == val_type)
627  			continue;
628  		if (TREE_CODE(val_type) != RECORD_TYPE)
629  			continue;
630  
631  		if (!lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(val_type)))
632  			continue;
633  		MISMATCH(DECL_SOURCE_LOCATION(var), "constructor\n", TYPE_MAIN_VARIANT(field_type), TYPE_MAIN_VARIANT(val_type));
634  	}
635  }
636  
637  /* derived from the constify plugin */
638  static void check_global_variables(void *event_data, void *data)
639  {
640  	struct varpool_node *node;
641  	tree init;
642  
643  	FOR_EACH_VARIABLE(node) {
644  		tree var = NODE_DECL(node);
645  		init = DECL_INITIAL(var);
646  		if (init == NULL_TREE)
647  			continue;
648  
649  		if (TREE_CODE(init) != CONSTRUCTOR)
650  			continue;
651  
652  		check_bad_casts_in_constructor(var, init);
653  	}
654  }
655  
656  static bool dominated_by_is_err(const_tree rhs, basic_block bb)
657  {
658  	basic_block dom;
659  	gimple dom_stmt;
660  	gimple call_stmt;
661  	const_tree dom_lhs;
662  	const_tree poss_is_err_cond;
663  	const_tree poss_is_err_func;
664  	const_tree is_err_arg;
665  
666  	dom = get_immediate_dominator(CDI_DOMINATORS, bb);
667  	if (!dom)
668  		return false;
669  
670  	dom_stmt = last_stmt(dom);
671  	if (!dom_stmt)
672  		return false;
673  
674  	if (gimple_code(dom_stmt) != GIMPLE_COND)
675  		return false;
676  
677  	if (gimple_cond_code(dom_stmt) != NE_EXPR)
678  		return false;
679  
680  	if (!integer_zerop(gimple_cond_rhs(dom_stmt)))
681  		return false;
682  
683  	poss_is_err_cond = gimple_cond_lhs(dom_stmt);
684  
685  	if (TREE_CODE(poss_is_err_cond) != SSA_NAME)
686  		return false;
687  
688  	call_stmt = SSA_NAME_DEF_STMT(poss_is_err_cond);
689  
690  	if (gimple_code(call_stmt) != GIMPLE_CALL)
691  		return false;
692  
693  	dom_lhs = gimple_get_lhs(call_stmt);
694  	poss_is_err_func = gimple_call_fndecl(call_stmt);
695  	if (!poss_is_err_func)
696  		return false;
697  	if (dom_lhs != poss_is_err_cond)
698  		return false;
699  	if (strcmp(DECL_NAME_POINTER(poss_is_err_func), "IS_ERR"))
700  		return false;
701  
702  	is_err_arg = gimple_call_arg(call_stmt, 0);
703  	if (!is_err_arg)
704  		return false;
705  
706  	if (is_err_arg != rhs)
707  		return false;
708  
709  	return true;
710  }
711  
712  static void handle_local_var_initializers(void)
713  {
714  	tree var;
715  	unsigned int i;
716  
717  	FOR_EACH_LOCAL_DECL(cfun, i, var) {
718  		tree init = DECL_INITIAL(var);
719  		if (!init)
720  			continue;
721  		if (TREE_CODE(init) != CONSTRUCTOR)
722  			continue;
723  		check_bad_casts_in_constructor(var, init);
724  	}
725  }
726  
727  /*
728   * iterate over all statements to find "bad" casts:
729   * those where the address of the start of a structure is cast
730   * to a pointer of a structure of a different type, or a
731   * structure pointer type is cast to a different structure pointer type
732   */
733  static unsigned int find_bad_casts_execute(void)
734  {
735  	basic_block bb;
736  
737  	handle_local_var_initializers();
738  
739  	FOR_EACH_BB_FN(bb, cfun) {
740  		gimple_stmt_iterator gsi;
741  
742  		for (gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) {
743  			gimple stmt;
744  			const_tree lhs;
745  			const_tree lhs_type;
746  			const_tree rhs1;
747  			const_tree rhs_type;
748  			const_tree ptr_lhs_type;
749  			const_tree ptr_rhs_type;
750  			const_tree op0;
751  			const_tree op0_type;
752  			enum tree_code rhs_code;
753  
754  			stmt = gsi_stmt(gsi);
755  
756  #ifdef __DEBUG_PLUGIN
757  #ifdef __DEBUG_VERBOSE
758  			debug_gimple_stmt(stmt);
759  			debug_tree(gimple_get_lhs(stmt));
760  #endif
761  #endif
762  
763  			if (gimple_code(stmt) != GIMPLE_ASSIGN)
764  				continue;
765  
766  #ifdef __DEBUG_PLUGIN
767  #ifdef __DEBUG_VERBOSE
768  			debug_tree(gimple_assign_rhs1(stmt));
769  #endif
770  #endif
771  
772  
773  			rhs_code = gimple_assign_rhs_code(stmt);
774  
775  			if (rhs_code != ADDR_EXPR && rhs_code != SSA_NAME)
776  				continue;
777  
778  			lhs = gimple_get_lhs(stmt);
779  			lhs_type = TREE_TYPE(lhs);
780  			rhs1 = gimple_assign_rhs1(stmt);
781  			rhs_type = TREE_TYPE(rhs1);
782  
783  			if (TREE_CODE(rhs_type) != POINTER_TYPE ||
784  			    TREE_CODE(lhs_type) != POINTER_TYPE)
785  				continue;
786  
787  			ptr_lhs_type = TYPE_MAIN_VARIANT(strip_array_types(TYPE_MAIN_VARIANT(TREE_TYPE(lhs_type))));
788  			ptr_rhs_type = TYPE_MAIN_VARIANT(strip_array_types(TYPE_MAIN_VARIANT(TREE_TYPE(rhs_type))));
789  
790  			if (ptr_rhs_type == void_type_node)
791  				continue;
792  
793  			if (ptr_lhs_type == void_type_node)
794  				continue;
795  
796  			if (dominated_by_is_err(rhs1, bb))
797  				continue;
798  
799  			if (TREE_CODE(ptr_rhs_type) != RECORD_TYPE) {
800  #ifndef __DEBUG_PLUGIN
801  				if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(ptr_lhs_type)))
802  #endif
803  				MISMATCH(gimple_location(stmt), "rhs", ptr_lhs_type, ptr_rhs_type);
804  				continue;
805  			}
806  
807  			if (rhs_code == SSA_NAME && ptr_lhs_type == ptr_rhs_type)
808  				continue;
809  
810  			if (rhs_code == ADDR_EXPR) {
811  				op0 = TREE_OPERAND(rhs1, 0);
812  
813  				if (op0 == NULL_TREE)
814  					continue;
815  
816  				if (TREE_CODE(op0) != VAR_DECL)
817  					continue;
818  
819  				op0_type = TYPE_MAIN_VARIANT(strip_array_types(TYPE_MAIN_VARIANT(TREE_TYPE(op0))));
820  				if (op0_type == ptr_lhs_type)
821  					continue;
822  
823  #ifndef __DEBUG_PLUGIN
824  				if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(op0_type)))
825  #endif
826  				MISMATCH(gimple_location(stmt), "op0", ptr_lhs_type, op0_type);
827  			} else {
828  				const_tree ssa_name_var = SSA_NAME_VAR(rhs1);
829  				/* skip bogus type casts introduced by container_of */
830  				if (ssa_name_var != NULL_TREE && DECL_NAME(ssa_name_var) &&
831  				    !strcmp((const char *)DECL_NAME_POINTER(ssa_name_var), "__mptr"))
832  					continue;
833  #ifndef __DEBUG_PLUGIN
834  				if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(ptr_rhs_type)))
835  #endif
836  				MISMATCH(gimple_location(stmt), "ssa", ptr_lhs_type, ptr_rhs_type);
837  			}
838  
839  		}
840  	}
841  	return 0;
842  }
843  
844  #define PASS_NAME find_bad_casts
845  #define NO_GATE
846  #define TODO_FLAGS_FINISH TODO_dump_func
847  #include "gcc-generate-gimple-pass.h"
848  
849  __visible int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version)
850  {
851  	int i;
852  	const char * const plugin_name = plugin_info->base_name;
853  	const int argc = plugin_info->argc;
854  	const struct plugin_argument * const argv = plugin_info->argv;
855  	bool enable = true;
856  	int obtained_seed = 0;
857  	struct register_pass_info find_bad_casts_pass_info;
858  
859  	find_bad_casts_pass_info.pass			= make_find_bad_casts_pass();
860  	find_bad_casts_pass_info.reference_pass_name	= "ssa";
861  	find_bad_casts_pass_info.ref_pass_instance_number	= 1;
862  	find_bad_casts_pass_info.pos_op			= PASS_POS_INSERT_AFTER;
863  
864  	if (!plugin_default_version_check(version, &gcc_version)) {
865  		error(G_("incompatible gcc/plugin versions"));
866  		return 1;
867  	}
868  
869  	if (strncmp(lang_hooks.name, "GNU C", 5) && !strncmp(lang_hooks.name, "GNU C+", 6)) {
870  		inform(UNKNOWN_LOCATION, G_("%s supports C only, not %s"), plugin_name, lang_hooks.name);
871  		enable = false;
872  	}
873  
874  	for (i = 0; i < argc; ++i) {
875  		if (!strcmp(argv[i].key, "disable")) {
876  			enable = false;
877  			continue;
878  		}
879  		if (!strcmp(argv[i].key, "performance-mode")) {
880  			performance_mode = 1;
881  			continue;
882  		}
883  		error(G_("unknown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key);
884  	}
885  
886  	if (strlen(randstruct_seed) != 64) {
887  		error(G_("invalid seed value supplied for %s plugin"), plugin_name);
888  		return 1;
889  	}
890  	obtained_seed = sscanf(randstruct_seed, "%016llx%016llx%016llx%016llx",
891  		&shuffle_seed[0], &shuffle_seed[1], &shuffle_seed[2], &shuffle_seed[3]);
892  	if (obtained_seed != 4) {
893  		error(G_("Invalid seed supplied for %s plugin"), plugin_name);
894  		return 1;
895  	}
896  
897  	register_callback(plugin_name, PLUGIN_INFO, NULL, &randomize_layout_plugin_info);
898  	if (enable) {
899  		register_callback(plugin_name, PLUGIN_ALL_IPA_PASSES_START, check_global_variables, NULL);
900  		register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &find_bad_casts_pass_info);
901  		register_callback(plugin_name, PLUGIN_FINISH_TYPE, finish_type, NULL);
902  		register_callback(plugin_name, PLUGIN_FINISH_DECL, randomize_layout_finish_decl, NULL);
903  	}
904  	register_callback(plugin_name, PLUGIN_ATTRIBUTES, register_attributes, NULL);
905  
906  	return 0;
907  }
908