linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] selftests/powerpc: Add a test of sigreturn vs VDSO
@ 2020-03-04 11:04 Michael Ellerman
  2020-03-06 18:25 ` Nathan Lynch
  2020-03-26 12:06 ` Michael Ellerman
  0 siblings, 2 replies; 6+ messages in thread
From: Michael Ellerman @ 2020-03-04 11:04 UTC (permalink / raw)
  To: linuxppc-dev

There's two different paths through the sigreturn code, depending on
whether the VDSO is mapped or not. We recently discovered a bug in the
unmapped case, because it's not commonly used these days.

So add a test that sends itself a signal, then moves the VDSO, takes
another signal and finally unmaps the VDSO before sending itself
another signal. That tests the standard signal path, the code that
handles the VDSO being moved, and also the signal path in the case
where the VDSO is unmapped.

Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
---
 .../selftests/powerpc/signal/.gitignore       |   1 +
 .../testing/selftests/powerpc/signal/Makefile |   2 +-
 .../selftests/powerpc/signal/sigreturn_vdso.c | 127 ++++++++++++++++++
 3 files changed, 129 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/powerpc/signal/sigreturn_vdso.c

diff --git a/tools/testing/selftests/powerpc/signal/.gitignore b/tools/testing/selftests/powerpc/signal/.gitignore
index dca5852a1546..03dafa795255 100644
--- a/tools/testing/selftests/powerpc/signal/.gitignore
+++ b/tools/testing/selftests/powerpc/signal/.gitignore
@@ -1,3 +1,4 @@
 signal
 signal_tm
 sigfuz
+sigreturn_vdso
diff --git a/tools/testing/selftests/powerpc/signal/Makefile b/tools/testing/selftests/powerpc/signal/Makefile
index 113838fbbe7f..63b57583e07d 100644
--- a/tools/testing/selftests/powerpc/signal/Makefile
+++ b/tools/testing/selftests/powerpc/signal/Makefile
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
-TEST_GEN_PROGS := signal signal_tm sigfuz
+TEST_GEN_PROGS := signal signal_tm sigfuz sigreturn_vdso
 
 CFLAGS += -maltivec
 $(OUTPUT)/signal_tm: CFLAGS += -mhtm
diff --git a/tools/testing/selftests/powerpc/signal/sigreturn_vdso.c b/tools/testing/selftests/powerpc/signal/sigreturn_vdso.c
new file mode 100644
index 000000000000..e282fff0fe25
--- /dev/null
+++ b/tools/testing/selftests/powerpc/signal/sigreturn_vdso.c
@@ -0,0 +1,127 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Test that we can take signals with and without the VDSO mapped, which trigger
+ * different paths in the signal handling code.
+ *
+ * See handle_rt_signal64() and setup_trampoline() in signal_64.c
+ */
+
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <stdio.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+// Ensure assert() is not compiled out
+#undef NDEBUG
+#include <assert.h>
+
+#include "utils.h"
+
+static int search_proc_maps(char *needle, unsigned long *low, unsigned long *high)
+{
+	unsigned long start, end;
+	static char buf[4096];
+	char name[128];
+	FILE *f;
+	int rc = -1;
+
+	f = fopen("/proc/self/maps", "r");
+	if (!f) {
+		perror("fopen");
+		return -1;
+	}
+
+	while (fgets(buf, sizeof(buf), f)) {
+		rc = sscanf(buf, "%lx-%lx %*c%*c%*c%*c %*x %*d:%*d %*d %127s\n",
+			    &start, &end, name);
+		if (rc == 2)
+			continue;
+
+		if (rc != 3) {
+			printf("sscanf errored\n");
+			rc = -1;
+			break;
+		}
+
+		if (strstr(name, needle)) {
+			*low = start;
+			*high = end - 1;
+			rc = 0;
+			break;
+		}
+	}
+
+	fclose(f);
+
+	return rc;
+}
+
+static volatile sig_atomic_t took_signal = 0;
+
+static void sigusr1_handler(int sig)
+{
+	took_signal++;
+}
+
+int test_sigreturn_vdso(void)
+{
+	unsigned long low, high, size;
+	struct sigaction act;
+	char *p;
+
+	act.sa_handler = sigusr1_handler;
+	act.sa_flags = 0;
+	sigemptyset(&act.sa_mask);
+
+	assert(sigaction(SIGUSR1, &act, NULL) == 0);
+
+	// Confirm the VDSO is mapped, and work out where it is
+	assert(search_proc_maps("[vdso]", &low, &high) == 0);
+	size = high - low + 1;
+	printf("VDSO is at 0x%lx-0x%lx (%lu bytes)\n", low, high, size);
+
+	kill(getpid(), SIGUSR1);
+	assert(took_signal == 1);
+	printf("Signal delivered OK with VDSO mapped\n");
+
+	// Remap the VDSO somewhere else
+	p = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+	assert(p != MAP_FAILED);
+	assert(mremap((void *)low, size, size, MREMAP_MAYMOVE|MREMAP_FIXED, p) != MAP_FAILED);
+	assert(search_proc_maps("[vdso]", &low, &high) == 0);
+	size = high - low + 1;
+	printf("VDSO moved to 0x%lx-0x%lx (%lu bytes)\n", low, high, size);
+
+	kill(getpid(), SIGUSR1);
+	assert(took_signal == 2);
+	printf("Signal delivered OK with VDSO moved\n");
+
+	assert(munmap((void *)low, size) == 0);
+	printf("Unmapped VDSO\n");
+
+	// Confirm the VDSO is not mapped anymore
+	assert(search_proc_maps("[vdso]", &low, &high) != 0);
+
+	// Make the stack executable
+	assert(search_proc_maps("[stack]", &low, &high) == 0);
+	size = high - low + 1;
+	mprotect((void *)low, size, PROT_READ|PROT_WRITE|PROT_EXEC);
+	printf("Remapped the stack executable\n");
+
+	kill(getpid(), SIGUSR1);
+	assert(took_signal == 3);
+	printf("Signal delivered OK with VDSO unmapped\n");
+
+	return 0;
+}
+
+int main(void)
+{
+	return test_harness(test_sigreturn_vdso, "sigreturn_vdso");
+}
-- 
2.21.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2021-06-17  9:01 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-03-04 11:04 [PATCH] selftests/powerpc: Add a test of sigreturn vs VDSO Michael Ellerman
2020-03-06 18:25 ` Nathan Lynch
2020-03-06 18:31   ` Nathan Lynch
2020-03-26 12:04     ` Michael Ellerman
2020-03-26 12:06 ` Michael Ellerman
2021-06-17  9:00   ` Christophe Leroy

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).