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

wild_bctr.c (3508B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * Copyright 2018, Michael Ellerman, IBM Corp.
      4 *
      5 * Test that an out-of-bounds branch to counter behaves as expected.
      6 */
      7
      8#include <setjmp.h>
      9#include <stdio.h>
     10#include <stdlib.h>
     11#include <string.h>
     12#include <sys/mman.h>
     13#include <sys/types.h>
     14#include <sys/wait.h>
     15#include <ucontext.h>
     16#include <unistd.h>
     17
     18#include "utils.h"
     19
     20
     21#define BAD_NIP	0x788c545a18000000ull
     22
     23static struct pt_regs signal_regs;
     24static jmp_buf setjmp_env;
     25
     26static void save_regs(ucontext_t *ctxt)
     27{
     28	struct pt_regs *regs = ctxt->uc_mcontext.regs;
     29
     30	memcpy(&signal_regs, regs, sizeof(signal_regs));
     31}
     32
     33static void segv_handler(int signum, siginfo_t *info, void *ctxt_v)
     34{
     35	save_regs(ctxt_v);
     36	longjmp(setjmp_env, 1);
     37}
     38
     39static void usr2_handler(int signum, siginfo_t *info, void *ctxt_v)
     40{
     41	save_regs(ctxt_v);
     42}
     43
     44static int ok(void)
     45{
     46	printf("Everything is OK in here.\n");
     47	return 0;
     48}
     49
     50#define REG_POISON	0x5a5a
     51#define POISONED_REG(n)	((((unsigned long)REG_POISON) << 48) | ((n) << 32) | \
     52			 (((unsigned long)REG_POISON) << 16) | (n))
     53
     54static inline void poison_regs(void)
     55{
     56	#define POISON_REG(n)	\
     57	  "lis  " __stringify(n) "," __stringify(REG_POISON) ";" \
     58	  "addi " __stringify(n) "," __stringify(n) "," __stringify(n) ";" \
     59	  "sldi " __stringify(n) "," __stringify(n) ", 32 ;" \
     60	  "oris " __stringify(n) "," __stringify(n) "," __stringify(REG_POISON) ";" \
     61	  "addi " __stringify(n) "," __stringify(n) "," __stringify(n) ";"
     62
     63	asm (POISON_REG(15)
     64	     POISON_REG(16)
     65	     POISON_REG(17)
     66	     POISON_REG(18)
     67	     POISON_REG(19)
     68	     POISON_REG(20)
     69	     POISON_REG(21)
     70	     POISON_REG(22)
     71	     POISON_REG(23)
     72	     POISON_REG(24)
     73	     POISON_REG(25)
     74	     POISON_REG(26)
     75	     POISON_REG(27)
     76	     POISON_REG(28)
     77	     POISON_REG(29)
     78	     : // inputs
     79	     : // outputs
     80	     : "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25",
     81	       "26", "27", "28", "29"
     82	);
     83	#undef POISON_REG
     84}
     85
     86static int check_regs(void)
     87{
     88	unsigned long i;
     89
     90	for (i = 15; i <= 29; i++)
     91		FAIL_IF(signal_regs.gpr[i] != POISONED_REG(i));
     92
     93	printf("Regs OK\n");
     94	return 0;
     95}
     96
     97static void dump_regs(void)
     98{
     99	for (int i = 0; i < 32; i += 4) {
    100		printf("r%02d 0x%016lx  r%02d 0x%016lx  " \
    101		       "r%02d 0x%016lx  r%02d 0x%016lx\n",
    102		       i, signal_regs.gpr[i],
    103		       i+1, signal_regs.gpr[i+1],
    104		       i+2, signal_regs.gpr[i+2],
    105		       i+3, signal_regs.gpr[i+3]);
    106	}
    107}
    108
    109#ifdef _CALL_AIXDESC
    110struct opd {
    111	unsigned long ip;
    112	unsigned long toc;
    113	unsigned long env;
    114};
    115static struct opd bad_opd = {
    116	.ip = BAD_NIP,
    117};
    118#define BAD_FUNC (&bad_opd)
    119#else
    120#define BAD_FUNC BAD_NIP
    121#endif
    122
    123int test_wild_bctr(void)
    124{
    125	int (*func_ptr)(void);
    126	struct sigaction segv = {
    127		.sa_sigaction = segv_handler,
    128		.sa_flags = SA_SIGINFO
    129	};
    130	struct sigaction usr2 = {
    131		.sa_sigaction = usr2_handler,
    132		.sa_flags = SA_SIGINFO
    133	};
    134
    135	FAIL_IF(sigaction(SIGSEGV, &segv, NULL));
    136	FAIL_IF(sigaction(SIGUSR2, &usr2, NULL));
    137
    138	bzero(&signal_regs, sizeof(signal_regs));
    139
    140	if (setjmp(setjmp_env) == 0) {
    141		func_ptr = ok;
    142		func_ptr();
    143
    144		kill(getpid(), SIGUSR2);
    145		printf("Regs before:\n");
    146		dump_regs();
    147		bzero(&signal_regs, sizeof(signal_regs));
    148
    149		poison_regs();
    150
    151		func_ptr = (int (*)(void))BAD_FUNC;
    152		func_ptr();
    153
    154		FAIL_IF(1); /* we didn't segv? */
    155	}
    156
    157	FAIL_IF(signal_regs.nip != BAD_NIP);
    158
    159	printf("All good - took SEGV as expected branching to 0x%llx\n", BAD_NIP);
    160
    161	dump_regs();
    162	FAIL_IF(check_regs());
    163
    164	return 0;
    165}
    166
    167int main(void)
    168{
    169	return test_harness(test_wild_bctr, "wild_bctr");
    170}