linux/tools/testing/selftests/sigaltstack/sas.c
<<
>>
Prefs
   1/*
   2 * Stas Sergeev <stsp@users.sourceforge.net>
   3 *
   4 * test sigaltstack(SS_ONSTACK | SS_AUTODISARM)
   5 * If that succeeds, then swapcontext() can be used inside sighandler safely.
   6 *
   7 */
   8
   9#define _GNU_SOURCE
  10#include <signal.h>
  11#include <stdio.h>
  12#include <stdlib.h>
  13#include <sys/mman.h>
  14#include <ucontext.h>
  15#include <alloca.h>
  16#include <string.h>
  17#include <assert.h>
  18#include <errno.h>
  19
  20#ifndef SS_AUTODISARM
  21#define SS_AUTODISARM  (1U << 31)
  22#endif
  23
  24static void *sstack, *ustack;
  25static ucontext_t uc, sc;
  26static const char *msg = "[OK]\tStack preserved";
  27static const char *msg2 = "[FAIL]\tStack corrupted";
  28struct stk_data {
  29        char msg[128];
  30        int flag;
  31};
  32
  33void my_usr1(int sig, siginfo_t *si, void *u)
  34{
  35        char *aa;
  36        int err;
  37        stack_t stk;
  38        struct stk_data *p;
  39
  40        register unsigned long sp asm("sp");
  41
  42        if (sp < (unsigned long)sstack ||
  43                        sp >= (unsigned long)sstack + SIGSTKSZ) {
  44                printf("[FAIL]\tSP is not on sigaltstack\n");
  45                exit(EXIT_FAILURE);
  46        }
  47        /* put some data on stack. other sighandler will try to overwrite it */
  48        aa = alloca(1024);
  49        assert(aa);
  50        p = (struct stk_data *)(aa + 512);
  51        strcpy(p->msg, msg);
  52        p->flag = 1;
  53        printf("[RUN]\tsignal USR1\n");
  54        err = sigaltstack(NULL, &stk);
  55        if (err) {
  56                perror("[FAIL]\tsigaltstack()");
  57                exit(EXIT_FAILURE);
  58        }
  59        if (stk.ss_flags != SS_DISABLE)
  60                printf("[FAIL]\tss_flags=%i, should be SS_DISABLE\n",
  61                                stk.ss_flags);
  62        else
  63                printf("[OK]\tsigaltstack is disabled in sighandler\n");
  64        swapcontext(&sc, &uc);
  65        printf("%s\n", p->msg);
  66        if (!p->flag) {
  67                printf("[RUN]\tAborting\n");
  68                exit(EXIT_FAILURE);
  69        }
  70}
  71
  72void my_usr2(int sig, siginfo_t *si, void *u)
  73{
  74        char *aa;
  75        struct stk_data *p;
  76
  77        printf("[RUN]\tsignal USR2\n");
  78        aa = alloca(1024);
  79        /* dont run valgrind on this */
  80        /* try to find the data stored by previous sighandler */
  81        p = memmem(aa, 1024, msg, strlen(msg));
  82        if (p) {
  83                printf("[FAIL]\tsigaltstack re-used\n");
  84                /* corrupt the data */
  85                strcpy(p->msg, msg2);
  86                /* tell other sighandler that his data is corrupted */
  87                p->flag = 0;
  88        }
  89}
  90
  91static void switch_fn(void)
  92{
  93        printf("[RUN]\tswitched to user ctx\n");
  94        raise(SIGUSR2);
  95        setcontext(&sc);
  96}
  97
  98int main(void)
  99{
 100        struct sigaction act;
 101        stack_t stk;
 102        int err;
 103
 104        sigemptyset(&act.sa_mask);
 105        act.sa_flags = SA_ONSTACK | SA_SIGINFO;
 106        act.sa_sigaction = my_usr1;
 107        sigaction(SIGUSR1, &act, NULL);
 108        act.sa_sigaction = my_usr2;
 109        sigaction(SIGUSR2, &act, NULL);
 110        sstack = mmap(NULL, SIGSTKSZ, PROT_READ | PROT_WRITE,
 111                      MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
 112        if (sstack == MAP_FAILED) {
 113                perror("mmap()");
 114                return EXIT_FAILURE;
 115        }
 116
 117        err = sigaltstack(NULL, &stk);
 118        if (err) {
 119                perror("[FAIL]\tsigaltstack()");
 120                exit(EXIT_FAILURE);
 121        }
 122        if (stk.ss_flags == SS_DISABLE) {
 123                printf("[OK]\tInitial sigaltstack state was SS_DISABLE\n");
 124        } else {
 125                printf("[FAIL]\tInitial sigaltstack state was %i; should have been SS_DISABLE\n", stk.ss_flags);
 126                return EXIT_FAILURE;
 127        }
 128
 129        stk.ss_sp = sstack;
 130        stk.ss_size = SIGSTKSZ;
 131        stk.ss_flags = SS_ONSTACK | SS_AUTODISARM;
 132        err = sigaltstack(&stk, NULL);
 133        if (err) {
 134                if (errno == EINVAL) {
 135                        printf("[NOTE]\tThe running kernel doesn't support SS_AUTODISARM\n");
 136                        /*
 137                         * If test cases for the !SS_AUTODISARM variant were
 138                         * added, we could still run them.  We don't have any
 139                         * test cases like that yet, so just exit and report
 140                         * success.
 141                         */
 142                        return 0;
 143                } else {
 144                        perror("[FAIL]\tsigaltstack(SS_ONSTACK | SS_AUTODISARM)");
 145                        return EXIT_FAILURE;
 146                }
 147        }
 148
 149        ustack = mmap(NULL, SIGSTKSZ, PROT_READ | PROT_WRITE,
 150                      MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
 151        if (ustack == MAP_FAILED) {
 152                perror("mmap()");
 153                return EXIT_FAILURE;
 154        }
 155        getcontext(&uc);
 156        uc.uc_link = NULL;
 157        uc.uc_stack.ss_sp = ustack;
 158        uc.uc_stack.ss_size = SIGSTKSZ;
 159        makecontext(&uc, switch_fn, 0);
 160        raise(SIGUSR1);
 161
 162        err = sigaltstack(NULL, &stk);
 163        if (err) {
 164                perror("[FAIL]\tsigaltstack()");
 165                exit(EXIT_FAILURE);
 166        }
 167        if (stk.ss_flags != SS_AUTODISARM) {
 168                printf("[FAIL]\tss_flags=%i, should be SS_AUTODISARM\n",
 169                                stk.ss_flags);
 170                exit(EXIT_FAILURE);
 171        }
 172        printf("[OK]\tsigaltstack is still SS_AUTODISARM after signal\n");
 173
 174        printf("[OK]\tTest passed\n");
 175        return 0;
 176}
 177