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

ptrace-perf-hwbreak.c (15055B)


      1// SPDX-License-Identifier: GPL-2.0+
      2#include <stdio.h>
      3#include <string.h>
      4#include <signal.h>
      5#include <stdlib.h>
      6#include <unistd.h>
      7#include <errno.h>
      8#include <linux/hw_breakpoint.h>
      9#include <linux/perf_event.h>
     10#include <asm/unistd.h>
     11#include <sys/ptrace.h>
     12#include <sys/wait.h>
     13#include "ptrace.h"
     14
     15char data[16];
     16
     17/* Overlapping address range */
     18volatile __u64 *ptrace_data1 = (__u64 *)&data[0];
     19volatile __u64 *perf_data1 = (__u64 *)&data[4];
     20
     21/* Non-overlapping address range */
     22volatile __u64 *ptrace_data2 = (__u64 *)&data[0];
     23volatile __u64 *perf_data2 = (__u64 *)&data[8];
     24
     25static unsigned long pid_max_addr(void)
     26{
     27	FILE *fp;
     28	char *line, *c;
     29	char addr[100];
     30	size_t len = 0;
     31
     32	fp = fopen("/proc/kallsyms", "r");
     33	if (!fp) {
     34		printf("Failed to read /proc/kallsyms. Exiting..\n");
     35		exit(EXIT_FAILURE);
     36	}
     37
     38	while (getline(&line, &len, fp) != -1) {
     39		if (!strstr(line, "pid_max") || strstr(line, "pid_max_max") ||
     40		    strstr(line, "pid_max_min"))
     41			continue;
     42
     43		strncpy(addr, line, len < 100 ? len : 100);
     44		c = strchr(addr, ' ');
     45		*c = '\0';
     46		return strtoul(addr, &c, 16);
     47	}
     48	fclose(fp);
     49	printf("Could not find pix_max. Exiting..\n");
     50	exit(EXIT_FAILURE);
     51	return -1;
     52}
     53
     54static void perf_user_event_attr_set(struct perf_event_attr *attr, __u64 addr, __u64 len)
     55{
     56	memset(attr, 0, sizeof(struct perf_event_attr));
     57	attr->type           = PERF_TYPE_BREAKPOINT;
     58	attr->size           = sizeof(struct perf_event_attr);
     59	attr->bp_type        = HW_BREAKPOINT_R;
     60	attr->bp_addr        = addr;
     61	attr->bp_len         = len;
     62	attr->exclude_kernel = 1;
     63	attr->exclude_hv     = 1;
     64}
     65
     66static void perf_kernel_event_attr_set(struct perf_event_attr *attr)
     67{
     68	memset(attr, 0, sizeof(struct perf_event_attr));
     69	attr->type           = PERF_TYPE_BREAKPOINT;
     70	attr->size           = sizeof(struct perf_event_attr);
     71	attr->bp_type        = HW_BREAKPOINT_R;
     72	attr->bp_addr        = pid_max_addr();
     73	attr->bp_len         = sizeof(unsigned long);
     74	attr->exclude_user   = 1;
     75	attr->exclude_hv     = 1;
     76}
     77
     78static int perf_cpu_event_open(int cpu, __u64 addr, __u64 len)
     79{
     80	struct perf_event_attr attr;
     81
     82	perf_user_event_attr_set(&attr, addr, len);
     83	return syscall(__NR_perf_event_open, &attr, -1, cpu, -1, 0);
     84}
     85
     86static int perf_thread_event_open(pid_t child_pid, __u64 addr, __u64 len)
     87{
     88	struct perf_event_attr attr;
     89
     90	perf_user_event_attr_set(&attr, addr, len);
     91	return syscall(__NR_perf_event_open, &attr, child_pid, -1, -1, 0);
     92}
     93
     94static int perf_thread_cpu_event_open(pid_t child_pid, int cpu, __u64 addr, __u64 len)
     95{
     96	struct perf_event_attr attr;
     97
     98	perf_user_event_attr_set(&attr, addr, len);
     99	return syscall(__NR_perf_event_open, &attr, child_pid, cpu, -1, 0);
    100}
    101
    102static int perf_thread_kernel_event_open(pid_t child_pid)
    103{
    104	struct perf_event_attr attr;
    105
    106	perf_kernel_event_attr_set(&attr);
    107	return syscall(__NR_perf_event_open, &attr, child_pid, -1, -1, 0);
    108}
    109
    110static int perf_cpu_kernel_event_open(int cpu)
    111{
    112	struct perf_event_attr attr;
    113
    114	perf_kernel_event_attr_set(&attr);
    115	return syscall(__NR_perf_event_open, &attr, -1, cpu, -1, 0);
    116}
    117
    118static int child(void)
    119{
    120	int ret;
    121
    122	ret = ptrace(PTRACE_TRACEME, 0, NULL, 0);
    123	if (ret) {
    124		printf("Error: PTRACE_TRACEME failed\n");
    125		return 0;
    126	}
    127	kill(getpid(), SIGUSR1); /* --> parent (SIGUSR1) */
    128
    129	return 0;
    130}
    131
    132static void ptrace_ppc_hw_breakpoint(struct ppc_hw_breakpoint *info, int type,
    133				     __u64 addr, int len)
    134{
    135	info->version = 1;
    136	info->trigger_type = type;
    137	info->condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
    138	info->addr = addr;
    139	info->addr2 = addr + len;
    140	info->condition_value = 0;
    141	if (!len)
    142		info->addr_mode = PPC_BREAKPOINT_MODE_EXACT;
    143	else
    144		info->addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
    145}
    146
    147static int ptrace_open(pid_t child_pid, __u64 wp_addr, int len)
    148{
    149	struct ppc_hw_breakpoint info;
    150
    151	ptrace_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_RW, wp_addr, len);
    152	return ptrace(PPC_PTRACE_SETHWDEBUG, child_pid, 0, &info);
    153}
    154
    155static int test1(pid_t child_pid)
    156{
    157	int perf_fd;
    158	int ptrace_fd;
    159	int ret = 0;
    160
    161	/* Test:
    162	 * if (new per thread event by ptrace)
    163	 *	if (existing cpu event by perf)
    164	 *		if (addr range overlaps)
    165	 *			fail;
    166	 */
    167
    168	perf_fd = perf_cpu_event_open(0, (__u64)perf_data1, sizeof(*perf_data1));
    169	if (perf_fd < 0)
    170		return -1;
    171
    172	ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1));
    173	if (ptrace_fd > 0 || errno != ENOSPC)
    174		ret = -1;
    175
    176	close(perf_fd);
    177	return ret;
    178}
    179
    180static int test2(pid_t child_pid)
    181{
    182	int perf_fd;
    183	int ptrace_fd;
    184	int ret = 0;
    185
    186	/* Test:
    187	 * if (new per thread event by ptrace)
    188	 *	if (existing cpu event by perf)
    189	 *		if (addr range does not overlaps)
    190	 *			allow;
    191	 */
    192
    193	perf_fd = perf_cpu_event_open(0, (__u64)perf_data2, sizeof(*perf_data2));
    194	if (perf_fd < 0)
    195		return -1;
    196
    197	ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data2, sizeof(*ptrace_data2));
    198	if (ptrace_fd < 0) {
    199		ret = -1;
    200		goto perf_close;
    201	}
    202	ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
    203
    204perf_close:
    205	close(perf_fd);
    206	return ret;
    207}
    208
    209static int test3(pid_t child_pid)
    210{
    211	int perf_fd;
    212	int ptrace_fd;
    213	int ret = 0;
    214
    215	/* Test:
    216	 * if (new per thread event by ptrace)
    217	 *	if (existing thread event by perf on the same thread)
    218	 *		if (addr range overlaps)
    219	 *			fail;
    220	 */
    221	perf_fd = perf_thread_event_open(child_pid, (__u64)perf_data1,
    222					 sizeof(*perf_data1));
    223	if (perf_fd < 0)
    224		return -1;
    225
    226	ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1));
    227	if (ptrace_fd > 0 || errno != ENOSPC)
    228		ret = -1;
    229
    230	close(perf_fd);
    231	return ret;
    232}
    233
    234static int test4(pid_t child_pid)
    235{
    236	int perf_fd;
    237	int ptrace_fd;
    238	int ret = 0;
    239
    240	/* Test:
    241	 * if (new per thread event by ptrace)
    242	 *	if (existing thread event by perf on the same thread)
    243	 *		if (addr range does not overlaps)
    244	 *			fail;
    245	 */
    246	perf_fd = perf_thread_event_open(child_pid, (__u64)perf_data2,
    247					 sizeof(*perf_data2));
    248	if (perf_fd < 0)
    249		return -1;
    250
    251	ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data2, sizeof(*ptrace_data2));
    252	if (ptrace_fd < 0) {
    253		ret = -1;
    254		goto perf_close;
    255	}
    256	ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
    257
    258perf_close:
    259	close(perf_fd);
    260	return ret;
    261}
    262
    263static int test5(pid_t child_pid)
    264{
    265	int perf_fd;
    266	int ptrace_fd;
    267	int cpid;
    268	int ret = 0;
    269
    270	/* Test:
    271	 * if (new per thread event by ptrace)
    272	 *	if (existing thread event by perf on the different thread)
    273	 *		allow;
    274	 */
    275	cpid = fork();
    276	if (!cpid) {
    277		/* Temporary Child */
    278		pause();
    279		exit(EXIT_SUCCESS);
    280	}
    281
    282	perf_fd = perf_thread_event_open(cpid, (__u64)perf_data1, sizeof(*perf_data1));
    283	if (perf_fd < 0) {
    284		ret = -1;
    285		goto kill_child;
    286	}
    287
    288	ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1));
    289	if (ptrace_fd < 0) {
    290		ret = -1;
    291		goto perf_close;
    292	}
    293
    294	ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
    295perf_close:
    296	close(perf_fd);
    297kill_child:
    298	kill(cpid, SIGINT);
    299	return ret;
    300}
    301
    302static int test6(pid_t child_pid)
    303{
    304	int perf_fd;
    305	int ptrace_fd;
    306	int ret = 0;
    307
    308	/* Test:
    309	 * if (new per thread kernel event by perf)
    310	 *	if (existing thread event by ptrace on the same thread)
    311	 *		allow;
    312	 * -- OR --
    313	 * if (new per cpu kernel event by perf)
    314	 *	if (existing thread event by ptrace)
    315	 *		allow;
    316	 */
    317	ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1));
    318	if (ptrace_fd < 0)
    319		return -1;
    320
    321	perf_fd = perf_thread_kernel_event_open(child_pid);
    322	if (perf_fd < 0) {
    323		ret = -1;
    324		goto ptrace_close;
    325	}
    326	close(perf_fd);
    327
    328	perf_fd = perf_cpu_kernel_event_open(0);
    329	if (perf_fd < 0) {
    330		ret = -1;
    331		goto ptrace_close;
    332	}
    333	close(perf_fd);
    334
    335ptrace_close:
    336	ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
    337	return ret;
    338}
    339
    340static int test7(pid_t child_pid)
    341{
    342	int perf_fd;
    343	int ptrace_fd;
    344	int ret = 0;
    345
    346	/* Test:
    347	 * if (new per thread event by perf)
    348	 *	if (existing thread event by ptrace on the same thread)
    349	 *		if (addr range overlaps)
    350	 *			fail;
    351	 */
    352	ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1));
    353	if (ptrace_fd < 0)
    354		return -1;
    355
    356	perf_fd = perf_thread_event_open(child_pid, (__u64)perf_data1,
    357					 sizeof(*perf_data1));
    358	if (perf_fd > 0 || errno != ENOSPC)
    359		ret = -1;
    360
    361	ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
    362	return ret;
    363}
    364
    365static int test8(pid_t child_pid)
    366{
    367	int perf_fd;
    368	int ptrace_fd;
    369	int ret = 0;
    370
    371	/* Test:
    372	 * if (new per thread event by perf)
    373	 *	if (existing thread event by ptrace on the same thread)
    374	 *		if (addr range does not overlaps)
    375	 *			allow;
    376	 */
    377	ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data2, sizeof(*ptrace_data2));
    378	if (ptrace_fd < 0)
    379		return -1;
    380
    381	perf_fd = perf_thread_event_open(child_pid, (__u64)perf_data2,
    382					 sizeof(*perf_data2));
    383	if (perf_fd < 0) {
    384		ret = -1;
    385		goto ptrace_close;
    386	}
    387	close(perf_fd);
    388
    389ptrace_close:
    390	ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
    391	return ret;
    392}
    393
    394static int test9(pid_t child_pid)
    395{
    396	int perf_fd;
    397	int ptrace_fd;
    398	int cpid;
    399	int ret = 0;
    400
    401	/* Test:
    402	 * if (new per thread event by perf)
    403	 *	if (existing thread event by ptrace on the other thread)
    404	 *		allow;
    405	 */
    406	ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1));
    407	if (ptrace_fd < 0)
    408		return -1;
    409
    410	cpid = fork();
    411	if (!cpid) {
    412		/* Temporary Child */
    413		pause();
    414		exit(EXIT_SUCCESS);
    415	}
    416
    417	perf_fd = perf_thread_event_open(cpid, (__u64)perf_data1, sizeof(*perf_data1));
    418	if (perf_fd < 0) {
    419		ret = -1;
    420		goto kill_child;
    421	}
    422	close(perf_fd);
    423
    424kill_child:
    425	kill(cpid, SIGINT);
    426	ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
    427	return ret;
    428}
    429
    430static int test10(pid_t child_pid)
    431{
    432	int perf_fd;
    433	int ptrace_fd;
    434	int ret = 0;
    435
    436	/* Test:
    437	 * if (new per cpu event by perf)
    438	 *	if (existing thread event by ptrace on the same thread)
    439	 *		if (addr range overlaps)
    440	 *			fail;
    441	 */
    442	ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1));
    443	if (ptrace_fd < 0)
    444		return -1;
    445
    446	perf_fd = perf_cpu_event_open(0, (__u64)perf_data1, sizeof(*perf_data1));
    447	if (perf_fd > 0 || errno != ENOSPC)
    448		ret = -1;
    449
    450	ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
    451	return ret;
    452}
    453
    454static int test11(pid_t child_pid)
    455{
    456	int perf_fd;
    457	int ptrace_fd;
    458	int ret = 0;
    459
    460	/* Test:
    461	 * if (new per cpu event by perf)
    462	 *	if (existing thread event by ptrace on the same thread)
    463	 *		if (addr range does not overlap)
    464	 *			allow;
    465	 */
    466	ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data2, sizeof(*ptrace_data2));
    467	if (ptrace_fd < 0)
    468		return -1;
    469
    470	perf_fd = perf_cpu_event_open(0, (__u64)perf_data2, sizeof(*perf_data2));
    471	if (perf_fd < 0) {
    472		ret = -1;
    473		goto ptrace_close;
    474	}
    475	close(perf_fd);
    476
    477ptrace_close:
    478	ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
    479	return ret;
    480}
    481
    482static int test12(pid_t child_pid)
    483{
    484	int perf_fd;
    485	int ptrace_fd;
    486	int ret = 0;
    487
    488	/* Test:
    489	 * if (new per thread and per cpu event by perf)
    490	 *	if (existing thread event by ptrace on the same thread)
    491	 *		if (addr range overlaps)
    492	 *			fail;
    493	 */
    494	ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1));
    495	if (ptrace_fd < 0)
    496		return -1;
    497
    498	perf_fd = perf_thread_cpu_event_open(child_pid, 0, (__u64)perf_data1, sizeof(*perf_data1));
    499	if (perf_fd > 0 || errno != ENOSPC)
    500		ret = -1;
    501
    502	ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
    503	return ret;
    504}
    505
    506static int test13(pid_t child_pid)
    507{
    508	int perf_fd;
    509	int ptrace_fd;
    510	int ret = 0;
    511
    512	/* Test:
    513	 * if (new per thread and per cpu event by perf)
    514	 *	if (existing thread event by ptrace on the same thread)
    515	 *		if (addr range does not overlap)
    516	 *			allow;
    517	 */
    518	ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data2, sizeof(*ptrace_data2));
    519	if (ptrace_fd < 0)
    520		return -1;
    521
    522	perf_fd = perf_thread_cpu_event_open(child_pid, 0, (__u64)perf_data2, sizeof(*perf_data2));
    523	if (perf_fd < 0) {
    524		ret = -1;
    525		goto ptrace_close;
    526	}
    527	close(perf_fd);
    528
    529ptrace_close:
    530	ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
    531	return ret;
    532}
    533
    534static int test14(pid_t child_pid)
    535{
    536	int perf_fd;
    537	int ptrace_fd;
    538	int cpid;
    539	int ret = 0;
    540
    541	/* Test:
    542	 * if (new per thread and per cpu event by perf)
    543	 *	if (existing thread event by ptrace on the other thread)
    544	 *		allow;
    545	 */
    546	ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1));
    547	if (ptrace_fd < 0)
    548		return -1;
    549
    550	cpid = fork();
    551	if (!cpid) {
    552		/* Temporary Child */
    553		pause();
    554		exit(EXIT_SUCCESS);
    555	}
    556
    557	perf_fd = perf_thread_cpu_event_open(cpid, 0, (__u64)perf_data1,
    558					     sizeof(*perf_data1));
    559	if (perf_fd < 0) {
    560		ret = -1;
    561		goto kill_child;
    562	}
    563	close(perf_fd);
    564
    565kill_child:
    566	kill(cpid, SIGINT);
    567	ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
    568	return ret;
    569}
    570
    571static int do_test(const char *msg, int (*fun)(pid_t arg), pid_t arg)
    572{
    573	int ret;
    574
    575	ret = fun(arg);
    576	if (ret)
    577		printf("%s: Error\n", msg);
    578	else
    579		printf("%s: Ok\n", msg);
    580	return ret;
    581}
    582
    583char *desc[14] = {
    584	"perf cpu event -> ptrace thread event (Overlapping)",
    585	"perf cpu event -> ptrace thread event (Non-overlapping)",
    586	"perf thread event -> ptrace same thread event (Overlapping)",
    587	"perf thread event -> ptrace same thread event (Non-overlapping)",
    588	"perf thread event -> ptrace other thread event",
    589	"ptrace thread event -> perf kernel event",
    590	"ptrace thread event -> perf same thread event (Overlapping)",
    591	"ptrace thread event -> perf same thread event (Non-overlapping)",
    592	"ptrace thread event -> perf other thread event",
    593	"ptrace thread event -> perf cpu event (Overlapping)",
    594	"ptrace thread event -> perf cpu event (Non-overlapping)",
    595	"ptrace thread event -> perf same thread & cpu event (Overlapping)",
    596	"ptrace thread event -> perf same thread & cpu event (Non-overlapping)",
    597	"ptrace thread event -> perf other thread & cpu event",
    598};
    599
    600static int test(pid_t child_pid)
    601{
    602	int ret = TEST_PASS;
    603
    604	ret |= do_test(desc[0], test1, child_pid);
    605	ret |= do_test(desc[1], test2, child_pid);
    606	ret |= do_test(desc[2], test3, child_pid);
    607	ret |= do_test(desc[3], test4, child_pid);
    608	ret |= do_test(desc[4], test5, child_pid);
    609	ret |= do_test(desc[5], test6, child_pid);
    610	ret |= do_test(desc[6], test7, child_pid);
    611	ret |= do_test(desc[7], test8, child_pid);
    612	ret |= do_test(desc[8], test9, child_pid);
    613	ret |= do_test(desc[9], test10, child_pid);
    614	ret |= do_test(desc[10], test11, child_pid);
    615	ret |= do_test(desc[11], test12, child_pid);
    616	ret |= do_test(desc[12], test13, child_pid);
    617	ret |= do_test(desc[13], test14, child_pid);
    618
    619	return ret;
    620}
    621
    622static void get_dbginfo(pid_t child_pid, struct ppc_debug_info *dbginfo)
    623{
    624	if (ptrace(PPC_PTRACE_GETHWDBGINFO, child_pid, NULL, dbginfo)) {
    625		perror("Can't get breakpoint info");
    626		exit(-1);
    627	}
    628}
    629
    630static int ptrace_perf_hwbreak(void)
    631{
    632	int ret;
    633	pid_t child_pid;
    634	struct ppc_debug_info dbginfo;
    635
    636	child_pid = fork();
    637	if (!child_pid)
    638		return child();
    639
    640	/* parent */
    641	wait(NULL); /* <-- child (SIGUSR1) */
    642
    643	get_dbginfo(child_pid, &dbginfo);
    644	SKIP_IF(dbginfo.num_data_bps <= 1);
    645
    646	ret = perf_cpu_event_open(0, (__u64)perf_data1, sizeof(*perf_data1));
    647	SKIP_IF(ret < 0);
    648	close(ret);
    649
    650	ret = test(child_pid);
    651
    652	ptrace(PTRACE_CONT, child_pid, NULL, 0);
    653	return ret;
    654}
    655
    656int main(int argc, char *argv[])
    657{
    658	return test_harness(ptrace_perf_hwbreak, "ptrace-perf-hwbreak");
    659}