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-eviction.c (4002B)


      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 <unistd.h>
      9#include <fcntl.h>
     10#include <err.h>
     11#include <string.h>
     12#include <stdbool.h>
     13#include <stdio.h>
     14#include <stdlib.h>
     15
     16#define SAMPLE_COUNT 64
     17
     18void
     19collect(struct kvm *kvm, uint8_t *counts)
     20{
     21	int ret;
     22
     23	ret = ioctl(kvm->vcpufd, KVM_RUN, NULL);
     24	if (ret == -1) err(1, "KVM_RUN");
     25
     26	if (kvm->run->exit_reason == KVM_EXIT_MMIO) {
     27		errx(1, "KVM died from OOB access! rip:%lu addr:%lu",
     28			vm_get_rip(), kvm->run->mmio.phys_addr);
     29	} else if (kvm->run->exit_reason != KVM_EXIT_HLT) {
     30		errx(1, "KVM died! rip:%lu code:%i",
     31			vm_get_rip(), kvm->run->exit_reason);
     32	}
     33
     34	ret = ioctl(kvm_dev, KVM_CPC_READ_COUNTS, counts);
     35	if (ret == -1) err(1, "KVM_CPC_READ_COUNTS");
     36}
     37
     38int
     39main(int argc, const char **argv)
     40{
     41	struct kvm vms[2];
     42	struct guest guests[2];
     43	uint8_t counts[2][SAMPLE_COUNT][L1_SETS];
     44	uint8_t baseline[L1_SETS];
     45	struct cpc_track_cfg cfg;
     46	int i, k, ret, exitcode;
     47
     48	setvbuf(stdout, NULL, _IONBF, 0);
     49
     50	parse_vmtype(argc, argv);
     51
     52	pin_process(0, TARGET_CORE, true);
     53
     54	kvm_setup_init();
     55
     56	guest_init(&guests[WITH], "test/kvm-eviction-with_guest");
     57	vm_init(&vms[WITH], &guests[WITH]);
     58	guest_deinit(&guests[WITH]);
     59
     60	guest_init(&guests[WITHOUT], "test/kvm-eviction-without_guest");
     61	vm_init(&vms[WITHOUT], &guests[WITHOUT]);
     62	guest_deinit(&guests[WITHOUT]);
     63
     64	/* reset kernel module state */
     65	ret = ioctl(kvm_dev, KVM_CPC_RESET);
     66	if (ret == -1) err(1, "KVM_CPC_RESET");
     67
     68	memset(&cfg, 0, sizeof(cfg));
     69	cfg.mode = CPC_TRACK_EXIT_EVICTIONS;
     70	ret = ioctl(kvm_dev, KVM_CPC_TRACK_MODE, &cfg);
     71	if (ret == -1) err(1, "KVM_CPC_TRACK_MODE");
     72
     73	/* resolve page faults in advance (code only covers 1 page)..
     74	 * we want the read counts to apply between KVM_RUN and KVM_EXIT_HLT,
     75	 * any exits through PFs inbetween will influence our measurement */
     76	collect(&vms[WITH], counts[WITH][0]);
     77	collect(&vms[WITHOUT], counts[WITHOUT][0]);
     78
     79	/* collect samples */
     80	for (i = 0; i < SAMPLE_COUNT; i++) {
     81		collect(&vms[WITH], counts[WITH][i]);
     82		collect(&vms[WITHOUT], counts[WITHOUT][i]);
     83	}
     84
     85	/* calculate measurement baseline */
     86	memset(baseline, 0xff, L1_SETS);
     87	for (i = 0; i < SAMPLE_COUNT; i++) {
     88		for (k = 0; k < L1_SETS; k++) {
     89			if (counts[WITH][i][k] < baseline[k])
     90				baseline[k] = counts[WITH][i][k];
     91			if (counts[WITHOUT][i][k] < baseline[k])
     92				baseline[k] = counts[WITHOUT][i][k];
     93		}
     94	}
     95
     96	printf("=== Baseline ===\n\n", i);
     97	print_counts(baseline);
     98	printf("\n");
     99	print_counts_raw(baseline);
    100	printf("\n");
    101
    102	/* apply baseline and output samples */
    103	for (i = 0; i < SAMPLE_COUNT; i++) {
    104		for (k = 0; k < L1_SETS; k++) {
    105			counts[WITH][i][k] -= baseline[k];
    106			counts[WITHOUT][i][k] -= baseline[k];
    107		}
    108
    109		printf("=== Sample %2i ===\n", i);
    110
    111		printf("\nWith eviction:\n\n");
    112		print_counts(counts[WITH][i]);
    113		printf("\n");
    114		print_counts_raw(counts[WITH][i]);
    115
    116		printf("\nWithout eviction:\n\n");
    117		print_counts(counts[WITHOUT][i]);
    118		printf("\n");
    119		print_counts_raw(counts[WITHOUT][i]);
    120		printf("\n");
    121	}
    122
    123	/* check for measurment errors */
    124	exitcode = 0;
    125	for (i = 0; i < SAMPLE_COUNT; i++) {
    126		for (k = 0; k < L1_SETS; k++) {
    127			if (counts[WITH][i][k] + baseline[k] > L1_ASSOC) {
    128				warnx("sample %i: With count OOB for set %i (=%i)",
    129					i, k, counts[WITH][i][k] + baseline[k]);
    130				exitcode = 1;
    131			}
    132
    133			if (counts[WITHOUT][i][k] + baseline[k] > L1_ASSOC) {
    134				warnx("sample %i: Without count OOB for set %i (=%i)",
    135					i, k, counts[WITHOUT][i][k] + baseline[k]);
    136				exitcode = 1;
    137			}
    138		}
    139
    140		if (!counts[WITH][i][TARGET_SET]) {
    141			warnx("sample %i: Missing eviction in target set %i (=%i,%i)",
    142				i, TARGET_SET, counts[WITH][i][TARGET_SET],
    143				counts[WITH][i][TARGET_SET] + baseline[TARGET_SET]);
    144			exitcode = 1;
    145		}
    146	}
    147
    148	vm_deinit(&vms[WITH]);
    149	vm_deinit(&vms[WITHOUT]);
    150
    151	ret = ioctl(kvm_dev, KVM_CPC_DEINIT);
    152	if (ret == -1) err(1, "KVM_CPC_DEINIT");
    153
    154	kvm_setup_deinit();
    155
    156	return exitcode;
    157}
    158