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-targetstep.c (5030B)


      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 (!baseline && event.type == CPC_EVENT_GUEST
     32			&& event.guest.type == CPC_GUEST_STOP_TRACK)
     33		return 2;
     34
     35	if (event.type == CPC_EVENT_TRACK_STEP) {
     36		ret = ioctl(kvm_dev, KVM_CPC_READ_COUNTS, counts);
     37		if (ret) err(1, "KVM_CPC_READ_COUNTS");
     38
     39		printf("Event: rip:%08llx cnt:%llu inst:%08llx data:%08llx ret:%llu\n",
     40			vm_get_rip(), event.step.fault_count,
     41			event.step.fault_gfns[0], event.step.fault_gfns[1],
     42			event.step.retinst);
     43		print_counts(counts);
     44		printf("\n");
     45		print_counts_raw(counts);
     46		printf("\n");
     47	}
     48
     49	ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.id);
     50	if (ret) err(1, "KVM_CPC_ACK_EVENT");
     51
     52	return 1;
     53}
     54
     55void
     56deinit(void)
     57{
     58	ioctl(kvm_dev, KVM_CPC_DEINIT);
     59
     60	kill(child, SIGKILL);
     61
     62	kvm_setup_deinit();
     63}
     64
     65int
     66main(int argc, const char **argv)
     67{
     68	struct ipc *ipc;
     69	struct guest guest;
     70	struct kvm kvm;
     71	uint8_t baseline[L1_SETS];
     72	struct cpc_track_cfg cfg;
     73	bool inst_gfn_avail;
     74	uint64_t inst_gfn;
     75	uint64_t eventcnt;
     76	uint32_t arg;
     77	int ret;
     78
     79	setvbuf(stdout, NULL, _IONBF, 0);
     80
     81	parse_vmtype(argc, argv);
     82
     83	kvm_setup_init();
     84
     85	ipc = ipc_alloc();
     86
     87	child = fork();
     88	if (child < 0) err(1, "fork");
     89
     90	if (child == 0) {
     91		pin_process(0, TARGET_CORE, true);
     92
     93		guest_init(&guest, "test/kvm-targetstep_guest");
     94		vm_init(&kvm, &guest);
     95		guest_deinit(&guest);
     96
     97		/* reset kernel module state */
     98		ret = ioctl(kvm_dev, KVM_CPC_RESET, NULL);
     99		if (ret < 0) err(1, "KVM_CPC_RESET");
    100
    101		ipc_signal_parent(ipc);
    102		ipc_wait_parent(ipc);
    103
    104		printf("VM start\n");
    105
    106		do {
    107			ret = ioctl(kvm.vcpufd, KVM_RUN, NULL);
    108			if (ret < 0) err(1, "KVM_RUN");
    109		} while (kvm.run->exit_reason == KVM_EXIT_HLT);
    110
    111		printf("VM exit\n");
    112
    113		vm_deinit(&kvm);
    114
    115		ipc_free(ipc);
    116		kvm_setup_deinit();
    117	} else {
    118		pin_process(0, SECONDARY_CORE, true);
    119
    120		atexit(deinit);
    121
    122		ipc_wait_child(ipc);
    123
    124		printf("Monitor start\n");
    125
    126		memset(&cfg, 0, sizeof(cfg));
    127		cfg.mode = CPC_TRACK_STEPS;
    128		cfg.steps.with_data = true;
    129		ret = ioctl(kvm_dev, KVM_CPC_TRACK_MODE, &cfg);
    130		if (ret) err(1, "KVM_CPC_TRACK_MODE");
    131
    132		arg = true;
    133		ret = ioctl(kvm_dev, KVM_CPC_CALC_BASELINE, &arg);
    134		if (ret) err(1, "KVM_CPC_CALC_BASELINE");
    135
    136		ipc_signal_child(ipc);
    137
    138		/* run vm while baseline is calculated */
    139		eventcnt = 0;
    140		while (eventcnt < 50) {
    141			eventcnt += monitor(&kvm, true);
    142		}
    143
    144		ret = ioctl(kvm_dev, KVM_CPC_VM_REQ_PAUSE);
    145		if (ret) err(1, "KVM_CPC_VM_REQ_PAUSE");
    146
    147		while (1) {
    148			ret = ioctl(kvm_dev, KVM_CPC_POLL_EVENT, &event);
    149			if (ret && errno == EAGAIN) continue;
    150			if (ret) err(1, "KVM_CPC_POLL_EVENT");
    151
    152			if (event.type == CPC_EVENT_PAUSE) break;
    153
    154			ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.id);
    155			if (ret) err(1, "KVM_CPC_ACK_EVENT");
    156		}
    157
    158		arg = false;
    159		ret = ioctl(kvm_dev, KVM_CPC_CALC_BASELINE, &arg);
    160		if (ret) err(1, "KVM_CPC_CALC_BASELINE");
    161
    162		ret = ioctl(kvm_dev, KVM_CPC_READ_BASELINE, baseline);
    163		if (ret) err(1, "KVM_CPC_READ_BASELINE");
    164
    165		printf("\nBaseline:\n");
    166		print_counts(baseline);
    167		printf("\n");
    168		print_counts_raw(baseline);
    169		printf("\n\n");
    170
    171		arg = true;
    172		ret = ioctl(kvm_dev, KVM_CPC_APPLY_BASELINE, &arg);
    173		if (ret) err(1, "KMV_CPC_APPLY_BASELINE");
    174
    175		memset(&cfg, 0, sizeof(cfg));
    176		cfg.mode = CPC_TRACK_PAGES;
    177		ret = ioctl(kvm_dev, KVM_CPC_TRACK_MODE, &cfg);
    178		if (ret) err(1, "KVM_CPC_TRACK_MODE");
    179
    180		ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.id);
    181		if (ret) err(1, "KVM_CPC_ACK_EVENT");
    182
    183		/* wait for CPC_GUEST_START_TRACK */
    184
    185		inst_gfn_avail = false;
    186		while (1) {
    187			ret = ioctl(kvm_dev, KVM_CPC_POLL_EVENT, &event);
    188			if (ret && errno == EAGAIN) continue;
    189			if (ret) err(1, "KVM_CPC_POLL_EVENT");
    190
    191			if (inst_gfn_avail && event.type == CPC_EVENT_GUEST
    192					&& event.guest.type == CPC_GUEST_START_TRACK)
    193				break;
    194
    195			if (event.type == CPC_EVENT_TRACK_PAGE) {
    196				inst_gfn = event.page.inst_gfn;
    197				inst_gfn_avail = true;
    198			}
    199
    200			ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.id);
    201			if (ret) err(1, "KVM_CPC_ACK_EVENT");
    202		}
    203
    204		/* start step tracking for target gfn */
    205
    206		printf("Target GFN: %08llx\n", inst_gfn);
    207
    208		memset(&cfg, 0, sizeof(cfg));
    209		cfg.mode = CPC_TRACK_STEPS;
    210		cfg.steps.target_gfn = inst_gfn;
    211		cfg.steps.use_target = true;
    212		cfg.steps.with_data = true;
    213		ret = ioctl(kvm_dev, KVM_CPC_TRACK_MODE, &cfg);
    214		if (ret) err(1, "KVM_CPC_TRACK_MODE");
    215
    216		ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.id);
    217		if (ret) err(1, "KVM_CPC_ACK_EVENT");
    218
    219		while (monitor(&kvm, false) != 2);
    220
    221		printf("Monitor exit\n");
    222
    223		ipc_free(ipc);
    224	}
    225}
    226