Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Stas Sergeev <stsp@users.sourceforge.net>
0004  *
0005  * test sigaltstack(SS_ONSTACK | SS_AUTODISARM)
0006  * If that succeeds, then swapcontext() can be used inside sighandler safely.
0007  *
0008  */
0009 
0010 #define _GNU_SOURCE
0011 #include <signal.h>
0012 #include <stdio.h>
0013 #include <stdlib.h>
0014 #include <sys/mman.h>
0015 #include <ucontext.h>
0016 #include <alloca.h>
0017 #include <string.h>
0018 #include <assert.h>
0019 #include <errno.h>
0020 #include <sys/auxv.h>
0021 
0022 #include "../kselftest.h"
0023 
0024 #ifndef SS_AUTODISARM
0025 #define SS_AUTODISARM  (1U << 31)
0026 #endif
0027 
0028 #ifndef AT_MINSIGSTKSZ
0029 #define AT_MINSIGSTKSZ  51
0030 #endif
0031 
0032 static unsigned int stack_size;
0033 static void *sstack, *ustack;
0034 static ucontext_t uc, sc;
0035 static const char *msg = "[OK]\tStack preserved";
0036 static const char *msg2 = "[FAIL]\tStack corrupted";
0037 struct stk_data {
0038     char msg[128];
0039     int flag;
0040 };
0041 
0042 void my_usr1(int sig, siginfo_t *si, void *u)
0043 {
0044     char *aa;
0045     int err;
0046     stack_t stk;
0047     struct stk_data *p;
0048 
0049 #if __s390x__
0050     register unsigned long sp asm("%15");
0051 #else
0052     register unsigned long sp asm("sp");
0053 #endif
0054 
0055     if (sp < (unsigned long)sstack ||
0056             sp >= (unsigned long)sstack + stack_size) {
0057         ksft_exit_fail_msg("SP is not on sigaltstack\n");
0058     }
0059     /* put some data on stack. other sighandler will try to overwrite it */
0060     aa = alloca(1024);
0061     assert(aa);
0062     p = (struct stk_data *)(aa + 512);
0063     strcpy(p->msg, msg);
0064     p->flag = 1;
0065     ksft_print_msg("[RUN]\tsignal USR1\n");
0066     err = sigaltstack(NULL, &stk);
0067     if (err) {
0068         ksft_exit_fail_msg("sigaltstack() - %s\n", strerror(errno));
0069         exit(EXIT_FAILURE);
0070     }
0071     if (stk.ss_flags != SS_DISABLE)
0072         ksft_test_result_fail("tss_flags=%x, should be SS_DISABLE\n",
0073                 stk.ss_flags);
0074     else
0075         ksft_test_result_pass(
0076                 "sigaltstack is disabled in sighandler\n");
0077     swapcontext(&sc, &uc);
0078     ksft_print_msg("%s\n", p->msg);
0079     if (!p->flag) {
0080         ksft_exit_fail_msg("[RUN]\tAborting\n");
0081         exit(EXIT_FAILURE);
0082     }
0083 }
0084 
0085 void my_usr2(int sig, siginfo_t *si, void *u)
0086 {
0087     char *aa;
0088     struct stk_data *p;
0089 
0090     ksft_print_msg("[RUN]\tsignal USR2\n");
0091     aa = alloca(1024);
0092     /* dont run valgrind on this */
0093     /* try to find the data stored by previous sighandler */
0094     p = memmem(aa, 1024, msg, strlen(msg));
0095     if (p) {
0096         ksft_test_result_fail("sigaltstack re-used\n");
0097         /* corrupt the data */
0098         strcpy(p->msg, msg2);
0099         /* tell other sighandler that his data is corrupted */
0100         p->flag = 0;
0101     }
0102 }
0103 
0104 static void switch_fn(void)
0105 {
0106     ksft_print_msg("[RUN]\tswitched to user ctx\n");
0107     raise(SIGUSR2);
0108     setcontext(&sc);
0109 }
0110 
0111 int main(void)
0112 {
0113     struct sigaction act;
0114     stack_t stk;
0115     int err;
0116 
0117     /* Make sure more than the required minimum. */
0118     stack_size = getauxval(AT_MINSIGSTKSZ) + SIGSTKSZ;
0119     ksft_print_msg("[NOTE]\tthe stack size is %lu\n", stack_size);
0120 
0121     ksft_print_header();
0122     ksft_set_plan(3);
0123 
0124     sigemptyset(&act.sa_mask);
0125     act.sa_flags = SA_ONSTACK | SA_SIGINFO;
0126     act.sa_sigaction = my_usr1;
0127     sigaction(SIGUSR1, &act, NULL);
0128     act.sa_sigaction = my_usr2;
0129     sigaction(SIGUSR2, &act, NULL);
0130     sstack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE,
0131               MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
0132     if (sstack == MAP_FAILED) {
0133         ksft_exit_fail_msg("mmap() - %s\n", strerror(errno));
0134         return EXIT_FAILURE;
0135     }
0136 
0137     err = sigaltstack(NULL, &stk);
0138     if (err) {
0139         ksft_exit_fail_msg("sigaltstack() - %s\n", strerror(errno));
0140         exit(EXIT_FAILURE);
0141     }
0142     if (stk.ss_flags == SS_DISABLE) {
0143         ksft_test_result_pass(
0144                 "Initial sigaltstack state was SS_DISABLE\n");
0145     } else {
0146         ksft_exit_fail_msg("Initial sigaltstack state was %x; "
0147                "should have been SS_DISABLE\n", stk.ss_flags);
0148         return EXIT_FAILURE;
0149     }
0150 
0151     stk.ss_sp = sstack;
0152     stk.ss_size = stack_size;
0153     stk.ss_flags = SS_ONSTACK | SS_AUTODISARM;
0154     err = sigaltstack(&stk, NULL);
0155     if (err) {
0156         if (errno == EINVAL) {
0157             ksft_test_result_skip(
0158                 "[NOTE]\tThe running kernel doesn't support SS_AUTODISARM\n");
0159             /*
0160              * If test cases for the !SS_AUTODISARM variant were
0161              * added, we could still run them.  We don't have any
0162              * test cases like that yet, so just exit and report
0163              * success.
0164              */
0165             return 0;
0166         } else {
0167             ksft_exit_fail_msg(
0168                 "sigaltstack(SS_ONSTACK | SS_AUTODISARM)  %s\n",
0169                     strerror(errno));
0170             return EXIT_FAILURE;
0171         }
0172     }
0173 
0174     ustack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE,
0175               MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
0176     if (ustack == MAP_FAILED) {
0177         ksft_exit_fail_msg("mmap() - %s\n", strerror(errno));
0178         return EXIT_FAILURE;
0179     }
0180     getcontext(&uc);
0181     uc.uc_link = NULL;
0182     uc.uc_stack.ss_sp = ustack;
0183     uc.uc_stack.ss_size = stack_size;
0184     makecontext(&uc, switch_fn, 0);
0185     raise(SIGUSR1);
0186 
0187     err = sigaltstack(NULL, &stk);
0188     if (err) {
0189         ksft_exit_fail_msg("sigaltstack() - %s\n", strerror(errno));
0190         exit(EXIT_FAILURE);
0191     }
0192     if (stk.ss_flags != SS_AUTODISARM) {
0193         ksft_exit_fail_msg("ss_flags=%x, should be SS_AUTODISARM\n",
0194                 stk.ss_flags);
0195         exit(EXIT_FAILURE);
0196     }
0197     ksft_test_result_pass(
0198             "sigaltstack is still SS_AUTODISARM after signal\n");
0199 
0200     ksft_exit_pass();
0201     return 0;
0202 }