root/tools/testing/selftests/sigaltstack/sas.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. my_usr1
  2. my_usr2
  3. switch_fn
  4. main

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

/* [<][>][^][v][top][bottom][index][help] */