1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (C) 2023 SUSE LLC
4 * Author: Nicolai Stange <[email protected]>
5 * LTP port: Martin Doucha <[email protected]>
6 */
7
8 /*\
9 * CVE 2021-3653
10 *
11 * Check that KVM either blocks enabling virtual interrupt controller (AVIC)
12 * in nested VMs or correctly sets up the required memory address translation.
13 * If AVIC is enabled without address translation in the host kernel,
14 * the nested VM will be able to read and write an arbitraty physical memory
15 * page specified by the parent VM. Unauthorized memory access fixed in:
16 *
17 * commit 0f923e07124df069ba68d8bb12324398f4b6b709
18 * Author: Maxim Levitsky <[email protected]>
19 * Date: Thu Jul 15 01:56:24 2021 +0300
20 *
21 * KVM: nSVM: avoid picking up unsupported bits from L2 in int_ctl (CVE-2021-3653)
22 */
23
24 #include "kvm_test.h"
25
26 #ifdef COMPILE_PAYLOAD
27 #if defined(__i386__) || defined(__x86_64__)
28
29 #include "kvm_x86_svm.h"
30
31 #define AVIC_REG_ADDR 0x280
32 #define AVIC_TEST_VAL 0xec
33 #define AVIC_READ_FAIL 0x12ead
34
35 #define AVIC_INFO_MASK ((1ULL << 32) | 0xff0)
36 #define AVIC_INFO_EXP ((1ULL << 32) | AVIC_REG_ADDR)
37
38 static uint32_t * const avic_ptr = (uint32_t *)AVIC_REG_ADDR;
39
guest_main(void)40 static int guest_main(void)
41 {
42 if (*avic_ptr != 0xaaaaaaaa)
43 return AVIC_READ_FAIL;
44
45 *avic_ptr = AVIC_TEST_VAL;
46 return 0;
47 }
48
main(void)49 void main(void)
50 {
51 struct kvm_svm_vcpu *vcpu;
52
53 kvm_init_svm();
54 vcpu = kvm_create_svm_vcpu(guest_main, 1);
55
56 /*
57 * Enable AVIC and set both the AVIC base address (where the nested VM
58 * will write) and backing page address (where the parent VM expects
59 * to see the changes) to 0
60 */
61 vcpu->vmcb->virt_intr_ctl |= SVM_INTR_AVIC;
62 vcpu->vmcb->avic_backing_page = 0;
63 vcpu->vmcb->avic_bar = 0;
64 memset((void *)8, 0xaa, PAGESIZE - 8);
65
66 /* Write into AVIC backing page in the nested VM */
67 kvm_svm_vmrun(vcpu);
68
69 switch (vcpu->vmcb->exitcode) {
70 case SVM_EXIT_HLT:
71 if (vcpu->vmcb->rax == AVIC_READ_FAIL) {
72 tst_res(TFAIL, "Nested VM can read host memory");
73 return;
74 }
75
76 if (vcpu->vmcb->rax)
77 tst_brk(TBROK, "Unexpected guest_main() return value");
78
79 break;
80
81 case SVM_EXIT_AVIC_NOACCEL:
82 if ((vcpu->vmcb->exitinfo1 & AVIC_INFO_MASK) == AVIC_INFO_EXP) {
83 tst_res(TPASS, "AVIC register write caused VMEXIT");
84 break;
85 }
86
87 /* unexpected exit, fall through */
88
89 default:
90 tst_brk(TBROK, "Nested VM exited unexpectedly");
91 }
92
93 if (*avic_ptr != AVIC_TEST_VAL) {
94 tst_res(TFAIL, "Write into AVIC ESR redirected to host memory");
95 return;
96 }
97
98 tst_res(TPASS, "Writes into AVIC backing page were not redirected");
99 }
100
101 #else /* defined(__i386__) || defined(__x86_64__) */
102 TST_TEST_TCONF("Test supported only on x86");
103 #endif /* defined(__i386__) || defined(__x86_64__) */
104
105 #else /* COMPILE_PAYLOAD */
106
107 static struct tst_test test = {
108 .test_all = tst_kvm_run,
109 .setup = tst_kvm_setup,
110 .cleanup = tst_kvm_cleanup,
111 .supported_archs = (const char *const []) {
112 "x86_64",
113 "x86",
114 NULL
115 },
116 .tags = (struct tst_tag[]){
117 {"linux-git", "0f923e07124d"},
118 {"CVE", "2021-3653"},
119 {}
120 }
121 };
122
123 #endif /* COMPILE_PAYLOAD */
124