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

pkey-helpers.h (5481B)


      1/* SPDX-License-Identifier: GPL-2.0 */
      2#ifndef _PKEYS_HELPER_H
      3#define _PKEYS_HELPER_H
      4#define _GNU_SOURCE
      5#include <string.h>
      6#include <stdarg.h>
      7#include <stdio.h>
      8#include <stdint.h>
      9#include <stdbool.h>
     10#include <signal.h>
     11#include <assert.h>
     12#include <stdlib.h>
     13#include <ucontext.h>
     14#include <sys/mman.h>
     15
     16#include "../kselftest.h"
     17
     18/* Define some kernel-like types */
     19#define  u8 __u8
     20#define u16 __u16
     21#define u32 __u32
     22#define u64 __u64
     23
     24#define PTR_ERR_ENOTSUP ((void *)-ENOTSUP)
     25
     26#ifndef DEBUG_LEVEL
     27#define DEBUG_LEVEL 0
     28#endif
     29#define DPRINT_IN_SIGNAL_BUF_SIZE 4096
     30extern int dprint_in_signal;
     31extern char dprint_in_signal_buffer[DPRINT_IN_SIGNAL_BUF_SIZE];
     32
     33extern int test_nr;
     34extern int iteration_nr;
     35
     36#ifdef __GNUC__
     37__attribute__((format(printf, 1, 2)))
     38#endif
     39static inline void sigsafe_printf(const char *format, ...)
     40{
     41	va_list ap;
     42
     43	if (!dprint_in_signal) {
     44		va_start(ap, format);
     45		vprintf(format, ap);
     46		va_end(ap);
     47	} else {
     48		int ret;
     49		/*
     50		 * No printf() functions are signal-safe.
     51		 * They deadlock easily. Write the format
     52		 * string to get some output, even if
     53		 * incomplete.
     54		 */
     55		ret = write(1, format, strlen(format));
     56		if (ret < 0)
     57			exit(1);
     58	}
     59}
     60#define dprintf_level(level, args...) do {	\
     61	if (level <= DEBUG_LEVEL)		\
     62		sigsafe_printf(args);		\
     63} while (0)
     64#define dprintf0(args...) dprintf_level(0, args)
     65#define dprintf1(args...) dprintf_level(1, args)
     66#define dprintf2(args...) dprintf_level(2, args)
     67#define dprintf3(args...) dprintf_level(3, args)
     68#define dprintf4(args...) dprintf_level(4, args)
     69
     70extern void abort_hooks(void);
     71#define pkey_assert(condition) do {		\
     72	if (!(condition)) {			\
     73		dprintf0("assert() at %s::%d test_nr: %d iteration: %d\n", \
     74				__FILE__, __LINE__,	\
     75				test_nr, iteration_nr);	\
     76		dprintf0("errno at assert: %d", errno);	\
     77		abort_hooks();			\
     78		exit(__LINE__);			\
     79	}					\
     80} while (0)
     81
     82__attribute__((noinline)) int read_ptr(int *ptr);
     83void expected_pkey_fault(int pkey);
     84int sys_pkey_alloc(unsigned long flags, unsigned long init_val);
     85int sys_pkey_free(unsigned long pkey);
     86int mprotect_pkey(void *ptr, size_t size, unsigned long orig_prot,
     87		unsigned long pkey);
     88void record_pkey_malloc(void *ptr, long size, int prot);
     89
     90#if defined(__i386__) || defined(__x86_64__) /* arch */
     91#include "pkey-x86.h"
     92#elif defined(__powerpc64__) /* arch */
     93#include "pkey-powerpc.h"
     94#else /* arch */
     95#error Architecture not supported
     96#endif /* arch */
     97
     98#define PKEY_MASK	(PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE)
     99
    100static inline u64 set_pkey_bits(u64 reg, int pkey, u64 flags)
    101{
    102	u32 shift = pkey_bit_position(pkey);
    103	/* mask out bits from pkey in old value */
    104	reg &= ~((u64)PKEY_MASK << shift);
    105	/* OR in new bits for pkey */
    106	reg |= (flags & PKEY_MASK) << shift;
    107	return reg;
    108}
    109
    110static inline u64 get_pkey_bits(u64 reg, int pkey)
    111{
    112	u32 shift = pkey_bit_position(pkey);
    113	/*
    114	 * shift down the relevant bits to the lowest two, then
    115	 * mask off all the other higher bits
    116	 */
    117	return ((reg >> shift) & PKEY_MASK);
    118}
    119
    120extern u64 shadow_pkey_reg;
    121
    122static inline u64 _read_pkey_reg(int line)
    123{
    124	u64 pkey_reg = __read_pkey_reg();
    125
    126	dprintf4("read_pkey_reg(line=%d) pkey_reg: %016llx"
    127			" shadow: %016llx\n",
    128			line, pkey_reg, shadow_pkey_reg);
    129	assert(pkey_reg == shadow_pkey_reg);
    130
    131	return pkey_reg;
    132}
    133
    134#define read_pkey_reg() _read_pkey_reg(__LINE__)
    135
    136static inline void write_pkey_reg(u64 pkey_reg)
    137{
    138	dprintf4("%s() changing %016llx to %016llx\n", __func__,
    139			__read_pkey_reg(), pkey_reg);
    140	/* will do the shadow check for us: */
    141	read_pkey_reg();
    142	__write_pkey_reg(pkey_reg);
    143	shadow_pkey_reg = pkey_reg;
    144	dprintf4("%s(%016llx) pkey_reg: %016llx\n", __func__,
    145			pkey_reg, __read_pkey_reg());
    146}
    147
    148/*
    149 * These are technically racy. since something could
    150 * change PKEY register between the read and the write.
    151 */
    152static inline void __pkey_access_allow(int pkey, int do_allow)
    153{
    154	u64 pkey_reg = read_pkey_reg();
    155	int bit = pkey * 2;
    156
    157	if (do_allow)
    158		pkey_reg &= (1<<bit);
    159	else
    160		pkey_reg |= (1<<bit);
    161
    162	dprintf4("pkey_reg now: %016llx\n", read_pkey_reg());
    163	write_pkey_reg(pkey_reg);
    164}
    165
    166static inline void __pkey_write_allow(int pkey, int do_allow_write)
    167{
    168	u64 pkey_reg = read_pkey_reg();
    169	int bit = pkey * 2 + 1;
    170
    171	if (do_allow_write)
    172		pkey_reg &= (1<<bit);
    173	else
    174		pkey_reg |= (1<<bit);
    175
    176	write_pkey_reg(pkey_reg);
    177	dprintf4("pkey_reg now: %016llx\n", read_pkey_reg());
    178}
    179
    180#define ALIGN_UP(x, align_to)	(((x) + ((align_to)-1)) & ~((align_to)-1))
    181#define ALIGN_DOWN(x, align_to) ((x) & ~((align_to)-1))
    182#define ALIGN_PTR_UP(p, ptr_align_to)	\
    183	((typeof(p))ALIGN_UP((unsigned long)(p), ptr_align_to))
    184#define ALIGN_PTR_DOWN(p, ptr_align_to)	\
    185	((typeof(p))ALIGN_DOWN((unsigned long)(p), ptr_align_to))
    186#define __stringify_1(x...)     #x
    187#define __stringify(x...)       __stringify_1(x)
    188
    189static inline u32 *siginfo_get_pkey_ptr(siginfo_t *si)
    190{
    191#ifdef si_pkey
    192	return &si->si_pkey;
    193#else
    194	return (u32 *)(((u8 *)si) + si_pkey_offset);
    195#endif
    196}
    197
    198static inline int kernel_has_pkeys(void)
    199{
    200	/* try allocating a key and see if it succeeds */
    201	int ret = sys_pkey_alloc(0, 0);
    202	if (ret <= 0) {
    203		return 0;
    204	}
    205	sys_pkey_free(ret);
    206	return 1;
    207}
    208
    209static inline int is_pkeys_supported(void)
    210{
    211	/* check if the cpu supports pkeys */
    212	if (!cpu_has_pkeys()) {
    213		dprintf1("SKIP: %s: no CPU support\n", __func__);
    214		return 0;
    215	}
    216
    217	/* check if the kernel supports pkeys */
    218	if (!kernel_has_pkeys()) {
    219		dprintf1("SKIP: %s: no kernel support\n", __func__);
    220		return 0;
    221	}
    222
    223	return 1;
    224}
    225
    226#endif /* _PKEYS_HELPER_H */