Re: [PATCH] selftests/powerpc: Add a test of sigreturn vs VDSO

2021-06-17 Thread Christophe Leroy




Le 26/03/2020 à 13:06, Michael Ellerman a écrit :

On Wed, 2020-03-04 at 11:04:02 UTC, Michael Ellerman wrote:

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 


Applied to powerpc next.

https://git.kernel.org/powerpc/c/a0968a025c04702427a4aee2c618f451a5098cd8

cheers



Doesn't work anymore since the split of VDSO and VVAR.

Christophe


Re: [PATCH] selftests/powerpc: Add a test of sigreturn vs VDSO

2020-03-26 Thread Michael Ellerman
On Wed, 2020-03-04 at 11:04:02 UTC, Michael Ellerman wrote:
> 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 

Applied to powerpc next.

https://git.kernel.org/powerpc/c/a0968a025c04702427a4aee2c618f451a5098cd8

cheers


Re: [PATCH] selftests/powerpc: Add a test of sigreturn vs VDSO

2020-03-26 Thread Michael Ellerman
Nathan Lynch  writes:
> Nathan Lynch  writes:
>> Michael Ellerman  writes:
>>> +static int search_proc_maps(char *needle, unsigned long *low, unsigned 
>>> long *high)
>>
>>^^ const?

Sorry I meant to do this but then forgot.

>>> +{
>>> +   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);
>>
>> I suspect it doesn't matter in practice for this particular test, but
>> since this looks like a generally useful function that could gain users
>> in the future: does this spuriously fail if the matching line straddles
>> a 4096-byte boundary? Maybe fscanf(3) should be used instead?
>
> Or maybe I should read the fgets man page more closely :-)
>
>   "Reading stops after an EOF or a newline."
>
> Sorry for the noise.

No worries, thanks for reviewing.

cheers


Re: [PATCH] selftests/powerpc: Add a test of sigreturn vs VDSO

2020-03-06 Thread Nathan Lynch
Nathan Lynch  writes:
> Michael Ellerman  writes:
>
>> +static int search_proc_maps(char *needle, unsigned long *low, unsigned long 
>> *high)
>
>^^ const?
>
>> +{
>> +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);
>
> I suspect it doesn't matter in practice for this particular test, but
> since this looks like a generally useful function that could gain users
> in the future: does this spuriously fail if the matching line straddles
> a 4096-byte boundary? Maybe fscanf(3) should be used instead?

Or maybe I should read the fgets man page more closely :-)

  "Reading stops after an EOF or a newline."

Sorry for the noise.


Re: [PATCH] selftests/powerpc: Add a test of sigreturn vs VDSO

2020-03-06 Thread Nathan Lynch
Michael Ellerman  writes:

> +static int search_proc_maps(char *needle, unsigned long *low, unsigned long 
> *high)

   ^^ const?
   
> +{
> + 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);

I suspect it doesn't matter in practice for this particular test, but
since this looks like a generally useful function that could gain users
in the future: does this spuriously fail if the matching line straddles
a 4096-byte boundary? Maybe fscanf(3) should be used instead?


> + 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");

I haven't looked at the test harness in detail but this should be
reliable if the program is a single thread - lgtm.


[PATCH] selftests/powerpc: Add a test of sigreturn vs VDSO

2020-03-04 Thread Michael Ellerman
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 
---
 .../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 ..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 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+// Ensure assert() is not compiled out
+#undef NDEBUG
+#include 
+
+#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) =