latent_entropy_plugin.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright 2012-2016 by the PaX Team <[email protected]>
  4. * Copyright 2016 by Emese Revfy <[email protected]>
  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. #include "gcc-common.h"
  78. __visible int plugin_is_GPL_compatible;
  79. static GTY(()) tree latent_entropy_decl;
  80. static struct plugin_info latent_entropy_plugin_info = {
  81. .version = PLUGIN_VERSION,
  82. .help = "disable\tturn off latent entropy instrumentation\n",
  83. };
  84. static unsigned HOST_WIDE_INT deterministic_seed;
  85. static unsigned HOST_WIDE_INT rnd_buf[32];
  86. static size_t rnd_idx = ARRAY_SIZE(rnd_buf);
  87. static int urandom_fd = -1;
  88. static unsigned HOST_WIDE_INT get_random_const(void)
  89. {
  90. if (deterministic_seed) {
  91. unsigned HOST_WIDE_INT w = deterministic_seed;
  92. w ^= w << 13;
  93. w ^= w >> 7;
  94. w ^= w << 17;
  95. deterministic_seed = w;
  96. return deterministic_seed;
  97. }
  98. if (urandom_fd < 0) {
  99. urandom_fd = open("/dev/urandom", O_RDONLY);
  100. gcc_assert(urandom_fd >= 0);
  101. }
  102. if (rnd_idx >= ARRAY_SIZE(rnd_buf)) {
  103. gcc_assert(read(urandom_fd, rnd_buf, sizeof(rnd_buf)) == sizeof(rnd_buf));
  104. rnd_idx = 0;
  105. }
  106. return rnd_buf[rnd_idx++];
  107. }
  108. static tree tree_get_random_const(tree type)
  109. {
  110. unsigned long long mask;
  111. mask = 1ULL << (TREE_INT_CST_LOW(TYPE_SIZE(type)) - 1);
  112. mask = 2 * (mask - 1) + 1;
  113. if (TYPE_UNSIGNED(type))
  114. return build_int_cstu(type, mask & get_random_const());
  115. return build_int_cst(type, mask & get_random_const());
  116. }
  117. static tree handle_latent_entropy_attribute(tree *node, tree name,
  118. tree args __unused,
  119. int flags __unused,
  120. bool *no_add_attrs)
  121. {
  122. tree type;
  123. vec<constructor_elt, va_gc> *vals;
  124. switch (TREE_CODE(*node)) {
  125. default:
  126. *no_add_attrs = true;
  127. error("%qE attribute only applies to functions and variables",
  128. name);
  129. break;
  130. case VAR_DECL:
  131. if (DECL_INITIAL(*node)) {
  132. *no_add_attrs = true;
  133. error("variable %qD with %qE attribute must not be initialized",
  134. *node, name);
  135. break;
  136. }
  137. if (!TREE_STATIC(*node)) {
  138. *no_add_attrs = true;
  139. error("variable %qD with %qE attribute must not be local",
  140. *node, name);
  141. break;
  142. }
  143. type = TREE_TYPE(*node);
  144. switch (TREE_CODE(type)) {
  145. default:
  146. *no_add_attrs = true;
  147. 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",
  148. *node, name);
  149. break;
  150. case RECORD_TYPE: {
  151. tree fld, lst = TYPE_FIELDS(type);
  152. unsigned int nelt = 0;
  153. for (fld = lst; fld; nelt++, fld = TREE_CHAIN(fld)) {
  154. tree fieldtype;
  155. fieldtype = TREE_TYPE(fld);
  156. if (TREE_CODE(fieldtype) == INTEGER_TYPE)
  157. continue;
  158. *no_add_attrs = true;
  159. error("structure variable %qD with %qE attribute has a non-integer field %qE",
  160. *node, name, fld);
  161. break;
  162. }
  163. if (fld)
  164. break;
  165. vec_alloc(vals, nelt);
  166. for (fld = lst; fld; fld = TREE_CHAIN(fld)) {
  167. tree random_const, fld_t = TREE_TYPE(fld);
  168. random_const = tree_get_random_const(fld_t);
  169. CONSTRUCTOR_APPEND_ELT(vals, fld, random_const);
  170. }
  171. /* Initialize the fields with random constants */
  172. DECL_INITIAL(*node) = build_constructor(type, vals);
  173. break;
  174. }
  175. /* Initialize the variable with a random constant */
  176. case INTEGER_TYPE:
  177. DECL_INITIAL(*node) = tree_get_random_const(type);
  178. break;
  179. case ARRAY_TYPE: {
  180. tree elt_type, array_size, elt_size;
  181. unsigned int i, nelt;
  182. HOST_WIDE_INT array_size_int, elt_size_int;
  183. elt_type = TREE_TYPE(type);
  184. elt_size = TYPE_SIZE_UNIT(TREE_TYPE(type));
  185. array_size = TYPE_SIZE_UNIT(type);
  186. if (TREE_CODE(elt_type) != INTEGER_TYPE || !array_size
  187. || TREE_CODE(array_size) != INTEGER_CST) {
  188. *no_add_attrs = true;
  189. error("array variable %qD with %qE attribute must be a fixed length integer array type",
  190. *node, name);
  191. break;
  192. }
  193. array_size_int = TREE_INT_CST_LOW(array_size);
  194. elt_size_int = TREE_INT_CST_LOW(elt_size);
  195. nelt = array_size_int / elt_size_int;
  196. vec_alloc(vals, nelt);
  197. for (i = 0; i < nelt; i++) {
  198. tree cst = size_int(i);
  199. tree rand_cst = tree_get_random_const(elt_type);
  200. CONSTRUCTOR_APPEND_ELT(vals, cst, rand_cst);
  201. }
  202. /*
  203. * Initialize the elements of the array with random
  204. * constants
  205. */
  206. DECL_INITIAL(*node) = build_constructor(type, vals);
  207. break;
  208. }
  209. }
  210. break;
  211. case FUNCTION_DECL:
  212. break;
  213. }
  214. return NULL_TREE;
  215. }
  216. static struct attribute_spec latent_entropy_attr = { };
  217. static void register_attributes(void *event_data __unused, void *data __unused)
  218. {
  219. latent_entropy_attr.name = "latent_entropy";
  220. latent_entropy_attr.decl_required = true;
  221. latent_entropy_attr.handler = handle_latent_entropy_attribute;
  222. register_attribute(&latent_entropy_attr);
  223. }
  224. static bool latent_entropy_gate(void)
  225. {
  226. tree list;
  227. /* don't bother with noreturn functions for now */
  228. if (TREE_THIS_VOLATILE(current_function_decl))
  229. return false;
  230. /* gcc-4.5 doesn't discover some trivial noreturn functions */
  231. if (EDGE_COUNT(EXIT_BLOCK_PTR_FOR_FN(cfun)->preds) == 0)
  232. return false;
  233. list = DECL_ATTRIBUTES(current_function_decl);
  234. return lookup_attribute("latent_entropy", list) != NULL_TREE;
  235. }
  236. static tree create_var(tree type, const char *name)
  237. {
  238. tree var;
  239. var = create_tmp_var(type, name);
  240. add_referenced_var(var);
  241. mark_sym_for_renaming(var);
  242. return var;
  243. }
  244. /*
  245. * Set up the next operation and its constant operand to use in the latent
  246. * entropy PRNG. When RHS is specified, the request is for perturbing the
  247. * local latent entropy variable, otherwise it is for perturbing the global
  248. * latent entropy variable where the two operands are already given by the
  249. * local and global latent entropy variables themselves.
  250. *
  251. * The operation is one of add/xor/rol when instrumenting the local entropy
  252. * variable and one of add/xor when perturbing the global entropy variable.
  253. * Rotation is not used for the latter case because it would transmit less
  254. * entropy to the global variable than the other two operations.
  255. */
  256. static enum tree_code get_op(tree *rhs)
  257. {
  258. static enum tree_code op;
  259. unsigned HOST_WIDE_INT random_const;
  260. random_const = get_random_const();
  261. switch (op) {
  262. case BIT_XOR_EXPR:
  263. op = PLUS_EXPR;
  264. break;
  265. case PLUS_EXPR:
  266. if (rhs) {
  267. op = LROTATE_EXPR;
  268. /*
  269. * This code limits the value of random_const to
  270. * the size of a long for the rotation
  271. */
  272. random_const %= TYPE_PRECISION(long_unsigned_type_node);
  273. break;
  274. }
  275. case LROTATE_EXPR:
  276. default:
  277. op = BIT_XOR_EXPR;
  278. break;
  279. }
  280. if (rhs)
  281. *rhs = build_int_cstu(long_unsigned_type_node, random_const);
  282. return op;
  283. }
  284. static gimple create_assign(enum tree_code code, tree lhs, tree op1,
  285. tree op2)
  286. {
  287. return gimple_build_assign_with_ops(code, lhs, op1, op2);
  288. }
  289. static void perturb_local_entropy(basic_block bb, tree local_entropy)
  290. {
  291. gimple_stmt_iterator gsi;
  292. gimple assign;
  293. tree rhs;
  294. enum tree_code op;
  295. op = get_op(&rhs);
  296. assign = create_assign(op, local_entropy, local_entropy, rhs);
  297. gsi = gsi_after_labels(bb);
  298. gsi_insert_before(&gsi, assign, GSI_NEW_STMT);
  299. update_stmt(assign);
  300. }
  301. static void __perturb_latent_entropy(gimple_stmt_iterator *gsi,
  302. tree local_entropy)
  303. {
  304. gimple assign;
  305. tree temp;
  306. enum tree_code op;
  307. /* 1. create temporary copy of latent_entropy */
  308. temp = create_var(long_unsigned_type_node, "temp_latent_entropy");
  309. /* 2. read... */
  310. add_referenced_var(latent_entropy_decl);
  311. mark_sym_for_renaming(latent_entropy_decl);
  312. assign = gimple_build_assign(temp, latent_entropy_decl);
  313. gsi_insert_before(gsi, assign, GSI_NEW_STMT);
  314. update_stmt(assign);
  315. /* 3. ...modify... */
  316. op = get_op(NULL);
  317. assign = create_assign(op, temp, temp, local_entropy);
  318. gsi_insert_after(gsi, assign, GSI_NEW_STMT);
  319. update_stmt(assign);
  320. /* 4. ...write latent_entropy */
  321. assign = gimple_build_assign(latent_entropy_decl, temp);
  322. gsi_insert_after(gsi, assign, GSI_NEW_STMT);
  323. update_stmt(assign);
  324. }
  325. static bool handle_tail_calls(basic_block bb, tree local_entropy)
  326. {
  327. gimple_stmt_iterator gsi;
  328. for (gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) {
  329. gcall *call;
  330. gimple stmt = gsi_stmt(gsi);
  331. if (!is_gimple_call(stmt))
  332. continue;
  333. call = as_a_gcall(stmt);
  334. if (!gimple_call_tail_p(call))
  335. continue;
  336. __perturb_latent_entropy(&gsi, local_entropy);
  337. return true;
  338. }
  339. return false;
  340. }
  341. static void perturb_latent_entropy(tree local_entropy)
  342. {
  343. edge_iterator ei;
  344. edge e, last_bb_e;
  345. basic_block last_bb;
  346. gcc_assert(single_pred_p(EXIT_BLOCK_PTR_FOR_FN(cfun)));
  347. last_bb_e = single_pred_edge(EXIT_BLOCK_PTR_FOR_FN(cfun));
  348. FOR_EACH_EDGE(e, ei, last_bb_e->src->preds) {
  349. if (ENTRY_BLOCK_PTR_FOR_FN(cfun) == e->src)
  350. continue;
  351. if (EXIT_BLOCK_PTR_FOR_FN(cfun) == e->src)
  352. continue;
  353. handle_tail_calls(e->src, local_entropy);
  354. }
  355. last_bb = single_pred(EXIT_BLOCK_PTR_FOR_FN(cfun));
  356. if (!handle_tail_calls(last_bb, local_entropy)) {
  357. gimple_stmt_iterator gsi = gsi_last_bb(last_bb);
  358. __perturb_latent_entropy(&gsi, local_entropy);
  359. }
  360. }
  361. static void init_local_entropy(basic_block bb, tree local_entropy)
  362. {
  363. gimple assign, call;
  364. tree frame_addr, rand_const, tmp, fndecl, udi_frame_addr;
  365. enum tree_code op;
  366. unsigned HOST_WIDE_INT rand_cst;
  367. gimple_stmt_iterator gsi = gsi_after_labels(bb);
  368. /* 1. create local_entropy_frameaddr */
  369. frame_addr = create_var(ptr_type_node, "local_entropy_frameaddr");
  370. /* 2. local_entropy_frameaddr = __builtin_frame_address() */
  371. fndecl = builtin_decl_implicit(BUILT_IN_FRAME_ADDRESS);
  372. call = gimple_build_call(fndecl, 1, integer_zero_node);
  373. gimple_call_set_lhs(call, frame_addr);
  374. gsi_insert_before(&gsi, call, GSI_NEW_STMT);
  375. update_stmt(call);
  376. udi_frame_addr = fold_convert(long_unsigned_type_node, frame_addr);
  377. assign = gimple_build_assign(local_entropy, udi_frame_addr);
  378. gsi_insert_after(&gsi, assign, GSI_NEW_STMT);
  379. update_stmt(assign);
  380. /* 3. create temporary copy of latent_entropy */
  381. tmp = create_var(long_unsigned_type_node, "temp_latent_entropy");
  382. /* 4. read the global entropy variable into local entropy */
  383. add_referenced_var(latent_entropy_decl);
  384. mark_sym_for_renaming(latent_entropy_decl);
  385. assign = gimple_build_assign(tmp, latent_entropy_decl);
  386. gsi_insert_after(&gsi, assign, GSI_NEW_STMT);
  387. update_stmt(assign);
  388. /* 5. mix local_entropy_frameaddr into local entropy */
  389. assign = create_assign(BIT_XOR_EXPR, local_entropy, local_entropy, tmp);
  390. gsi_insert_after(&gsi, assign, GSI_NEW_STMT);
  391. update_stmt(assign);
  392. rand_cst = get_random_const();
  393. rand_const = build_int_cstu(long_unsigned_type_node, rand_cst);
  394. op = get_op(NULL);
  395. assign = create_assign(op, local_entropy, local_entropy, rand_const);
  396. gsi_insert_after(&gsi, assign, GSI_NEW_STMT);
  397. update_stmt(assign);
  398. }
  399. static bool create_latent_entropy_decl(void)
  400. {
  401. varpool_node_ptr node;
  402. if (latent_entropy_decl != NULL_TREE)
  403. return true;
  404. FOR_EACH_VARIABLE(node) {
  405. tree name, var = NODE_DECL(node);
  406. if (DECL_NAME_LENGTH(var) < sizeof("latent_entropy") - 1)
  407. continue;
  408. name = DECL_NAME(var);
  409. if (strcmp(IDENTIFIER_POINTER(name), "latent_entropy"))
  410. continue;
  411. latent_entropy_decl = var;
  412. break;
  413. }
  414. return latent_entropy_decl != NULL_TREE;
  415. }
  416. static unsigned int latent_entropy_execute(void)
  417. {
  418. basic_block bb;
  419. tree local_entropy;
  420. if (!create_latent_entropy_decl())
  421. return 0;
  422. /* prepare for step 2 below */
  423. gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun)));
  424. bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun));
  425. if (!single_pred_p(bb)) {
  426. split_edge(single_succ_edge(ENTRY_BLOCK_PTR_FOR_FN(cfun)));
  427. gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun)));
  428. bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun));
  429. }
  430. /* 1. create the local entropy variable */
  431. local_entropy = create_var(long_unsigned_type_node, "local_entropy");
  432. /* 2. initialize the local entropy variable */
  433. init_local_entropy(bb, local_entropy);
  434. bb = bb->next_bb;
  435. /*
  436. * 3. instrument each BB with an operation on the
  437. * local entropy variable
  438. */
  439. while (bb != EXIT_BLOCK_PTR_FOR_FN(cfun)) {
  440. perturb_local_entropy(bb, local_entropy);
  441. bb = bb->next_bb;
  442. }
  443. /* 4. mix local entropy into the global entropy variable */
  444. perturb_latent_entropy(local_entropy);
  445. return 0;
  446. }
  447. static void latent_entropy_start_unit(void *gcc_data __unused,
  448. void *user_data __unused)
  449. {
  450. tree type, id;
  451. int quals;
  452. if (in_lto_p)
  453. return;
  454. /* extern volatile unsigned long latent_entropy */
  455. quals = TYPE_QUALS(long_unsigned_type_node) | TYPE_QUAL_VOLATILE;
  456. type = build_qualified_type(long_unsigned_type_node, quals);
  457. id = get_identifier("latent_entropy");
  458. latent_entropy_decl = build_decl(UNKNOWN_LOCATION, VAR_DECL, id, type);
  459. TREE_STATIC(latent_entropy_decl) = 1;
  460. TREE_PUBLIC(latent_entropy_decl) = 1;
  461. TREE_USED(latent_entropy_decl) = 1;
  462. DECL_PRESERVE_P(latent_entropy_decl) = 1;
  463. TREE_THIS_VOLATILE(latent_entropy_decl) = 1;
  464. DECL_EXTERNAL(latent_entropy_decl) = 1;
  465. DECL_ARTIFICIAL(latent_entropy_decl) = 1;
  466. lang_hooks.decls.pushdecl(latent_entropy_decl);
  467. }
  468. #define PASS_NAME latent_entropy
  469. #define PROPERTIES_REQUIRED PROP_gimple_leh | PROP_cfg
  470. #define TODO_FLAGS_FINISH TODO_verify_ssa | TODO_verify_stmts | TODO_dump_func \
  471. | TODO_update_ssa
  472. #include "gcc-generate-gimple-pass.h"
  473. __visible int plugin_init(struct plugin_name_args *plugin_info,
  474. struct plugin_gcc_version *version)
  475. {
  476. bool enabled = true;
  477. const char * const plugin_name = plugin_info->base_name;
  478. const int argc = plugin_info->argc;
  479. const struct plugin_argument * const argv = plugin_info->argv;
  480. int i;
  481. /*
  482. * Call get_random_seed() with noinit=true, so that this returns
  483. * 0 in the case where no seed has been passed via -frandom-seed.
  484. */
  485. deterministic_seed = get_random_seed(true);
  486. static const struct ggc_root_tab gt_ggc_r_gt_latent_entropy[] = {
  487. {
  488. .base = &latent_entropy_decl,
  489. .nelt = 1,
  490. .stride = sizeof(latent_entropy_decl),
  491. .cb = &gt_ggc_mx_tree_node,
  492. .pchw = &gt_pch_nx_tree_node
  493. },
  494. LAST_GGC_ROOT_TAB
  495. };
  496. PASS_INFO(latent_entropy, "optimized", 1, PASS_POS_INSERT_BEFORE);
  497. if (!plugin_default_version_check(version, &gcc_version)) {
  498. error(G_("incompatible gcc/plugin versions"));
  499. return 1;
  500. }
  501. for (i = 0; i < argc; ++i) {
  502. if (!(strcmp(argv[i].key, "disable"))) {
  503. enabled = false;
  504. continue;
  505. }
  506. error(G_("unknown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key);
  507. }
  508. register_callback(plugin_name, PLUGIN_INFO, NULL,
  509. &latent_entropy_plugin_info);
  510. if (enabled) {
  511. register_callback(plugin_name, PLUGIN_START_UNIT,
  512. &latent_entropy_start_unit, NULL);
  513. register_callback(plugin_name, PLUGIN_REGISTER_GGC_ROOTS,
  514. NULL, (void *)&gt_ggc_r_gt_latent_entropy);
  515. register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL,
  516. &latent_entropy_pass_info);
  517. }
  518. register_callback(plugin_name, PLUGIN_ATTRIBUTES, register_attributes,
  519. NULL);
  520. return 0;
  521. }