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

wp.c (4661B)


      1// SPDX-License-Identifier: GPL-2.0
      2#include <stdlib.h>
      3#include <string.h>
      4#include <unistd.h>
      5#include <sys/ioctl.h>
      6#include <linux/hw_breakpoint.h>
      7#include <linux/kernel.h>
      8#include "tests.h"
      9#include "debug.h"
     10#include "event.h"
     11#include "cloexec.h"
     12#include "../perf-sys.h"
     13
     14#define WP_TEST_ASSERT_VAL(fd, text, val)       \
     15do {                                            \
     16	long long count;                        \
     17	wp_read(fd, &count, sizeof(long long)); \
     18	TEST_ASSERT_VAL(text, count == val);    \
     19} while (0)
     20
     21volatile u64 data1;
     22volatile u8 data2[3];
     23
     24#ifndef __s390x__
     25static int wp_read(int fd, long long *count, int size)
     26{
     27	int ret = read(fd, count, size);
     28
     29	if (ret != size) {
     30		pr_debug("failed to read: %d\n", ret);
     31		return -1;
     32	}
     33	return 0;
     34}
     35
     36static void get__perf_event_attr(struct perf_event_attr *attr, int wp_type,
     37				 void *wp_addr, unsigned long wp_len)
     38{
     39	memset(attr, 0, sizeof(struct perf_event_attr));
     40	attr->type           = PERF_TYPE_BREAKPOINT;
     41	attr->size           = sizeof(struct perf_event_attr);
     42	attr->config         = 0;
     43	attr->bp_type        = wp_type;
     44	attr->bp_addr        = (unsigned long)wp_addr;
     45	attr->bp_len         = wp_len;
     46	attr->sample_period  = 1;
     47	attr->sample_type    = PERF_SAMPLE_IP;
     48	attr->exclude_kernel = 1;
     49	attr->exclude_hv     = 1;
     50}
     51
     52static int __event(int wp_type, void *wp_addr, unsigned long wp_len)
     53{
     54	int fd;
     55	struct perf_event_attr attr;
     56
     57	get__perf_event_attr(&attr, wp_type, wp_addr, wp_len);
     58	fd = sys_perf_event_open(&attr, 0, -1, -1,
     59				 perf_event_open_cloexec_flag());
     60	if (fd < 0)
     61		pr_debug("failed opening event %x\n", attr.bp_type);
     62
     63	return fd;
     64}
     65#endif
     66
     67static int test__wp_ro(struct test_suite *test __maybe_unused,
     68		       int subtest __maybe_unused)
     69{
     70#if defined(__s390x__) || defined(__x86_64__) || defined(__i386__)
     71	return TEST_SKIP;
     72#else
     73	int fd;
     74	unsigned long tmp, tmp1 = rand();
     75
     76	fd = __event(HW_BREAKPOINT_R, (void *)&data1, sizeof(data1));
     77	if (fd < 0)
     78		return -1;
     79
     80	tmp = data1;
     81	WP_TEST_ASSERT_VAL(fd, "RO watchpoint", 1);
     82
     83	data1 = tmp1 + tmp;
     84	WP_TEST_ASSERT_VAL(fd, "RO watchpoint", 1);
     85
     86	close(fd);
     87	return 0;
     88#endif
     89}
     90
     91static int test__wp_wo(struct test_suite *test __maybe_unused,
     92		       int subtest __maybe_unused)
     93{
     94#if defined(__s390x__)
     95	return TEST_SKIP;
     96#else
     97	int fd;
     98	unsigned long tmp, tmp1 = rand();
     99
    100	fd = __event(HW_BREAKPOINT_W, (void *)&data1, sizeof(data1));
    101	if (fd < 0)
    102		return -1;
    103
    104	tmp = data1;
    105	WP_TEST_ASSERT_VAL(fd, "WO watchpoint", 0);
    106
    107	data1 = tmp1 + tmp;
    108	WP_TEST_ASSERT_VAL(fd, "WO watchpoint", 1);
    109
    110	close(fd);
    111	return 0;
    112#endif
    113}
    114
    115static int test__wp_rw(struct test_suite *test __maybe_unused,
    116		       int subtest __maybe_unused)
    117{
    118#if defined(__s390x__)
    119	return TEST_SKIP;
    120#else
    121	int fd;
    122	unsigned long tmp, tmp1 = rand();
    123
    124	fd = __event(HW_BREAKPOINT_R | HW_BREAKPOINT_W, (void *)&data1,
    125		     sizeof(data1));
    126	if (fd < 0)
    127		return -1;
    128
    129	tmp = data1;
    130	WP_TEST_ASSERT_VAL(fd, "RW watchpoint", 1);
    131
    132	data1 = tmp1 + tmp;
    133	WP_TEST_ASSERT_VAL(fd, "RW watchpoint", 2);
    134
    135	close(fd);
    136	return 0;
    137#endif
    138}
    139
    140static int test__wp_modify(struct test_suite *test __maybe_unused,
    141			   int subtest __maybe_unused)
    142{
    143#if defined(__s390x__)
    144	return TEST_SKIP;
    145#else
    146	int fd, ret;
    147	unsigned long tmp = rand();
    148	struct perf_event_attr new_attr;
    149
    150	fd = __event(HW_BREAKPOINT_W, (void *)&data1, sizeof(data1));
    151	if (fd < 0)
    152		return -1;
    153
    154	data1 = tmp;
    155	WP_TEST_ASSERT_VAL(fd, "Modify watchpoint", 1);
    156
    157	/* Modify watchpoint with disabled = 1 */
    158	get__perf_event_attr(&new_attr, HW_BREAKPOINT_W, (void *)&data2[0],
    159			     sizeof(u8) * 2);
    160	new_attr.disabled = 1;
    161	ret = ioctl(fd, PERF_EVENT_IOC_MODIFY_ATTRIBUTES, &new_attr);
    162	if (ret < 0) {
    163		pr_debug("ioctl(PERF_EVENT_IOC_MODIFY_ATTRIBUTES) failed\n");
    164		close(fd);
    165		return ret;
    166	}
    167
    168	data2[1] = tmp; /* Not Counted */
    169	WP_TEST_ASSERT_VAL(fd, "Modify watchpoint", 1);
    170
    171	/* Enable the event */
    172	ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);
    173	if (ret < 0) {
    174		pr_debug("Failed to enable event\n");
    175		close(fd);
    176		return ret;
    177	}
    178
    179	data2[1] = tmp; /* Counted */
    180	WP_TEST_ASSERT_VAL(fd, "Modify watchpoint", 2);
    181
    182	data2[2] = tmp; /* Not Counted */
    183	WP_TEST_ASSERT_VAL(fd, "Modify watchpoint", 2);
    184
    185	close(fd);
    186	return 0;
    187#endif
    188}
    189
    190static struct test_case wp_tests[] = {
    191	TEST_CASE_REASON("Read Only Watchpoint", wp_ro, "missing hardware support"),
    192	TEST_CASE_REASON("Write Only Watchpoint", wp_wo, "missing hardware support"),
    193	TEST_CASE_REASON("Read / Write Watchpoint", wp_rw, "missing hardware support"),
    194	TEST_CASE_REASON("Modify Watchpoint", wp_modify, "missing hardware support"),
    195	{ .name = NULL, }
    196};
    197
    198struct test_suite suite__wp = {
    199	.desc = "Watchpoint",
    200	.test_cases = wp_tests,
    201};