Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/sigaltstack: Add new testcase for sigaltstack(SS_ONSTACK|SS_AUTODISARM)

This patch adds the test case for SS_AUTODISARM flag.
The test-case tries to set SS_AUTODISARM flag and checks if
the nested signal corrupts the stack after swapcontext().

Signed-off-by: Stas Sergeev <stsp@list.ru>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Pavel Emelyanov <xemul@parallels.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Shuah Khan <shuahkh@osg.samsung.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-api@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Link: http://lkml.kernel.org/r/1460665206-13646-5-git-send-email-stsp@list.ru
Signed-off-by: Ingo Molnar <mingo@kernel.org>

authored by

Stas Sergeev and committed by
Ingo Molnar
19fd2868 2a742138

+165
+1
tools/testing/selftests/Makefile
··· 19 19 TARGETS += pstore 20 20 TARGETS += ptrace 21 21 TARGETS += seccomp 22 + TARGETS += sigaltstack 22 23 TARGETS += size 23 24 TARGETS += static_keys 24 25 TARGETS += sysctl
+8
tools/testing/selftests/sigaltstack/Makefile
··· 1 + CFLAGS = -Wall 2 + BINARIES = sas 3 + all: $(BINARIES) 4 + 5 + include ../lib.mk 6 + 7 + clean: 8 + rm -rf $(BINARIES)
+156
tools/testing/selftests/sigaltstack/sas.c
··· 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 + 19 + #ifndef SS_AUTODISARM 20 + #define SS_AUTODISARM (1 << 4) 21 + #endif 22 + 23 + static void *sstack, *ustack; 24 + static ucontext_t uc, sc; 25 + static const char *msg = "[OK]\tStack preserved"; 26 + static const char *msg2 = "[FAIL]\tStack corrupted"; 27 + struct stk_data { 28 + char msg[128]; 29 + int flag; 30 + }; 31 + 32 + void my_usr1(int sig, siginfo_t *si, void *u) 33 + { 34 + char *aa; 35 + int err; 36 + stack_t stk; 37 + struct stk_data *p; 38 + 39 + register unsigned long sp asm("sp"); 40 + 41 + if (sp < (unsigned long)sstack || 42 + sp >= (unsigned long)sstack + SIGSTKSZ) { 43 + printf("[FAIL]\tSP is not on sigaltstack\n"); 44 + exit(EXIT_FAILURE); 45 + } 46 + /* put some data on stack. other sighandler will try to overwrite it */ 47 + aa = alloca(1024); 48 + assert(aa); 49 + p = (struct stk_data *)(aa + 512); 50 + strcpy(p->msg, msg); 51 + p->flag = 1; 52 + printf("[RUN]\tsignal USR1\n"); 53 + err = sigaltstack(NULL, &stk); 54 + if (err) { 55 + perror("[FAIL]\tsigaltstack()"); 56 + exit(EXIT_FAILURE); 57 + } 58 + if (stk.ss_flags != SS_DISABLE) 59 + printf("[FAIL]\tss_flags=%i, should be SS_DISABLE\n", 60 + stk.ss_flags); 61 + else 62 + printf("[OK]\tsigaltstack is disabled in sighandler\n"); 63 + swapcontext(&sc, &uc); 64 + printf("%s\n", p->msg); 65 + if (!p->flag) { 66 + printf("[RUN]\tAborting\n"); 67 + exit(EXIT_FAILURE); 68 + } 69 + } 70 + 71 + void my_usr2(int sig, siginfo_t *si, void *u) 72 + { 73 + char *aa; 74 + struct stk_data *p; 75 + 76 + printf("[RUN]\tsignal USR2\n"); 77 + aa = alloca(1024); 78 + /* dont run valgrind on this */ 79 + /* try to find the data stored by previous sighandler */ 80 + p = memmem(aa, 1024, msg, strlen(msg)); 81 + if (p) { 82 + printf("[FAIL]\tsigaltstack re-used\n"); 83 + /* corrupt the data */ 84 + strcpy(p->msg, msg2); 85 + /* tell other sighandler that his data is corrupted */ 86 + p->flag = 0; 87 + } 88 + } 89 + 90 + static void switch_fn(void) 91 + { 92 + printf("[RUN]\tswitched to user ctx\n"); 93 + raise(SIGUSR2); 94 + setcontext(&sc); 95 + } 96 + 97 + int main(void) 98 + { 99 + struct sigaction act; 100 + stack_t stk; 101 + int err; 102 + 103 + sigemptyset(&act.sa_mask); 104 + act.sa_flags = SA_ONSTACK | SA_SIGINFO; 105 + act.sa_sigaction = my_usr1; 106 + sigaction(SIGUSR1, &act, NULL); 107 + act.sa_sigaction = my_usr2; 108 + sigaction(SIGUSR2, &act, NULL); 109 + sstack = mmap(NULL, SIGSTKSZ, PROT_READ | PROT_WRITE, 110 + MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); 111 + if (sstack == MAP_FAILED) { 112 + perror("mmap()"); 113 + return EXIT_FAILURE; 114 + } 115 + stk.ss_sp = sstack; 116 + stk.ss_size = SIGSTKSZ; 117 + stk.ss_flags = SS_ONSTACK | SS_AUTODISARM; 118 + err = sigaltstack(&stk, NULL); 119 + if (err) { 120 + perror("[FAIL]\tsigaltstack(SS_ONSTACK | SS_AUTODISARM)"); 121 + stk.ss_flags = SS_ONSTACK; 122 + } 123 + err = sigaltstack(&stk, NULL); 124 + if (err) { 125 + perror("[FAIL]\tsigaltstack(SS_ONSTACK)"); 126 + return EXIT_FAILURE; 127 + } 128 + 129 + ustack = mmap(NULL, SIGSTKSZ, PROT_READ | PROT_WRITE, 130 + MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); 131 + if (ustack == MAP_FAILED) { 132 + perror("mmap()"); 133 + return EXIT_FAILURE; 134 + } 135 + getcontext(&uc); 136 + uc.uc_link = NULL; 137 + uc.uc_stack.ss_sp = ustack; 138 + uc.uc_stack.ss_size = SIGSTKSZ; 139 + makecontext(&uc, switch_fn, 0); 140 + raise(SIGUSR1); 141 + 142 + err = sigaltstack(NULL, &stk); 143 + if (err) { 144 + perror("[FAIL]\tsigaltstack()"); 145 + exit(EXIT_FAILURE); 146 + } 147 + if (stk.ss_flags != 0) { 148 + printf("[FAIL]\tss_flags=%i, should be 0\n", 149 + stk.ss_flags); 150 + exit(EXIT_FAILURE); 151 + } 152 + printf("[OK]\tsigaltstack is enabled after signal\n"); 153 + 154 + printf("[OK]\tTest passed\n"); 155 + return 0; 156 + }