summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/Kconfig18
-rw-r--r--arch/powerpc/kernel/Makefile5
-rw-r--r--include/linux/random.h11
-rw-r--r--init/main.c1
-rw-r--r--kernel/fork.c1
-rw-r--r--mm/page_alloc.c5
-rw-r--r--scripts/Makefile.gcc-plugins9
-rw-r--r--scripts/gcc-plugins/latent_entropy_plugin.c640
8 files changed, 689 insertions, 1 deletions
diff --git a/arch/Kconfig b/arch/Kconfig
index fd6e9712af81..ae80cd24e8f0 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -383,6 +383,24 @@ config GCC_PLUGIN_SANCOV
383 gcc-4.5 on). It is based on the commit "Add fuzzing coverage support" 383 gcc-4.5 on). It is based on the commit "Add fuzzing coverage support"
384 by Dmitry Vyukov <dvyukov@google.com>. 384 by Dmitry Vyukov <dvyukov@google.com>.
385 385
386config GCC_PLUGIN_LATENT_ENTROPY
387 bool "Generate some entropy during boot and runtime"
388 depends on GCC_PLUGINS
389 help
390 By saying Y here the kernel will instrument some kernel code to
391 extract some entropy from both original and artificially created
392 program state. This will help especially embedded systems where
393 there is little 'natural' source of entropy normally. The cost
394 is some slowdown of the boot process (about 0.5%) and fork and
395 irq processing.
396
397 Note that entropy extracted this way is not cryptographically
398 secure!
399
400 This plugin was ported from grsecurity/PaX. More information at:
401 * https://grsecurity.net/
402 * https://pax.grsecurity.net/
403
386config HAVE_CC_STACKPROTECTOR 404config HAVE_CC_STACKPROTECTOR
387 bool 405 bool
388 help 406 help
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index fe4c075bcf50..62df36c3f138 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -14,6 +14,11 @@ CFLAGS_prom_init.o += -fPIC
14CFLAGS_btext.o += -fPIC 14CFLAGS_btext.o += -fPIC
15endif 15endif
16 16
17CFLAGS_cputable.o += $(DISABLE_LATENT_ENTROPY_PLUGIN)
18CFLAGS_init.o += $(DISABLE_LATENT_ENTROPY_PLUGIN)
19CFLAGS_btext.o += $(DISABLE_LATENT_ENTROPY_PLUGIN)
20CFLAGS_prom.o += $(DISABLE_LATENT_ENTROPY_PLUGIN)
21
17ifdef CONFIG_FUNCTION_TRACER 22ifdef CONFIG_FUNCTION_TRACER
18# Do not trace early boot code 23# Do not trace early boot code
19CFLAGS_REMOVE_cputable.o = -mno-sched-epilog $(CC_FLAGS_FTRACE) 24CFLAGS_REMOVE_cputable.o = -mno-sched-epilog $(CC_FLAGS_FTRACE)
diff --git a/include/linux/random.h b/include/linux/random.h
index 3d6e9815cd85..a59c74cdb1eb 100644
--- a/include/linux/random.h
+++ b/include/linux/random.h
@@ -18,6 +18,17 @@ struct random_ready_callback {
18}; 18};
19 19
20extern void add_device_randomness(const void *, unsigned int); 20extern void add_device_randomness(const void *, unsigned int);
21
22#if defined(CONFIG_GCC_PLUGIN_LATENT_ENTROPY) && !defined(__CHECKER__)
23static inline void add_latent_entropy(void)
24{
25 add_device_randomness((const void *)&latent_entropy,
26 sizeof(latent_entropy));
27}
28#else
29static inline void add_latent_entropy(void) {}
30#endif
31
21extern void add_input_randomness(unsigned int type, unsigned int code, 32extern void add_input_randomness(unsigned int type, unsigned int code,
22 unsigned int value); 33 unsigned int value);
23extern void add_interrupt_randomness(int irq, int irq_flags); 34extern void add_interrupt_randomness(int irq, int irq_flags);
diff --git a/init/main.c b/init/main.c
index a8a58e2794a5..2858be732f6d 100644
--- a/init/main.c
+++ b/init/main.c
@@ -789,6 +789,7 @@ int __init_or_module do_one_initcall(initcall_t fn)
789 } 789 }
790 WARN(msgbuf[0], "initcall %pF returned with %s\n", fn, msgbuf); 790 WARN(msgbuf[0], "initcall %pF returned with %s\n", fn, msgbuf);
791 791
792 add_latent_entropy();
792 return ret; 793 return ret;
793} 794}
794 795
diff --git a/kernel/fork.c b/kernel/fork.c
index beb31725f7e2..001b18473a07 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1780,6 +1780,7 @@ long _do_fork(unsigned long clone_flags,
1780 1780
1781 p = copy_process(clone_flags, stack_start, stack_size, 1781 p = copy_process(clone_flags, stack_start, stack_size,
1782 child_tidptr, NULL, trace, tls, NUMA_NO_NODE); 1782 child_tidptr, NULL, trace, tls, NUMA_NO_NODE);
1783 add_latent_entropy();
1783 /* 1784 /*
1784 * Do this prior waking up the new thread - the thread pointer 1785 * Do this prior waking up the new thread - the thread pointer
1785 * might get invalid after that point, if the thread exits quickly. 1786 * might get invalid after that point, if the thread exits quickly.
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index a2214c64ed3c..248851d1fc86 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -91,6 +91,11 @@ EXPORT_PER_CPU_SYMBOL(_numa_mem_);
91int _node_numa_mem_[MAX_NUMNODES]; 91int _node_numa_mem_[MAX_NUMNODES];
92#endif 92#endif
93 93
94#ifdef CONFIG_GCC_PLUGIN_LATENT_ENTROPY
95volatile u64 latent_entropy;
96EXPORT_SYMBOL(latent_entropy);
97#endif
98
94/* 99/*
95 * Array of node states. 100 * Array of node states.
96 */ 101 */
diff --git a/scripts/Makefile.gcc-plugins b/scripts/Makefile.gcc-plugins
index 61f0e6db909b..060d2cb373db 100644
--- a/scripts/Makefile.gcc-plugins
+++ b/scripts/Makefile.gcc-plugins
@@ -6,6 +6,12 @@ ifdef CONFIG_GCC_PLUGINS
6 6
7 gcc-plugin-$(CONFIG_GCC_PLUGIN_CYC_COMPLEXITY) += cyc_complexity_plugin.so 7 gcc-plugin-$(CONFIG_GCC_PLUGIN_CYC_COMPLEXITY) += cyc_complexity_plugin.so
8 8
9 gcc-plugin-$(CONFIG_GCC_PLUGIN_LATENT_ENTROPY) += latent_entropy_plugin.so
10 gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_LATENT_ENTROPY) += -DLATENT_ENTROPY_PLUGIN
11 ifdef CONFIG_PAX_LATENT_ENTROPY
12 DISABLE_LATENT_ENTROPY_PLUGIN += -fplugin-arg-latent_entropy_plugin-disable
13 endif
14
9 ifdef CONFIG_GCC_PLUGIN_SANCOV 15 ifdef CONFIG_GCC_PLUGIN_SANCOV
10 ifeq ($(CFLAGS_KCOV),) 16 ifeq ($(CFLAGS_KCOV),)
11 # It is needed because of the gcc-plugin.sh and gcc version checks. 17 # It is needed because of the gcc-plugin.sh and gcc version checks.
@@ -21,7 +27,8 @@ ifdef CONFIG_GCC_PLUGINS
21 27
22 GCC_PLUGINS_CFLAGS := $(strip $(addprefix -fplugin=$(objtree)/scripts/gcc-plugins/, $(gcc-plugin-y)) $(gcc-plugin-cflags-y)) 28 GCC_PLUGINS_CFLAGS := $(strip $(addprefix -fplugin=$(objtree)/scripts/gcc-plugins/, $(gcc-plugin-y)) $(gcc-plugin-cflags-y))
23 29
24 export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGIN GCC_PLUGIN_SUBDIR SANCOV_PLUGIN 30 export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGIN GCC_PLUGIN_SUBDIR
31 export SANCOV_PLUGIN DISABLE_LATENT_ENTROPY_PLUGIN
25 32
26 ifneq ($(PLUGINCC),) 33 ifneq ($(PLUGINCC),)
27 # SANCOV_PLUGIN can be only in CFLAGS_KCOV because avoid duplication. 34 # SANCOV_PLUGIN can be only in CFLAGS_KCOV because avoid duplication.
diff --git a/scripts/gcc-plugins/latent_entropy_plugin.c b/scripts/gcc-plugins/latent_entropy_plugin.c
new file mode 100644
index 000000000000..ff1939b804ae
--- /dev/null
+++ b/scripts/gcc-plugins/latent_entropy_plugin.c
@@ -0,0 +1,640 @@
1/*
2 * Copyright 2012-2016 by the PaX Team <pageexec@freemail.hu>
3 * Copyright 2016 by Emese Revfy <re.emese@gmail.com>
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 * This gcc plugin helps generate a little bit of entropy from program state,
12 * used throughout the uptime of the kernel. Here is an instrumentation example:
13 *
14 * before:
15 * void __latent_entropy test(int argc, char *argv[])
16 * {
17 * if (argc <= 1)
18 * printf("%s: no command arguments :(\n", *argv);
19 * else
20 * printf("%s: %d command arguments!\n", *argv, args - 1);
21 * }
22 *
23 * after:
24 * void __latent_entropy test(int argc, char *argv[])
25 * {
26 * // latent_entropy_execute() 1.
27 * unsigned long local_entropy;
28 * // init_local_entropy() 1.
29 * void *local_entropy_frameaddr;
30 * // init_local_entropy() 3.
31 * unsigned long tmp_latent_entropy;
32 *
33 * // init_local_entropy() 2.
34 * local_entropy_frameaddr = __builtin_frame_address(0);
35 * local_entropy = (unsigned long) local_entropy_frameaddr;
36 *
37 * // init_local_entropy() 4.
38 * tmp_latent_entropy = latent_entropy;
39 * // init_local_entropy() 5.
40 * local_entropy ^= tmp_latent_entropy;
41 *
42 * // latent_entropy_execute() 3.
43 * if (argc <= 1) {
44 * // perturb_local_entropy()
45 * local_entropy += 4623067384293424948;
46 * printf("%s: no command arguments :(\n", *argv);
47 * // perturb_local_entropy()
48 * } else {
49 * local_entropy ^= 3896280633962944730;
50 * printf("%s: %d command arguments!\n", *argv, args - 1);
51 * }
52 *
53 * // latent_entropy_execute() 4.
54 * tmp_latent_entropy = rol(tmp_latent_entropy, local_entropy);
55 * latent_entropy = tmp_latent_entropy;
56 * }
57 *
58 * TODO:
59 * - add ipa pass to identify not explicitly marked candidate functions
60 * - mix in more program state (function arguments/return values,
61 * loop variables, etc)
62 * - more instrumentation control via attribute parameters
63 *
64 * BUGS:
65 * - none known
66 *
67 * Options:
68 * -fplugin-arg-latent_entropy_plugin-disable
69 *
70 * Attribute: __attribute__((latent_entropy))
71 * The latent_entropy gcc attribute can be only on functions and variables.
72 * If it is on a function then the plugin will instrument it. If the attribute
73 * is on a variable then the plugin will initialize it with a random value.
74 * The variable must be an integer, an integer array type or a structure
75 * with integer fields.
76 */
77
78#include "gcc-common.h"
79
80int plugin_is_GPL_compatible;
81
82static GTY(()) tree latent_entropy_decl;
83
84static struct plugin_info latent_entropy_plugin_info = {
85 .version = "201606141920vanilla",
86 .help = "disable\tturn off latent entropy instrumentation\n",
87};
88
89static unsigned HOST_WIDE_INT seed;
90/*
91 * get_random_seed() (this is a GCC function) generates the seed.
92 * This is a simple random generator without any cryptographic security because
93 * the entropy doesn't come from here.
94 */
95static unsigned HOST_WIDE_INT get_random_const(void)
96{
97 unsigned int i;
98 unsigned HOST_WIDE_INT ret = 0;
99
100 for (i = 0; i < 8 * sizeof(ret); i++) {
101 ret = (ret << 1) | (seed & 1);
102 seed >>= 1;
103 if (ret & 1)
104 seed ^= 0xD800000000000000ULL;
105 }
106
107 return ret;
108}
109
110static tree tree_get_random_const(tree type)
111{
112 unsigned long long mask;
113
114 mask = 1ULL << (TREE_INT_CST_LOW(TYPE_SIZE(type)) - 1);
115 mask = 2 * (mask - 1) + 1;
116
117 if (TYPE_UNSIGNED(type))
118 return build_int_cstu(type, mask & get_random_const());
119 return build_int_cst(type, mask & get_random_const());
120}
121
122static tree handle_latent_entropy_attribute(tree *node, tree name,
123 tree args __unused,
124 int flags __unused,
125 bool *no_add_attrs)
126{
127 tree type;
128#if BUILDING_GCC_VERSION <= 4007
129 VEC(constructor_elt, gc) *vals;
130#else
131 vec<constructor_elt, va_gc> *vals;
132#endif
133
134 switch (TREE_CODE(*node)) {
135 default:
136 *no_add_attrs = true;
137 error("%qE attribute only applies to functions and variables",
138 name);
139 break;
140
141 case VAR_DECL:
142 if (DECL_INITIAL(*node)) {
143 *no_add_attrs = true;
144 error("variable %qD with %qE attribute must not be initialized",
145 *node, name);
146 break;
147 }
148
149 if (!TREE_STATIC(*node)) {
150 *no_add_attrs = true;
151 error("variable %qD with %qE attribute must not be local",
152 *node, name);
153 break;
154 }
155
156 type = TREE_TYPE(*node);
157 switch (TREE_CODE(type)) {
158 default:
159 *no_add_attrs = true;
160 error("variable %qD with %qE attribute must be an integer or a fixed length integer array type or a fixed sized structure with integer fields",
161 *node, name);
162 break;
163
164 case RECORD_TYPE: {
165 tree fld, lst = TYPE_FIELDS(type);
166 unsigned int nelt = 0;
167
168 for (fld = lst; fld; nelt++, fld = TREE_CHAIN(fld)) {
169 tree fieldtype;
170
171 fieldtype = TREE_TYPE(fld);
172 if (TREE_CODE(fieldtype) == INTEGER_TYPE)
173 continue;
174
175 *no_add_attrs = true;
176 error("structure variable %qD with %qE attribute has a non-integer field %qE",
177 *node, name, fld);
178 break;
179 }
180
181 if (fld)
182 break;
183
184#if BUILDING_GCC_VERSION <= 4007
185 vals = VEC_alloc(constructor_elt, gc, nelt);
186#else
187 vec_alloc(vals, nelt);
188#endif
189
190 for (fld = lst; fld; fld = TREE_CHAIN(fld)) {
191 tree random_const, fld_t = TREE_TYPE(fld);
192
193 random_const = tree_get_random_const(fld_t);
194 CONSTRUCTOR_APPEND_ELT(vals, fld, random_const);
195 }
196
197 /* Initialize the fields with random constants */
198 DECL_INITIAL(*node) = build_constructor(type, vals);
199 break;
200 }
201
202 /* Initialize the variable with a random constant */
203 case INTEGER_TYPE:
204 DECL_INITIAL(*node) = tree_get_random_const(type);
205 break;
206
207 case ARRAY_TYPE: {
208 tree elt_type, array_size, elt_size;
209 unsigned int i, nelt;
210 HOST_WIDE_INT array_size_int, elt_size_int;
211
212 elt_type = TREE_TYPE(type);
213 elt_size = TYPE_SIZE_UNIT(TREE_TYPE(type));
214 array_size = TYPE_SIZE_UNIT(type);
215
216 if (TREE_CODE(elt_type) != INTEGER_TYPE || !array_size
217 || TREE_CODE(array_size) != INTEGER_CST) {
218 *no_add_attrs = true;
219 error("array variable %qD with %qE attribute must be a fixed length integer array type",
220 *node, name);
221 break;
222 }
223
224 array_size_int = TREE_INT_CST_LOW(array_size);
225 elt_size_int = TREE_INT_CST_LOW(elt_size);
226 nelt = array_size_int / elt_size_int;
227
228#if BUILDING_GCC_VERSION <= 4007
229 vals = VEC_alloc(constructor_elt, gc, nelt);
230#else
231 vec_alloc(vals, nelt);
232#endif
233
234 for (i = 0; i < nelt; i++) {
235 tree cst = size_int(i);
236 tree rand_cst = tree_get_random_const(elt_type);
237
238 CONSTRUCTOR_APPEND_ELT(vals, cst, rand_cst);
239 }
240
241 /*
242 * Initialize the elements of the array with random
243 * constants
244 */
245 DECL_INITIAL(*node) = build_constructor(type, vals);
246 break;
247 }
248 }
249 break;
250
251 case FUNCTION_DECL:
252 break;
253 }
254
255 return NULL_TREE;
256}
257
258static struct attribute_spec latent_entropy_attr = {
259 .name = "latent_entropy",
260 .min_length = 0,
261 .max_length = 0,
262 .decl_required = true,
263 .type_required = false,
264 .function_type_required = false,
265 .handler = handle_latent_entropy_attribute,
266#if BUILDING_GCC_VERSION >= 4007
267 .affects_type_identity = false
268#endif
269};
270
271static void register_attributes(void *event_data __unused, void *data __unused)
272{
273 register_attribute(&latent_entropy_attr);
274}
275
276static bool latent_entropy_gate(void)
277{
278 tree list;
279
280 /* don't bother with noreturn functions for now */
281 if (TREE_THIS_VOLATILE(current_function_decl))
282 return false;
283
284 /* gcc-4.5 doesn't discover some trivial noreturn functions */
285 if (EDGE_COUNT(EXIT_BLOCK_PTR_FOR_FN(cfun)->preds) == 0)
286 return false;
287
288 list = DECL_ATTRIBUTES(current_function_decl);
289 return lookup_attribute("latent_entropy", list) != NULL_TREE;
290}
291
292static tree create_var(tree type, const char *name)
293{
294 tree var;
295
296 var = create_tmp_var(type, name);
297 add_referenced_var(var);
298 mark_sym_for_renaming(var);
299 return var;
300}
301
302/*
303 * Set up the next operation and its constant operand to use in the latent
304 * entropy PRNG. When RHS is specified, the request is for perturbing the
305 * local latent entropy variable, otherwise it is for perturbing the global
306 * latent entropy variable where the two operands are already given by the
307 * local and global latent entropy variables themselves.
308 *
309 * The operation is one of add/xor/rol when instrumenting the local entropy
310 * variable and one of add/xor when perturbing the global entropy variable.
311 * Rotation is not used for the latter case because it would transmit less
312 * entropy to the global variable than the other two operations.
313 */
314static enum tree_code get_op(tree *rhs)
315{
316 static enum tree_code op;
317 unsigned HOST_WIDE_INT random_const;
318
319 random_const = get_random_const();
320
321 switch (op) {
322 case BIT_XOR_EXPR:
323 op = PLUS_EXPR;
324 break;
325
326 case PLUS_EXPR:
327 if (rhs) {
328 op = LROTATE_EXPR;
329 /*
330 * This code limits the value of random_const to
331 * the size of a wide int for the rotation
332 */
333 random_const &= HOST_BITS_PER_WIDE_INT - 1;
334 break;
335 }
336
337 case LROTATE_EXPR:
338 default:
339 op = BIT_XOR_EXPR;
340 break;
341 }
342 if (rhs)
343 *rhs = build_int_cstu(unsigned_intDI_type_node, random_const);
344 return op;
345}
346
347static gimple create_assign(enum tree_code code, tree lhs, tree op1,
348 tree op2)
349{
350 return gimple_build_assign_with_ops(code, lhs, op1, op2);
351}
352
353static void perturb_local_entropy(basic_block bb, tree local_entropy)
354{
355 gimple_stmt_iterator gsi;
356 gimple assign;
357 tree rhs;
358 enum tree_code op;
359
360 op = get_op(&rhs);
361 assign = create_assign(op, local_entropy, local_entropy, rhs);
362 gsi = gsi_after_labels(bb);
363 gsi_insert_before(&gsi, assign, GSI_NEW_STMT);
364 update_stmt(assign);
365}
366
367static void __perturb_latent_entropy(gimple_stmt_iterator *gsi,
368 tree local_entropy)
369{
370 gimple assign;
371 tree temp;
372 enum tree_code op;
373
374 /* 1. create temporary copy of latent_entropy */
375 temp = create_var(unsigned_intDI_type_node, "tmp_latent_entropy");
376
377 /* 2. read... */
378 add_referenced_var(latent_entropy_decl);
379 mark_sym_for_renaming(latent_entropy_decl);
380 assign = gimple_build_assign(temp, latent_entropy_decl);
381 gsi_insert_before(gsi, assign, GSI_NEW_STMT);
382 update_stmt(assign);
383
384 /* 3. ...modify... */
385 op = get_op(NULL);
386 assign = create_assign(op, temp, temp, local_entropy);
387 gsi_insert_after(gsi, assign, GSI_NEW_STMT);
388 update_stmt(assign);
389
390 /* 4. ...write latent_entropy */
391 assign = gimple_build_assign(latent_entropy_decl, temp);
392 gsi_insert_after(gsi, assign, GSI_NEW_STMT);
393 update_stmt(assign);
394}
395
396static bool handle_tail_calls(basic_block bb, tree local_entropy)
397{
398 gimple_stmt_iterator gsi;
399
400 for (gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) {
401 gcall *call;
402 gimple stmt = gsi_stmt(gsi);
403
404 if (!is_gimple_call(stmt))
405 continue;
406
407 call = as_a_gcall(stmt);
408 if (!gimple_call_tail_p(call))
409 continue;
410
411 __perturb_latent_entropy(&gsi, local_entropy);
412 return true;
413 }
414
415 return false;
416}
417
418static void perturb_latent_entropy(tree local_entropy)
419{
420 edge_iterator ei;
421 edge e, last_bb_e;
422 basic_block last_bb;
423
424 gcc_assert(single_pred_p(EXIT_BLOCK_PTR_FOR_FN(cfun)));
425 last_bb_e = single_pred_edge(EXIT_BLOCK_PTR_FOR_FN(cfun));
426
427 FOR_EACH_EDGE(e, ei, last_bb_e->src->preds) {
428 if (ENTRY_BLOCK_PTR_FOR_FN(cfun) == e->src)
429 continue;
430 if (EXIT_BLOCK_PTR_FOR_FN(cfun) == e->src)
431 continue;
432
433 handle_tail_calls(e->src, local_entropy);
434 }
435
436 last_bb = single_pred(EXIT_BLOCK_PTR_FOR_FN(cfun));
437 if (!handle_tail_calls(last_bb, local_entropy)) {
438 gimple_stmt_iterator gsi = gsi_last_bb(last_bb);
439
440 __perturb_latent_entropy(&gsi, local_entropy);
441 }
442}
443
444static void init_local_entropy(basic_block bb, tree local_entropy)
445{
446 gimple assign, call;
447 tree frame_addr, rand_const, tmp, fndecl, udi_frame_addr;
448 enum tree_code op;
449 unsigned HOST_WIDE_INT rand_cst;
450 gimple_stmt_iterator gsi = gsi_after_labels(bb);
451
452 /* 1. create local_entropy_frameaddr */
453 frame_addr = create_var(ptr_type_node, "local_entropy_frameaddr");
454
455 /* 2. local_entropy_frameaddr = __builtin_frame_address() */
456 fndecl = builtin_decl_implicit(BUILT_IN_FRAME_ADDRESS);
457 call = gimple_build_call(fndecl, 1, integer_zero_node);
458 gimple_call_set_lhs(call, frame_addr);
459 gsi_insert_before(&gsi, call, GSI_NEW_STMT);
460 update_stmt(call);
461
462 udi_frame_addr = fold_convert(unsigned_intDI_type_node, frame_addr);
463 assign = gimple_build_assign(local_entropy, udi_frame_addr);
464 gsi_insert_after(&gsi, assign, GSI_NEW_STMT);
465 update_stmt(assign);
466
467 /* 3. create temporary copy of latent_entropy */
468 tmp = create_var(unsigned_intDI_type_node, "tmp_latent_entropy");
469
470 /* 4. read the global entropy variable into local entropy */
471 add_referenced_var(latent_entropy_decl);
472 mark_sym_for_renaming(latent_entropy_decl);
473 assign = gimple_build_assign(tmp, latent_entropy_decl);
474 gsi_insert_after(&gsi, assign, GSI_NEW_STMT);
475 update_stmt(assign);
476
477 /* 5. mix local_entropy_frameaddr into local entropy */
478 assign = create_assign(BIT_XOR_EXPR, local_entropy, local_entropy, tmp);
479 gsi_insert_after(&gsi, assign, GSI_NEW_STMT);
480 update_stmt(assign);
481
482 rand_cst = get_random_const();
483 rand_const = build_int_cstu(unsigned_intDI_type_node, rand_cst);
484 op = get_op(NULL);
485 assign = create_assign(op, local_entropy, local_entropy, rand_const);
486 gsi_insert_after(&gsi, assign, GSI_NEW_STMT);
487 update_stmt(assign);
488}
489
490static bool create_latent_entropy_decl(void)
491{
492 varpool_node_ptr node;
493
494 if (latent_entropy_decl != NULL_TREE)
495 return true;
496
497 FOR_EACH_VARIABLE(node) {
498 tree name, var = NODE_DECL(node);
499
500 if (DECL_NAME_LENGTH(var) < sizeof("latent_entropy") - 1)
501 continue;
502
503 name = DECL_NAME(var);
504 if (strcmp(IDENTIFIER_POINTER(name), "latent_entropy"))
505 continue;
506
507 latent_entropy_decl = var;
508 break;
509 }
510
511 return latent_entropy_decl != NULL_TREE;
512}
513
514static unsigned int latent_entropy_execute(void)
515{
516 basic_block bb;
517 tree local_entropy;
518
519 if (!create_latent_entropy_decl())
520 return 0;
521
522 /* prepare for step 2 below */
523 gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun)));
524 bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun));
525 if (!single_pred_p(bb)) {
526 split_edge(single_succ_edge(ENTRY_BLOCK_PTR_FOR_FN(cfun)));
527 gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun)));
528 bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun));
529 }
530
531 /* 1. create the local entropy variable */
532 local_entropy = create_var(unsigned_intDI_type_node, "local_entropy");
533
534 /* 2. initialize the local entropy variable */
535 init_local_entropy(bb, local_entropy);
536
537 bb = bb->next_bb;
538
539 /*
540 * 3. instrument each BB with an operation on the
541 * local entropy variable
542 */
543 while (bb != EXIT_BLOCK_PTR_FOR_FN(cfun)) {
544 perturb_local_entropy(bb, local_entropy);
545 bb = bb->next_bb;
546 };
547
548 /* 4. mix local entropy into the global entropy variable */
549 perturb_latent_entropy(local_entropy);
550 return 0;
551}
552
553static void latent_entropy_start_unit(void *gcc_data __unused,
554 void *user_data __unused)
555{
556 tree type, id;
557 int quals;
558
559 seed = get_random_seed(false);
560
561 if (in_lto_p)
562 return;
563
564 /* extern volatile u64 latent_entropy */
565 gcc_assert(TYPE_PRECISION(long_long_unsigned_type_node) == 64);
566 quals = TYPE_QUALS(long_long_unsigned_type_node) | TYPE_QUAL_VOLATILE;
567 type = build_qualified_type(long_long_unsigned_type_node, quals);
568 id = get_identifier("latent_entropy");
569 latent_entropy_decl = build_decl(UNKNOWN_LOCATION, VAR_DECL, id, type);
570
571 TREE_STATIC(latent_entropy_decl) = 1;
572 TREE_PUBLIC(latent_entropy_decl) = 1;
573 TREE_USED(latent_entropy_decl) = 1;
574 DECL_PRESERVE_P(latent_entropy_decl) = 1;
575 TREE_THIS_VOLATILE(latent_entropy_decl) = 1;
576 DECL_EXTERNAL(latent_entropy_decl) = 1;
577 DECL_ARTIFICIAL(latent_entropy_decl) = 1;
578 lang_hooks.decls.pushdecl(latent_entropy_decl);
579}
580
581#define PASS_NAME latent_entropy
582#define PROPERTIES_REQUIRED PROP_gimple_leh | PROP_cfg
583#define TODO_FLAGS_FINISH TODO_verify_ssa | TODO_verify_stmts | TODO_dump_func \
584 | TODO_update_ssa
585#include "gcc-generate-gimple-pass.h"
586
587int plugin_init(struct plugin_name_args *plugin_info,
588 struct plugin_gcc_version *version)
589{
590 bool enabled = true;
591 const char * const plugin_name = plugin_info->base_name;
592 const int argc = plugin_info->argc;
593 const struct plugin_argument * const argv = plugin_info->argv;
594 int i;
595
596 struct register_pass_info latent_entropy_pass_info;
597
598 latent_entropy_pass_info.pass = make_latent_entropy_pass();
599 latent_entropy_pass_info.reference_pass_name = "optimized";
600 latent_entropy_pass_info.ref_pass_instance_number = 1;
601 latent_entropy_pass_info.pos_op = PASS_POS_INSERT_BEFORE;
602 static const struct ggc_root_tab gt_ggc_r_gt_latent_entropy[] = {
603 {
604 .base = &latent_entropy_decl,
605 .nelt = 1,
606 .stride = sizeof(latent_entropy_decl),
607 .cb = &gt_ggc_mx_tree_node,
608 .pchw = &gt_pch_nx_tree_node
609 },
610 LAST_GGC_ROOT_TAB
611 };
612
613 if (!plugin_default_version_check(version, &gcc_version)) {
614 error(G_("incompatible gcc/plugin versions"));
615 return 1;
616 }
617
618 for (i = 0; i < argc; ++i) {
619 if (!(strcmp(argv[i].key, "disable"))) {
620 enabled = false;
621 continue;
622 }
623 error(G_("unkown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key);
624 }
625
626 register_callback(plugin_name, PLUGIN_INFO, NULL,
627 &latent_entropy_plugin_info);
628 if (enabled) {
629 register_callback(plugin_name, PLUGIN_START_UNIT,
630 &latent_entropy_start_unit, NULL);
631 register_callback(plugin_name, PLUGIN_REGISTER_GGC_ROOTS,
632 NULL, (void *)&gt_ggc_r_gt_latent_entropy);
633 register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL,
634 &latent_entropy_pass_info);
635 }
636 register_callback(plugin_name, PLUGIN_ATTRIBUTES, register_attributes,
637 NULL);
638
639 return 0;
640}