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

lib.c (3675B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright 2014, Michael Ellerman, IBM Corp.
      4 */
      5
      6#define _GNU_SOURCE	/* For CPU_ZERO etc. */
      7
      8#include <errno.h>
      9#include <sched.h>
     10#include <setjmp.h>
     11#include <stdlib.h>
     12#include <sys/wait.h>
     13
     14#include "utils.h"
     15#include "lib.h"
     16
     17
     18int bind_to_cpu(int cpu)
     19{
     20	cpu_set_t mask;
     21
     22	printf("Binding to cpu %d\n", cpu);
     23
     24	CPU_ZERO(&mask);
     25	CPU_SET(cpu, &mask);
     26
     27	return sched_setaffinity(0, sizeof(mask), &mask);
     28}
     29
     30#define PARENT_TOKEN	0xAA
     31#define CHILD_TOKEN	0x55
     32
     33int sync_with_child(union pipe read_pipe, union pipe write_pipe)
     34{
     35	char c = PARENT_TOKEN;
     36
     37	FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1);
     38	FAIL_IF(read(read_pipe.read_fd, &c, 1) != 1);
     39	if (c != CHILD_TOKEN) /* sometimes expected */
     40		return 1;
     41
     42	return 0;
     43}
     44
     45int wait_for_parent(union pipe read_pipe)
     46{
     47	char c;
     48
     49	FAIL_IF(read(read_pipe.read_fd, &c, 1) != 1);
     50	FAIL_IF(c != PARENT_TOKEN);
     51
     52	return 0;
     53}
     54
     55int notify_parent(union pipe write_pipe)
     56{
     57	char c = CHILD_TOKEN;
     58
     59	FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1);
     60
     61	return 0;
     62}
     63
     64int notify_parent_of_error(union pipe write_pipe)
     65{
     66	char c = ~CHILD_TOKEN;
     67
     68	FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1);
     69
     70	return 0;
     71}
     72
     73int wait_for_child(pid_t child_pid)
     74{
     75	int rc;
     76
     77	if (waitpid(child_pid, &rc, 0) == -1) {
     78		perror("waitpid");
     79		return 1;
     80	}
     81
     82	if (WIFEXITED(rc))
     83		rc = WEXITSTATUS(rc);
     84	else
     85		rc = 1; /* Signal or other */
     86
     87	return rc;
     88}
     89
     90int kill_child_and_wait(pid_t child_pid)
     91{
     92	kill(child_pid, SIGTERM);
     93
     94	return wait_for_child(child_pid);
     95}
     96
     97static int eat_cpu_child(union pipe read_pipe, union pipe write_pipe)
     98{
     99	volatile int i = 0;
    100
    101	/*
    102	 * We are just here to eat cpu and die. So make sure we can be killed,
    103	 * and also don't do any custom SIGTERM handling.
    104	 */
    105	signal(SIGTERM, SIG_DFL);
    106
    107	notify_parent(write_pipe);
    108	wait_for_parent(read_pipe);
    109
    110	/* Soak up cpu forever */
    111	while (1) i++;
    112
    113	return 0;
    114}
    115
    116pid_t eat_cpu(int (test_function)(void))
    117{
    118	union pipe read_pipe, write_pipe;
    119	int cpu, rc;
    120	pid_t pid;
    121
    122	cpu = pick_online_cpu();
    123	FAIL_IF(cpu < 0);
    124	FAIL_IF(bind_to_cpu(cpu));
    125
    126	if (pipe(read_pipe.fds) == -1)
    127		return -1;
    128
    129	if (pipe(write_pipe.fds) == -1)
    130		return -1;
    131
    132	pid = fork();
    133	if (pid == 0)
    134		exit(eat_cpu_child(write_pipe, read_pipe));
    135
    136	if (sync_with_child(read_pipe, write_pipe)) {
    137		rc = -1;
    138		goto out;
    139	}
    140
    141	printf("main test running as pid %d\n", getpid());
    142
    143	rc = test_function();
    144out:
    145	kill(pid, SIGKILL);
    146
    147	return rc;
    148}
    149
    150struct addr_range libc, vdso;
    151
    152int parse_proc_maps(void)
    153{
    154	unsigned long start, end;
    155	char execute, name[128];
    156	FILE *f;
    157	int rc;
    158
    159	f = fopen("/proc/self/maps", "r");
    160	if (!f) {
    161		perror("fopen");
    162		return -1;
    163	}
    164
    165	do {
    166		/* This skips line with no executable which is what we want */
    167		rc = fscanf(f, "%lx-%lx %*c%*c%c%*c %*x %*d:%*d %*d %127s\n",
    168			    &start, &end, &execute, name);
    169		if (rc <= 0)
    170			break;
    171
    172		if (execute != 'x')
    173			continue;
    174
    175		if (strstr(name, "libc")) {
    176			libc.first = start;
    177			libc.last = end - 1;
    178		} else if (strstr(name, "[vdso]")) {
    179			vdso.first = start;
    180			vdso.last = end - 1;
    181		}
    182	} while(1);
    183
    184	fclose(f);
    185
    186	return 0;
    187}
    188
    189#define PARANOID_PATH	"/proc/sys/kernel/perf_event_paranoid"
    190
    191bool require_paranoia_below(int level)
    192{
    193	long current;
    194	char *end, buf[16];
    195	FILE *f;
    196	bool rc;
    197
    198	rc = false;
    199
    200	f = fopen(PARANOID_PATH, "r");
    201	if (!f) {
    202		perror("fopen");
    203		goto out;
    204	}
    205
    206	if (!fgets(buf, sizeof(buf), f)) {
    207		printf("Couldn't read " PARANOID_PATH "?\n");
    208		goto out_close;
    209	}
    210
    211	current = strtol(buf, &end, 10);
    212
    213	if (end == buf) {
    214		printf("Couldn't parse " PARANOID_PATH "?\n");
    215		goto out_close;
    216	}
    217
    218	if (current >= level)
    219		goto out_close;
    220
    221	rc = true;
    222out_close:
    223	fclose(f);
    224out:
    225	return rc;
    226}
    227