Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753220AbcCGQwd (ORCPT ); Mon, 7 Mar 2016 11:52:33 -0500 Received: from smtp43.i.mail.ru ([94.100.177.103]:55544 "EHLO smtp43.i.mail.ru" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752905AbcCGQwZ (ORCPT ); Mon, 7 Mar 2016 11:52:25 -0500 From: Stas Sergeev To: stsp@list.ru Cc: Shuah Khan , linux-kernel@vger.kernel.org, linux-api@vger.kernel.org, Andy Lutomirski , Stas Sergeev Subject: [PATCH 4/4] selftests: Add test for sigaltstack(SS_ONSTACK|SS_AUTODISARM) Date: Mon, 7 Mar 2016 19:52:07 +0300 Message-Id: <1457369527-11452-5-git-send-email-stsp@list.ru> X-Mailer: git-send-email 2.7.2 In-Reply-To: <1457369527-11452-1-git-send-email-stsp@list.ru> References: <1457369527-11452-1-git-send-email-stsp@list.ru> X-Mras: Ok Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 5377 Lines: 208 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(). CC: Shuah Khan CC: linux-kernel@vger.kernel.org CC: linux-api@vger.kernel.org CC: Andy Lutomirski Signed-off-by: Stas Sergeev --- tools/testing/selftests/Makefile | 1 + tools/testing/selftests/sigaltstack/Makefile | 8 ++ tools/testing/selftests/sigaltstack/sas.c | 156 +++++++++++++++++++++++++++ 3 files changed, 165 insertions(+) create mode 100644 tools/testing/selftests/sigaltstack/Makefile create mode 100644 tools/testing/selftests/sigaltstack/sas.c diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index b04afc3..ff9e5f2 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -19,6 +19,7 @@ TARGETS += powerpc TARGETS += pstore TARGETS += ptrace TARGETS += seccomp +TARGETS += sigaltstack TARGETS += size TARGETS += static_keys TARGETS += sysctl diff --git a/tools/testing/selftests/sigaltstack/Makefile b/tools/testing/selftests/sigaltstack/Makefile new file mode 100644 index 0000000..56af56e --- /dev/null +++ b/tools/testing/selftests/sigaltstack/Makefile @@ -0,0 +1,8 @@ +CFLAGS = -Wall +BINARIES = sas +all: $(BINARIES) + +include ../lib.mk + +clean: + rm -rf $(BINARIES) diff --git a/tools/testing/selftests/sigaltstack/sas.c b/tools/testing/selftests/sigaltstack/sas.c new file mode 100644 index 0000000..57da8bf --- /dev/null +++ b/tools/testing/selftests/sigaltstack/sas.c @@ -0,0 +1,156 @@ +/* + * Stas Sergeev + * + * test sigaltstack(SS_ONSTACK | SS_AUTODISARM) + * If that succeeds, then swapcontext() can be used inside sighandler safely. + * + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef SS_AUTODISARM +#define SS_AUTODISARM (1 << 4) +#endif + +static void *sstack, *ustack; +static ucontext_t uc, sc; +static const char *msg = "[OK]\tStack preserved"; +static const char *msg2 = "[FAIL]\tStack corrupted"; +struct stk_data { + char msg[128]; + int flag; +}; + +void my_usr1(int sig, siginfo_t *si, void *u) +{ + char *aa; + int err; + stack_t stk; + struct stk_data *p; + + register unsigned long sp asm("sp"); + + if (sp < (unsigned long)sstack || + sp >= (unsigned long)sstack + SIGSTKSZ) { + printf("[FAIL]\tSP is not on sigaltstack\n"); + exit(EXIT_FAILURE); + } + /* put some data on stack. other sighandler will try to overwrite it */ + aa = alloca(1024); + assert(aa); + p = (struct stk_data *)(aa + 512); + strcpy(p->msg, msg); + p->flag = 1; + printf("[RUN]\tsignal USR1\n"); + err = sigaltstack(NULL, &stk); + if (err) { + perror("[FAIL]\tsigaltstack()"); + exit(EXIT_FAILURE); + } + if (stk.ss_flags != SS_DISABLE) + printf("[FAIL]\tss_flags=%i, should be SS_DISABLE\n", + stk.ss_flags); + else + printf("[OK]\tsigaltstack is disabled in sighandler\n"); + swapcontext(&sc, &uc); + printf("%s\n", p->msg); + if (!p->flag) { + printf("[RUN]\tAborting\n"); + exit(EXIT_FAILURE); + } +} + +void my_usr2(int sig, siginfo_t *si, void *u) +{ + char *aa; + struct stk_data *p; + + printf("[RUN]\tsignal USR2\n"); + aa = alloca(1024); + /* dont run valgrind on this */ + /* try to find the data stored by previous sighandler */ + p = memmem(aa, 1024, msg, strlen(msg)); + if (p) { + printf("[FAIL]\tsigaltstack re-used\n"); + /* corrupt the data */ + strcpy(p->msg, msg2); + /* tell other sighandler that his data is corrupted */ + p->flag = 0; + } +} + +static void switch_fn(void) +{ + printf("[RUN]\tswitched to user ctx\n"); + raise(SIGUSR2); + setcontext(&sc); +} + +int main(void) +{ + struct sigaction act; + stack_t stk; + int err; + + sigemptyset(&act.sa_mask); + act.sa_flags = SA_ONSTACK | SA_SIGINFO; + act.sa_sigaction = my_usr1; + sigaction(SIGUSR1, &act, NULL); + act.sa_sigaction = my_usr2; + sigaction(SIGUSR2, &act, NULL); + sstack = mmap(NULL, SIGSTKSZ, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); + if (sstack == MAP_FAILED) { + perror("mmap()"); + return EXIT_FAILURE; + } + stk.ss_sp = sstack; + stk.ss_size = SIGSTKSZ; + stk.ss_flags = SS_ONSTACK | SS_AUTODISARM; + err = sigaltstack(&stk, NULL); + if (err) { + perror("[FAIL]\tsigaltstack(SS_ONSTACK | SS_AUTODISARM)"); + stk.ss_flags = SS_ONSTACK; + } + err = sigaltstack(&stk, NULL); + if (err) { + perror("[FAIL]\tsigaltstack(SS_ONSTACK)"); + return EXIT_FAILURE; + } + + ustack = mmap(NULL, SIGSTKSZ, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); + if (ustack == MAP_FAILED) { + perror("mmap()"); + return EXIT_FAILURE; + } + getcontext(&uc); + uc.uc_link = NULL; + uc.uc_stack.ss_sp = ustack; + uc.uc_stack.ss_size = SIGSTKSZ; + makecontext(&uc, switch_fn, 0); + raise(SIGUSR1); + + err = sigaltstack(NULL, &stk); + if (err) { + perror("[FAIL]\tsigaltstack()"); + exit(EXIT_FAILURE); + } + if (stk.ss_flags != 0) { + printf("[FAIL]\tss_flags=%i, should be 0\n", + stk.ss_flags); + exit(EXIT_FAILURE); + } + printf("[OK]\tsigaltstack is enabled after signal\n"); + + printf("[OK]\tTest passed\n"); + return 0; +} -- 2.7.2