| /* |
| * vdso_restorer.c - tests vDSO-based signal restore |
| * Copyright (c) 2015 Andrew Lutomirski |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms and conditions of the GNU General Public License, |
| * version 2, as published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope it will be useful, but |
| * WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * General Public License for more details. |
| * |
| * This makes sure that sa_restorer == NULL keeps working on 32-bit |
| * configurations. Modern glibc doesn't use it under any circumstances, |
| * so it's easy to overlook breakage. |
| * |
| * 64-bit userspace has never supported sa_restorer == NULL, so this is |
| * 32-bit only. |
| */ |
| |
| #define _GNU_SOURCE |
| |
| #include <err.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <signal.h> |
| #include <unistd.h> |
| #include <syscall.h> |
| #include <sys/syscall.h> |
| |
| /* Open-code this -- the headers are too messy to easily use them. */ |
| struct real_sigaction { |
| void *handler; |
| unsigned long flags; |
| void *restorer; |
| unsigned int mask[2]; |
| }; |
| |
| static volatile sig_atomic_t handler_called; |
| |
| static void handler_with_siginfo(int sig, siginfo_t *info, void *ctx_void) |
| { |
| handler_called = 1; |
| } |
| |
| static void handler_without_siginfo(int sig) |
| { |
| handler_called = 1; |
| } |
| |
| int main() |
| { |
| int nerrs = 0; |
| struct real_sigaction sa; |
| |
| memset(&sa, 0, sizeof(sa)); |
| sa.handler = handler_with_siginfo; |
| sa.flags = SA_SIGINFO; |
| sa.restorer = NULL; /* request kernel-provided restorer */ |
| |
| if (syscall(SYS_rt_sigaction, SIGUSR1, &sa, NULL, 8) != 0) |
| err(1, "raw rt_sigaction syscall"); |
| |
| raise(SIGUSR1); |
| |
| if (handler_called) { |
| printf("[OK]\tSA_SIGINFO handler returned successfully\n"); |
| } else { |
| printf("[FAIL]\tSA_SIGINFO handler was not called\n"); |
| nerrs++; |
| } |
| |
| sa.flags = 0; |
| sa.handler = handler_without_siginfo; |
| if (syscall(SYS_sigaction, SIGUSR1, &sa, 0) != 0) |
| err(1, "raw sigaction syscall"); |
| handler_called = 0; |
| |
| raise(SIGUSR1); |
| |
| if (handler_called) { |
| printf("[OK]\t!SA_SIGINFO handler returned successfully\n"); |
| } else { |
| printf("[FAIL]\t!SA_SIGINFO handler was not called\n"); |
| nerrs++; |
| } |
| } |