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