1*053f45beSAndroid Build Coastguard WorkerFrom 1c3b492b2863b4833ec3f9a4df5a827e69c64af8 Mon Sep 17 00:00:00 2001
2*053f45beSAndroid Build Coastguard WorkerFrom: Quentin Perret <[email protected]>
3*053f45beSAndroid Build Coastguard WorkerDate: Thu, 17 Feb 2022 19:34:27 +0000
4*053f45beSAndroid Build Coastguard WorkerSubject: [PATCH 14/20] ANDROID: kvm: Test that pVM memory is wiped during
5*053f45beSAndroid Build Coastguard Worker teardown
6*053f45beSAndroid Build Coastguard Worker
7*053f45beSAndroid Build Coastguard WorkerIn protected KVM mode, we expect the hypervisor to protect guest secrets
8*053f45beSAndroid Build Coastguard Workerwhen they are torn down. Add a test checking this property by running a
9*053f45beSAndroid Build Coastguard Workerminimal guest, and checking that the content of memory has been wiped by
10*053f45beSAndroid Build Coastguard Workerthe hypervisor after teardown.
11*053f45beSAndroid Build Coastguard Worker
12*053f45beSAndroid Build Coastguard WorkerNote: although some of the pKVM code has already landed upstream, the
13*053f45beSAndroid Build Coastguard Workerfunctionality tested here hasn't at the time of writing. Once it does,
14*053f45beSAndroid Build Coastguard Workerthis test should be sent upstream for review to replace this ANDROID
15*053f45beSAndroid Build Coastguard Workerpatch.
16*053f45beSAndroid Build Coastguard Worker
17*053f45beSAndroid Build Coastguard Worker(cherry picked from commit a9dc703806031c8535c84c9905979f86dfaec1d3)
18*053f45beSAndroid Build Coastguard WorkerBug: 218934075
19*053f45beSAndroid Build Coastguard WorkerSigned-off-by: Quentin Perret <[email protected]>
20*053f45beSAndroid Build Coastguard Worker---
21*053f45beSAndroid Build Coastguard Worker .../selftests/kvm/aarch64/pvm_wipe_mem.c      | 174 ++++++++++++++++++
22*053f45beSAndroid Build Coastguard Worker 1 file changed, 174 insertions(+)
23*053f45beSAndroid Build Coastguard Worker create mode 100644 tools/testing/selftests/kvm/aarch64/pvm_wipe_mem.c
24*053f45beSAndroid Build Coastguard Worker
25*053f45beSAndroid Build Coastguard Workerdiff --git a/tools/testing/selftests/kvm/aarch64/pvm_wipe_mem.c b/tools/testing/selftests/kvm/aarch64/pvm_wipe_mem.c
26*053f45beSAndroid Build Coastguard Workernew file mode 100644
27*053f45beSAndroid Build Coastguard Workerindex 000000000000..4af8ca3c4bad
28*053f45beSAndroid Build Coastguard Worker--- /dev/null
29*053f45beSAndroid Build Coastguard Worker+++ b/tools/testing/selftests/kvm/aarch64/pvm_wipe_mem.c
30*053f45beSAndroid Build Coastguard Worker@@ -0,0 +1,174 @@
31*053f45beSAndroid Build Coastguard Worker+// SPDX-License-Identifier: GPL-2.0-only
32*053f45beSAndroid Build Coastguard Worker+/*
33*053f45beSAndroid Build Coastguard Worker+ * Test checking that memory of protected guests is wiped after teardown.
34*053f45beSAndroid Build Coastguard Worker+ *
35*053f45beSAndroid Build Coastguard Worker+ * Copyright (C) 2022, Google LLC.
36*053f45beSAndroid Build Coastguard Worker+ */
37*053f45beSAndroid Build Coastguard Worker+
38*053f45beSAndroid Build Coastguard Worker+#define _GNU_SOURCE
39*053f45beSAndroid Build Coastguard Worker+
40*053f45beSAndroid Build Coastguard Worker+#include <err.h>
41*053f45beSAndroid Build Coastguard Worker+#include <errno.h>
42*053f45beSAndroid Build Coastguard Worker+#include <fcntl.h>
43*053f45beSAndroid Build Coastguard Worker+#include <stdio.h>
44*053f45beSAndroid Build Coastguard Worker+#include <stdint.h>
45*053f45beSAndroid Build Coastguard Worker+#include <stdlib.h>
46*053f45beSAndroid Build Coastguard Worker+#include <string.h>
47*053f45beSAndroid Build Coastguard Worker+#include <unistd.h>
48*053f45beSAndroid Build Coastguard Worker+
49*053f45beSAndroid Build Coastguard Worker+#include <linux/kvm.h>
50*053f45beSAndroid Build Coastguard Worker+#include <sys/ioctl.h>
51*053f45beSAndroid Build Coastguard Worker+#include <sys/mman.h>
52*053f45beSAndroid Build Coastguard Worker+
53*053f45beSAndroid Build Coastguard Worker+#include "kselftest.h"
54*053f45beSAndroid Build Coastguard Worker+
55*053f45beSAndroid Build Coastguard Worker+#define KVM_VM_TYPE_ARM_PROTECTED	(1UL << 31)
56*053f45beSAndroid Build Coastguard Worker+
57*053f45beSAndroid Build Coastguard Worker+#define REG_X(number)	(0x6030000000100000ULL + (number) * 2UL)
58*053f45beSAndroid Build Coastguard Worker+#define REG_PC		0x6030000000100040ULL
59*053f45beSAndroid Build Coastguard Worker+
60*053f45beSAndroid Build Coastguard Worker+static void set_one_reg(int vcpufd, uint64_t reg_id, uint64_t val)
61*053f45beSAndroid Build Coastguard Worker+{
62*053f45beSAndroid Build Coastguard Worker+	uint64_t reg_data;
63*053f45beSAndroid Build Coastguard Worker+	struct kvm_one_reg reg;
64*053f45beSAndroid Build Coastguard Worker+	int ret;
65*053f45beSAndroid Build Coastguard Worker+
66*053f45beSAndroid Build Coastguard Worker+	reg.addr = (__u64) &reg_data;
67*053f45beSAndroid Build Coastguard Worker+	reg_data = val;
68*053f45beSAndroid Build Coastguard Worker+	reg.id = reg_id;
69*053f45beSAndroid Build Coastguard Worker+
70*053f45beSAndroid Build Coastguard Worker+	ret = ioctl(vcpufd, KVM_SET_ONE_REG, &reg);
71*053f45beSAndroid Build Coastguard Worker+	if (ret < 0)
72*053f45beSAndroid Build Coastguard Worker+		ksft_exit_fail_msg("Failed to set reg: %d\n", ret);
73*053f45beSAndroid Build Coastguard Worker+}
74*053f45beSAndroid Build Coastguard Worker+
75*053f45beSAndroid Build Coastguard Worker+static int get_kvm(void)
76*053f45beSAndroid Build Coastguard Worker+{
77*053f45beSAndroid Build Coastguard Worker+	size_t run_size;
78*053f45beSAndroid Build Coastguard Worker+	int kvm, ret;
79*053f45beSAndroid Build Coastguard Worker+
80*053f45beSAndroid Build Coastguard Worker+	kvm = open("/dev/kvm", O_RDWR | O_CLOEXEC);
81*053f45beSAndroid Build Coastguard Worker+	if (kvm < 0)
82*053f45beSAndroid Build Coastguard Worker+		ksft_exit_skip("KVM not supported\n");
83*053f45beSAndroid Build Coastguard Worker+
84*053f45beSAndroid Build Coastguard Worker+	ret = ioctl(kvm, KVM_GET_API_VERSION, NULL);
85*053f45beSAndroid Build Coastguard Worker+	if (ret != 12)
86*053f45beSAndroid Build Coastguard Worker+		ksft_exit_fail_msg("KVM_GET_API_VERSION %d, expected 12", ret);
87*053f45beSAndroid Build Coastguard Worker+
88*053f45beSAndroid Build Coastguard Worker+	run_size = ioctl(kvm, KVM_GET_VCPU_MMAP_SIZE, NULL);
89*053f45beSAndroid Build Coastguard Worker+	if (run_size < sizeof(struct kvm_run))
90*053f45beSAndroid Build Coastguard Worker+		ksft_exit_fail_msg("KVM_GET_VCPU_MMAP_SIZE unexpectedly small\n");
91*053f45beSAndroid Build Coastguard Worker+
92*053f45beSAndroid Build Coastguard Worker+	return kvm;
93*053f45beSAndroid Build Coastguard Worker+}
94*053f45beSAndroid Build Coastguard Worker+
95*053f45beSAndroid Build Coastguard Worker+static int create_protected_vm(int kvm)
96*053f45beSAndroid Build Coastguard Worker+{
97*053f45beSAndroid Build Coastguard Worker+	int vmfd = ioctl(kvm, KVM_CREATE_VM, KVM_VM_TYPE_ARM_PROTECTED);
98*053f45beSAndroid Build Coastguard Worker+
99*053f45beSAndroid Build Coastguard Worker+	if (vmfd < 0)
100*053f45beSAndroid Build Coastguard Worker+		ksft_exit_skip("Protected guests not supported: %d\n", vmfd);
101*053f45beSAndroid Build Coastguard Worker+
102*053f45beSAndroid Build Coastguard Worker+	return vmfd;
103*053f45beSAndroid Build Coastguard Worker+}
104*053f45beSAndroid Build Coastguard Worker+
105*053f45beSAndroid Build Coastguard Worker+static int create_vcpu(int vmfd, struct kvm_run **run)
106*053f45beSAndroid Build Coastguard Worker+{
107*053f45beSAndroid Build Coastguard Worker+	struct kvm_vcpu_init vcpu_init;
108*053f45beSAndroid Build Coastguard Worker+	int vcpufd, ret;
109*053f45beSAndroid Build Coastguard Worker+
110*053f45beSAndroid Build Coastguard Worker+	ret = ioctl(vmfd, KVM_ARM_PREFERRED_TARGET, &vcpu_init);
111*053f45beSAndroid Build Coastguard Worker+	if (ret)
112*053f45beSAndroid Build Coastguard Worker+		ksft_exit_fail_msg("Failed to set kvm_vcpu_init %d\n", ret);
113*053f45beSAndroid Build Coastguard Worker+
114*053f45beSAndroid Build Coastguard Worker+	vcpufd = ioctl(vmfd, KVM_CREATE_VCPU, (unsigned long)0);
115*053f45beSAndroid Build Coastguard Worker+	if (vcpufd < 0)
116*053f45beSAndroid Build Coastguard Worker+		ksft_exit_fail_msg("Failed to create VCPU: %d\n", vcpufd);
117*053f45beSAndroid Build Coastguard Worker+
118*053f45beSAndroid Build Coastguard Worker+	*run = mmap(NULL, sizeof(**run), PROT_READ | PROT_WRITE, MAP_SHARED, vcpufd, 0);
119*053f45beSAndroid Build Coastguard Worker+	if (!run)
120*053f45beSAndroid Build Coastguard Worker+		ksft_exit_fail_msg("Failed to mmap vcpu_run struct\n");
121*053f45beSAndroid Build Coastguard Worker+
122*053f45beSAndroid Build Coastguard Worker+	ret = ioctl(vcpufd, KVM_ARM_VCPU_INIT, &vcpu_init);
123*053f45beSAndroid Build Coastguard Worker+	if (ret)
124*053f45beSAndroid Build Coastguard Worker+		ksft_exit_fail_msg("Failed to initialize VCPU %d\n", ret);
125*053f45beSAndroid Build Coastguard Worker+
126*053f45beSAndroid Build Coastguard Worker+	return vcpufd;
127*053f45beSAndroid Build Coastguard Worker+}
128*053f45beSAndroid Build Coastguard Worker+
129*053f45beSAndroid Build Coastguard Worker+static void teardown(int kvm, int vmfd, int vcpufd, struct kvm_run *run)
130*053f45beSAndroid Build Coastguard Worker+{
131*053f45beSAndroid Build Coastguard Worker+	int ret = munmap(run, sizeof(*run));
132*053f45beSAndroid Build Coastguard Worker+
133*053f45beSAndroid Build Coastguard Worker+	if (ret)
134*053f45beSAndroid Build Coastguard Worker+		ksft_exit_fail_msg("Failed to unmap vCPU run: %d\n", ret);
135*053f45beSAndroid Build Coastguard Worker+
136*053f45beSAndroid Build Coastguard Worker+	ret = close(vcpufd);
137*053f45beSAndroid Build Coastguard Worker+	if (ret)
138*053f45beSAndroid Build Coastguard Worker+		ksft_exit_fail_msg("Failed to destroy VCPU: %d\n", ret);
139*053f45beSAndroid Build Coastguard Worker+
140*053f45beSAndroid Build Coastguard Worker+	ret = close(vmfd);
141*053f45beSAndroid Build Coastguard Worker+	if (ret)
142*053f45beSAndroid Build Coastguard Worker+		ksft_exit_fail_msg("Failed to destroy VM: %d\n", ret);
143*053f45beSAndroid Build Coastguard Worker+
144*053f45beSAndroid Build Coastguard Worker+	ret = close(kvm);
145*053f45beSAndroid Build Coastguard Worker+	if (ret)
146*053f45beSAndroid Build Coastguard Worker+		ksft_exit_fail_msg("Failed to close KVM fd: %d\n", ret);
147*053f45beSAndroid Build Coastguard Worker+}
148*053f45beSAndroid Build Coastguard Worker+
149*053f45beSAndroid Build Coastguard Worker+int main(void)
150*053f45beSAndroid Build Coastguard Worker+{
151*053f45beSAndroid Build Coastguard Worker+	struct kvm_userspace_memory_region region;
152*053f45beSAndroid Build Coastguard Worker+	long page_size = sysconf(_SC_PAGESIZE);
153*053f45beSAndroid Build Coastguard Worker+	int ret, kvm, vmfd, vcpufd;
154*053f45beSAndroid Build Coastguard Worker+	uint32_t guest_code[2];
155*053f45beSAndroid Build Coastguard Worker+	struct kvm_run *run;
156*053f45beSAndroid Build Coastguard Worker+	uint8_t *guest_mem;
157*053f45beSAndroid Build Coastguard Worker+	size_t run_size;
158*053f45beSAndroid Build Coastguard Worker+
159*053f45beSAndroid Build Coastguard Worker+	kvm = get_kvm();
160*053f45beSAndroid Build Coastguard Worker+	vmfd = create_protected_vm(kvm);
161*053f45beSAndroid Build Coastguard Worker+	vcpufd = create_vcpu(vmfd, &run);
162*053f45beSAndroid Build Coastguard Worker+
163*053f45beSAndroid Build Coastguard Worker+	/* Create a one-page memslot for the guest */
164*053f45beSAndroid Build Coastguard Worker+	guest_mem = mmap(NULL, page_size, PROT_READ | PROT_WRITE,
165*053f45beSAndroid Build Coastguard Worker+			MAP_SHARED | MAP_ANONYMOUS, -1, 0);
166*053f45beSAndroid Build Coastguard Worker+	if (guest_mem == MAP_FAILED)
167*053f45beSAndroid Build Coastguard Worker+		ksft_exit_fail_msg("Failed to mmap guest memory\n");
168*053f45beSAndroid Build Coastguard Worker+	region = (struct kvm_userspace_memory_region) {
169*053f45beSAndroid Build Coastguard Worker+		.slot = 0,
170*053f45beSAndroid Build Coastguard Worker+		.guest_phys_addr = 1UL << 30,
171*053f45beSAndroid Build Coastguard Worker+		.memory_size = page_size,
172*053f45beSAndroid Build Coastguard Worker+		.userspace_addr = (uint64_t)guest_mem,
173*053f45beSAndroid Build Coastguard Worker+	};
174*053f45beSAndroid Build Coastguard Worker+
175*053f45beSAndroid Build Coastguard Worker+	/* Copy some code in guest memory. */
176*053f45beSAndroid Build Coastguard Worker+	guest_code[0] = 0xf9400001;	/* 1:  ldr	x1, [x0]  */
177*053f45beSAndroid Build Coastguard Worker+	guest_code[1] = 0x17ffffff;	/*     b	1b	  */
178*053f45beSAndroid Build Coastguard Worker+	memcpy(guest_mem, guest_code, sizeof(guest_code));
179*053f45beSAndroid Build Coastguard Worker+	ret = ioctl(vmfd, KVM_SET_USER_MEMORY_REGION, &region);
180*053f45beSAndroid Build Coastguard Worker+	if (ret)
181*053f45beSAndroid Build Coastguard Worker+		ksft_exit_fail_msg("Failed to set memory region: %d\n", ret);
182*053f45beSAndroid Build Coastguard Worker+
183*053f45beSAndroid Build Coastguard Worker+	/*
184*053f45beSAndroid Build Coastguard Worker+	 * Get the VCPU to run one instruction, to be sure the page containing
185*053f45beSAndroid Build Coastguard Worker+	 * the code has been faulted in.
186*053f45beSAndroid Build Coastguard Worker+	 */
187*053f45beSAndroid Build Coastguard Worker+	set_one_reg(vcpufd, REG_PC, region.guest_phys_addr);
188*053f45beSAndroid Build Coastguard Worker+	set_one_reg(vcpufd, REG_X(0), region.guest_phys_addr + region.memory_size);
189*053f45beSAndroid Build Coastguard Worker+	ret = ioctl(vcpufd, KVM_RUN, NULL);
190*053f45beSAndroid Build Coastguard Worker+	if (ret)
191*053f45beSAndroid Build Coastguard Worker+		ksft_exit_fail_msg("Failed to run vcpu: %d\n", ret);
192*053f45beSAndroid Build Coastguard Worker+	if (run->exit_reason != KVM_EXIT_MMIO)
193*053f45beSAndroid Build Coastguard Worker+		ksft_exit_fail_msg("Unexpected KVM exit reason: %u\n", run->exit_reason);
194*053f45beSAndroid Build Coastguard Worker+
195*053f45beSAndroid Build Coastguard Worker+	/*
196*053f45beSAndroid Build Coastguard Worker+	 * Tear the guest down, and check that the donated memory has been
197*053f45beSAndroid Build Coastguard Worker+	 * wiped by the hypervisor.
198*053f45beSAndroid Build Coastguard Worker+	 */
199*053f45beSAndroid Build Coastguard Worker+	teardown(kvm, vmfd, vcpufd, run);
200*053f45beSAndroid Build Coastguard Worker+	if (!memcmp(guest_mem, guest_code, sizeof(guest_code)))
201*053f45beSAndroid Build Coastguard Worker+		ksft_exit_fail_msg("Protected guest memory has not been poisoned\n");
202*053f45beSAndroid Build Coastguard Worker+
203*053f45beSAndroid Build Coastguard Worker+	ksft_exit_pass();
204*053f45beSAndroid Build Coastguard Worker+}
205*053f45beSAndroid Build Coastguard Worker--
206*053f45beSAndroid Build Coastguard Worker2.42.0.609.gbb76f46606-goog
207*053f45beSAndroid Build Coastguard Worker
208