brintos

brintos / linux-shallow public Read only

0
0
Text · 8.7 KiB · 08f9afe Raw
326 lines · c
1// SPDX-License-Identifier: GPL-2.02/*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 set9 * of different ways, trying to create different scenario for testing10 * purpose.11 *12 * This test works raising a signal and calling sigreturn interleaved with13 * TM operations, as starting, suspending and terminating a transaction. The14 * test depends on random numbers, and, based on them, it sets different TM15 * states.16 *17 * Other than that, the test fills out the user context struct that is passed18 * to the sigreturn system call with random data, in order to make sure that19 * the signal handler syscall can handle different and invalid states20 * properly.21 *22 * This selftest has command line parameters to control what kind of tests the23 * user wants to run, as for example, if a transaction should be started prior24 * to signal being raised, or, after the signal being raised and before the25 * 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 set28 * properly by the kernel. Its purpose, at this time, is basically29 * 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	600		/* Number of interactions */46#define THREADS		16		/* Number of threads */47 48/* Arguments options */49#define ARG_MESS_WITH_TM_AT	0x150#define ARG_MESS_WITH_TM_BEFORE	0x251#define ARG_MESS_WITH_MSR_AT	0x452#define ARG_FOREVER		0x1053#define ARG_COMPLETE		(ARG_MESS_WITH_TM_AT |		\54				ARG_MESS_WITH_TM_BEFORE |	\55				ARG_MESS_WITH_MSR_AT)56 57static int args;58static int nthread = THREADS;59static int count_max = COUNT_MAX;60 61/* checkpoint context */62static ucontext_t *tmp_uc;63 64/* Return true with 1/x probability */65static int one_in_chance(int x)66{67	return rand() % x == 0;68}69 70/* Change TM states */71static 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() */89static 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 chunk98	 *  - Cloning ucp into uc_link99	 *  - Allocating a new memory chunk100	 */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 193static void seg_signal_handler(int signo, siginfo_t *si, void *uc)194{195	/* Clear exit for process that segfaults */196	exit(0);197}198 199static 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 249static 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 274static 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 288int 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}326