1*49cdfc7eSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0-or-later
2*49cdfc7eSAndroid Build Coastguard Worker /*
3*49cdfc7eSAndroid Build Coastguard Worker * Copyright (C) 2023 SUSE LLC
4*49cdfc7eSAndroid Build Coastguard Worker * Author: Nicolai Stange <[email protected]>
5*49cdfc7eSAndroid Build Coastguard Worker * LTP port: Martin Doucha <[email protected]>
6*49cdfc7eSAndroid Build Coastguard Worker */
7*49cdfc7eSAndroid Build Coastguard Worker
8*49cdfc7eSAndroid Build Coastguard Worker /*\
9*49cdfc7eSAndroid Build Coastguard Worker * CVE 2021-3656
10*49cdfc7eSAndroid Build Coastguard Worker *
11*49cdfc7eSAndroid Build Coastguard Worker * Check that KVM correctly intercepts VMSAVE and VMLOAD instructions
12*49cdfc7eSAndroid Build Coastguard Worker * in a nested virtual machine even when the parent guest disables
13*49cdfc7eSAndroid Build Coastguard Worker * intercepting either instruction. If KVM does not override the disabled
14*49cdfc7eSAndroid Build Coastguard Worker * intercepts, it'll give the nested VM read/write access to a few bytes
15*49cdfc7eSAndroid Build Coastguard Worker * of an arbitrary physical memory page. Unauthorized memory access fixed in:
16*49cdfc7eSAndroid Build Coastguard Worker *
17*49cdfc7eSAndroid Build Coastguard Worker * commit c7dfa4009965a9b2d7b329ee970eb8da0d32f0bc
18*49cdfc7eSAndroid Build Coastguard Worker * Author: Maxim Levitsky <[email protected]>
19*49cdfc7eSAndroid Build Coastguard Worker * Date: Mon Jul 19 16:05:00 2021 +0300
20*49cdfc7eSAndroid Build Coastguard Worker *
21*49cdfc7eSAndroid Build Coastguard Worker * KVM: nSVM: always intercept VMLOAD/VMSAVE when nested (CVE-2021-3656)
22*49cdfc7eSAndroid Build Coastguard Worker */
23*49cdfc7eSAndroid Build Coastguard Worker
24*49cdfc7eSAndroid Build Coastguard Worker #include "kvm_test.h"
25*49cdfc7eSAndroid Build Coastguard Worker
26*49cdfc7eSAndroid Build Coastguard Worker #ifdef COMPILE_PAYLOAD
27*49cdfc7eSAndroid Build Coastguard Worker #if defined(__i386__) || defined(__x86_64__)
28*49cdfc7eSAndroid Build Coastguard Worker
29*49cdfc7eSAndroid Build Coastguard Worker #include "kvm_x86_svm.h"
30*49cdfc7eSAndroid Build Coastguard Worker
31*49cdfc7eSAndroid Build Coastguard Worker static void *vmsave_buf;
32*49cdfc7eSAndroid Build Coastguard Worker
33*49cdfc7eSAndroid Build Coastguard Worker /* Load FS, GS, TR and LDTR state from vmsave_buf */
guest_vmload(void)34*49cdfc7eSAndroid Build Coastguard Worker static int guest_vmload(void)
35*49cdfc7eSAndroid Build Coastguard Worker {
36*49cdfc7eSAndroid Build Coastguard Worker kvm_svm_vmload(vmsave_buf);
37*49cdfc7eSAndroid Build Coastguard Worker return 0;
38*49cdfc7eSAndroid Build Coastguard Worker }
39*49cdfc7eSAndroid Build Coastguard Worker
40*49cdfc7eSAndroid Build Coastguard Worker /* Save current FS, GS, TR and LDTR state to vmsave_buf */
guest_vmsave(void)41*49cdfc7eSAndroid Build Coastguard Worker static int guest_vmsave(void)
42*49cdfc7eSAndroid Build Coastguard Worker {
43*49cdfc7eSAndroid Build Coastguard Worker kvm_svm_vmsave(vmsave_buf);
44*49cdfc7eSAndroid Build Coastguard Worker return 0;
45*49cdfc7eSAndroid Build Coastguard Worker }
46*49cdfc7eSAndroid Build Coastguard Worker
cmp_descriptor(const struct kvm_vmcb_descriptor * a,const struct kvm_vmcb_descriptor * b)47*49cdfc7eSAndroid Build Coastguard Worker static int cmp_descriptor(const struct kvm_vmcb_descriptor *a,
48*49cdfc7eSAndroid Build Coastguard Worker const struct kvm_vmcb_descriptor *b)
49*49cdfc7eSAndroid Build Coastguard Worker {
50*49cdfc7eSAndroid Build Coastguard Worker int ret;
51*49cdfc7eSAndroid Build Coastguard Worker
52*49cdfc7eSAndroid Build Coastguard Worker ret = a->selector != b->selector;
53*49cdfc7eSAndroid Build Coastguard Worker ret = ret || a->attrib != b->attrib;
54*49cdfc7eSAndroid Build Coastguard Worker ret = ret || a->limit != b->limit;
55*49cdfc7eSAndroid Build Coastguard Worker ret = ret || a->base != b->base;
56*49cdfc7eSAndroid Build Coastguard Worker return ret;
57*49cdfc7eSAndroid Build Coastguard Worker }
58*49cdfc7eSAndroid Build Coastguard Worker
59*49cdfc7eSAndroid Build Coastguard Worker /* Return non-zero if the VMCB fields touched by vmsave/vmload differ */
cmp_vmcb(const struct kvm_vmcb * a,const struct kvm_vmcb * b)60*49cdfc7eSAndroid Build Coastguard Worker static int cmp_vmcb(const struct kvm_vmcb *a, const struct kvm_vmcb *b)
61*49cdfc7eSAndroid Build Coastguard Worker {
62*49cdfc7eSAndroid Build Coastguard Worker int ret;
63*49cdfc7eSAndroid Build Coastguard Worker
64*49cdfc7eSAndroid Build Coastguard Worker ret = cmp_descriptor(&a->fs, &b->fs);
65*49cdfc7eSAndroid Build Coastguard Worker ret = ret || cmp_descriptor(&a->gs, &b->gs);
66*49cdfc7eSAndroid Build Coastguard Worker ret = ret || cmp_descriptor(&a->tr, &b->tr);
67*49cdfc7eSAndroid Build Coastguard Worker ret = ret || cmp_descriptor(&a->ldtr, &b->ldtr);
68*49cdfc7eSAndroid Build Coastguard Worker ret = ret || a->kernel_gs_base != b->kernel_gs_base;
69*49cdfc7eSAndroid Build Coastguard Worker ret = ret || a->star != b->star;
70*49cdfc7eSAndroid Build Coastguard Worker ret = ret || a->lstar != b->lstar;
71*49cdfc7eSAndroid Build Coastguard Worker ret = ret || a->cstar != b->cstar;
72*49cdfc7eSAndroid Build Coastguard Worker ret = ret || a->sfmask != b->sfmask;
73*49cdfc7eSAndroid Build Coastguard Worker ret = ret || a->sysenter_cs != b->sysenter_cs;
74*49cdfc7eSAndroid Build Coastguard Worker ret = ret || a->sysenter_esp != b->sysenter_esp;
75*49cdfc7eSAndroid Build Coastguard Worker ret = ret || a->sysenter_eip != b->sysenter_eip;
76*49cdfc7eSAndroid Build Coastguard Worker return ret;
77*49cdfc7eSAndroid Build Coastguard Worker }
78*49cdfc7eSAndroid Build Coastguard Worker
main(void)79*49cdfc7eSAndroid Build Coastguard Worker void main(void)
80*49cdfc7eSAndroid Build Coastguard Worker {
81*49cdfc7eSAndroid Build Coastguard Worker uint16_t ss;
82*49cdfc7eSAndroid Build Coastguard Worker uint64_t rsp;
83*49cdfc7eSAndroid Build Coastguard Worker struct kvm_svm_vcpu *vcpu;
84*49cdfc7eSAndroid Build Coastguard Worker
85*49cdfc7eSAndroid Build Coastguard Worker kvm_init_svm();
86*49cdfc7eSAndroid Build Coastguard Worker vcpu = kvm_create_svm_vcpu(guest_vmload, 1);
87*49cdfc7eSAndroid Build Coastguard Worker kvm_vmcb_set_intercept(vcpu->vmcb, SVM_INTERCEPT_VMLOAD, 0);
88*49cdfc7eSAndroid Build Coastguard Worker vmsave_buf = kvm_alloc_vmcb();
89*49cdfc7eSAndroid Build Coastguard Worker
90*49cdfc7eSAndroid Build Coastguard Worker /* Save allocated stack for later VM reinit */
91*49cdfc7eSAndroid Build Coastguard Worker ss = vcpu->vmcb->ss.selector >> 3;
92*49cdfc7eSAndroid Build Coastguard Worker rsp = vcpu->vmcb->rsp;
93*49cdfc7eSAndroid Build Coastguard Worker
94*49cdfc7eSAndroid Build Coastguard Worker /* Load partial state from vmsave_buf and save it to vcpu->vmcb */
95*49cdfc7eSAndroid Build Coastguard Worker kvm_svm_vmrun(vcpu);
96*49cdfc7eSAndroid Build Coastguard Worker
97*49cdfc7eSAndroid Build Coastguard Worker if (vcpu->vmcb->exitcode != SVM_EXIT_HLT)
98*49cdfc7eSAndroid Build Coastguard Worker tst_brk(TBROK, "Nested VM exited unexpectedly");
99*49cdfc7eSAndroid Build Coastguard Worker
100*49cdfc7eSAndroid Build Coastguard Worker if (cmp_vmcb(vcpu->vmcb, vmsave_buf)) {
101*49cdfc7eSAndroid Build Coastguard Worker tst_res(TFAIL, "Nested VM can read host memory");
102*49cdfc7eSAndroid Build Coastguard Worker return;
103*49cdfc7eSAndroid Build Coastguard Worker }
104*49cdfc7eSAndroid Build Coastguard Worker
105*49cdfc7eSAndroid Build Coastguard Worker /* Load state from vcpu->vmcb and save it to vmsave_buf */
106*49cdfc7eSAndroid Build Coastguard Worker memset(vmsave_buf, 0xaa, sizeof(struct kvm_vmcb));
107*49cdfc7eSAndroid Build Coastguard Worker kvm_init_guest_vmcb(vcpu->vmcb, 1, ss, (void *)rsp, guest_vmsave);
108*49cdfc7eSAndroid Build Coastguard Worker kvm_vmcb_set_intercept(vcpu->vmcb, SVM_INTERCEPT_VMSAVE, 0);
109*49cdfc7eSAndroid Build Coastguard Worker kvm_svm_vmrun(vcpu);
110*49cdfc7eSAndroid Build Coastguard Worker
111*49cdfc7eSAndroid Build Coastguard Worker if (vcpu->vmcb->exitcode != SVM_EXIT_HLT)
112*49cdfc7eSAndroid Build Coastguard Worker tst_brk(TBROK, "Nested VM exited unexpectedly");
113*49cdfc7eSAndroid Build Coastguard Worker
114*49cdfc7eSAndroid Build Coastguard Worker if (cmp_vmcb(vcpu->vmcb, vmsave_buf)) {
115*49cdfc7eSAndroid Build Coastguard Worker tst_res(TFAIL, "Nested VM can overwrite host memory");
116*49cdfc7eSAndroid Build Coastguard Worker return;
117*49cdfc7eSAndroid Build Coastguard Worker }
118*49cdfc7eSAndroid Build Coastguard Worker
119*49cdfc7eSAndroid Build Coastguard Worker tst_res(TPASS, "VMLOAD and VMSAVE were intercepted by kernel");
120*49cdfc7eSAndroid Build Coastguard Worker }
121*49cdfc7eSAndroid Build Coastguard Worker
122*49cdfc7eSAndroid Build Coastguard Worker #else /* defined(__i386__) || defined(__x86_64__) */
123*49cdfc7eSAndroid Build Coastguard Worker TST_TEST_TCONF("Test supported only on x86");
124*49cdfc7eSAndroid Build Coastguard Worker #endif /* defined(__i386__) || defined(__x86_64__) */
125*49cdfc7eSAndroid Build Coastguard Worker
126*49cdfc7eSAndroid Build Coastguard Worker #else /* COMPILE_PAYLOAD */
127*49cdfc7eSAndroid Build Coastguard Worker
128*49cdfc7eSAndroid Build Coastguard Worker static struct tst_test test = {
129*49cdfc7eSAndroid Build Coastguard Worker .test_all = tst_kvm_run,
130*49cdfc7eSAndroid Build Coastguard Worker .setup = tst_kvm_setup,
131*49cdfc7eSAndroid Build Coastguard Worker .cleanup = tst_kvm_cleanup,
132*49cdfc7eSAndroid Build Coastguard Worker .supported_archs = (const char *const []) {
133*49cdfc7eSAndroid Build Coastguard Worker "x86_64",
134*49cdfc7eSAndroid Build Coastguard Worker "x86",
135*49cdfc7eSAndroid Build Coastguard Worker NULL
136*49cdfc7eSAndroid Build Coastguard Worker },
137*49cdfc7eSAndroid Build Coastguard Worker .tags = (struct tst_tag[]){
138*49cdfc7eSAndroid Build Coastguard Worker {"linux-git", "c7dfa4009965"},
139*49cdfc7eSAndroid Build Coastguard Worker {"CVE", "2021-3656"},
140*49cdfc7eSAndroid Build Coastguard Worker {}
141*49cdfc7eSAndroid Build Coastguard Worker }
142*49cdfc7eSAndroid Build Coastguard Worker };
143*49cdfc7eSAndroid Build Coastguard Worker
144*49cdfc7eSAndroid Build Coastguard Worker #endif /* COMPILE_PAYLOAD */
145