randstruct_kunit.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Test cases for struct randomization, i.e. CONFIG_RANDSTRUCT=y.
  4. *
  5. * For example, see:
  6. * "Running tests with kunit_tool" at Documentation/dev-tools/kunit/start.rst
  7. * ./tools/testing/kunit/kunit.py run randstruct [--raw_output] \
  8. * [--make_option LLVM=1] \
  9. * --kconfig_add CONFIG_RANDSTRUCT_FULL=y
  10. *
  11. */
  12. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  13. #include <kunit/test.h>
  14. #include <linux/init.h>
  15. #include <linux/kernel.h>
  16. #include <linux/module.h>
  17. #include <linux/string.h>
  18. #define DO_MANY_MEMBERS(macro, args...) \
  19. macro(a, args) \
  20. macro(b, args) \
  21. macro(c, args) \
  22. macro(d, args) \
  23. macro(e, args) \
  24. macro(f, args) \
  25. macro(g, args) \
  26. macro(h, args)
  27. #define do_enum(x, ignored) MEMBER_NAME_ ## x,
  28. enum randstruct_member_names {
  29. DO_MANY_MEMBERS(do_enum)
  30. MEMBER_NAME_MAX,
  31. };
  32. /* Make sure the macros are working: want 8 test members. */
  33. _Static_assert(MEMBER_NAME_MAX == 8, "Number of test members changed?!");
  34. /* This is an unsigned long member to match the function pointer size */
  35. #define unsigned_long_member(x, ignored) unsigned long x;
  36. struct randstruct_untouched {
  37. DO_MANY_MEMBERS(unsigned_long_member)
  38. };
  39. /* Struct explicitly marked with __randomize_layout. */
  40. struct randstruct_shuffled {
  41. DO_MANY_MEMBERS(unsigned_long_member)
  42. } __randomize_layout;
  43. #undef unsigned_long_member
  44. /* Struct implicitly randomized from being all func ptrs. */
  45. #define func_member(x, ignored) size_t (*x)(int);
  46. struct randstruct_funcs_untouched {
  47. DO_MANY_MEMBERS(func_member)
  48. } __no_randomize_layout;
  49. struct randstruct_funcs_shuffled {
  50. DO_MANY_MEMBERS(func_member)
  51. };
  52. #define func_body(x, ignored) \
  53. static noinline size_t func_##x(int arg) \
  54. { \
  55. return offsetof(struct randstruct_funcs_untouched, x); \
  56. }
  57. DO_MANY_MEMBERS(func_body)
  58. /* Various mixed types. */
  59. #define mixed_members \
  60. bool a; \
  61. short b; \
  62. unsigned int c __aligned(16); \
  63. size_t d; \
  64. char e; \
  65. u64 f; \
  66. union { \
  67. struct randstruct_shuffled shuffled; \
  68. uintptr_t g; \
  69. }; \
  70. union { \
  71. void *ptr; \
  72. char h; \
  73. };
  74. struct randstruct_mixed_untouched {
  75. mixed_members
  76. };
  77. struct randstruct_mixed_shuffled {
  78. mixed_members
  79. } __randomize_layout;
  80. #undef mixed_members
  81. struct contains_randstruct_untouched {
  82. int before;
  83. struct randstruct_untouched untouched;
  84. int after;
  85. };
  86. struct contains_randstruct_shuffled {
  87. int before;
  88. struct randstruct_shuffled shuffled;
  89. int after;
  90. };
  91. struct contains_func_untouched {
  92. struct randstruct_funcs_shuffled inner;
  93. DO_MANY_MEMBERS(func_member)
  94. } __no_randomize_layout;
  95. struct contains_func_shuffled {
  96. struct randstruct_funcs_shuffled inner;
  97. DO_MANY_MEMBERS(func_member)
  98. };
  99. #undef func_member
  100. #define check_mismatch(x, untouched, shuffled) \
  101. if (offsetof(untouched, x) != offsetof(shuffled, x)) \
  102. mismatches++; \
  103. kunit_info(test, #shuffled "::" #x " @ %zu (vs %zu)\n", \
  104. offsetof(shuffled, x), \
  105. offsetof(untouched, x)); \
  106. #define check_pair(outcome, untouched, shuffled, checker...) \
  107. mismatches = 0; \
  108. DO_MANY_MEMBERS(checker, untouched, shuffled) \
  109. kunit_info(test, "Differing " #untouched " vs " #shuffled " member positions: %d\n", \
  110. mismatches); \
  111. KUNIT_##outcome##_MSG(test, mismatches, 0, \
  112. #untouched " vs " #shuffled " layouts: unlucky or broken?\n");
  113. static void randstruct_layout_same(struct kunit *test)
  114. {
  115. int mismatches;
  116. check_pair(EXPECT_EQ, struct randstruct_untouched, struct randstruct_untouched,
  117. check_mismatch)
  118. check_pair(EXPECT_GT, struct randstruct_untouched, struct randstruct_shuffled,
  119. check_mismatch)
  120. }
  121. static void randstruct_layout_mixed(struct kunit *test)
  122. {
  123. int mismatches;
  124. check_pair(EXPECT_EQ, struct randstruct_mixed_untouched, struct randstruct_mixed_untouched,
  125. check_mismatch)
  126. check_pair(EXPECT_GT, struct randstruct_mixed_untouched, struct randstruct_mixed_shuffled,
  127. check_mismatch)
  128. }
  129. static void randstruct_layout_fptr(struct kunit *test)
  130. {
  131. int mismatches;
  132. check_pair(EXPECT_EQ, struct randstruct_untouched, struct randstruct_untouched,
  133. check_mismatch)
  134. check_pair(EXPECT_GT, struct randstruct_untouched, struct randstruct_funcs_shuffled,
  135. check_mismatch)
  136. check_pair(EXPECT_GT, struct randstruct_funcs_untouched, struct randstruct_funcs_shuffled,
  137. check_mismatch)
  138. }
  139. #define check_mismatch_prefixed(x, prefix, untouched, shuffled) \
  140. check_mismatch(prefix.x, untouched, shuffled)
  141. static void randstruct_layout_fptr_deep(struct kunit *test)
  142. {
  143. int mismatches;
  144. if (IS_ENABLED(CONFIG_CC_IS_CLANG))
  145. kunit_skip(test, "Clang randstruct misses inner functions: https://github.com/llvm/llvm-project/issues/138355");
  146. check_pair(EXPECT_EQ, struct contains_func_untouched, struct contains_func_untouched,
  147. check_mismatch_prefixed, inner)
  148. check_pair(EXPECT_GT, struct contains_func_untouched, struct contains_func_shuffled,
  149. check_mismatch_prefixed, inner)
  150. }
  151. #undef check_pair
  152. #undef check_mismatch
  153. #define check_mismatch(x, ignore) \
  154. KUNIT_EXPECT_EQ_MSG(test, untouched->x, shuffled->x, \
  155. "Mismatched member value in %s initializer\n", \
  156. name);
  157. static void test_check_init(struct kunit *test, const char *name,
  158. struct randstruct_untouched *untouched,
  159. struct randstruct_shuffled *shuffled)
  160. {
  161. DO_MANY_MEMBERS(check_mismatch)
  162. }
  163. static void test_check_mixed_init(struct kunit *test, const char *name,
  164. struct randstruct_mixed_untouched *untouched,
  165. struct randstruct_mixed_shuffled *shuffled)
  166. {
  167. DO_MANY_MEMBERS(check_mismatch)
  168. }
  169. #undef check_mismatch
  170. #define check_mismatch(x, ignore) \
  171. KUNIT_EXPECT_EQ_MSG(test, untouched->untouched.x, \
  172. shuffled->shuffled.x, \
  173. "Mismatched member value in %s initializer\n", \
  174. name);
  175. static void test_check_contained_init(struct kunit *test, const char *name,
  176. struct contains_randstruct_untouched *untouched,
  177. struct contains_randstruct_shuffled *shuffled)
  178. {
  179. DO_MANY_MEMBERS(check_mismatch)
  180. }
  181. #undef check_mismatch
  182. #define check_mismatch(x, ignore) \
  183. KUNIT_EXPECT_PTR_EQ_MSG(test, untouched->x, shuffled->x, \
  184. "Mismatched member value in %s initializer\n", \
  185. name);
  186. static void test_check_funcs_init(struct kunit *test, const char *name,
  187. struct randstruct_funcs_untouched *untouched,
  188. struct randstruct_funcs_shuffled *shuffled)
  189. {
  190. DO_MANY_MEMBERS(check_mismatch)
  191. }
  192. #undef check_mismatch
  193. static void randstruct_initializers(struct kunit *test)
  194. {
  195. #define init_members \
  196. .a = 1, \
  197. .b = 3, \
  198. .c = 5, \
  199. .d = 7, \
  200. .e = 11, \
  201. .f = 13, \
  202. .g = 17, \
  203. .h = 19,
  204. struct randstruct_untouched untouched = {
  205. init_members
  206. };
  207. struct randstruct_shuffled shuffled = {
  208. init_members
  209. };
  210. struct randstruct_mixed_untouched mixed_untouched = {
  211. init_members
  212. };
  213. struct randstruct_mixed_shuffled mixed_shuffled = {
  214. init_members
  215. };
  216. struct contains_randstruct_untouched contains_untouched = {
  217. .untouched = {
  218. init_members
  219. },
  220. };
  221. struct contains_randstruct_shuffled contains_shuffled = {
  222. .shuffled = {
  223. init_members
  224. },
  225. };
  226. #define func_member(x, ignored) \
  227. .x = func_##x,
  228. struct randstruct_funcs_untouched funcs_untouched = {
  229. DO_MANY_MEMBERS(func_member)
  230. };
  231. struct randstruct_funcs_shuffled funcs_shuffled = {
  232. DO_MANY_MEMBERS(func_member)
  233. };
  234. test_check_init(test, "named", &untouched, &shuffled);
  235. test_check_init(test, "unnamed", &untouched,
  236. &(struct randstruct_shuffled){
  237. init_members
  238. });
  239. test_check_contained_init(test, "named", &contains_untouched, &contains_shuffled);
  240. test_check_contained_init(test, "unnamed", &contains_untouched,
  241. &(struct contains_randstruct_shuffled){
  242. .shuffled = (struct randstruct_shuffled){
  243. init_members
  244. },
  245. });
  246. test_check_contained_init(test, "named", &contains_untouched, &contains_shuffled);
  247. test_check_contained_init(test, "unnamed copy", &contains_untouched,
  248. &(struct contains_randstruct_shuffled){
  249. /* full struct copy initializer */
  250. .shuffled = shuffled,
  251. });
  252. test_check_mixed_init(test, "named", &mixed_untouched, &mixed_shuffled);
  253. test_check_mixed_init(test, "unnamed", &mixed_untouched,
  254. &(struct randstruct_mixed_shuffled){
  255. init_members
  256. });
  257. test_check_funcs_init(test, "named", &funcs_untouched, &funcs_shuffled);
  258. test_check_funcs_init(test, "unnamed", &funcs_untouched,
  259. &(struct randstruct_funcs_shuffled){
  260. DO_MANY_MEMBERS(func_member)
  261. });
  262. #undef func_member
  263. #undef init_members
  264. }
  265. static int randstruct_test_init(struct kunit *test)
  266. {
  267. if (!IS_ENABLED(CONFIG_RANDSTRUCT))
  268. kunit_skip(test, "Not built with CONFIG_RANDSTRUCT=y");
  269. return 0;
  270. }
  271. static struct kunit_case randstruct_test_cases[] = {
  272. KUNIT_CASE(randstruct_layout_same),
  273. KUNIT_CASE(randstruct_layout_mixed),
  274. KUNIT_CASE(randstruct_layout_fptr),
  275. KUNIT_CASE(randstruct_layout_fptr_deep),
  276. KUNIT_CASE(randstruct_initializers),
  277. {}
  278. };
  279. static struct kunit_suite randstruct_test_suite = {
  280. .name = "randstruct",
  281. .init = randstruct_test_init,
  282. .test_cases = randstruct_test_cases,
  283. };
  284. kunit_test_suites(&randstruct_test_suite);
  285. MODULE_DESCRIPTION("Test cases for struct randomization");
  286. MODULE_LICENSE("GPL");