xref: /linux/tools/testing/selftests/kvm/x86/set_sregs_test.c (revision 67f8bc848ee31831336bd478e57d2f993551902e)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * KVM_SET_SREGS tests
4  *
5  * Copyright (C) 2018, Google LLC.
6  *
7  * This is a regression test for the bug fixed by the following commit:
8  * d3802286fa0f ("kvm: x86: Disallow illegal IA32_APIC_BASE MSR values")
9  *
10  * That bug allowed a user-mode program that called the KVM_SET_SREGS
11  * ioctl to put a VCPU's local APIC into an invalid state.
12  */
13 #include <fcntl.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <sys/ioctl.h>
18 
19 #include "test_util.h"
20 
21 #include "kvm_util.h"
22 #include "processor.h"
23 
24 #define TEST_INVALID_SREG_BIT(vcpu, reg, orig, bit)				\
25 do {										\
26 	struct kvm_sregs new;							\
27 	int rc;									\
28 										\
29 	/* Skip the sub-test, the feature/bit is supported. */			\
30 	if (orig.reg & bit)							\
31 		break;								\
32 										\
33 	memcpy(&new, &orig, sizeof(new));					\
34 	new.reg |= bit;								\
35 										\
36 	rc = _vcpu_sregs_set(vcpu, &new);					\
37 	TEST_ASSERT(rc, "KVM allowed invalid " #reg " bit (0x%lx)", (u64)bit);	\
38 										\
39 	/* Sanity check that KVM didn't change anything. */			\
40 	vcpu_sregs_get(vcpu, &new);						\
41 	TEST_ASSERT(!memcmp(&new, &orig, sizeof(new)), "KVM modified sregs");	\
42 } while (0)
43 
44 #define KVM_ALWAYS_ALLOWED_CR4 (X86_CR4_VME | X86_CR4_PVI | X86_CR4_TSD |	\
45 				X86_CR4_DE | X86_CR4_PSE | X86_CR4_PAE |	\
46 				X86_CR4_MCE | X86_CR4_PGE | X86_CR4_PCE |	\
47 				X86_CR4_OSFXSR | X86_CR4_OSXMMEXCPT)
48 
49 #define KVM_ALWAYS_ALLOWED_EFER EFER_SCE
50 
51 static u64 calc_supported_cr4_feature_bits(void)
52 {
53 	u64 cr4 = KVM_ALWAYS_ALLOWED_CR4;
54 
55 	if (kvm_cpu_has(X86_FEATURE_UMIP))
56 		cr4 |= X86_CR4_UMIP;
57 	if (kvm_cpu_has(X86_FEATURE_LA57))
58 		cr4 |= X86_CR4_LA57;
59 	if (kvm_cpu_has(X86_FEATURE_VMX))
60 		cr4 |= X86_CR4_VMXE;
61 	if (kvm_cpu_has(X86_FEATURE_SMX))
62 		cr4 |= X86_CR4_SMXE;
63 	if (kvm_cpu_has(X86_FEATURE_FSGSBASE))
64 		cr4 |= X86_CR4_FSGSBASE;
65 	if (kvm_cpu_has(X86_FEATURE_PCID))
66 		cr4 |= X86_CR4_PCIDE;
67 	if (kvm_cpu_has(X86_FEATURE_XSAVE))
68 		cr4 |= X86_CR4_OSXSAVE;
69 	if (kvm_cpu_has(X86_FEATURE_SMEP))
70 		cr4 |= X86_CR4_SMEP;
71 	if (kvm_cpu_has(X86_FEATURE_SMAP))
72 		cr4 |= X86_CR4_SMAP;
73 	if (kvm_cpu_has(X86_FEATURE_PKU))
74 		cr4 |= X86_CR4_PKE;
75 
76 	return cr4;
77 }
78 
79 static u64 calc_supported_efer_feature_bits(void)
80 {
81 	u64 efer = KVM_ALWAYS_ALLOWED_EFER;
82 
83 	if (kvm_cpu_has(X86_FEATURE_LM))
84 		efer |= (EFER_LME | EFER_LMA);
85 	if (kvm_cpu_has(X86_FEATURE_NX))
86 		efer |= EFER_NX;
87 	if (kvm_cpu_has(X86_FEATURE_SVM))
88 		efer |= EFER_SVME;
89 	if (kvm_cpu_has(X86_FEATURE_FXSR_OPT))
90 		efer |= EFER_FFXSR;
91 	if (kvm_cpu_has(X86_FEATURE_AUTOIBRS))
92 		efer |= EFER_AUTOIBRS;
93 
94 	return efer;
95 }
96 
97 static void test_cr_bits(struct kvm_vcpu *vcpu, u64 cr4)
98 {
99 	struct kvm_sregs sregs;
100 	int rc, i;
101 
102 	vcpu_sregs_get(vcpu, &sregs);
103 	sregs.cr0 &= ~(X86_CR0_CD | X86_CR0_NW);
104 	sregs.cr4 |= cr4;
105 	rc = _vcpu_sregs_set(vcpu, &sregs);
106 	TEST_ASSERT(!rc, "Failed to set supported CR4 bits (0x%lx)", cr4);
107 
108 	TEST_ASSERT(!!(sregs.cr4 & X86_CR4_OSXSAVE) ==
109 		    (vcpu->cpuid && vcpu_cpuid_has(vcpu, X86_FEATURE_OSXSAVE)),
110 		    "KVM didn't %s OSXSAVE in CPUID as expected",
111 		    (sregs.cr4 & X86_CR4_OSXSAVE) ? "set" : "clear");
112 
113 	TEST_ASSERT(!!(sregs.cr4 & X86_CR4_PKE) ==
114 		    (vcpu->cpuid && vcpu_cpuid_has(vcpu, X86_FEATURE_OSPKE)),
115 		    "KVM didn't %s OSPKE in CPUID as expected",
116 		    (sregs.cr4 & X86_CR4_PKE) ? "set" : "clear");
117 
118 	vcpu_sregs_get(vcpu, &sregs);
119 	TEST_ASSERT_EQ(sregs.cr4, cr4);
120 
121 	TEST_INVALID_SREG_BIT(vcpu, cr4, sregs, X86_CR4_UMIP);
122 	TEST_INVALID_SREG_BIT(vcpu, cr4, sregs, X86_CR4_LA57);
123 	TEST_INVALID_SREG_BIT(vcpu, cr4, sregs, X86_CR4_VMXE);
124 	TEST_INVALID_SREG_BIT(vcpu, cr4, sregs, X86_CR4_SMXE);
125 	TEST_INVALID_SREG_BIT(vcpu, cr4, sregs, X86_CR4_FSGSBASE);
126 	TEST_INVALID_SREG_BIT(vcpu, cr4, sregs, X86_CR4_PCIDE);
127 	TEST_INVALID_SREG_BIT(vcpu, cr4, sregs, X86_CR4_OSXSAVE);
128 	TEST_INVALID_SREG_BIT(vcpu, cr4, sregs, X86_CR4_SMEP);
129 	TEST_INVALID_SREG_BIT(vcpu, cr4, sregs, X86_CR4_SMAP);
130 	TEST_INVALID_SREG_BIT(vcpu, cr4, sregs, X86_CR4_PKE);
131 
132 	for (i = 32; i < 64; i++)
133 		TEST_INVALID_SREG_BIT(vcpu, cr0, sregs, BIT(i));
134 
135 	/* NW without CD is illegal, as is PG without PE. */
136 	TEST_INVALID_SREG_BIT(vcpu, cr0, sregs, X86_CR0_NW);
137 	TEST_INVALID_SREG_BIT(vcpu, cr0, sregs, X86_CR0_PG);
138 }
139 
140 static void test_efer_bits(struct kvm_vcpu *vcpu, u64 efer)
141 {
142 	struct kvm_sregs sregs;
143 	int rc;
144 
145 	vcpu_sregs_get(vcpu, &sregs);
146 	sregs.efer |= efer;
147 	rc = _vcpu_sregs_set(vcpu, &sregs);
148 	TEST_ASSERT(!rc, "Failed to set supported EFER bits (0x%llx)", sregs.efer);
149 
150 	vcpu_sregs_get(vcpu, &sregs);
151 	TEST_ASSERT_EQ(sregs.efer, efer);
152 
153 	TEST_INVALID_SREG_BIT(vcpu, efer, sregs, EFER_LME);
154 	TEST_INVALID_SREG_BIT(vcpu, efer, sregs, EFER_NX);
155 	TEST_INVALID_SREG_BIT(vcpu, efer, sregs, EFER_SVME);
156 	TEST_INVALID_SREG_BIT(vcpu, efer, sregs, EFER_FFXSR);
157 	TEST_INVALID_SREG_BIT(vcpu, efer, sregs, EFER_AUTOIBRS);
158 }
159 
160 int main(int argc, char *argv[])
161 {
162 	struct kvm_sregs sregs;
163 	struct kvm_vcpu *vcpu;
164 	struct kvm_vm *vm;
165 	int rc;
166 
167 	/*
168 	 * Create a dummy VM, specifically to avoid doing KVM_SET_CPUID2, and
169 	 * use it to verify KVM enforces guest CPUID even if *userspace* never
170 	 * sets CPUID.
171 	 */
172 	vm = vm_create_barebones();
173 	vcpu = __vm_vcpu_add(vm, 0);
174 	test_efer_bits(vcpu, KVM_ALWAYS_ALLOWED_EFER);
175 	test_cr_bits(vcpu, KVM_ALWAYS_ALLOWED_CR4);
176 	kvm_vm_free(vm);
177 
178 	/* Create a "real" VM with a fully populated guest CPUID and verify
179 	 * APIC_BASE and all supported CR4 can be set.
180 	 */
181 	vm = vm_create_with_one_vcpu(&vcpu, NULL);
182 
183 	vcpu_sregs_get(vcpu, &sregs);
184 	sregs.apic_base = 1 << 10;
185 	rc = _vcpu_sregs_set(vcpu, &sregs);
186 	TEST_ASSERT(rc, "Set IA32_APIC_BASE to %llx (invalid)",
187 		    sregs.apic_base);
188 	sregs.apic_base = 1 << 11;
189 	rc = _vcpu_sregs_set(vcpu, &sregs);
190 	TEST_ASSERT(!rc, "Couldn't set IA32_APIC_BASE to %llx (valid)",
191 		    sregs.apic_base);
192 
193 	test_cr_bits(vcpu, calc_supported_cr4_feature_bits());
194 	test_efer_bits(vcpu, calc_supported_efer_feature_bits());
195 
196 	kvm_vm_free(vm);
197 
198 	return 0;
199 }
200