// 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"); }