sigfuz.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright 2018, Breno Leitao, IBM Corp.
  4. * Licensed under GPLv2.
  5. *
  6. * Sigfuz(tm): A PowerPC TM-aware signal fuzzer.
  7. *
  8. * This is a new selftest that raises SIGUSR1 signals and handles it in a set
  9. * of different ways, trying to create different scenario for testing
  10. * purpose.
  11. *
  12. * This test works raising a signal and calling sigreturn interleaved with
  13. * TM operations, as starting, suspending and terminating a transaction. The
  14. * test depends on random numbers, and, based on them, it sets different TM
  15. * states.
  16. *
  17. * Other than that, the test fills out the user context struct that is passed
  18. * to the sigreturn system call with random data, in order to make sure that
  19. * the signal handler syscall can handle different and invalid states
  20. * properly.
  21. *
  22. * This selftest has command line parameters to control what kind of tests the
  23. * user wants to run, as for example, if a transaction should be started prior
  24. * to signal being raised, or, after the signal being raised and before the
  25. * sigreturn. If no parameter is given, the default is enabling all options.
  26. *
  27. * This test does not check if the user context is being read and set
  28. * properly by the kernel. Its purpose, at this time, is basically
  29. * guaranteeing that the kernel does not crash on invalid scenarios.
  30. */
  31. #include <stdio.h>
  32. #include <limits.h>
  33. #include <sys/wait.h>
  34. #include <unistd.h>
  35. #include <stdlib.h>
  36. #include <signal.h>
  37. #include <string.h>
  38. #include <ucontext.h>
  39. #include <sys/mman.h>
  40. #include <pthread.h>
  41. #include "utils.h"
  42. /* Selftest defaults */
  43. #define COUNT_MAX 600 /* Number of interactions */
  44. #define THREADS 16 /* Number of threads */
  45. /* Arguments options */
  46. #define ARG_MESS_WITH_TM_AT 0x1
  47. #define ARG_MESS_WITH_TM_BEFORE 0x2
  48. #define ARG_MESS_WITH_MSR_AT 0x4
  49. #define ARG_FOREVER 0x10
  50. #define ARG_COMPLETE (ARG_MESS_WITH_TM_AT | \
  51. ARG_MESS_WITH_TM_BEFORE | \
  52. ARG_MESS_WITH_MSR_AT)
  53. static int args;
  54. static int nthread = THREADS;
  55. static int count_max = COUNT_MAX;
  56. /* checkpoint context */
  57. static ucontext_t *tmp_uc;
  58. /* Return true with 1/x probability */
  59. static int one_in_chance(int x)
  60. {
  61. return rand() % x == 0;
  62. }
  63. /* Change TM states */
  64. static void mess_with_tm(void)
  65. {
  66. /* Starts a transaction 33% of the time */
  67. if (one_in_chance(3)) {
  68. asm ("tbegin. ;"
  69. "beq 8 ;");
  70. /* And suspended half of them */
  71. if (one_in_chance(2))
  72. asm("tsuspend. ;");
  73. }
  74. /* Call 'tend' in 5% of the runs */
  75. if (one_in_chance(20))
  76. asm("tend. ;");
  77. }
  78. /* Signal handler that will be invoked with raise() */
  79. static void trap_signal_handler(int signo, siginfo_t *si, void *uc)
  80. {
  81. ucontext_t *ucp = uc;
  82. ucp->uc_link = tmp_uc;
  83. /*
  84. * Set uc_link in three possible ways:
  85. * - Setting a single 'int' in the whole chunk
  86. * - Cloning ucp into uc_link
  87. * - Allocating a new memory chunk
  88. */
  89. if (one_in_chance(3)) {
  90. memset(ucp->uc_link, rand(), sizeof(ucontext_t));
  91. } else if (one_in_chance(2)) {
  92. memcpy(ucp->uc_link, uc, sizeof(ucontext_t));
  93. } else if (one_in_chance(2)) {
  94. if (tmp_uc) {
  95. free(tmp_uc);
  96. tmp_uc = NULL;
  97. }
  98. tmp_uc = malloc(sizeof(ucontext_t));
  99. ucp->uc_link = tmp_uc;
  100. /* Trying to cause a major page fault at Kernel level */
  101. madvise(ucp->uc_link, sizeof(ucontext_t), MADV_DONTNEED);
  102. }
  103. if (args & ARG_MESS_WITH_MSR_AT) {
  104. /* Changing the checkpointed registers */
  105. if (one_in_chance(4)) {
  106. ucp->uc_link->uc_mcontext.gp_regs[PT_MSR] |= MSR_TS_S;
  107. } else {
  108. if (one_in_chance(2)) {
  109. ucp->uc_link->uc_mcontext.gp_regs[PT_MSR] |=
  110. MSR_TS_T;
  111. } else if (one_in_chance(2)) {
  112. ucp->uc_link->uc_mcontext.gp_regs[PT_MSR] |=
  113. MSR_TS_T | MSR_TS_S;
  114. }
  115. }
  116. /* Checking the current register context */
  117. if (one_in_chance(2)) {
  118. ucp->uc_mcontext.gp_regs[PT_MSR] |= MSR_TS_S;
  119. } else if (one_in_chance(2)) {
  120. if (one_in_chance(2))
  121. ucp->uc_mcontext.gp_regs[PT_MSR] |=
  122. MSR_TS_T;
  123. else if (one_in_chance(2))
  124. ucp->uc_mcontext.gp_regs[PT_MSR] |=
  125. MSR_TS_T | MSR_TS_S;
  126. }
  127. }
  128. if (one_in_chance(20)) {
  129. /* Nested transaction start */
  130. if (one_in_chance(5))
  131. mess_with_tm();
  132. /* Return without changing any other context info */
  133. return;
  134. }
  135. if (one_in_chance(10))
  136. ucp->uc_mcontext.gp_regs[PT_MSR] = random();
  137. if (one_in_chance(10))
  138. ucp->uc_mcontext.gp_regs[PT_NIP] = random();
  139. if (one_in_chance(10))
  140. ucp->uc_link->uc_mcontext.gp_regs[PT_MSR] = random();
  141. if (one_in_chance(10))
  142. ucp->uc_link->uc_mcontext.gp_regs[PT_NIP] = random();
  143. ucp->uc_mcontext.gp_regs[PT_TRAP] = random();
  144. ucp->uc_mcontext.gp_regs[PT_DSISR] = random();
  145. ucp->uc_mcontext.gp_regs[PT_DAR] = random();
  146. ucp->uc_mcontext.gp_regs[PT_ORIG_R3] = random();
  147. ucp->uc_mcontext.gp_regs[PT_XER] = random();
  148. ucp->uc_mcontext.gp_regs[PT_RESULT] = random();
  149. ucp->uc_mcontext.gp_regs[PT_SOFTE] = random();
  150. ucp->uc_mcontext.gp_regs[PT_DSCR] = random();
  151. ucp->uc_mcontext.gp_regs[PT_CTR] = random();
  152. ucp->uc_mcontext.gp_regs[PT_LNK] = random();
  153. ucp->uc_mcontext.gp_regs[PT_CCR] = random();
  154. ucp->uc_mcontext.gp_regs[PT_REGS_COUNT] = random();
  155. ucp->uc_link->uc_mcontext.gp_regs[PT_TRAP] = random();
  156. ucp->uc_link->uc_mcontext.gp_regs[PT_DSISR] = random();
  157. ucp->uc_link->uc_mcontext.gp_regs[PT_DAR] = random();
  158. ucp->uc_link->uc_mcontext.gp_regs[PT_ORIG_R3] = random();
  159. ucp->uc_link->uc_mcontext.gp_regs[PT_XER] = random();
  160. ucp->uc_link->uc_mcontext.gp_regs[PT_RESULT] = random();
  161. ucp->uc_link->uc_mcontext.gp_regs[PT_SOFTE] = random();
  162. ucp->uc_link->uc_mcontext.gp_regs[PT_DSCR] = random();
  163. ucp->uc_link->uc_mcontext.gp_regs[PT_CTR] = random();
  164. ucp->uc_link->uc_mcontext.gp_regs[PT_LNK] = random();
  165. ucp->uc_link->uc_mcontext.gp_regs[PT_CCR] = random();
  166. ucp->uc_link->uc_mcontext.gp_regs[PT_REGS_COUNT] = random();
  167. if (args & ARG_MESS_WITH_TM_BEFORE) {
  168. if (one_in_chance(2))
  169. mess_with_tm();
  170. }
  171. }
  172. static void seg_signal_handler(int signo, siginfo_t *si, void *uc)
  173. {
  174. /* Clear exit for process that segfaults */
  175. exit(0);
  176. }
  177. static void *sigfuz_test(void *thrid)
  178. {
  179. struct sigaction trap_sa, seg_sa;
  180. int ret, i = 0;
  181. pid_t t;
  182. tmp_uc = malloc(sizeof(ucontext_t));
  183. /* Main signal handler */
  184. trap_sa.sa_flags = SA_SIGINFO;
  185. trap_sa.sa_sigaction = trap_signal_handler;
  186. /* SIGSEGV signal handler */
  187. seg_sa.sa_flags = SA_SIGINFO;
  188. seg_sa.sa_sigaction = seg_signal_handler;
  189. /* The signal handler will enable MSR_TS */
  190. sigaction(SIGUSR1, &trap_sa, NULL);
  191. /* If it does not crash, it will segfault, avoid it to retest */
  192. sigaction(SIGSEGV, &seg_sa, NULL);
  193. while (i < count_max) {
  194. t = fork();
  195. if (t == 0) {
  196. /* Once seed per process */
  197. srand(time(NULL) + getpid());
  198. if (args & ARG_MESS_WITH_TM_AT) {
  199. if (one_in_chance(2))
  200. mess_with_tm();
  201. }
  202. raise(SIGUSR1);
  203. exit(0);
  204. } else {
  205. waitpid(t, &ret, 0);
  206. }
  207. if (!(args & ARG_FOREVER))
  208. i++;
  209. }
  210. /* If not freed already, free now */
  211. if (tmp_uc) {
  212. free(tmp_uc);
  213. tmp_uc = NULL;
  214. }
  215. return NULL;
  216. }
  217. static int signal_fuzzer(void)
  218. {
  219. int t, rc;
  220. pthread_t *threads;
  221. threads = malloc(nthread * sizeof(pthread_t));
  222. for (t = 0; t < nthread; t++) {
  223. rc = pthread_create(&threads[t], NULL, sigfuz_test,
  224. (void *)&t);
  225. if (rc)
  226. perror("Thread creation error\n");
  227. }
  228. for (t = 0; t < nthread; t++) {
  229. rc = pthread_join(threads[t], NULL);
  230. if (rc)
  231. perror("Thread join error\n");
  232. }
  233. free(threads);
  234. return EXIT_SUCCESS;
  235. }
  236. static void show_help(char *name)
  237. {
  238. printf("%s: Sigfuzzer for powerpc\n", name);
  239. printf("Usage:\n");
  240. printf("\t-b\t Mess with TM before raising a SIGUSR1 signal\n");
  241. printf("\t-a\t Mess with TM after raising a SIGUSR1 signal\n");
  242. printf("\t-m\t Mess with MSR[TS] bits at mcontext\n");
  243. printf("\t-x\t Mess with everything above\n");
  244. printf("\t-f\t Run forever (Press ^C to Quit)\n");
  245. printf("\t-i\t Amount of interactions. (Default = %d)\n", COUNT_MAX);
  246. printf("\t-t\t Amount of threads. (Default = %d)\n", THREADS);
  247. exit(-1);
  248. }
  249. int main(int argc, char **argv)
  250. {
  251. int opt;
  252. while ((opt = getopt(argc, argv, "bamxt:fi:h")) != -1) {
  253. if (opt == 'b') {
  254. printf("Mess with TM before signal\n");
  255. args |= ARG_MESS_WITH_TM_BEFORE;
  256. } else if (opt == 'a') {
  257. printf("Mess with TM at signal handler\n");
  258. args |= ARG_MESS_WITH_TM_AT;
  259. } else if (opt == 'm') {
  260. printf("Mess with MSR[TS] bits in mcontext\n");
  261. args |= ARG_MESS_WITH_MSR_AT;
  262. } else if (opt == 'x') {
  263. printf("Running with all options enabled\n");
  264. args |= ARG_COMPLETE;
  265. } else if (opt == 't') {
  266. nthread = atoi(optarg);
  267. printf("Threads = %d\n", nthread);
  268. } else if (opt == 'f') {
  269. args |= ARG_FOREVER;
  270. printf("Press ^C to stop\n");
  271. test_harness_set_timeout(-1);
  272. } else if (opt == 'i') {
  273. count_max = atoi(optarg);
  274. printf("Running for %d interactions\n", count_max);
  275. } else if (opt == 'h') {
  276. show_help(argv[0]);
  277. }
  278. }
  279. /* Default test suite */
  280. if (!args)
  281. args = ARG_COMPLETE;
  282. test_harness(signal_fuzzer, "signal_fuzzer");
  283. }