// SPDX-License-Identifier: GPL-2.0 /* * Copyright 2018, Breno Leitao, IBM Corp. * Licensed under GPLv2. * * Sigfuz(tm): A PowerPC TM-aware signal fuzzer. * * This is a new selftest that raises SIGUSR1 signals and handles it in a set * of different ways, trying to create different scenario for testing * purpose. * * This test works raising a signal and calling sigreturn interleaved with * TM operations, as starting, suspending and terminating a transaction. The * test depends on random numbers, and, based on them, it sets different TM * states. * * Other than that, the test fills out the user context struct that is passed * to the sigreturn system call with random data, in order to make sure that * the signal handler syscall can handle different and invalid states * properly. * * This selftest has command line parameters to control what kind of tests the * user wants to run, as for example, if a transaction should be started prior * to signal being raised, or, after the signal being raised and before the * sigreturn. If no parameter is given, the default is enabling all options. * * This test does not check if the user context is being read and set * properly by the kernel. Its purpose, at this time, is basically * guaranteeing that the kernel does not crash on invalid scenarios.
*/
/* Return true with 1/x probability */ staticint one_in_chance(int x)
{ return rand() % x == 0;
}
/* Change TM states */ staticvoid mess_with_tm(void)
{ /* Starts a transaction 33% of the time */ if (one_in_chance(3)) { asm ("tbegin. ;" "beq 8 ;");
/* And suspended half of them */ if (one_in_chance(2)) asm("tsuspend. ;");
}
/* Call 'tend' in 5% of the runs */ if (one_in_chance(20)) asm("tend. ;");
}
/* Signal handler that will be invoked with raise() */ staticvoid trap_signal_handler(int signo, siginfo_t *si, void *uc)
{
ucontext_t *ucp = uc;
ucp->uc_link = tmp_uc;
/* * Set uc_link in three possible ways: * - Setting a single 'int' in the whole chunk * - Cloning ucp into uc_link * - Allocating a new memory chunk
*/ if (one_in_chance(3)) {
memset(ucp->uc_link, rand(), sizeof(ucontext_t));
} elseif (one_in_chance(2)) {
memcpy(ucp->uc_link, uc, sizeof(ucontext_t));
} elseif (one_in_chance(2)) { if (tmp_uc) {
free(tmp_uc);
tmp_uc = NULL;
}
tmp_uc = malloc(sizeof(ucontext_t));
ucp->uc_link = tmp_uc; /* Trying to cause a major page fault at Kernel level */
madvise(ucp->uc_link, sizeof(ucontext_t), MADV_DONTNEED);
}
if (args & ARG_MESS_WITH_MSR_AT) { /* Changing the checkpointed registers */ if (one_in_chance(4)) {
ucp->uc_link->uc_mcontext.gp_regs[PT_MSR] |= MSR_TS_S;
} else { if (one_in_chance(2)) {
ucp->uc_link->uc_mcontext.gp_regs[PT_MSR] |=
MSR_TS_T;
} elseif (one_in_chance(2)) {
ucp->uc_link->uc_mcontext.gp_regs[PT_MSR] |=
MSR_TS_T | MSR_TS_S;
}
}
/* Checking the current register context */ if (one_in_chance(2)) {
ucp->uc_mcontext.gp_regs[PT_MSR] |= MSR_TS_S;
} elseif (one_in_chance(2)) { if (one_in_chance(2))
ucp->uc_mcontext.gp_regs[PT_MSR] |=
MSR_TS_T; elseif (one_in_chance(2))
ucp->uc_mcontext.gp_regs[PT_MSR] |=
MSR_TS_T | MSR_TS_S;
}
}
if (one_in_chance(20)) { /* Nested transaction start */ if (one_in_chance(5))
mess_with_tm();
/* Return without changing any other context info */ return;
}
if (one_in_chance(10))
ucp->uc_mcontext.gp_regs[PT_MSR] = random(); if (one_in_chance(10))
ucp->uc_mcontext.gp_regs[PT_NIP] = random(); if (one_in_chance(10))
ucp->uc_link->uc_mcontext.gp_regs[PT_MSR] = random(); if (one_in_chance(10))
ucp->uc_link->uc_mcontext.gp_regs[PT_NIP] = random();
/* The signal handler will enable MSR_TS */
sigaction(SIGUSR1, &trap_sa, NULL);
/* If it does not crash, it will segfault, avoid it to retest */
sigaction(SIGSEGV, &seg_sa, NULL);
while (i < count_max) {
t = fork();
if (t == 0) { /* Once seed per process */
srand(time(NULL) + getpid()); if (args & ARG_MESS_WITH_TM_AT) { if (one_in_chance(2))
mess_with_tm();
}
raise(SIGUSR1); exit(0);
} else {
waitpid(t, &ret, 0);
} if (!(args & ARG_FOREVER))
i++;
}
/* If not freed already, free now */ if (tmp_uc) {
free(tmp_uc);
tmp_uc = NULL;
}
return NULL;
}
staticint signal_fuzzer(void)
{ int t, rc;
pthread_t *threads;
threads = malloc(nthread * sizeof(pthread_t));
for (t = 0; t < nthread; t++) {
rc = pthread_create(&threads[t], NULL, sigfuz_test,
(void *)&t); if (rc)
perror("Thread creation error\n");
}
for (t = 0; t < nthread; t++) {
rc = pthread_join(threads[t], NULL); if (rc)
perror("Thread join error\n");
}
free(threads);
return EXIT_SUCCESS;
}
staticvoid show_help(char *name)
{
printf("%s: Sigfuzzer for powerpc\n", name);
printf("Usage:\n");
printf("\t-b\t Mess with TM before raising a SIGUSR1 signal\n");
printf("\t-a\t Mess with TM after raising a SIGUSR1 signal\n");
printf("\t-m\t Mess with MSR[TS] bits at mcontext\n");
printf("\t-x\t Mess with everything above\n");
printf("\t-f\t Run forever (Press ^C to Quit)\n");
printf("\t-i\t Amount of interactions. (Default = %d)\n", COUNT_MAX);
printf("\t-t\t Amount of threads. (Default = %d)\n", THREADS); exit(-1);
}
int main(int argc, char **argv)
{ int opt;
while ((opt = getopt(argc, argv, "bamxt:fi:h")) != -1) { if (opt == 'b') {
printf("Mess with TM before signal\n");
args |= ARG_MESS_WITH_TM_BEFORE;
} elseif (opt == 'a') {
printf("Mess with TM at signal handler\n");
args |= ARG_MESS_WITH_TM_AT;
} elseif (opt == 'm') {
printf("Mess with MSR[TS] bits in mcontext\n");
args |= ARG_MESS_WITH_MSR_AT;
} elseif (opt == 'x') {
printf("Running with all options enabled\n");
args |= ARG_COMPLETE;
} elseif (opt == 't') {
nthread = atoi(optarg);
printf("Threads = %d\n", nthread);
} elseif (opt == 'f') {
args |= ARG_FOREVER;
printf("Press ^C to stop\n");
test_harness_set_timeout(-1);
} elseif (opt == 'i') {
count_max = atoi(optarg);
printf("Running for %d interactions\n", count_max);
} elseif (opt == 'h') {
show_help(argv[0]);
}
}
/* Default test suite */ if (!args)
args = ARG_COMPLETE;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.