183e367f9SBreno Leitao // SPDX-License-Identifier: GPL-2.0 283e367f9SBreno Leitao /* 383e367f9SBreno Leitao * Copyright 2018, Breno Leitao, IBM Corp. 483e367f9SBreno Leitao * Licensed under GPLv2. 583e367f9SBreno Leitao * 683e367f9SBreno Leitao * Sigfuz(tm): A PowerPC TM-aware signal fuzzer. 783e367f9SBreno Leitao * 883e367f9SBreno Leitao * This is a new selftest that raises SIGUSR1 signals and handles it in a set 983e367f9SBreno Leitao * of different ways, trying to create different scenario for testing 1083e367f9SBreno Leitao * purpose. 1183e367f9SBreno Leitao * 1283e367f9SBreno Leitao * This test works raising a signal and calling sigreturn interleaved with 1383e367f9SBreno Leitao * TM operations, as starting, suspending and terminating a transaction. The 1483e367f9SBreno Leitao * test depends on random numbers, and, based on them, it sets different TM 1583e367f9SBreno Leitao * states. 1683e367f9SBreno Leitao * 1783e367f9SBreno Leitao * Other than that, the test fills out the user context struct that is passed 1883e367f9SBreno Leitao * to the sigreturn system call with random data, in order to make sure that 1983e367f9SBreno Leitao * the signal handler syscall can handle different and invalid states 2083e367f9SBreno Leitao * properly. 2183e367f9SBreno Leitao * 2283e367f9SBreno Leitao * This selftest has command line parameters to control what kind of tests the 2383e367f9SBreno Leitao * user wants to run, as for example, if a transaction should be started prior 2483e367f9SBreno Leitao * to signal being raised, or, after the signal being raised and before the 2583e367f9SBreno Leitao * sigreturn. If no parameter is given, the default is enabling all options. 2683e367f9SBreno Leitao * 2783e367f9SBreno Leitao * This test does not check if the user context is being read and set 2883e367f9SBreno Leitao * properly by the kernel. Its purpose, at this time, is basically 2983e367f9SBreno Leitao * guaranteeing that the kernel does not crash on invalid scenarios. 3083e367f9SBreno Leitao */ 3183e367f9SBreno Leitao 3283e367f9SBreno Leitao #include <stdio.h> 3383e367f9SBreno Leitao #include <limits.h> 3483e367f9SBreno Leitao #include <sys/wait.h> 3583e367f9SBreno Leitao #include <unistd.h> 3683e367f9SBreno Leitao #include <stdlib.h> 3783e367f9SBreno Leitao #include <signal.h> 3883e367f9SBreno Leitao #include <string.h> 3983e367f9SBreno Leitao #include <ucontext.h> 4083e367f9SBreno Leitao #include <sys/mman.h> 4183e367f9SBreno Leitao #include <pthread.h> 4283e367f9SBreno Leitao #include "utils.h" 4383e367f9SBreno Leitao 4483e367f9SBreno Leitao /* Selftest defaults */ 45*4f5c5b76SMichael Ellerman #define COUNT_MAX 600 /* Number of interactions */ 4683e367f9SBreno Leitao #define THREADS 16 /* Number of threads */ 4783e367f9SBreno Leitao 4883e367f9SBreno Leitao /* Arguments options */ 4983e367f9SBreno Leitao #define ARG_MESS_WITH_TM_AT 0x1 5083e367f9SBreno Leitao #define ARG_MESS_WITH_TM_BEFORE 0x2 5183e367f9SBreno Leitao #define ARG_MESS_WITH_MSR_AT 0x4 5283e367f9SBreno Leitao #define ARG_FOREVER 0x10 5383e367f9SBreno Leitao #define ARG_COMPLETE (ARG_MESS_WITH_TM_AT | \ 5483e367f9SBreno Leitao ARG_MESS_WITH_TM_BEFORE | \ 5583e367f9SBreno Leitao ARG_MESS_WITH_MSR_AT) 5683e367f9SBreno Leitao 5783e367f9SBreno Leitao static int args; 5883e367f9SBreno Leitao static int nthread = THREADS; 5983e367f9SBreno Leitao static int count_max = COUNT_MAX; 6083e367f9SBreno Leitao 6183e367f9SBreno Leitao /* checkpoint context */ 6283e367f9SBreno Leitao static ucontext_t *tmp_uc; 6383e367f9SBreno Leitao 6483e367f9SBreno Leitao /* Return true with 1/x probability */ 6583e367f9SBreno Leitao static int one_in_chance(int x) 6683e367f9SBreno Leitao { 6783e367f9SBreno Leitao return rand() % x == 0; 6883e367f9SBreno Leitao } 6983e367f9SBreno Leitao 7083e367f9SBreno Leitao /* Change TM states */ 7183e367f9SBreno Leitao static void mess_with_tm(void) 7283e367f9SBreno Leitao { 7383e367f9SBreno Leitao /* Starts a transaction 33% of the time */ 7483e367f9SBreno Leitao if (one_in_chance(3)) { 7583e367f9SBreno Leitao asm ("tbegin. ;" 7683e367f9SBreno Leitao "beq 8 ;"); 7783e367f9SBreno Leitao 7883e367f9SBreno Leitao /* And suspended half of them */ 7983e367f9SBreno Leitao if (one_in_chance(2)) 8083e367f9SBreno Leitao asm("tsuspend. ;"); 8183e367f9SBreno Leitao } 8283e367f9SBreno Leitao 8383e367f9SBreno Leitao /* Call 'tend' in 5% of the runs */ 8483e367f9SBreno Leitao if (one_in_chance(20)) 8583e367f9SBreno Leitao asm("tend. ;"); 8683e367f9SBreno Leitao } 8783e367f9SBreno Leitao 8883e367f9SBreno Leitao /* Signal handler that will be invoked with raise() */ 8983e367f9SBreno Leitao static void trap_signal_handler(int signo, siginfo_t *si, void *uc) 9083e367f9SBreno Leitao { 9183e367f9SBreno Leitao ucontext_t *ucp = uc; 9283e367f9SBreno Leitao 9383e367f9SBreno Leitao ucp->uc_link = tmp_uc; 9483e367f9SBreno Leitao 9583e367f9SBreno Leitao /* 9683e367f9SBreno Leitao * Set uc_link in three possible ways: 9783e367f9SBreno Leitao * - Setting a single 'int' in the whole chunk 9883e367f9SBreno Leitao * - Cloning ucp into uc_link 9983e367f9SBreno Leitao * - Allocating a new memory chunk 10083e367f9SBreno Leitao */ 10183e367f9SBreno Leitao if (one_in_chance(3)) { 10283e367f9SBreno Leitao memset(ucp->uc_link, rand(), sizeof(ucontext_t)); 10383e367f9SBreno Leitao } else if (one_in_chance(2)) { 10483e367f9SBreno Leitao memcpy(ucp->uc_link, uc, sizeof(ucontext_t)); 10583e367f9SBreno Leitao } else if (one_in_chance(2)) { 10683e367f9SBreno Leitao if (tmp_uc) { 10783e367f9SBreno Leitao free(tmp_uc); 10883e367f9SBreno Leitao tmp_uc = NULL; 10983e367f9SBreno Leitao } 11083e367f9SBreno Leitao tmp_uc = malloc(sizeof(ucontext_t)); 11183e367f9SBreno Leitao ucp->uc_link = tmp_uc; 11283e367f9SBreno Leitao /* Trying to cause a major page fault at Kernel level */ 11383e367f9SBreno Leitao madvise(ucp->uc_link, sizeof(ucontext_t), MADV_DONTNEED); 11483e367f9SBreno Leitao } 11583e367f9SBreno Leitao 11683e367f9SBreno Leitao if (args & ARG_MESS_WITH_MSR_AT) { 11783e367f9SBreno Leitao /* Changing the checkpointed registers */ 11883e367f9SBreno Leitao if (one_in_chance(4)) { 11983e367f9SBreno Leitao ucp->uc_link->uc_mcontext.gp_regs[PT_MSR] |= MSR_TS_S; 12083e367f9SBreno Leitao } else { 12183e367f9SBreno Leitao if (one_in_chance(2)) { 12283e367f9SBreno Leitao ucp->uc_link->uc_mcontext.gp_regs[PT_MSR] |= 12383e367f9SBreno Leitao MSR_TS_T; 12483e367f9SBreno Leitao } else if (one_in_chance(2)) { 12583e367f9SBreno Leitao ucp->uc_link->uc_mcontext.gp_regs[PT_MSR] |= 12683e367f9SBreno Leitao MSR_TS_T | MSR_TS_S; 12783e367f9SBreno Leitao } 12883e367f9SBreno Leitao } 12983e367f9SBreno Leitao 13083e367f9SBreno Leitao /* Checking the current register context */ 13183e367f9SBreno Leitao if (one_in_chance(2)) { 13283e367f9SBreno Leitao ucp->uc_mcontext.gp_regs[PT_MSR] |= MSR_TS_S; 13383e367f9SBreno Leitao } else if (one_in_chance(2)) { 13483e367f9SBreno Leitao if (one_in_chance(2)) 13583e367f9SBreno Leitao ucp->uc_mcontext.gp_regs[PT_MSR] |= 13683e367f9SBreno Leitao MSR_TS_T; 13783e367f9SBreno Leitao else if (one_in_chance(2)) 13883e367f9SBreno Leitao ucp->uc_mcontext.gp_regs[PT_MSR] |= 13983e367f9SBreno Leitao MSR_TS_T | MSR_TS_S; 14083e367f9SBreno Leitao } 14183e367f9SBreno Leitao } 14283e367f9SBreno Leitao 14383e367f9SBreno Leitao if (one_in_chance(20)) { 14483e367f9SBreno Leitao /* Nested transaction start */ 14583e367f9SBreno Leitao if (one_in_chance(5)) 14683e367f9SBreno Leitao mess_with_tm(); 14783e367f9SBreno Leitao 14883e367f9SBreno Leitao /* Return without changing any other context info */ 14983e367f9SBreno Leitao return; 15083e367f9SBreno Leitao } 15183e367f9SBreno Leitao 15283e367f9SBreno Leitao if (one_in_chance(10)) 15383e367f9SBreno Leitao ucp->uc_mcontext.gp_regs[PT_MSR] = random(); 15483e367f9SBreno Leitao if (one_in_chance(10)) 15583e367f9SBreno Leitao ucp->uc_mcontext.gp_regs[PT_NIP] = random(); 15683e367f9SBreno Leitao if (one_in_chance(10)) 15783e367f9SBreno Leitao ucp->uc_link->uc_mcontext.gp_regs[PT_MSR] = random(); 15883e367f9SBreno Leitao if (one_in_chance(10)) 15983e367f9SBreno Leitao ucp->uc_link->uc_mcontext.gp_regs[PT_NIP] = random(); 16083e367f9SBreno Leitao 16183e367f9SBreno Leitao ucp->uc_mcontext.gp_regs[PT_TRAP] = random(); 16283e367f9SBreno Leitao ucp->uc_mcontext.gp_regs[PT_DSISR] = random(); 16383e367f9SBreno Leitao ucp->uc_mcontext.gp_regs[PT_DAR] = random(); 16483e367f9SBreno Leitao ucp->uc_mcontext.gp_regs[PT_ORIG_R3] = random(); 16583e367f9SBreno Leitao ucp->uc_mcontext.gp_regs[PT_XER] = random(); 16683e367f9SBreno Leitao ucp->uc_mcontext.gp_regs[PT_RESULT] = random(); 16783e367f9SBreno Leitao ucp->uc_mcontext.gp_regs[PT_SOFTE] = random(); 16883e367f9SBreno Leitao ucp->uc_mcontext.gp_regs[PT_DSCR] = random(); 16983e367f9SBreno Leitao ucp->uc_mcontext.gp_regs[PT_CTR] = random(); 17083e367f9SBreno Leitao ucp->uc_mcontext.gp_regs[PT_LNK] = random(); 17183e367f9SBreno Leitao ucp->uc_mcontext.gp_regs[PT_CCR] = random(); 17283e367f9SBreno Leitao ucp->uc_mcontext.gp_regs[PT_REGS_COUNT] = random(); 17383e367f9SBreno Leitao 17483e367f9SBreno Leitao ucp->uc_link->uc_mcontext.gp_regs[PT_TRAP] = random(); 17583e367f9SBreno Leitao ucp->uc_link->uc_mcontext.gp_regs[PT_DSISR] = random(); 17683e367f9SBreno Leitao ucp->uc_link->uc_mcontext.gp_regs[PT_DAR] = random(); 17783e367f9SBreno Leitao ucp->uc_link->uc_mcontext.gp_regs[PT_ORIG_R3] = random(); 17883e367f9SBreno Leitao ucp->uc_link->uc_mcontext.gp_regs[PT_XER] = random(); 17983e367f9SBreno Leitao ucp->uc_link->uc_mcontext.gp_regs[PT_RESULT] = random(); 18083e367f9SBreno Leitao ucp->uc_link->uc_mcontext.gp_regs[PT_SOFTE] = random(); 18183e367f9SBreno Leitao ucp->uc_link->uc_mcontext.gp_regs[PT_DSCR] = random(); 18283e367f9SBreno Leitao ucp->uc_link->uc_mcontext.gp_regs[PT_CTR] = random(); 18383e367f9SBreno Leitao ucp->uc_link->uc_mcontext.gp_regs[PT_LNK] = random(); 18483e367f9SBreno Leitao ucp->uc_link->uc_mcontext.gp_regs[PT_CCR] = random(); 18583e367f9SBreno Leitao ucp->uc_link->uc_mcontext.gp_regs[PT_REGS_COUNT] = random(); 18683e367f9SBreno Leitao 18783e367f9SBreno Leitao if (args & ARG_MESS_WITH_TM_BEFORE) { 18883e367f9SBreno Leitao if (one_in_chance(2)) 18983e367f9SBreno Leitao mess_with_tm(); 19083e367f9SBreno Leitao } 19183e367f9SBreno Leitao } 19283e367f9SBreno Leitao 19383e367f9SBreno Leitao static void seg_signal_handler(int signo, siginfo_t *si, void *uc) 19483e367f9SBreno Leitao { 19583e367f9SBreno Leitao /* Clear exit for process that segfaults */ 19683e367f9SBreno Leitao exit(0); 19783e367f9SBreno Leitao } 19883e367f9SBreno Leitao 19983e367f9SBreno Leitao static void *sigfuz_test(void *thrid) 20083e367f9SBreno Leitao { 20183e367f9SBreno Leitao struct sigaction trap_sa, seg_sa; 20283e367f9SBreno Leitao int ret, i = 0; 20383e367f9SBreno Leitao pid_t t; 20483e367f9SBreno Leitao 20583e367f9SBreno Leitao tmp_uc = malloc(sizeof(ucontext_t)); 20683e367f9SBreno Leitao 20783e367f9SBreno Leitao /* Main signal handler */ 20883e367f9SBreno Leitao trap_sa.sa_flags = SA_SIGINFO; 20983e367f9SBreno Leitao trap_sa.sa_sigaction = trap_signal_handler; 21083e367f9SBreno Leitao 21183e367f9SBreno Leitao /* SIGSEGV signal handler */ 21283e367f9SBreno Leitao seg_sa.sa_flags = SA_SIGINFO; 21383e367f9SBreno Leitao seg_sa.sa_sigaction = seg_signal_handler; 21483e367f9SBreno Leitao 21583e367f9SBreno Leitao /* The signal handler will enable MSR_TS */ 21683e367f9SBreno Leitao sigaction(SIGUSR1, &trap_sa, NULL); 21783e367f9SBreno Leitao 21883e367f9SBreno Leitao /* If it does not crash, it will segfault, avoid it to retest */ 21983e367f9SBreno Leitao sigaction(SIGSEGV, &seg_sa, NULL); 22083e367f9SBreno Leitao 22183e367f9SBreno Leitao while (i < count_max) { 22283e367f9SBreno Leitao t = fork(); 22383e367f9SBreno Leitao 22483e367f9SBreno Leitao if (t == 0) { 22583e367f9SBreno Leitao /* Once seed per process */ 22683e367f9SBreno Leitao srand(time(NULL) + getpid()); 22783e367f9SBreno Leitao if (args & ARG_MESS_WITH_TM_AT) { 22883e367f9SBreno Leitao if (one_in_chance(2)) 22983e367f9SBreno Leitao mess_with_tm(); 23083e367f9SBreno Leitao } 23183e367f9SBreno Leitao raise(SIGUSR1); 23283e367f9SBreno Leitao exit(0); 23383e367f9SBreno Leitao } else { 23483e367f9SBreno Leitao waitpid(t, &ret, 0); 23583e367f9SBreno Leitao } 23683e367f9SBreno Leitao if (!(args & ARG_FOREVER)) 23783e367f9SBreno Leitao i++; 23883e367f9SBreno Leitao } 23983e367f9SBreno Leitao 24083e367f9SBreno Leitao /* If not freed already, free now */ 24183e367f9SBreno Leitao if (tmp_uc) { 24283e367f9SBreno Leitao free(tmp_uc); 24383e367f9SBreno Leitao tmp_uc = NULL; 24483e367f9SBreno Leitao } 24583e367f9SBreno Leitao 24683e367f9SBreno Leitao return NULL; 24783e367f9SBreno Leitao } 24883e367f9SBreno Leitao 24983e367f9SBreno Leitao static int signal_fuzzer(void) 25083e367f9SBreno Leitao { 25183e367f9SBreno Leitao int t, rc; 25283e367f9SBreno Leitao pthread_t *threads; 25383e367f9SBreno Leitao 25483e367f9SBreno Leitao threads = malloc(nthread * sizeof(pthread_t)); 25583e367f9SBreno Leitao 25683e367f9SBreno Leitao for (t = 0; t < nthread; t++) { 25783e367f9SBreno Leitao rc = pthread_create(&threads[t], NULL, sigfuz_test, 25883e367f9SBreno Leitao (void *)&t); 25983e367f9SBreno Leitao if (rc) 26083e367f9SBreno Leitao perror("Thread creation error\n"); 26183e367f9SBreno Leitao } 26283e367f9SBreno Leitao 26383e367f9SBreno Leitao for (t = 0; t < nthread; t++) { 26483e367f9SBreno Leitao rc = pthread_join(threads[t], NULL); 26583e367f9SBreno Leitao if (rc) 26683e367f9SBreno Leitao perror("Thread join error\n"); 26783e367f9SBreno Leitao } 26883e367f9SBreno Leitao 26983e367f9SBreno Leitao free(threads); 27083e367f9SBreno Leitao 27183e367f9SBreno Leitao return EXIT_SUCCESS; 27283e367f9SBreno Leitao } 27383e367f9SBreno Leitao 27483e367f9SBreno Leitao static void show_help(char *name) 27583e367f9SBreno Leitao { 27683e367f9SBreno Leitao printf("%s: Sigfuzzer for powerpc\n", name); 27783e367f9SBreno Leitao printf("Usage:\n"); 27883e367f9SBreno Leitao printf("\t-b\t Mess with TM before raising a SIGUSR1 signal\n"); 27983e367f9SBreno Leitao printf("\t-a\t Mess with TM after raising a SIGUSR1 signal\n"); 28083e367f9SBreno Leitao printf("\t-m\t Mess with MSR[TS] bits at mcontext\n"); 28183e367f9SBreno Leitao printf("\t-x\t Mess with everything above\n"); 28283e367f9SBreno Leitao printf("\t-f\t Run forever (Press ^C to Quit)\n"); 28383e367f9SBreno Leitao printf("\t-i\t Amount of interactions. (Default = %d)\n", COUNT_MAX); 28483e367f9SBreno Leitao printf("\t-t\t Amount of threads. (Default = %d)\n", THREADS); 28583e367f9SBreno Leitao exit(-1); 28683e367f9SBreno Leitao } 28783e367f9SBreno Leitao 28883e367f9SBreno Leitao int main(int argc, char **argv) 28983e367f9SBreno Leitao { 29083e367f9SBreno Leitao int opt; 29183e367f9SBreno Leitao 29283e367f9SBreno Leitao while ((opt = getopt(argc, argv, "bamxt:fi:h")) != -1) { 29383e367f9SBreno Leitao if (opt == 'b') { 29483e367f9SBreno Leitao printf("Mess with TM before signal\n"); 29583e367f9SBreno Leitao args |= ARG_MESS_WITH_TM_BEFORE; 29683e367f9SBreno Leitao } else if (opt == 'a') { 29783e367f9SBreno Leitao printf("Mess with TM at signal handler\n"); 29883e367f9SBreno Leitao args |= ARG_MESS_WITH_TM_AT; 29983e367f9SBreno Leitao } else if (opt == 'm') { 30083e367f9SBreno Leitao printf("Mess with MSR[TS] bits in mcontext\n"); 30183e367f9SBreno Leitao args |= ARG_MESS_WITH_MSR_AT; 30283e367f9SBreno Leitao } else if (opt == 'x') { 30383e367f9SBreno Leitao printf("Running with all options enabled\n"); 30483e367f9SBreno Leitao args |= ARG_COMPLETE; 30583e367f9SBreno Leitao } else if (opt == 't') { 30683e367f9SBreno Leitao nthread = atoi(optarg); 30783e367f9SBreno Leitao printf("Threads = %d\n", nthread); 30883e367f9SBreno Leitao } else if (opt == 'f') { 30983e367f9SBreno Leitao args |= ARG_FOREVER; 31083e367f9SBreno Leitao printf("Press ^C to stop\n"); 31183e367f9SBreno Leitao test_harness_set_timeout(-1); 31283e367f9SBreno Leitao } else if (opt == 'i') { 31383e367f9SBreno Leitao count_max = atoi(optarg); 31483e367f9SBreno Leitao printf("Running for %d interactions\n", count_max); 31583e367f9SBreno Leitao } else if (opt == 'h') { 31683e367f9SBreno Leitao show_help(argv[0]); 31783e367f9SBreno Leitao } 31883e367f9SBreno Leitao } 31983e367f9SBreno Leitao 32083e367f9SBreno Leitao /* Default test suite */ 32183e367f9SBreno Leitao if (!args) 32283e367f9SBreno Leitao args = ARG_COMPLETE; 32383e367f9SBreno Leitao 32483e367f9SBreno Leitao test_harness(signal_fuzzer, "signal_fuzzer"); 32583e367f9SBreno Leitao } 326