1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright 2018, Breno Leitao, IBM Corp.
4 * Licensed under GPLv2.
6 * Sigfuz(tm): A PowerPC TM-aware signal fuzzer.
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
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
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
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.
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.
44 /* Selftest defaults */
45 #define COUNT_MAX 600 /* Number of interactions */
46 #define THREADS 16 /* Number of threads */
48 /* Arguments options */
49 #define ARG_MESS_WITH_TM_AT 0x1
50 #define ARG_MESS_WITH_TM_BEFORE 0x2
51 #define ARG_MESS_WITH_MSR_AT 0x4
52 #define ARG_FOREVER 0x10
53 #define ARG_COMPLETE (ARG_MESS_WITH_TM_AT | \
54 ARG_MESS_WITH_TM_BEFORE | \
58 static int nthread
= THREADS
;
59 static int count_max
= COUNT_MAX
;
61 /* checkpoint context */
62 static ucontext_t
*tmp_uc
;
64 /* Return true with 1/x probability */
65 static int one_in_chance(int x
)
67 return rand() % x
== 0;
70 /* Change TM states */
71 static void mess_with_tm(void)
73 /* Starts a transaction 33% of the time */
74 if (one_in_chance(3)) {
78 /* And suspended half of them */
83 /* Call 'tend' in 5% of the runs */
84 if (one_in_chance(20))
88 /* Signal handler that will be invoked with raise() */
89 static void trap_signal_handler(int signo
, siginfo_t
*si
, void *uc
)
93 ucp
->uc_link
= tmp_uc
;
96 * Set uc_link in three possible ways:
97 * - Setting a single 'int' in the whole chunk
98 * - Cloning ucp into uc_link
99 * - Allocating a new memory chunk
101 if (one_in_chance(3)) {
102 memset(ucp
->uc_link
, rand(), sizeof(ucontext_t
));
103 } else if (one_in_chance(2)) {
104 memcpy(ucp
->uc_link
, uc
, sizeof(ucontext_t
));
105 } else if (one_in_chance(2)) {
110 tmp_uc
= malloc(sizeof(ucontext_t
));
111 ucp
->uc_link
= tmp_uc
;
112 /* Trying to cause a major page fault at Kernel level */
113 madvise(ucp
->uc_link
, sizeof(ucontext_t
), MADV_DONTNEED
);
116 if (args
& ARG_MESS_WITH_MSR_AT
) {
117 /* Changing the checkpointed registers */
118 if (one_in_chance(4)) {
119 ucp
->uc_link
->uc_mcontext
.gp_regs
[PT_MSR
] |= MSR_TS_S
;
121 if (one_in_chance(2)) {
122 ucp
->uc_link
->uc_mcontext
.gp_regs
[PT_MSR
] |=
124 } else if (one_in_chance(2)) {
125 ucp
->uc_link
->uc_mcontext
.gp_regs
[PT_MSR
] |=
130 /* Checking the current register context */
131 if (one_in_chance(2)) {
132 ucp
->uc_mcontext
.gp_regs
[PT_MSR
] |= MSR_TS_S
;
133 } else if (one_in_chance(2)) {
134 if (one_in_chance(2))
135 ucp
->uc_mcontext
.gp_regs
[PT_MSR
] |=
137 else if (one_in_chance(2))
138 ucp
->uc_mcontext
.gp_regs
[PT_MSR
] |=
143 if (one_in_chance(20)) {
144 /* Nested transaction start */
145 if (one_in_chance(5))
148 /* Return without changing any other context info */
152 if (one_in_chance(10))
153 ucp
->uc_mcontext
.gp_regs
[PT_MSR
] = random();
154 if (one_in_chance(10))
155 ucp
->uc_mcontext
.gp_regs
[PT_NIP
] = random();
156 if (one_in_chance(10))
157 ucp
->uc_link
->uc_mcontext
.gp_regs
[PT_MSR
] = random();
158 if (one_in_chance(10))
159 ucp
->uc_link
->uc_mcontext
.gp_regs
[PT_NIP
] = random();
161 ucp
->uc_mcontext
.gp_regs
[PT_TRAP
] = random();
162 ucp
->uc_mcontext
.gp_regs
[PT_DSISR
] = random();
163 ucp
->uc_mcontext
.gp_regs
[PT_DAR
] = random();
164 ucp
->uc_mcontext
.gp_regs
[PT_ORIG_R3
] = random();
165 ucp
->uc_mcontext
.gp_regs
[PT_XER
] = random();
166 ucp
->uc_mcontext
.gp_regs
[PT_RESULT
] = random();
167 ucp
->uc_mcontext
.gp_regs
[PT_SOFTE
] = random();
168 ucp
->uc_mcontext
.gp_regs
[PT_DSCR
] = random();
169 ucp
->uc_mcontext
.gp_regs
[PT_CTR
] = random();
170 ucp
->uc_mcontext
.gp_regs
[PT_LNK
] = random();
171 ucp
->uc_mcontext
.gp_regs
[PT_CCR
] = random();
172 ucp
->uc_mcontext
.gp_regs
[PT_REGS_COUNT
] = random();
174 ucp
->uc_link
->uc_mcontext
.gp_regs
[PT_TRAP
] = random();
175 ucp
->uc_link
->uc_mcontext
.gp_regs
[PT_DSISR
] = random();
176 ucp
->uc_link
->uc_mcontext
.gp_regs
[PT_DAR
] = random();
177 ucp
->uc_link
->uc_mcontext
.gp_regs
[PT_ORIG_R3
] = random();
178 ucp
->uc_link
->uc_mcontext
.gp_regs
[PT_XER
] = random();
179 ucp
->uc_link
->uc_mcontext
.gp_regs
[PT_RESULT
] = random();
180 ucp
->uc_link
->uc_mcontext
.gp_regs
[PT_SOFTE
] = random();
181 ucp
->uc_link
->uc_mcontext
.gp_regs
[PT_DSCR
] = random();
182 ucp
->uc_link
->uc_mcontext
.gp_regs
[PT_CTR
] = random();
183 ucp
->uc_link
->uc_mcontext
.gp_regs
[PT_LNK
] = random();
184 ucp
->uc_link
->uc_mcontext
.gp_regs
[PT_CCR
] = random();
185 ucp
->uc_link
->uc_mcontext
.gp_regs
[PT_REGS_COUNT
] = random();
187 if (args
& ARG_MESS_WITH_TM_BEFORE
) {
188 if (one_in_chance(2))
193 static void seg_signal_handler(int signo
, siginfo_t
*si
, void *uc
)
195 /* Clear exit for process that segfaults */
199 static void *sigfuz_test(void *thrid
)
201 struct sigaction trap_sa
, seg_sa
;
205 tmp_uc
= malloc(sizeof(ucontext_t
));
207 /* Main signal handler */
208 trap_sa
.sa_flags
= SA_SIGINFO
;
209 trap_sa
.sa_sigaction
= trap_signal_handler
;
211 /* SIGSEGV signal handler */
212 seg_sa
.sa_flags
= SA_SIGINFO
;
213 seg_sa
.sa_sigaction
= seg_signal_handler
;
215 /* The signal handler will enable MSR_TS */
216 sigaction(SIGUSR1
, &trap_sa
, NULL
);
218 /* If it does not crash, it will segfault, avoid it to retest */
219 sigaction(SIGSEGV
, &seg_sa
, NULL
);
221 while (i
< count_max
) {
225 /* Once seed per process */
226 srand(time(NULL
) + getpid());
227 if (args
& ARG_MESS_WITH_TM_AT
) {
228 if (one_in_chance(2))
236 if (!(args
& ARG_FOREVER
))
240 /* If not freed already, free now */
249 static int signal_fuzzer(void)
254 threads
= malloc(nthread
* sizeof(pthread_t
));
256 for (t
= 0; t
< nthread
; t
++) {
257 rc
= pthread_create(&threads
[t
], NULL
, sigfuz_test
,
260 perror("Thread creation error\n");
263 for (t
= 0; t
< nthread
; t
++) {
264 rc
= pthread_join(threads
[t
], NULL
);
266 perror("Thread join error\n");
274 static void show_help(char *name
)
276 printf("%s: Sigfuzzer for powerpc\n", name
);
278 printf("\t-b\t Mess with TM before raising a SIGUSR1 signal\n");
279 printf("\t-a\t Mess with TM after raising a SIGUSR1 signal\n");
280 printf("\t-m\t Mess with MSR[TS] bits at mcontext\n");
281 printf("\t-x\t Mess with everything above\n");
282 printf("\t-f\t Run forever (Press ^C to Quit)\n");
283 printf("\t-i\t Amount of interactions. (Default = %d)\n", COUNT_MAX
);
284 printf("\t-t\t Amount of threads. (Default = %d)\n", THREADS
);
288 int main(int argc
, char **argv
)
292 while ((opt
= getopt(argc
, argv
, "bamxt:fi:h")) != -1) {
294 printf("Mess with TM before signal\n");
295 args
|= ARG_MESS_WITH_TM_BEFORE
;
296 } else if (opt
== 'a') {
297 printf("Mess with TM at signal handler\n");
298 args
|= ARG_MESS_WITH_TM_AT
;
299 } else if (opt
== 'm') {
300 printf("Mess with MSR[TS] bits in mcontext\n");
301 args
|= ARG_MESS_WITH_MSR_AT
;
302 } else if (opt
== 'x') {
303 printf("Running with all options enabled\n");
304 args
|= ARG_COMPLETE
;
305 } else if (opt
== 't') {
306 nthread
= atoi(optarg
);
307 printf("Threads = %d\n", nthread
);
308 } else if (opt
== 'f') {
310 printf("Press ^C to stop\n");
311 test_harness_set_timeout(-1);
312 } else if (opt
== 'i') {
313 count_max
= atoi(optarg
);
314 printf("Running for %d interactions\n", count_max
);
315 } else if (opt
== 'h') {
320 /* Default test suite */
324 test_harness(signal_fuzzer
, "signal_fuzzer");