root/tools/testing/selftests/powerpc/signal/sigfuz.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. one_in_chance
  2. mess_with_tm
  3. trap_signal_handler
  4. seg_signal_handler
  5. sigfuz_test
  6. signal_fuzzer
  7. show_help
  8. main

   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 
  32 #include <stdio.h>
  33 #include <limits.h>
  34 #include <sys/wait.h>
  35 #include <unistd.h>
  36 #include <stdlib.h>
  37 #include <signal.h>
  38 #include <string.h>
  39 #include <ucontext.h>
  40 #include <sys/mman.h>
  41 #include <pthread.h>
  42 #include "utils.h"
  43 
  44 /* Selftest defaults */
  45 #define COUNT_MAX       4000            /* Number of interactions */
  46 #define THREADS         16              /* Number of threads */
  47 
  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 |       \
  55                                 ARG_MESS_WITH_MSR_AT)
  56 
  57 static int args;
  58 static int nthread = THREADS;
  59 static int count_max = COUNT_MAX;
  60 
  61 /* checkpoint context */
  62 static ucontext_t *tmp_uc;
  63 
  64 /* Return true with 1/x probability */
  65 static int one_in_chance(int x)
  66 {
  67         return rand() % x == 0;
  68 }
  69 
  70 /* Change TM states */
  71 static void mess_with_tm(void)
  72 {
  73         /* Starts a transaction 33% of the time */
  74         if (one_in_chance(3)) {
  75                 asm ("tbegin.   ;"
  76                      "beq 8     ;");
  77 
  78                 /* And suspended half of them */
  79                 if (one_in_chance(2))
  80                         asm("tsuspend.  ;");
  81         }
  82 
  83         /* Call 'tend' in 5% of the runs */
  84         if (one_in_chance(20))
  85                 asm("tend.      ;");
  86 }
  87 
  88 /* Signal handler that will be invoked with raise() */
  89 static void trap_signal_handler(int signo, siginfo_t *si, void *uc)
  90 {
  91         ucontext_t *ucp = uc;
  92 
  93         ucp->uc_link = tmp_uc;
  94 
  95         /*
  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
 100          */
 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)) {
 106                 if (tmp_uc) {
 107                         free(tmp_uc);
 108                         tmp_uc = NULL;
 109                 }
 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);
 114         }
 115 
 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;
 120                 } else {
 121                         if (one_in_chance(2)) {
 122                                 ucp->uc_link->uc_mcontext.gp_regs[PT_MSR] |=
 123                                                  MSR_TS_T;
 124                         } else if (one_in_chance(2)) {
 125                                 ucp->uc_link->uc_mcontext.gp_regs[PT_MSR] |=
 126                                                 MSR_TS_T | MSR_TS_S;
 127                         }
 128                 }
 129 
 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] |=
 136                                         MSR_TS_T;
 137                         else if (one_in_chance(2))
 138                                 ucp->uc_mcontext.gp_regs[PT_MSR] |=
 139                                         MSR_TS_T | MSR_TS_S;
 140                 }
 141         }
 142 
 143         if (one_in_chance(20)) {
 144                 /* Nested transaction start */
 145                 if (one_in_chance(5))
 146                         mess_with_tm();
 147 
 148                 /* Return without changing any other context info */
 149                 return;
 150         }
 151 
 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();
 160 
 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();
 173 
 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();
 186 
 187         if (args & ARG_MESS_WITH_TM_BEFORE) {
 188                 if (one_in_chance(2))
 189                         mess_with_tm();
 190         }
 191 }
 192 
 193 static void seg_signal_handler(int signo, siginfo_t *si, void *uc)
 194 {
 195         /* Clear exit for process that segfaults */
 196         exit(0);
 197 }
 198 
 199 static void *sigfuz_test(void *thrid)
 200 {
 201         struct sigaction trap_sa, seg_sa;
 202         int ret, i = 0;
 203         pid_t t;
 204 
 205         tmp_uc = malloc(sizeof(ucontext_t));
 206 
 207         /* Main signal handler */
 208         trap_sa.sa_flags = SA_SIGINFO;
 209         trap_sa.sa_sigaction = trap_signal_handler;
 210 
 211         /* SIGSEGV signal handler */
 212         seg_sa.sa_flags = SA_SIGINFO;
 213         seg_sa.sa_sigaction = seg_signal_handler;
 214 
 215         /* The signal handler will enable MSR_TS */
 216         sigaction(SIGUSR1, &trap_sa, NULL);
 217 
 218         /* If it does not crash, it will segfault, avoid it to retest */
 219         sigaction(SIGSEGV, &seg_sa, NULL);
 220 
 221         while (i < count_max) {
 222                 t = fork();
 223 
 224                 if (t == 0) {
 225                         /* Once seed per process */
 226                         srand(time(NULL) + getpid());
 227                         if (args & ARG_MESS_WITH_TM_AT) {
 228                                 if (one_in_chance(2))
 229                                         mess_with_tm();
 230                         }
 231                         raise(SIGUSR1);
 232                         exit(0);
 233                 } else {
 234                         waitpid(t, &ret, 0);
 235                 }
 236                 if (!(args & ARG_FOREVER))
 237                         i++;
 238         }
 239 
 240         /* If not freed already, free now */
 241         if (tmp_uc) {
 242                 free(tmp_uc);
 243                 tmp_uc = NULL;
 244         }
 245 
 246         return NULL;
 247 }
 248 
 249 static int signal_fuzzer(void)
 250 {
 251         int t, rc;
 252         pthread_t *threads;
 253 
 254         threads = malloc(nthread * sizeof(pthread_t));
 255 
 256         for (t = 0; t < nthread; t++) {
 257                 rc = pthread_create(&threads[t], NULL, sigfuz_test,
 258                                     (void *)&t);
 259                 if (rc)
 260                         perror("Thread creation error\n");
 261         }
 262 
 263         for (t = 0; t < nthread; t++) {
 264                 rc = pthread_join(threads[t], NULL);
 265                 if (rc)
 266                         perror("Thread join error\n");
 267         }
 268 
 269         free(threads);
 270 
 271         return EXIT_SUCCESS;
 272 }
 273 
 274 static void show_help(char *name)
 275 {
 276         printf("%s: Sigfuzzer for powerpc\n", name);
 277         printf("Usage:\n");
 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);
 285         exit(-1);
 286 }
 287 
 288 int main(int argc, char **argv)
 289 {
 290         int opt;
 291 
 292         while ((opt = getopt(argc, argv, "bamxt:fi:h")) != -1) {
 293                 if (opt == 'b') {
 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') {
 309                         args |= ARG_FOREVER;
 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') {
 316                         show_help(argv[0]);
 317                 }
 318         }
 319 
 320         /* Default test suite */
 321         if (!args)
 322                 args = ARG_COMPLETE;
 323 
 324         test_harness(signal_fuzzer, "signal_fuzzer");
 325 }

/* [<][>][^][v][top][bottom][index][help] */