cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sas.c (4913B)


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