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

breakpoint_test_arm64.c (5559B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2016 Google, Inc.
      4 *
      5 * Original Code by Pavel Labath <labath@google.com>
      6 *
      7 * Code modified by Pratyush Anand <panand@redhat.com>
      8 * for testing different byte select for each access size.
      9 */
     10
     11#define _GNU_SOURCE
     12
     13#include <asm/ptrace.h>
     14#include <sys/types.h>
     15#include <sys/wait.h>
     16#include <sys/ptrace.h>
     17#include <sys/param.h>
     18#include <sys/uio.h>
     19#include <stdint.h>
     20#include <stdbool.h>
     21#include <stddef.h>
     22#include <string.h>
     23#include <stdio.h>
     24#include <unistd.h>
     25#include <elf.h>
     26#include <errno.h>
     27#include <signal.h>
     28
     29#include "../kselftest.h"
     30
     31static volatile uint8_t var[96] __attribute__((__aligned__(32)));
     32
     33static void child(int size, int wr)
     34{
     35	volatile uint8_t *addr = &var[32 + wr];
     36
     37	if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) != 0) {
     38		ksft_print_msg(
     39			"ptrace(PTRACE_TRACEME) failed: %s\n",
     40			strerror(errno));
     41		_exit(1);
     42	}
     43
     44	if (raise(SIGSTOP) != 0) {
     45		ksft_print_msg(
     46			"raise(SIGSTOP) failed: %s\n", strerror(errno));
     47		_exit(1);
     48	}
     49
     50	if ((uintptr_t) addr % size) {
     51		ksft_print_msg(
     52			 "Wrong address write for the given size: %s\n",
     53			 strerror(errno));
     54		_exit(1);
     55	}
     56
     57	switch (size) {
     58	case 1:
     59		*addr = 47;
     60		break;
     61	case 2:
     62		*(uint16_t *)addr = 47;
     63		break;
     64	case 4:
     65		*(uint32_t *)addr = 47;
     66		break;
     67	case 8:
     68		*(uint64_t *)addr = 47;
     69		break;
     70	case 16:
     71		__asm__ volatile ("stp x29, x30, %0" : "=m" (addr[0]));
     72		break;
     73	case 32:
     74		__asm__ volatile ("stp q29, q30, %0" : "=m" (addr[0]));
     75		break;
     76	}
     77
     78	_exit(0);
     79}
     80
     81static bool set_watchpoint(pid_t pid, int size, int wp)
     82{
     83	const volatile uint8_t *addr = &var[32 + wp];
     84	const int offset = (uintptr_t)addr % 8;
     85	const unsigned int byte_mask = ((1 << size) - 1) << offset;
     86	const unsigned int type = 2; /* Write */
     87	const unsigned int enable = 1;
     88	const unsigned int control = byte_mask << 5 | type << 3 | enable;
     89	struct user_hwdebug_state dreg_state;
     90	struct iovec iov;
     91
     92	memset(&dreg_state, 0, sizeof(dreg_state));
     93	dreg_state.dbg_regs[0].addr = (uintptr_t)(addr - offset);
     94	dreg_state.dbg_regs[0].ctrl = control;
     95	iov.iov_base = &dreg_state;
     96	iov.iov_len = offsetof(struct user_hwdebug_state, dbg_regs) +
     97				sizeof(dreg_state.dbg_regs[0]);
     98	if (ptrace(PTRACE_SETREGSET, pid, NT_ARM_HW_WATCH, &iov) == 0)
     99		return true;
    100
    101	if (errno == EIO)
    102		ksft_print_msg(
    103			"ptrace(PTRACE_SETREGSET, NT_ARM_HW_WATCH) not supported on this hardware: %s\n",
    104			strerror(errno));
    105
    106	ksft_print_msg(
    107		"ptrace(PTRACE_SETREGSET, NT_ARM_HW_WATCH) failed: %s\n",
    108		strerror(errno));
    109	return false;
    110}
    111
    112static bool run_test(int wr_size, int wp_size, int wr, int wp)
    113{
    114	int status;
    115	siginfo_t siginfo;
    116	pid_t pid = fork();
    117	pid_t wpid;
    118
    119	if (pid < 0) {
    120		ksft_test_result_fail(
    121			"fork() failed: %s\n", strerror(errno));
    122		return false;
    123	}
    124	if (pid == 0)
    125		child(wr_size, wr);
    126
    127	wpid = waitpid(pid, &status, __WALL);
    128	if (wpid != pid) {
    129		ksft_print_msg(
    130			"waitpid() failed: %s\n", strerror(errno));
    131		return false;
    132	}
    133	if (!WIFSTOPPED(status)) {
    134		ksft_print_msg(
    135			"child did not stop: %s\n", strerror(errno));
    136		return false;
    137	}
    138	if (WSTOPSIG(status) != SIGSTOP) {
    139		ksft_print_msg("child did not stop with SIGSTOP\n");
    140		return false;
    141	}
    142
    143	if (!set_watchpoint(pid, wp_size, wp))
    144		return false;
    145
    146	if (ptrace(PTRACE_CONT, pid, NULL, NULL) < 0) {
    147		ksft_print_msg(
    148			"ptrace(PTRACE_CONT) failed: %s\n",
    149			strerror(errno));
    150		return false;
    151	}
    152
    153	alarm(3);
    154	wpid = waitpid(pid, &status, __WALL);
    155	if (wpid != pid) {
    156		ksft_print_msg(
    157			"waitpid() failed: %s\n", strerror(errno));
    158		return false;
    159	}
    160	alarm(0);
    161	if (WIFEXITED(status)) {
    162		ksft_print_msg("child exited prematurely\n");
    163		return false;
    164	}
    165	if (!WIFSTOPPED(status)) {
    166		ksft_print_msg("child did not stop\n");
    167		return false;
    168	}
    169	if (WSTOPSIG(status) != SIGTRAP) {
    170		ksft_print_msg("child did not stop with SIGTRAP\n");
    171		return false;
    172	}
    173	if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &siginfo) != 0) {
    174		ksft_print_msg(
    175			"ptrace(PTRACE_GETSIGINFO): %s\n",
    176			strerror(errno));
    177		return false;
    178	}
    179	if (siginfo.si_code != TRAP_HWBKPT) {
    180		ksft_print_msg(
    181			"Unexpected si_code %d\n", siginfo.si_code);
    182		return false;
    183	}
    184
    185	kill(pid, SIGKILL);
    186	wpid = waitpid(pid, &status, 0);
    187	if (wpid != pid) {
    188		ksft_print_msg(
    189			"waitpid() failed: %s\n", strerror(errno));
    190		return false;
    191	}
    192	return true;
    193}
    194
    195static void sigalrm(int sig)
    196{
    197}
    198
    199int main(int argc, char **argv)
    200{
    201	int opt;
    202	bool succeeded = true;
    203	struct sigaction act;
    204	int wr, wp, size;
    205	bool result;
    206
    207	ksft_print_header();
    208	ksft_set_plan(213);
    209
    210	act.sa_handler = sigalrm;
    211	sigemptyset(&act.sa_mask);
    212	act.sa_flags = 0;
    213	sigaction(SIGALRM, &act, NULL);
    214	for (size = 1; size <= 32; size = size*2) {
    215		for (wr = 0; wr <= 32; wr = wr + size) {
    216			for (wp = wr - size; wp <= wr + size; wp = wp + size) {
    217				result = run_test(size, MIN(size, 8), wr, wp);
    218				if ((result && wr == wp) ||
    219				    (!result && wr != wp))
    220					ksft_test_result_pass(
    221						"Test size = %d write offset = %d watchpoint offset = %d\n",
    222						size, wr, wp);
    223				else {
    224					ksft_test_result_fail(
    225						"Test size = %d write offset = %d watchpoint offset = %d\n",
    226						size, wr, wp);
    227					succeeded = false;
    228				}
    229			}
    230		}
    231	}
    232
    233	for (size = 1; size <= 32; size = size*2) {
    234		if (run_test(size, 8, -size, -8))
    235			ksft_test_result_pass(
    236				"Test size = %d write offset = %d watchpoint offset = -8\n",
    237				size, -size);
    238		else {
    239			ksft_test_result_fail(
    240				"Test size = %d write offset = %d watchpoint offset = -8\n",
    241				size, -size);
    242			succeeded = false;
    243		}
    244	}
    245
    246	if (succeeded)
    247		ksft_exit_pass();
    248	else
    249		ksft_exit_fail();
    250}