linux/tools/testing/selftests/x86/sigaltstack.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2
   3#define _GNU_SOURCE
   4#include <signal.h>
   5#include <stdio.h>
   6#include <stdbool.h>
   7#include <string.h>
   8#include <err.h>
   9#include <errno.h>
  10#include <limits.h>
  11#include <sys/mman.h>
  12#include <sys/auxv.h>
  13#include <sys/prctl.h>
  14#include <sys/resource.h>
  15#include <setjmp.h>
  16
  17/* sigaltstack()-enforced minimum stack */
  18#define ENFORCED_MINSIGSTKSZ    2048
  19
  20#ifndef AT_MINSIGSTKSZ
  21#  define AT_MINSIGSTKSZ        51
  22#endif
  23
  24static int nerrs;
  25
  26static bool sigalrm_expected;
  27
  28static unsigned long at_minstack_size;
  29
  30static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
  31                       int flags)
  32{
  33        struct sigaction sa;
  34
  35        memset(&sa, 0, sizeof(sa));
  36        sa.sa_sigaction = handler;
  37        sa.sa_flags = SA_SIGINFO | flags;
  38        sigemptyset(&sa.sa_mask);
  39        if (sigaction(sig, &sa, 0))
  40                err(1, "sigaction");
  41}
  42
  43static void clearhandler(int sig)
  44{
  45        struct sigaction sa;
  46
  47        memset(&sa, 0, sizeof(sa));
  48        sa.sa_handler = SIG_DFL;
  49        sigemptyset(&sa.sa_mask);
  50        if (sigaction(sig, &sa, 0))
  51                err(1, "sigaction");
  52}
  53
  54static int setup_altstack(void *start, unsigned long size)
  55{
  56        stack_t ss;
  57
  58        memset(&ss, 0, sizeof(ss));
  59        ss.ss_size = size;
  60        ss.ss_sp = start;
  61
  62        return sigaltstack(&ss, NULL);
  63}
  64
  65static jmp_buf jmpbuf;
  66
  67static void sigsegv(int sig, siginfo_t *info, void *ctx_void)
  68{
  69        if (sigalrm_expected) {
  70                printf("[FAIL]\tWrong signal delivered: SIGSEGV (expected SIGALRM).");
  71                nerrs++;
  72        } else {
  73                printf("[OK]\tSIGSEGV signal delivered.\n");
  74        }
  75
  76        siglongjmp(jmpbuf, 1);
  77}
  78
  79static void sigalrm(int sig, siginfo_t *info, void *ctx_void)
  80{
  81        if (!sigalrm_expected) {
  82                printf("[FAIL]\tWrong signal delivered: SIGALRM (expected SIGSEGV).");
  83                nerrs++;
  84        } else {
  85                printf("[OK]\tSIGALRM signal delivered.\n");
  86        }
  87}
  88
  89static void test_sigaltstack(void *altstack, unsigned long size)
  90{
  91        if (setup_altstack(altstack, size))
  92                err(1, "sigaltstack()");
  93
  94        sigalrm_expected = (size > at_minstack_size) ? true : false;
  95
  96        sethandler(SIGSEGV, sigsegv, 0);
  97        sethandler(SIGALRM, sigalrm, SA_ONSTACK);
  98
  99        if (!sigsetjmp(jmpbuf, 1)) {
 100                printf("[RUN]\tTest an alternate signal stack of %ssufficient size.\n",
 101                       sigalrm_expected ? "" : "in");
 102                printf("\tRaise SIGALRM. %s is expected to be delivered.\n",
 103                       sigalrm_expected ? "It" : "SIGSEGV");
 104                raise(SIGALRM);
 105        }
 106
 107        clearhandler(SIGALRM);
 108        clearhandler(SIGSEGV);
 109}
 110
 111int main(void)
 112{
 113        void *altstack;
 114
 115        at_minstack_size = getauxval(AT_MINSIGSTKSZ);
 116
 117        altstack = mmap(NULL, at_minstack_size + SIGSTKSZ, PROT_READ | PROT_WRITE,
 118                        MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
 119        if (altstack == MAP_FAILED)
 120                err(1, "mmap()");
 121
 122        if ((ENFORCED_MINSIGSTKSZ + 1) < at_minstack_size)
 123                test_sigaltstack(altstack, ENFORCED_MINSIGSTKSZ + 1);
 124
 125        test_sigaltstack(altstack, at_minstack_size + SIGSTKSZ);
 126
 127        return nerrs == 0 ? 0 : 1;
 128}
 129