From 47d99948eee48a84a4b242c17915a4ff59a29b5d Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Fri, 29 Mar 2019 10:00:00 +0000 Subject: powerpc/mm: Move book3s64 specifics in subdirectory mm/book3s64 Many files in arch/powerpc/mm are only for book3S64. This patch creates a subdirectory for them. Signed-off-by: Christophe Leroy [mpe: Update the selftest sym links, shorten new filenames, cleanup some whitespace and formatting in the new files.] Signed-off-by: Michael Ellerman --- tools/testing/selftests/powerpc/vphn/vphn.c | 2 +- tools/testing/selftests/powerpc/vphn/vphn.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/powerpc/vphn/vphn.c b/tools/testing/selftests/powerpc/vphn/vphn.c index 186b906e66d5..1d1f5f2be3b2 120000 --- a/tools/testing/selftests/powerpc/vphn/vphn.c +++ b/tools/testing/selftests/powerpc/vphn/vphn.c @@ -1 +1 @@ -../../../../../arch/powerpc/mm/vphn.c \ No newline at end of file +../../../../../arch/powerpc/mm/book3s64/vphn.c \ No newline at end of file diff --git a/tools/testing/selftests/powerpc/vphn/vphn.h b/tools/testing/selftests/powerpc/vphn/vphn.h index 7131efe38c65..45fe160f8288 120000 --- a/tools/testing/selftests/powerpc/vphn/vphn.h +++ b/tools/testing/selftests/powerpc/vphn/vphn.h @@ -1 +1 @@ -../../../../../arch/powerpc/mm/vphn.h \ No newline at end of file +../../../../../arch/powerpc/mm/book3s64/vphn.h \ No newline at end of file -- cgit v1.2.3 From 26deb04342e343ac58ab05bc7d2345ff0be9b667 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Fri, 26 Apr 2019 16:23:26 +0000 Subject: powerpc: prepare string/mem functions for KASAN CONFIG_KASAN implements wrappers for memcpy() memmove() and memset() Those wrappers are doing the verification then call respectively __memcpy() __memmove() and __memset(). The arches are therefore expected to rename their optimised functions that way. For files on which KASAN is inhibited, #defines are used to allow them to directly call optimised versions of the functions without going through the KASAN wrappers. See commit 393f203f5fd5 ("x86_64: kasan: add interceptors for memset/memmove/memcpy functions") for details. Other string / mem functions do not (yet) have kasan wrappers, we therefore have to fallback to the generic versions when KASAN is active, otherwise KASAN checks will be skipped. Signed-off-by: Christophe Leroy [mpe: Fixups to keep selftests working] Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/kasan.h | 15 ++++++++++ arch/powerpc/include/asm/string.h | 32 ++++++++++++++++++++-- arch/powerpc/kernel/prom_init_check.sh | 10 ++++++- arch/powerpc/lib/Makefile | 11 ++++++-- arch/powerpc/lib/copy_32.S | 12 ++++++-- arch/powerpc/lib/mem_64.S | 9 ++++-- arch/powerpc/lib/memcpy_64.S | 4 ++- .../selftests/powerpc/copyloops/asm/export.h | 1 + .../selftests/powerpc/copyloops/asm/kasan.h | 0 .../selftests/powerpc/copyloops/asm/ppc_asm.h | 1 + 10 files changed, 82 insertions(+), 13 deletions(-) create mode 100644 arch/powerpc/include/asm/kasan.h create mode 100644 tools/testing/selftests/powerpc/copyloops/asm/kasan.h (limited to 'tools/testing') diff --git a/arch/powerpc/include/asm/kasan.h b/arch/powerpc/include/asm/kasan.h new file mode 100644 index 000000000000..2c179a39d4ba --- /dev/null +++ b/arch/powerpc/include/asm/kasan.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ASM_KASAN_H +#define __ASM_KASAN_H + +#ifdef CONFIG_KASAN +#define _GLOBAL_KASAN(fn) _GLOBAL(__##fn) +#define _GLOBAL_TOC_KASAN(fn) _GLOBAL_TOC(__##fn) +#define EXPORT_SYMBOL_KASAN(fn) EXPORT_SYMBOL(__##fn) +#else +#define _GLOBAL_KASAN(fn) _GLOBAL(fn) +#define _GLOBAL_TOC_KASAN(fn) _GLOBAL_TOC(fn) +#define EXPORT_SYMBOL_KASAN(fn) +#endif + +#endif diff --git a/arch/powerpc/include/asm/string.h b/arch/powerpc/include/asm/string.h index 1647de15a31e..9bf6dffb4090 100644 --- a/arch/powerpc/include/asm/string.h +++ b/arch/powerpc/include/asm/string.h @@ -4,14 +4,17 @@ #ifdef __KERNEL__ +#ifndef CONFIG_KASAN #define __HAVE_ARCH_STRNCPY #define __HAVE_ARCH_STRNCMP +#define __HAVE_ARCH_MEMCHR +#define __HAVE_ARCH_MEMCMP +#define __HAVE_ARCH_MEMSET16 +#endif + #define __HAVE_ARCH_MEMSET #define __HAVE_ARCH_MEMCPY #define __HAVE_ARCH_MEMMOVE -#define __HAVE_ARCH_MEMCMP -#define __HAVE_ARCH_MEMCHR -#define __HAVE_ARCH_MEMSET16 #define __HAVE_ARCH_MEMCPY_FLUSHCACHE extern char * strcpy(char *,const char *); @@ -27,7 +30,27 @@ extern int memcmp(const void *,const void *,__kernel_size_t); extern void * memchr(const void *,int,__kernel_size_t); extern void * memcpy_flushcache(void *,const void *,__kernel_size_t); +void *__memset(void *s, int c, __kernel_size_t count); +void *__memcpy(void *to, const void *from, __kernel_size_t n); +void *__memmove(void *to, const void *from, __kernel_size_t n); + +#if defined(CONFIG_KASAN) && !defined(__SANITIZE_ADDRESS__) +/* + * For files that are not instrumented (e.g. mm/slub.c) we + * should use not instrumented version of mem* functions. + */ +#define memcpy(dst, src, len) __memcpy(dst, src, len) +#define memmove(dst, src, len) __memmove(dst, src, len) +#define memset(s, c, n) __memset(s, c, n) + +#ifndef __NO_FORTIFY +#define __NO_FORTIFY /* FORTIFY_SOURCE uses __builtin_memcpy, etc. */ +#endif + +#endif + #ifdef CONFIG_PPC64 +#ifndef CONFIG_KASAN #define __HAVE_ARCH_MEMSET32 #define __HAVE_ARCH_MEMSET64 @@ -49,8 +72,11 @@ static inline void *memset64(uint64_t *p, uint64_t v, __kernel_size_t n) { return __memset64(p, v, n * 8); } +#endif #else +#ifndef CONFIG_KASAN #define __HAVE_ARCH_STRLEN +#endif extern void *memset16(uint16_t *, uint16_t, __kernel_size_t); #endif diff --git a/arch/powerpc/kernel/prom_init_check.sh b/arch/powerpc/kernel/prom_init_check.sh index 667df97d2595..181fd10008ef 100644 --- a/arch/powerpc/kernel/prom_init_check.sh +++ b/arch/powerpc/kernel/prom_init_check.sh @@ -16,8 +16,16 @@ # If you really need to reference something from prom_init.o add # it to the list below: +grep "^CONFIG_KASAN=y$" .config >/dev/null +if [ $? -eq 0 ] +then + MEM_FUNCS="__memcpy __memset" +else + MEM_FUNCS="memcpy memset" +fi + WHITELIST="add_reloc_offset __bss_start __bss_stop copy_and_flush -_end enter_prom memcpy memset reloc_offset __secondary_hold +_end enter_prom $MEM_FUNCS reloc_offset __secondary_hold __secondary_hold_acknowledge __secondary_hold_spinloop __start strcmp strcpy strlcpy strlen strncmp strstr kstrtobool logo_linux_clut224 reloc_got2 kernstart_addr memstart_addr linux_banner _stext diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile index 79396e184bca..47a4de434c22 100644 --- a/arch/powerpc/lib/Makefile +++ b/arch/powerpc/lib/Makefile @@ -8,9 +8,14 @@ ccflags-$(CONFIG_PPC64) := $(NO_MINIMAL_TOC) CFLAGS_REMOVE_code-patching.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_feature-fixups.o = $(CC_FLAGS_FTRACE) -obj-y += string.o alloc.o code-patching.o feature-fixups.o +obj-y += alloc.o code-patching.o feature-fixups.o -obj-$(CONFIG_PPC32) += div64.o copy_32.o crtsavres.o strlen_32.o +ifndef CONFIG_KASAN +obj-y += string.o memcmp_$(BITS).o +obj-$(CONFIG_PPC32) += strlen_32.o +endif + +obj-$(CONFIG_PPC32) += div64.o copy_32.o crtsavres.o obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o @@ -34,7 +39,7 @@ obj64-$(CONFIG_KPROBES_SANITY_TEST) += test_emulate_step.o \ test_emulate_step_exec_instr.o obj-y += checksum_$(BITS).o checksum_wrappers.o \ - string_$(BITS).o memcmp_$(BITS).o + string_$(BITS).o obj-y += sstep.o ldstfp.o quad.o obj64-y += quad.o diff --git a/arch/powerpc/lib/copy_32.S b/arch/powerpc/lib/copy_32.S index ba66846fe973..d5642481fb98 100644 --- a/arch/powerpc/lib/copy_32.S +++ b/arch/powerpc/lib/copy_32.S @@ -14,6 +14,7 @@ #include #include #include +#include #define COPY_16_BYTES \ lwz r7,4(r4); \ @@ -68,6 +69,7 @@ CACHELINE_BYTES = L1_CACHE_BYTES LG_CACHELINE_BYTES = L1_CACHE_SHIFT CACHELINE_MASK = (L1_CACHE_BYTES-1) +#ifndef CONFIG_KASAN _GLOBAL(memset16) rlwinm. r0 ,r5, 31, 1, 31 addi r6, r3, -4 @@ -81,6 +83,7 @@ _GLOBAL(memset16) sth r4, 4(r6) blr EXPORT_SYMBOL(memset16) +#endif /* * Use dcbz on the complete cache lines in the destination @@ -91,7 +94,7 @@ EXPORT_SYMBOL(memset16) * We therefore skip the optimised bloc that uses dcbz. This jump is * replaced by a nop once cache is active. This is done in machine_init() */ -_GLOBAL(memset) +_GLOBAL_KASAN(memset) cmplwi 0,r5,4 blt 7f @@ -151,6 +154,7 @@ _GLOBAL(memset) bdnz 9b blr EXPORT_SYMBOL(memset) +EXPORT_SYMBOL_KASAN(memset) /* * This version uses dcbz on the complete cache lines in the @@ -163,12 +167,12 @@ EXPORT_SYMBOL(memset) * We therefore jump to generic_memcpy which doesn't use dcbz. This jump is * replaced by a nop once cache is active. This is done in machine_init() */ -_GLOBAL(memmove) +_GLOBAL_KASAN(memmove) cmplw 0,r3,r4 bgt backwards_memcpy /* fall through */ -_GLOBAL(memcpy) +_GLOBAL_KASAN(memcpy) 1: b generic_memcpy patch_site 1b, patch__memcpy_nocache @@ -244,6 +248,8 @@ _GLOBAL(memcpy) 65: blr EXPORT_SYMBOL(memcpy) EXPORT_SYMBOL(memmove) +EXPORT_SYMBOL_KASAN(memcpy) +EXPORT_SYMBOL_KASAN(memmove) generic_memcpy: srwi. r7,r5,3 diff --git a/arch/powerpc/lib/mem_64.S b/arch/powerpc/lib/mem_64.S index 3c3be02f33b7..7f6bd031c306 100644 --- a/arch/powerpc/lib/mem_64.S +++ b/arch/powerpc/lib/mem_64.S @@ -12,7 +12,9 @@ #include #include #include +#include +#ifndef CONFIG_KASAN _GLOBAL(__memset16) rlwimi r4,r4,16,0,15 /* fall through */ @@ -29,8 +31,9 @@ _GLOBAL(__memset64) EXPORT_SYMBOL(__memset16) EXPORT_SYMBOL(__memset32) EXPORT_SYMBOL(__memset64) +#endif -_GLOBAL(memset) +_GLOBAL_KASAN(memset) neg r0,r3 rlwimi r4,r4,8,16,23 andi. r0,r0,7 /* # bytes to be 8-byte aligned */ @@ -96,8 +99,9 @@ _GLOBAL(memset) stb r4,0(r6) blr EXPORT_SYMBOL(memset) +EXPORT_SYMBOL_KASAN(memset) -_GLOBAL_TOC(memmove) +_GLOBAL_TOC_KASAN(memmove) cmplw 0,r3,r4 bgt backwards_memcpy b memcpy @@ -139,3 +143,4 @@ _GLOBAL(backwards_memcpy) mtctr r7 b 1b EXPORT_SYMBOL(memmove) +EXPORT_SYMBOL_KASAN(memmove) diff --git a/arch/powerpc/lib/memcpy_64.S b/arch/powerpc/lib/memcpy_64.S index 273ea67e60a1..25c3772c1dfb 100644 --- a/arch/powerpc/lib/memcpy_64.S +++ b/arch/powerpc/lib/memcpy_64.S @@ -11,6 +11,7 @@ #include #include #include +#include #ifndef SELFTEST_CASE /* For big-endian, 0 == most CPUs, 1 == POWER6, 2 == Cell */ @@ -18,7 +19,7 @@ #endif .align 7 -_GLOBAL_TOC(memcpy) +_GLOBAL_TOC_KASAN(memcpy) BEGIN_FTR_SECTION #ifdef __LITTLE_ENDIAN__ cmpdi cr7,r5,0 @@ -230,3 +231,4 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD) blr #endif EXPORT_SYMBOL(memcpy) +EXPORT_SYMBOL_KASAN(memcpy) diff --git a/tools/testing/selftests/powerpc/copyloops/asm/export.h b/tools/testing/selftests/powerpc/copyloops/asm/export.h index 0bab35f6777a..05c1663c89b0 100644 --- a/tools/testing/selftests/powerpc/copyloops/asm/export.h +++ b/tools/testing/selftests/powerpc/copyloops/asm/export.h @@ -1,2 +1,3 @@ /* SPDX-License-Identifier: GPL-2.0 */ #define EXPORT_SYMBOL(x) +#define EXPORT_SYMBOL_KASAN(x) diff --git a/tools/testing/selftests/powerpc/copyloops/asm/kasan.h b/tools/testing/selftests/powerpc/copyloops/asm/kasan.h new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h b/tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h index 0605df807593..58c1cef3e399 100644 --- a/tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h +++ b/tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h @@ -25,6 +25,7 @@ #define _GLOBAL(A) FUNC_START(test_ ## A) #define _GLOBAL_TOC(A) _GLOBAL(A) +#define _GLOBAL_TOC_KASAN(A) _GLOBAL(A) #define PPC_MTOCRF(A, B) mtocrf A, B -- cgit v1.2.3 From 83e367f9ad18d42a1883ee29f20608a2b93e1071 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Thu, 17 Jan 2019 15:01:54 -0200 Subject: selftests/powerpc: Add a signal fuzzer selftest 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. Signed-off-by: Breno Leitao Signed-off-by: Michael Ellerman --- tools/testing/selftests/powerpc/harness.c | 6 +- tools/testing/selftests/powerpc/include/reg.h | 2 + tools/testing/selftests/powerpc/signal/.gitignore | 1 + tools/testing/selftests/powerpc/signal/Makefile | 3 +- tools/testing/selftests/powerpc/signal/sigfuz.c | 325 ++++++++++++++++++++++ 5 files changed, 334 insertions(+), 3 deletions(-) create mode 100644 tools/testing/selftests/powerpc/signal/sigfuz.c (limited to 'tools/testing') diff --git a/tools/testing/selftests/powerpc/harness.c b/tools/testing/selftests/powerpc/harness.c index 9d7166dfad1e..ba89353abfcc 100644 --- a/tools/testing/selftests/powerpc/harness.c +++ b/tools/testing/selftests/powerpc/harness.c @@ -21,6 +21,7 @@ #define KILL_TIMEOUT 5 +/* Setting timeout to -1 disables the alarm */ static uint64_t timeout = 120; int run_test(int (test_function)(void), char *name) @@ -43,8 +44,9 @@ int run_test(int (test_function)(void), char *name) setpgid(pid, pid); - /* Wake us up in timeout seconds */ - alarm(timeout); + if (timeout != -1) + /* Wake us up in timeout seconds */ + alarm(timeout); terminated = false; wait: diff --git a/tools/testing/selftests/powerpc/include/reg.h b/tools/testing/selftests/powerpc/include/reg.h index 96043b9b9829..1e797ae396ee 100644 --- a/tools/testing/selftests/powerpc/include/reg.h +++ b/tools/testing/selftests/powerpc/include/reg.h @@ -79,11 +79,13 @@ /* MSR register bits */ #define MSR_TS_S_LG 33 /* Trans Mem state: Suspended */ +#define MSR_TS_T_LG 34 /* Trans Mem state: Active */ #define __MASK(X) (1UL<<(X)) /* macro to check TM MSR bits */ #define MSR_TS_S __MASK(MSR_TS_S_LG) /* Transaction Suspended */ +#define MSR_TS_T __MASK(MSR_TS_T_LG) /* Transaction Transactional */ /* Vector Instructions */ #define VSX_XX1(xs, ra, rb) (((xs) & 0x1f) << 21 | ((ra) << 16) | \ diff --git a/tools/testing/selftests/powerpc/signal/.gitignore b/tools/testing/selftests/powerpc/signal/.gitignore index 1b89224a8aab..dca5852a1546 100644 --- a/tools/testing/selftests/powerpc/signal/.gitignore +++ b/tools/testing/selftests/powerpc/signal/.gitignore @@ -1,2 +1,3 @@ signal signal_tm +sigfuz diff --git a/tools/testing/selftests/powerpc/signal/Makefile b/tools/testing/selftests/powerpc/signal/Makefile index 209a958dca12..113838fbbe7f 100644 --- a/tools/testing/selftests/powerpc/signal/Makefile +++ b/tools/testing/selftests/powerpc/signal/Makefile @@ -1,8 +1,9 @@ # SPDX-License-Identifier: GPL-2.0 -TEST_GEN_PROGS := signal signal_tm +TEST_GEN_PROGS := signal signal_tm sigfuz CFLAGS += -maltivec $(OUTPUT)/signal_tm: CFLAGS += -mhtm +$(OUTPUT)/sigfuz: CFLAGS += -pthread -m64 top_srcdir = ../../../../.. include ../../lib.mk diff --git a/tools/testing/selftests/powerpc/signal/sigfuz.c b/tools/testing/selftests/powerpc/signal/sigfuz.c new file mode 100644 index 000000000000..dade00c698c2 --- /dev/null +++ b/tools/testing/selftests/powerpc/signal/sigfuz.c @@ -0,0 +1,325 @@ +// 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "utils.h" + +/* Selftest defaults */ +#define COUNT_MAX 4000 /* Number of interactions */ +#define THREADS 16 /* Number of threads */ + +/* Arguments options */ +#define ARG_MESS_WITH_TM_AT 0x1 +#define ARG_MESS_WITH_TM_BEFORE 0x2 +#define ARG_MESS_WITH_MSR_AT 0x4 +#define ARG_FOREVER 0x10 +#define ARG_COMPLETE (ARG_MESS_WITH_TM_AT | \ + ARG_MESS_WITH_TM_BEFORE | \ + ARG_MESS_WITH_MSR_AT) + +static int args; +static int nthread = THREADS; +static int count_max = COUNT_MAX; + +/* checkpoint context */ +static ucontext_t *tmp_uc; + +/* Return true with 1/x probability */ +static int one_in_chance(int x) +{ + return rand() % x == 0; +} + +/* Change TM states */ +static void 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() */ +static void 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)); + } else if (one_in_chance(2)) { + memcpy(ucp->uc_link, uc, sizeof(ucontext_t)); + } else if (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; + } else if (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; + } else if (one_in_chance(2)) { + if (one_in_chance(2)) + ucp->uc_mcontext.gp_regs[PT_MSR] |= + MSR_TS_T; + else if (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(); + + ucp->uc_mcontext.gp_regs[PT_TRAP] = random(); + ucp->uc_mcontext.gp_regs[PT_DSISR] = random(); + ucp->uc_mcontext.gp_regs[PT_DAR] = random(); + ucp->uc_mcontext.gp_regs[PT_ORIG_R3] = random(); + ucp->uc_mcontext.gp_regs[PT_XER] = random(); + ucp->uc_mcontext.gp_regs[PT_RESULT] = random(); + ucp->uc_mcontext.gp_regs[PT_SOFTE] = random(); + ucp->uc_mcontext.gp_regs[PT_DSCR] = random(); + ucp->uc_mcontext.gp_regs[PT_CTR] = random(); + ucp->uc_mcontext.gp_regs[PT_LNK] = random(); + ucp->uc_mcontext.gp_regs[PT_CCR] = random(); + ucp->uc_mcontext.gp_regs[PT_REGS_COUNT] = random(); + + ucp->uc_link->uc_mcontext.gp_regs[PT_TRAP] = random(); + ucp->uc_link->uc_mcontext.gp_regs[PT_DSISR] = random(); + ucp->uc_link->uc_mcontext.gp_regs[PT_DAR] = random(); + ucp->uc_link->uc_mcontext.gp_regs[PT_ORIG_R3] = random(); + ucp->uc_link->uc_mcontext.gp_regs[PT_XER] = random(); + ucp->uc_link->uc_mcontext.gp_regs[PT_RESULT] = random(); + ucp->uc_link->uc_mcontext.gp_regs[PT_SOFTE] = random(); + ucp->uc_link->uc_mcontext.gp_regs[PT_DSCR] = random(); + ucp->uc_link->uc_mcontext.gp_regs[PT_CTR] = random(); + ucp->uc_link->uc_mcontext.gp_regs[PT_LNK] = random(); + ucp->uc_link->uc_mcontext.gp_regs[PT_CCR] = random(); + ucp->uc_link->uc_mcontext.gp_regs[PT_REGS_COUNT] = random(); + + if (args & ARG_MESS_WITH_TM_BEFORE) { + if (one_in_chance(2)) + mess_with_tm(); + } +} + +static void seg_signal_handler(int signo, siginfo_t *si, void *uc) +{ + /* Clear exit for process that segfaults */ + exit(0); +} + +static void *sigfuz_test(void *thrid) +{ + struct sigaction trap_sa, seg_sa; + int ret, i = 0; + pid_t t; + + tmp_uc = malloc(sizeof(ucontext_t)); + + /* Main signal handler */ + trap_sa.sa_flags = SA_SIGINFO; + trap_sa.sa_sigaction = trap_signal_handler; + + /* SIGSEGV signal handler */ + seg_sa.sa_flags = SA_SIGINFO; + seg_sa.sa_sigaction = seg_signal_handler; + + /* 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; +} + +static int 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; +} + +static void 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; + } else if (opt == 'a') { + printf("Mess with TM at signal handler\n"); + args |= ARG_MESS_WITH_TM_AT; + } else if (opt == 'm') { + printf("Mess with MSR[TS] bits in mcontext\n"); + args |= ARG_MESS_WITH_MSR_AT; + } else if (opt == 'x') { + printf("Running with all options enabled\n"); + args |= ARG_COMPLETE; + } else if (opt == 't') { + nthread = atoi(optarg); + printf("Threads = %d\n", nthread); + } else if (opt == 'f') { + args |= ARG_FOREVER; + printf("Press ^C to stop\n"); + test_harness_set_timeout(-1); + } else if (opt == 'i') { + count_max = atoi(optarg); + printf("Running for %d interactions\n", count_max); + } else if (opt == 'h') { + show_help(argv[0]); + } + } + + /* Default test suite */ + if (!args) + args = ARG_COMPLETE; + + test_harness(signal_fuzzer, "signal_fuzzer"); +} -- cgit v1.2.3