162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Stas Sergeev <stsp@users.sourceforge.net> 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * test sigaltstack(SS_ONSTACK | SS_AUTODISARM) 662306a36Sopenharmony_ci * If that succeeds, then swapcontext() can be used inside sighandler safely. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#define _GNU_SOURCE 1162306a36Sopenharmony_ci#include <signal.h> 1262306a36Sopenharmony_ci#include <stdio.h> 1362306a36Sopenharmony_ci#include <stdlib.h> 1462306a36Sopenharmony_ci#include <sys/mman.h> 1562306a36Sopenharmony_ci#include <ucontext.h> 1662306a36Sopenharmony_ci#include <alloca.h> 1762306a36Sopenharmony_ci#include <string.h> 1862306a36Sopenharmony_ci#include <assert.h> 1962306a36Sopenharmony_ci#include <errno.h> 2062306a36Sopenharmony_ci#include <sys/auxv.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include "../kselftest.h" 2362306a36Sopenharmony_ci#include "current_stack_pointer.h" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#ifndef SS_AUTODISARM 2662306a36Sopenharmony_ci#define SS_AUTODISARM (1U << 31) 2762306a36Sopenharmony_ci#endif 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#ifndef AT_MINSIGSTKSZ 3062306a36Sopenharmony_ci#define AT_MINSIGSTKSZ 51 3162306a36Sopenharmony_ci#endif 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic unsigned int stack_size; 3462306a36Sopenharmony_cistatic void *sstack, *ustack; 3562306a36Sopenharmony_cistatic ucontext_t uc, sc; 3662306a36Sopenharmony_cistatic const char *msg = "[OK]\tStack preserved"; 3762306a36Sopenharmony_cistatic const char *msg2 = "[FAIL]\tStack corrupted"; 3862306a36Sopenharmony_cistruct stk_data { 3962306a36Sopenharmony_ci char msg[128]; 4062306a36Sopenharmony_ci int flag; 4162306a36Sopenharmony_ci}; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_civoid my_usr1(int sig, siginfo_t *si, void *u) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci char *aa; 4662306a36Sopenharmony_ci int err; 4762306a36Sopenharmony_ci stack_t stk; 4862306a36Sopenharmony_ci struct stk_data *p; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci if (sp < (unsigned long)sstack || 5162306a36Sopenharmony_ci sp >= (unsigned long)sstack + stack_size) { 5262306a36Sopenharmony_ci ksft_exit_fail_msg("SP is not on sigaltstack\n"); 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci /* put some data on stack. other sighandler will try to overwrite it */ 5562306a36Sopenharmony_ci aa = alloca(1024); 5662306a36Sopenharmony_ci assert(aa); 5762306a36Sopenharmony_ci p = (struct stk_data *)(aa + 512); 5862306a36Sopenharmony_ci strcpy(p->msg, msg); 5962306a36Sopenharmony_ci p->flag = 1; 6062306a36Sopenharmony_ci ksft_print_msg("[RUN]\tsignal USR1\n"); 6162306a36Sopenharmony_ci err = sigaltstack(NULL, &stk); 6262306a36Sopenharmony_ci if (err) { 6362306a36Sopenharmony_ci ksft_exit_fail_msg("sigaltstack() - %s\n", strerror(errno)); 6462306a36Sopenharmony_ci exit(EXIT_FAILURE); 6562306a36Sopenharmony_ci } 6662306a36Sopenharmony_ci if (stk.ss_flags != SS_DISABLE) 6762306a36Sopenharmony_ci ksft_test_result_fail("tss_flags=%x, should be SS_DISABLE\n", 6862306a36Sopenharmony_ci stk.ss_flags); 6962306a36Sopenharmony_ci else 7062306a36Sopenharmony_ci ksft_test_result_pass( 7162306a36Sopenharmony_ci "sigaltstack is disabled in sighandler\n"); 7262306a36Sopenharmony_ci swapcontext(&sc, &uc); 7362306a36Sopenharmony_ci ksft_print_msg("%s\n", p->msg); 7462306a36Sopenharmony_ci if (!p->flag) { 7562306a36Sopenharmony_ci ksft_exit_fail_msg("[RUN]\tAborting\n"); 7662306a36Sopenharmony_ci exit(EXIT_FAILURE); 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_civoid my_usr2(int sig, siginfo_t *si, void *u) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci char *aa; 8362306a36Sopenharmony_ci struct stk_data *p; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci ksft_print_msg("[RUN]\tsignal USR2\n"); 8662306a36Sopenharmony_ci aa = alloca(1024); 8762306a36Sopenharmony_ci /* dont run valgrind on this */ 8862306a36Sopenharmony_ci /* try to find the data stored by previous sighandler */ 8962306a36Sopenharmony_ci p = memmem(aa, 1024, msg, strlen(msg)); 9062306a36Sopenharmony_ci if (p) { 9162306a36Sopenharmony_ci ksft_test_result_fail("sigaltstack re-used\n"); 9262306a36Sopenharmony_ci /* corrupt the data */ 9362306a36Sopenharmony_ci strcpy(p->msg, msg2); 9462306a36Sopenharmony_ci /* tell other sighandler that his data is corrupted */ 9562306a36Sopenharmony_ci p->flag = 0; 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic void switch_fn(void) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci ksft_print_msg("[RUN]\tswitched to user ctx\n"); 10262306a36Sopenharmony_ci raise(SIGUSR2); 10362306a36Sopenharmony_ci setcontext(&sc); 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ciint main(void) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci struct sigaction act; 10962306a36Sopenharmony_ci stack_t stk; 11062306a36Sopenharmony_ci int err; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci /* Make sure more than the required minimum. */ 11362306a36Sopenharmony_ci stack_size = getauxval(AT_MINSIGSTKSZ) + SIGSTKSZ; 11462306a36Sopenharmony_ci ksft_print_msg("[NOTE]\tthe stack size is %lu\n", stack_size); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci ksft_print_header(); 11762306a36Sopenharmony_ci ksft_set_plan(3); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci sigemptyset(&act.sa_mask); 12062306a36Sopenharmony_ci act.sa_flags = SA_ONSTACK | SA_SIGINFO; 12162306a36Sopenharmony_ci act.sa_sigaction = my_usr1; 12262306a36Sopenharmony_ci sigaction(SIGUSR1, &act, NULL); 12362306a36Sopenharmony_ci act.sa_sigaction = my_usr2; 12462306a36Sopenharmony_ci sigaction(SIGUSR2, &act, NULL); 12562306a36Sopenharmony_ci sstack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, 12662306a36Sopenharmony_ci MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); 12762306a36Sopenharmony_ci if (sstack == MAP_FAILED) { 12862306a36Sopenharmony_ci ksft_exit_fail_msg("mmap() - %s\n", strerror(errno)); 12962306a36Sopenharmony_ci return EXIT_FAILURE; 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci err = sigaltstack(NULL, &stk); 13362306a36Sopenharmony_ci if (err) { 13462306a36Sopenharmony_ci ksft_exit_fail_msg("sigaltstack() - %s\n", strerror(errno)); 13562306a36Sopenharmony_ci exit(EXIT_FAILURE); 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci if (stk.ss_flags == SS_DISABLE) { 13862306a36Sopenharmony_ci ksft_test_result_pass( 13962306a36Sopenharmony_ci "Initial sigaltstack state was SS_DISABLE\n"); 14062306a36Sopenharmony_ci } else { 14162306a36Sopenharmony_ci ksft_exit_fail_msg("Initial sigaltstack state was %x; " 14262306a36Sopenharmony_ci "should have been SS_DISABLE\n", stk.ss_flags); 14362306a36Sopenharmony_ci return EXIT_FAILURE; 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci stk.ss_sp = sstack; 14762306a36Sopenharmony_ci stk.ss_size = stack_size; 14862306a36Sopenharmony_ci stk.ss_flags = SS_ONSTACK | SS_AUTODISARM; 14962306a36Sopenharmony_ci err = sigaltstack(&stk, NULL); 15062306a36Sopenharmony_ci if (err) { 15162306a36Sopenharmony_ci if (errno == EINVAL) { 15262306a36Sopenharmony_ci ksft_test_result_skip( 15362306a36Sopenharmony_ci "[NOTE]\tThe running kernel doesn't support SS_AUTODISARM\n"); 15462306a36Sopenharmony_ci /* 15562306a36Sopenharmony_ci * If test cases for the !SS_AUTODISARM variant were 15662306a36Sopenharmony_ci * added, we could still run them. We don't have any 15762306a36Sopenharmony_ci * test cases like that yet, so just exit and report 15862306a36Sopenharmony_ci * success. 15962306a36Sopenharmony_ci */ 16062306a36Sopenharmony_ci return 0; 16162306a36Sopenharmony_ci } else { 16262306a36Sopenharmony_ci ksft_exit_fail_msg( 16362306a36Sopenharmony_ci "sigaltstack(SS_ONSTACK | SS_AUTODISARM) %s\n", 16462306a36Sopenharmony_ci strerror(errno)); 16562306a36Sopenharmony_ci return EXIT_FAILURE; 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci ustack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, 17062306a36Sopenharmony_ci MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); 17162306a36Sopenharmony_ci if (ustack == MAP_FAILED) { 17262306a36Sopenharmony_ci ksft_exit_fail_msg("mmap() - %s\n", strerror(errno)); 17362306a36Sopenharmony_ci return EXIT_FAILURE; 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci getcontext(&uc); 17662306a36Sopenharmony_ci uc.uc_link = NULL; 17762306a36Sopenharmony_ci uc.uc_stack.ss_sp = ustack; 17862306a36Sopenharmony_ci uc.uc_stack.ss_size = stack_size; 17962306a36Sopenharmony_ci makecontext(&uc, switch_fn, 0); 18062306a36Sopenharmony_ci raise(SIGUSR1); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci err = sigaltstack(NULL, &stk); 18362306a36Sopenharmony_ci if (err) { 18462306a36Sopenharmony_ci ksft_exit_fail_msg("sigaltstack() - %s\n", strerror(errno)); 18562306a36Sopenharmony_ci exit(EXIT_FAILURE); 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci if (stk.ss_flags != SS_AUTODISARM) { 18862306a36Sopenharmony_ci ksft_exit_fail_msg("ss_flags=%x, should be SS_AUTODISARM\n", 18962306a36Sopenharmony_ci stk.ss_flags); 19062306a36Sopenharmony_ci exit(EXIT_FAILURE); 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci ksft_test_result_pass( 19362306a36Sopenharmony_ci "sigaltstack is still SS_AUTODISARM after signal\n"); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci ksft_exit_pass(); 19662306a36Sopenharmony_ci return 0; 19762306a36Sopenharmony_ci} 198