cachepc

Prime+Probe cache-based side-channel attack on AMD SEV-SNP protected virtual machines
git clone https://git.sinitax.com/sinitax/cachepc
Log | Files | Refs | Submodules | README | sfeed.txt

kvm-step.c (3985B)


      1#include "test/kvm-eviction.h"
      2#include "test/kvm.h"
      3#include "test/util.h"
      4#include "cachepc/uapi.h"
      5
      6#include <sys/ioctl.h>
      7#include <sys/mman.h>
      8#include <signal.h>
      9#include <unistd.h>
     10#include <fcntl.h>
     11#include <errno.h>
     12#include <err.h>
     13#include <string.h>
     14#include <stdbool.h>
     15#include <stdio.h>
     16#include <stdlib.h>
     17
     18static int child;
     19static struct cpc_event event;
     20
     21uint64_t
     22monitor(struct kvm *kvm, bool baseline)
     23{
     24	uint8_t counts[L1_SETS];
     25	int ret;
     26
     27	ret = ioctl(kvm_dev, KVM_CPC_POLL_EVENT, &event);
     28	if (ret && errno == EAGAIN) return 0;
     29	if (ret) err(1, "KVM_CPC_POLL_EVENT");
     30
     31	if (event.type != CPC_EVENT_TRACK_STEP)
     32		errx(1, "unexpected event type %i", event.type);
     33
     34	ret = ioctl(kvm_dev, KVM_CPC_READ_COUNTS, counts);
     35	if (ret) err(1, "KVM_CPC_READ_COUNTS");
     36
     37	printf("Event: rip:%08llx cnt:%llu inst:%08llx data:%08llx ret:%llu misses:%u\n",
     38		vm_get_rip(), event.step.fault_count,
     39		event.step.fault_gfns[0], event.step.fault_gfns[1],
     40		event.step.retinst, event.step.misses);
     41	print_counts(counts);
     42	printf("\n");
     43	print_counts_raw(counts);
     44	printf("\n");
     45
     46	ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.id);
     47	if (ret) err(1, "KVM_CPC_ACK_EVENT");
     48
     49	return 1;
     50}
     51
     52void
     53deinit(void)
     54{
     55	ioctl(kvm_dev, KVM_CPC_DEINIT);
     56
     57	kill(child, SIGKILL);
     58
     59	kvm_setup_deinit();
     60}
     61
     62int
     63main(int argc, const char **argv)
     64{
     65	struct ipc *ipc;
     66	struct guest guest;
     67	struct kvm kvm;
     68	uint8_t baseline[L1_SETS];
     69	struct cpc_track_cfg cfg;
     70	uint64_t eventcnt;
     71	uint32_t arg;
     72	bool with_data;
     73	int ret;
     74
     75	setvbuf(stdout, NULL, _IONBF, 0);
     76
     77	with_data = true;
     78	if (argc > 1 && !strcmp(argv[1], "--exec-only")) {
     79		with_data = false;
     80		argc--;
     81		argv++;
     82	}
     83
     84	parse_vmtype(argc, argv);
     85
     86	kvm_setup_init();
     87
     88	ipc = ipc_alloc();
     89
     90	child = fork();
     91	if (child < 0) err(1, "fork");
     92
     93	if (child == 0) {
     94		pin_process(0, TARGET_CORE, true);
     95
     96		guest_init(&guest, "test/kvm-step_guest");
     97		vm_init(&kvm, &guest);
     98		guest_deinit(&guest);
     99
    100		/* reset kernel module state */
    101		ret = ioctl(kvm_dev, KVM_CPC_RESET, NULL);
    102		if (ret < 0) err(1, "KVM_CPC_RESET");
    103
    104		ipc_signal_parent(ipc);
    105		ipc_wait_parent(ipc);
    106
    107		printf("VM start\n");
    108
    109		do {
    110			ret = ioctl(kvm.vcpufd, KVM_RUN, NULL);
    111			if (ret < 0) err(1, "KVM_RUN");
    112		} while (kvm.run->exit_reason == KVM_EXIT_HLT);
    113
    114		printf("VM exit\n");
    115
    116		vm_deinit(&kvm);
    117
    118		ipc_free(ipc);
    119		kvm_setup_deinit();
    120	} else {
    121		pin_process(0, SECONDARY_CORE, true);
    122
    123		atexit(deinit);
    124
    125		ipc_wait_child(ipc);
    126
    127		printf("Monitor start\n");
    128
    129		memset(&cfg, 0, sizeof(cfg));
    130		cfg.mode = CPC_TRACK_STEPS;
    131		cfg.steps.with_data = with_data;
    132		ret = ioctl(kvm_dev, KVM_CPC_TRACK_MODE, &cfg);
    133		if (ret) err(1, "KVM_CPC_TRACK_MODE");
    134
    135		arg = true;
    136		ret = ioctl(kvm_dev, KVM_CPC_CALC_BASELINE, &arg);
    137		if (ret) err(1, "KVM_CPC_CALC_BASELINE");
    138
    139		ipc_signal_child(ipc);
    140
    141		/* run vm while baseline is calculated */
    142		eventcnt = 0;
    143		while (eventcnt < 50) {
    144			eventcnt += monitor(&kvm, true);
    145		}
    146
    147		ret = ioctl(kvm_dev, KVM_CPC_VM_REQ_PAUSE);
    148		if (ret) err(1, "KVM_CPC_VM_REQ_PAUSE");
    149
    150		while (1) {
    151			ret = ioctl(kvm_dev, KVM_CPC_POLL_EVENT, &event);
    152			if (ret && errno == EAGAIN) continue;
    153			if (ret) err(1, "KVM_CPC_POLL_EVENT");
    154
    155			if (event.type == CPC_EVENT_PAUSE) break;
    156
    157			ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.id);
    158			if (ret) err(1, "KVM_CPC_ACK_EVENT");
    159		}
    160
    161		arg = false;
    162		ret = ioctl(kvm_dev, KVM_CPC_CALC_BASELINE, &arg);
    163		if (ret) err(1, "KVM_CPC_CALC_BASELINE");
    164
    165		ret = ioctl(kvm_dev, KVM_CPC_READ_BASELINE, baseline);
    166		if (ret) err(1, "KVM_CPC_READ_BASELINE");
    167
    168		printf("\nBaseline:\n");
    169		print_counts(baseline);
    170		printf("\n");
    171		print_counts_raw(baseline);
    172		printf("\n\n");
    173
    174		arg = true;
    175		ret = ioctl(kvm_dev, KVM_CPC_APPLY_BASELINE, &arg);
    176		if (ret) err(1, "KMV_CPC_APPLY_BASELINE");
    177
    178		ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.id);
    179		if (ret) err(1, "KVM_CPC_ACK_EVENT");
    180
    181		eventcnt = 0;
    182		while (eventcnt < 57) {
    183			eventcnt += monitor(&kvm, false);
    184		}
    185
    186		printf("Monitor exit\n");
    187
    188		ipc_free(ipc);
    189	}
    190}
    191