Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright 2018, Breno Leitao, IBM Corp.
0004  * Licensed under GPLv2.
0005  *
0006  * Sigfuz(tm): A PowerPC TM-aware signal fuzzer.
0007  *
0008  * This is a new selftest that raises SIGUSR1 signals and handles it in a set
0009  * of different ways, trying to create different scenario for testing
0010  * purpose.
0011  *
0012  * This test works raising a signal and calling sigreturn interleaved with
0013  * TM operations, as starting, suspending and terminating a transaction. The
0014  * test depends on random numbers, and, based on them, it sets different TM
0015  * states.
0016  *
0017  * Other than that, the test fills out the user context struct that is passed
0018  * to the sigreturn system call with random data, in order to make sure that
0019  * the signal handler syscall can handle different and invalid states
0020  * properly.
0021  *
0022  * This selftest has command line parameters to control what kind of tests the
0023  * user wants to run, as for example, if a transaction should be started prior
0024  * to signal being raised, or, after the signal being raised and before the
0025  * sigreturn. If no parameter is given, the default is enabling all options.
0026  *
0027  * This test does not check if the user context is being read and set
0028  * properly by the kernel. Its purpose, at this time, is basically
0029  * guaranteeing that the kernel does not crash on invalid scenarios.
0030  */
0031 
0032 #include <stdio.h>
0033 #include <limits.h>
0034 #include <sys/wait.h>
0035 #include <unistd.h>
0036 #include <stdlib.h>
0037 #include <signal.h>
0038 #include <string.h>
0039 #include <ucontext.h>
0040 #include <sys/mman.h>
0041 #include <pthread.h>
0042 #include "utils.h"
0043 
0044 /* Selftest defaults */
0045 #define COUNT_MAX   600     /* Number of interactions */
0046 #define THREADS     16      /* Number of threads */
0047 
0048 /* Arguments options */
0049 #define ARG_MESS_WITH_TM_AT 0x1
0050 #define ARG_MESS_WITH_TM_BEFORE 0x2
0051 #define ARG_MESS_WITH_MSR_AT    0x4
0052 #define ARG_FOREVER     0x10
0053 #define ARG_COMPLETE        (ARG_MESS_WITH_TM_AT |      \
0054                 ARG_MESS_WITH_TM_BEFORE |   \
0055                 ARG_MESS_WITH_MSR_AT)
0056 
0057 static int args;
0058 static int nthread = THREADS;
0059 static int count_max = COUNT_MAX;
0060 
0061 /* checkpoint context */
0062 static ucontext_t *tmp_uc;
0063 
0064 /* Return true with 1/x probability */
0065 static int one_in_chance(int x)
0066 {
0067     return rand() % x == 0;
0068 }
0069 
0070 /* Change TM states */
0071 static void mess_with_tm(void)
0072 {
0073     /* Starts a transaction 33% of the time */
0074     if (one_in_chance(3)) {
0075         asm ("tbegin.   ;"
0076              "beq 8 ;");
0077 
0078         /* And suspended half of them */
0079         if (one_in_chance(2))
0080             asm("tsuspend.  ;");
0081     }
0082 
0083     /* Call 'tend' in 5% of the runs */
0084     if (one_in_chance(20))
0085         asm("tend.  ;");
0086 }
0087 
0088 /* Signal handler that will be invoked with raise() */
0089 static void trap_signal_handler(int signo, siginfo_t *si, void *uc)
0090 {
0091     ucontext_t *ucp = uc;
0092 
0093     ucp->uc_link = tmp_uc;
0094 
0095     /*
0096      * Set uc_link in three possible ways:
0097      *  - Setting a single 'int' in the whole chunk
0098      *  - Cloning ucp into uc_link
0099      *  - Allocating a new memory chunk
0100      */
0101     if (one_in_chance(3)) {
0102         memset(ucp->uc_link, rand(), sizeof(ucontext_t));
0103     } else if (one_in_chance(2)) {
0104         memcpy(ucp->uc_link, uc, sizeof(ucontext_t));
0105     } else if (one_in_chance(2)) {
0106         if (tmp_uc) {
0107             free(tmp_uc);
0108             tmp_uc = NULL;
0109         }
0110         tmp_uc = malloc(sizeof(ucontext_t));
0111         ucp->uc_link = tmp_uc;
0112         /* Trying to cause a major page fault at Kernel level */
0113         madvise(ucp->uc_link, sizeof(ucontext_t), MADV_DONTNEED);
0114     }
0115 
0116     if (args & ARG_MESS_WITH_MSR_AT) {
0117         /* Changing the checkpointed registers */
0118         if (one_in_chance(4)) {
0119             ucp->uc_link->uc_mcontext.gp_regs[PT_MSR] |= MSR_TS_S;
0120         } else {
0121             if (one_in_chance(2)) {
0122                 ucp->uc_link->uc_mcontext.gp_regs[PT_MSR] |=
0123                          MSR_TS_T;
0124             } else if (one_in_chance(2)) {
0125                 ucp->uc_link->uc_mcontext.gp_regs[PT_MSR] |=
0126                         MSR_TS_T | MSR_TS_S;
0127             }
0128         }
0129 
0130         /* Checking the current register context */
0131         if (one_in_chance(2)) {
0132             ucp->uc_mcontext.gp_regs[PT_MSR] |= MSR_TS_S;
0133         } else if (one_in_chance(2)) {
0134             if (one_in_chance(2))
0135                 ucp->uc_mcontext.gp_regs[PT_MSR] |=
0136                     MSR_TS_T;
0137             else if (one_in_chance(2))
0138                 ucp->uc_mcontext.gp_regs[PT_MSR] |=
0139                     MSR_TS_T | MSR_TS_S;
0140         }
0141     }
0142 
0143     if (one_in_chance(20)) {
0144         /* Nested transaction start */
0145         if (one_in_chance(5))
0146             mess_with_tm();
0147 
0148         /* Return without changing any other context info */
0149         return;
0150     }
0151 
0152     if (one_in_chance(10))
0153         ucp->uc_mcontext.gp_regs[PT_MSR] = random();
0154     if (one_in_chance(10))
0155         ucp->uc_mcontext.gp_regs[PT_NIP] = random();
0156     if (one_in_chance(10))
0157         ucp->uc_link->uc_mcontext.gp_regs[PT_MSR] = random();
0158     if (one_in_chance(10))
0159         ucp->uc_link->uc_mcontext.gp_regs[PT_NIP] = random();
0160 
0161     ucp->uc_mcontext.gp_regs[PT_TRAP] = random();
0162     ucp->uc_mcontext.gp_regs[PT_DSISR] = random();
0163     ucp->uc_mcontext.gp_regs[PT_DAR] = random();
0164     ucp->uc_mcontext.gp_regs[PT_ORIG_R3] = random();
0165     ucp->uc_mcontext.gp_regs[PT_XER] = random();
0166     ucp->uc_mcontext.gp_regs[PT_RESULT] = random();
0167     ucp->uc_mcontext.gp_regs[PT_SOFTE] = random();
0168     ucp->uc_mcontext.gp_regs[PT_DSCR] = random();
0169     ucp->uc_mcontext.gp_regs[PT_CTR] = random();
0170     ucp->uc_mcontext.gp_regs[PT_LNK] = random();
0171     ucp->uc_mcontext.gp_regs[PT_CCR] = random();
0172     ucp->uc_mcontext.gp_regs[PT_REGS_COUNT] = random();
0173 
0174     ucp->uc_link->uc_mcontext.gp_regs[PT_TRAP] = random();
0175     ucp->uc_link->uc_mcontext.gp_regs[PT_DSISR] = random();
0176     ucp->uc_link->uc_mcontext.gp_regs[PT_DAR] = random();
0177     ucp->uc_link->uc_mcontext.gp_regs[PT_ORIG_R3] = random();
0178     ucp->uc_link->uc_mcontext.gp_regs[PT_XER] = random();
0179     ucp->uc_link->uc_mcontext.gp_regs[PT_RESULT] = random();
0180     ucp->uc_link->uc_mcontext.gp_regs[PT_SOFTE] = random();
0181     ucp->uc_link->uc_mcontext.gp_regs[PT_DSCR] = random();
0182     ucp->uc_link->uc_mcontext.gp_regs[PT_CTR] = random();
0183     ucp->uc_link->uc_mcontext.gp_regs[PT_LNK] = random();
0184     ucp->uc_link->uc_mcontext.gp_regs[PT_CCR] = random();
0185     ucp->uc_link->uc_mcontext.gp_regs[PT_REGS_COUNT] = random();
0186 
0187     if (args & ARG_MESS_WITH_TM_BEFORE) {
0188         if (one_in_chance(2))
0189             mess_with_tm();
0190     }
0191 }
0192 
0193 static void seg_signal_handler(int signo, siginfo_t *si, void *uc)
0194 {
0195     /* Clear exit for process that segfaults */
0196     exit(0);
0197 }
0198 
0199 static void *sigfuz_test(void *thrid)
0200 {
0201     struct sigaction trap_sa, seg_sa;
0202     int ret, i = 0;
0203     pid_t t;
0204 
0205     tmp_uc = malloc(sizeof(ucontext_t));
0206 
0207     /* Main signal handler */
0208     trap_sa.sa_flags = SA_SIGINFO;
0209     trap_sa.sa_sigaction = trap_signal_handler;
0210 
0211     /* SIGSEGV signal handler */
0212     seg_sa.sa_flags = SA_SIGINFO;
0213     seg_sa.sa_sigaction = seg_signal_handler;
0214 
0215     /* The signal handler will enable MSR_TS */
0216     sigaction(SIGUSR1, &trap_sa, NULL);
0217 
0218     /* If it does not crash, it will segfault, avoid it to retest */
0219     sigaction(SIGSEGV, &seg_sa, NULL);
0220 
0221     while (i < count_max) {
0222         t = fork();
0223 
0224         if (t == 0) {
0225             /* Once seed per process */
0226             srand(time(NULL) + getpid());
0227             if (args & ARG_MESS_WITH_TM_AT) {
0228                 if (one_in_chance(2))
0229                     mess_with_tm();
0230             }
0231             raise(SIGUSR1);
0232             exit(0);
0233         } else {
0234             waitpid(t, &ret, 0);
0235         }
0236         if (!(args & ARG_FOREVER))
0237             i++;
0238     }
0239 
0240     /* If not freed already, free now */
0241     if (tmp_uc) {
0242         free(tmp_uc);
0243         tmp_uc = NULL;
0244     }
0245 
0246     return NULL;
0247 }
0248 
0249 static int signal_fuzzer(void)
0250 {
0251     int t, rc;
0252     pthread_t *threads;
0253 
0254     threads = malloc(nthread * sizeof(pthread_t));
0255 
0256     for (t = 0; t < nthread; t++) {
0257         rc = pthread_create(&threads[t], NULL, sigfuz_test,
0258                     (void *)&t);
0259         if (rc)
0260             perror("Thread creation error\n");
0261     }
0262 
0263     for (t = 0; t < nthread; t++) {
0264         rc = pthread_join(threads[t], NULL);
0265         if (rc)
0266             perror("Thread join error\n");
0267     }
0268 
0269     free(threads);
0270 
0271     return EXIT_SUCCESS;
0272 }
0273 
0274 static void show_help(char *name)
0275 {
0276     printf("%s: Sigfuzzer for powerpc\n", name);
0277     printf("Usage:\n");
0278     printf("\t-b\t Mess with TM before raising a SIGUSR1 signal\n");
0279     printf("\t-a\t Mess with TM after raising a SIGUSR1 signal\n");
0280     printf("\t-m\t Mess with MSR[TS] bits at mcontext\n");
0281     printf("\t-x\t Mess with everything above\n");
0282     printf("\t-f\t Run forever (Press ^C to Quit)\n");
0283     printf("\t-i\t Amount of interactions.  (Default = %d)\n", COUNT_MAX);
0284     printf("\t-t\t Amount of threads.   (Default = %d)\n", THREADS);
0285     exit(-1);
0286 }
0287 
0288 int main(int argc, char **argv)
0289 {
0290     int opt;
0291 
0292     while ((opt = getopt(argc, argv, "bamxt:fi:h")) != -1) {
0293         if (opt == 'b') {
0294             printf("Mess with TM before signal\n");
0295             args |= ARG_MESS_WITH_TM_BEFORE;
0296         } else if (opt == 'a') {
0297             printf("Mess with TM at signal handler\n");
0298             args |= ARG_MESS_WITH_TM_AT;
0299         } else if (opt == 'm') {
0300             printf("Mess with MSR[TS] bits in mcontext\n");
0301             args |= ARG_MESS_WITH_MSR_AT;
0302         } else if (opt == 'x') {
0303             printf("Running with all options enabled\n");
0304             args |= ARG_COMPLETE;
0305         } else if (opt == 't') {
0306             nthread = atoi(optarg);
0307             printf("Threads = %d\n", nthread);
0308         } else if (opt == 'f') {
0309             args |= ARG_FOREVER;
0310             printf("Press ^C to stop\n");
0311             test_harness_set_timeout(-1);
0312         } else if (opt == 'i') {
0313             count_max = atoi(optarg);
0314             printf("Running for %d interactions\n", count_max);
0315         } else if (opt == 'h') {
0316             show_help(argv[0]);
0317         }
0318     }
0319 
0320     /* Default test suite */
0321     if (!args)
0322         args = ARG_COMPLETE;
0323 
0324     test_harness(signal_fuzzer, "signal_fuzzer");
0325 }