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