File Index
Files and directories
Sign in
FILE

randomize_layout_plugin.c

File preview with syntax highlighting.

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