selftests/powerpc: Add TM signal with invalid stack test
authorMichael Neuling <mikey@neuling.org>
Fri, 20 Nov 2015 04:15:34 +0000 (15:15 +1100)
committerMichael Ellerman <mpe@ellerman.id.au>
Mon, 14 Dec 2015 09:41:49 +0000 (20:41 +1100)
Test the kernels signal generation code to ensure it can handle an
invalid stack pointer when transactional.

Signed-off-by: Michael Neuling <mikey@neuling.org>
Tested-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
[mpe: Skip if we don't have TM]
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
tools/testing/selftests/powerpc/tm/.gitignore
tools/testing/selftests/powerpc/tm/Makefile
tools/testing/selftests/powerpc/tm/tm-signal-stack.c [new file with mode: 0644]

index 61c318fdace4e7a505aa83cc0e37784abdeba815..e6668217ccd0749e965ab7f1a5bb977c6e764e98 100644 (file)
@@ -1,3 +1,4 @@
 tm-resched-dscr
 tm-syscall
 tm-signal-msr-resv
+tm-signal-stack
index c6b4ca8b2812ba2bcff2ec1750be8b81f9a68b64..e7ceff809fa0f3e5357dbcb3a0601bdc1b22c94b 100644 (file)
@@ -1,4 +1,4 @@
-TEST_PROGS := tm-resched-dscr tm-syscall tm-signal-msr-resv
+TEST_PROGS := tm-resched-dscr tm-syscall tm-signal-msr-resv tm-signal-stack
 
 all: $(TEST_PROGS)
 
diff --git a/tools/testing/selftests/powerpc/tm/tm-signal-stack.c b/tools/testing/selftests/powerpc/tm/tm-signal-stack.c
new file mode 100644 (file)
index 0000000..e44a238
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2015, Michael Neuling, IBM Corp.
+ * Licensed under GPLv2.
+ *
+ * Test the kernel's signal delievery code to ensure that we don't
+ * trelaim twice in the kernel signal delivery code.  This can happen
+ * if we trigger a signal when in a transaction and the stack pointer
+ * is bogus.
+ *
+ * This test case registers a SEGV handler, sets the stack pointer
+ * (r1) to NULL, starts a transaction and then generates a SEGV.  The
+ * SEGV should be handled but we exit here as the stack pointer is
+ * invalid and hance we can't sigreturn.  We only need to check that
+ * this flow doesn't crash the kernel.
+ */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <signal.h>
+
+#include "utils.h"
+#include "tm.h"
+
+void signal_segv(int signum)
+{
+       /* This should never actually run since stack is foobar */
+       exit(1);
+}
+
+int tm_signal_stack()
+{
+       int pid;
+
+       SKIP_IF(!have_htm());
+
+       pid = fork();
+       if (pid < 0)
+               exit(1);
+
+       if (pid) { /* Parent */
+               /*
+                * It's likely the whole machine will crash here so if
+                * the child ever exits, we are good.
+                */
+               wait(NULL);
+               return 0;
+       }
+
+       /*
+        * The flow here is:
+        * 1) register a signal handler (so signal delievery occurs)
+        * 2) make stack pointer (r1) = NULL
+        * 3) start transaction
+        * 4) cause segv
+        */
+       if (signal(SIGSEGV, signal_segv) == SIG_ERR)
+               exit(1);
+       asm volatile("li 1, 0 ;"                /* stack ptr == NULL */
+                    "1:"
+                    ".long 0x7C00051D ;"       /* tbegin */
+                    "beq 1b ;"                 /* retry forever */
+                    ".long 0x7C0005DD ; ;"     /* tsuspend */
+                    "ld 2, 0(1) ;"             /* trigger segv" */
+                    : : : "memory");
+
+       /* This should never get here due to above segv */
+       return 1;
+}
+
+int main(void)
+{
+       return test_harness(tm_signal_stack, "tm_signal_stack");
+}