198 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Stas Sergeev <stsp@users.sourceforge.net>4 *5 * test sigaltstack(SS_ONSTACK | SS_AUTODISARM)6 * If that succeeds, then swapcontext() can be used inside sighandler safely.7 *8 */9 10#define _GNU_SOURCE11#include <signal.h>12#include <stdio.h>13#include <stdlib.h>14#include <sys/mman.h>15#include <ucontext.h>16#include <alloca.h>17#include <string.h>18#include <assert.h>19#include <errno.h>20#include <sys/auxv.h>21 22#include "../kselftest.h"23#include "current_stack_pointer.h"24 25#ifndef SS_AUTODISARM26#define SS_AUTODISARM (1U << 31)27#endif28 29#ifndef AT_MINSIGSTKSZ30#define AT_MINSIGSTKSZ 5131#endif32 33static unsigned int stack_size;34static void *sstack, *ustack;35static ucontext_t uc, sc;36static const char *msg = "[OK]\tStack preserved";37static const char *msg2 = "[FAIL]\tStack corrupted";38struct stk_data {39 char msg[128];40 int flag;41};42 43void my_usr1(int sig, siginfo_t *si, void *u)44{45 char *aa;46 int err;47 stack_t stk;48 struct stk_data *p;49 50 if (sp < (unsigned long)sstack ||51 sp >= (unsigned long)sstack + stack_size) {52 ksft_exit_fail_msg("SP is not on sigaltstack\n");53 }54 /* put some data on stack. other sighandler will try to overwrite it */55 aa = alloca(1024);56 assert(aa);57 p = (struct stk_data *)(aa + 512);58 strcpy(p->msg, msg);59 p->flag = 1;60 ksft_print_msg("[RUN]\tsignal USR1\n");61 err = sigaltstack(NULL, &stk);62 if (err) {63 ksft_exit_fail_msg("sigaltstack() - %s\n", strerror(errno));64 exit(EXIT_FAILURE);65 }66 if (stk.ss_flags != SS_DISABLE)67 ksft_test_result_fail("tss_flags=%x, should be SS_DISABLE\n",68 stk.ss_flags);69 else70 ksft_test_result_pass(71 "sigaltstack is disabled in sighandler\n");72 swapcontext(&sc, &uc);73 ksft_print_msg("%s\n", p->msg);74 if (!p->flag) {75 ksft_exit_fail_msg("[RUN]\tAborting\n");76 exit(EXIT_FAILURE);77 }78}79 80void my_usr2(int sig, siginfo_t *si, void *u)81{82 char *aa;83 struct stk_data *p;84 85 ksft_print_msg("[RUN]\tsignal USR2\n");86 aa = alloca(1024);87 /* dont run valgrind on this */88 /* try to find the data stored by previous sighandler */89 p = memmem(aa, 1024, msg, strlen(msg));90 if (p) {91 ksft_test_result_fail("sigaltstack re-used\n");92 /* corrupt the data */93 strcpy(p->msg, msg2);94 /* tell other sighandler that his data is corrupted */95 p->flag = 0;96 }97}98 99static void switch_fn(void)100{101 ksft_print_msg("[RUN]\tswitched to user ctx\n");102 raise(SIGUSR2);103 setcontext(&sc);104}105 106int main(void)107{108 struct sigaction act;109 stack_t stk;110 int err;111 112 /* Make sure more than the required minimum. */113 stack_size = getauxval(AT_MINSIGSTKSZ) + SIGSTKSZ;114 ksft_print_msg("[NOTE]\tthe stack size is %u\n", stack_size);115 116 ksft_print_header();117 ksft_set_plan(3);118 119 sigemptyset(&act.sa_mask);120 act.sa_flags = SA_ONSTACK | SA_SIGINFO;121 act.sa_sigaction = my_usr1;122 sigaction(SIGUSR1, &act, NULL);123 act.sa_sigaction = my_usr2;124 sigaction(SIGUSR2, &act, NULL);125 sstack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE,126 MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);127 if (sstack == MAP_FAILED) {128 ksft_exit_fail_msg("mmap() - %s\n", strerror(errno));129 return EXIT_FAILURE;130 }131 132 err = sigaltstack(NULL, &stk);133 if (err) {134 ksft_exit_fail_msg("sigaltstack() - %s\n", strerror(errno));135 exit(EXIT_FAILURE);136 }137 if (stk.ss_flags == SS_DISABLE) {138 ksft_test_result_pass(139 "Initial sigaltstack state was SS_DISABLE\n");140 } else {141 ksft_exit_fail_msg("Initial sigaltstack state was %x; "142 "should have been SS_DISABLE\n", stk.ss_flags);143 return EXIT_FAILURE;144 }145 146 stk.ss_sp = sstack;147 stk.ss_size = stack_size;148 stk.ss_flags = SS_ONSTACK | SS_AUTODISARM;149 err = sigaltstack(&stk, NULL);150 if (err) {151 if (errno == EINVAL) {152 ksft_test_result_skip(153 "[NOTE]\tThe running kernel doesn't support SS_AUTODISARM\n");154 /*155 * If test cases for the !SS_AUTODISARM variant were156 * added, we could still run them. We don't have any157 * test cases like that yet, so just exit and report158 * success.159 */160 return 0;161 } else {162 ksft_exit_fail_msg(163 "sigaltstack(SS_ONSTACK | SS_AUTODISARM) %s\n",164 strerror(errno));165 return EXIT_FAILURE;166 }167 }168 169 ustack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE,170 MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);171 if (ustack == MAP_FAILED) {172 ksft_exit_fail_msg("mmap() - %s\n", strerror(errno));173 return EXIT_FAILURE;174 }175 getcontext(&uc);176 uc.uc_link = NULL;177 uc.uc_stack.ss_sp = ustack;178 uc.uc_stack.ss_size = stack_size;179 makecontext(&uc, switch_fn, 0);180 raise(SIGUSR1);181 182 err = sigaltstack(NULL, &stk);183 if (err) {184 ksft_exit_fail_msg("sigaltstack() - %s\n", strerror(errno));185 exit(EXIT_FAILURE);186 }187 if (stk.ss_flags != SS_AUTODISARM) {188 ksft_exit_fail_msg("ss_flags=%x, should be SS_AUTODISARM\n",189 stk.ss_flags);190 exit(EXIT_FAILURE);191 }192 ksft_test_result_pass(193 "sigaltstack is still SS_AUTODISARM after signal\n");194 195 ksft_exit_pass();196 return 0;197}198