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) ®_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, ®); 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, ®ion); 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