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 24 static void *sstack, *ustack; 25 static ucontext_t uc, sc; 26 static const char *msg = "[OK]\tStack preserved"; 27 static const char *msg2 = "[FAIL]\tStack corrupted"; 28 struct stk_data { 29 char msg[128]; 30 int flag; 31 }; 32 33 void 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 72 void 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 91 static void switch_fn(void) 92 { 93 printf("[RUN]\tswitched to user ctx\n"); 94 raise(SIGUSR2); 95 setcontext(&sc); 96 } 97 98 int 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