162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * vdso_restorer.c - tests vDSO-based signal restore 462306a36Sopenharmony_ci * Copyright (c) 2015 Andrew Lutomirski 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * This makes sure that sa_restorer == NULL keeps working on 32-bit 762306a36Sopenharmony_ci * configurations. Modern glibc doesn't use it under any circumstances, 862306a36Sopenharmony_ci * so it's easy to overlook breakage. 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * 64-bit userspace has never supported sa_restorer == NULL, so this is 1162306a36Sopenharmony_ci * 32-bit only. 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define _GNU_SOURCE 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <err.h> 1762306a36Sopenharmony_ci#include <stdio.h> 1862306a36Sopenharmony_ci#include <dlfcn.h> 1962306a36Sopenharmony_ci#include <string.h> 2062306a36Sopenharmony_ci#include <signal.h> 2162306a36Sopenharmony_ci#include <unistd.h> 2262306a36Sopenharmony_ci#include <syscall.h> 2362306a36Sopenharmony_ci#include <sys/syscall.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci/* Open-code this -- the headers are too messy to easily use them. */ 2662306a36Sopenharmony_cistruct real_sigaction { 2762306a36Sopenharmony_ci void *handler; 2862306a36Sopenharmony_ci unsigned long flags; 2962306a36Sopenharmony_ci void *restorer; 3062306a36Sopenharmony_ci unsigned int mask[2]; 3162306a36Sopenharmony_ci}; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic volatile sig_atomic_t handler_called; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic void handler_with_siginfo(int sig, siginfo_t *info, void *ctx_void) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci handler_called = 1; 3862306a36Sopenharmony_ci} 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic void handler_without_siginfo(int sig) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci handler_called = 1; 4362306a36Sopenharmony_ci} 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ciint main() 4662306a36Sopenharmony_ci{ 4762306a36Sopenharmony_ci int nerrs = 0; 4862306a36Sopenharmony_ci struct real_sigaction sa; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci void *vdso = dlopen("linux-vdso.so.1", 5162306a36Sopenharmony_ci RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); 5262306a36Sopenharmony_ci if (!vdso) 5362306a36Sopenharmony_ci vdso = dlopen("linux-gate.so.1", 5462306a36Sopenharmony_ci RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); 5562306a36Sopenharmony_ci if (!vdso) { 5662306a36Sopenharmony_ci printf("[SKIP]\tFailed to find vDSO. Tests are not expected to work.\n"); 5762306a36Sopenharmony_ci return 0; 5862306a36Sopenharmony_ci } 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci memset(&sa, 0, sizeof(sa)); 6162306a36Sopenharmony_ci sa.handler = handler_with_siginfo; 6262306a36Sopenharmony_ci sa.flags = SA_SIGINFO; 6362306a36Sopenharmony_ci sa.restorer = NULL; /* request kernel-provided restorer */ 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci printf("[RUN]\tRaise a signal, SA_SIGINFO, sa.restorer == NULL\n"); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci if (syscall(SYS_rt_sigaction, SIGUSR1, &sa, NULL, 8) != 0) 6862306a36Sopenharmony_ci err(1, "raw rt_sigaction syscall"); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci raise(SIGUSR1); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci if (handler_called) { 7362306a36Sopenharmony_ci printf("[OK]\tSA_SIGINFO handler returned successfully\n"); 7462306a36Sopenharmony_ci } else { 7562306a36Sopenharmony_ci printf("[FAIL]\tSA_SIGINFO handler was not called\n"); 7662306a36Sopenharmony_ci nerrs++; 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci printf("[RUN]\tRaise a signal, !SA_SIGINFO, sa.restorer == NULL\n"); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci sa.flags = 0; 8262306a36Sopenharmony_ci sa.handler = handler_without_siginfo; 8362306a36Sopenharmony_ci if (syscall(SYS_sigaction, SIGUSR1, &sa, 0) != 0) 8462306a36Sopenharmony_ci err(1, "raw sigaction syscall"); 8562306a36Sopenharmony_ci handler_called = 0; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci raise(SIGUSR1); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci if (handler_called) { 9062306a36Sopenharmony_ci printf("[OK]\t!SA_SIGINFO handler returned successfully\n"); 9162306a36Sopenharmony_ci } else { 9262306a36Sopenharmony_ci printf("[FAIL]\t!SA_SIGINFO handler was not called\n"); 9362306a36Sopenharmony_ci nerrs++; 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci} 96