Skip to content

Commit 2d5588f

Browse files
sean-jcjfvogel
authored andcommitted
KVM: x86: Account for KVM-reserved CR4 bits when passing through CR4 on VMX
Drop x86.c's local pre-computed cr4_reserved bits and instead fold KVM's reserved bits into the guest's reserved bits. This fixes a bug where VMX's set_cr4_guest_host_mask() fails to account for KVM-reserved bits when deciding which bits can be passed through to the guest. In most cases, letting the guest directly write reserved CR4 bits is ok, i.e. attempting to set the bit(s) will still #GP, but not if a feature is available in hardware but explicitly disabled by the host, e.g. if FSGSBASE support is disabled via "nofsgsbase". Note, the extra overhead of computing host reserved bits every time userspace sets guest CPUID is negligible. The feature bits that are queried are packed nicely into a handful of words, and so checking and setting each reserved bit costs in the neighborhood of ~5 cycles, i.e. the total cost will be in the noise even if the number of checked CR4 bits doubles over the next few years. In other words, x86 will run out of CR4 bits long before the overhead becomes problematic. Note #2, __cr4_reserved_bits() starts from CR4_RESERVED_BITS, which is why the existing __kvm_cpu_cap_has() processing doesn't explicitly OR in CR4_RESERVED_BITS (and why the new code doesn't do so either). Fixes: 2ed41aa ("KVM: VMX: Intercept guest reserved CR4 bits to inject #GP fault") Reviewed-by: Maxim Levitsky <[email protected]> Reviewed-by: Chao Gao <[email protected]> Reviewed-by: Binbin Wu <[email protected]> Reviewed-by: Xiaoyao Li <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Sean Christopherson <[email protected]> (cherry picked from commit 7520a53) Orabug: 38359602 Signed-off-by: Ross Philipson <[email protected]> Reviewed-by: Jagannathan Raman <[email protected]>
1 parent b2056e9 commit 2d5588f

File tree

2 files changed

+5
-11
lines changed

2 files changed

+5
-11
lines changed

arch/x86/kvm/cpuid.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -421,8 +421,11 @@ void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
421421
vcpu->arch.reserved_gpa_bits = kvm_vcpu_reserved_gpa_bits_raw(vcpu);
422422

423423
kvm_pmu_refresh(vcpu);
424-
vcpu->arch.cr4_guest_rsvd_bits =
425-
__cr4_reserved_bits(guest_cpuid_has, vcpu);
424+
425+
#define __kvm_cpu_cap_has(UNUSED_, f) kvm_cpu_cap_has(f)
426+
vcpu->arch.cr4_guest_rsvd_bits = __cr4_reserved_bits(__kvm_cpu_cap_has, UNUSED_) |
427+
__cr4_reserved_bits(guest_cpuid_has, vcpu);
428+
#undef __kvm_cpu_cap_has
426429

427430
kvm_hv_set_cpuid(vcpu, kvm_cpuid_has_hyperv(vcpu->arch.cpuid_entries,
428431
vcpu->arch.cpuid_nent));

arch/x86/kvm/x86.c

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,6 @@ u64 __read_mostly efer_reserved_bits = ~((u64)(EFER_SCE | EFER_LME | EFER_LMA));
119119
static u64 __read_mostly efer_reserved_bits = ~((u64)EFER_SCE);
120120
#endif
121121

122-
static u64 __read_mostly cr4_reserved_bits = CR4_RESERVED_BITS;
123-
124122
#define KVM_EXIT_HYPERCALL_VALID_MASK (1 << KVM_HC_MAP_GPA_RANGE)
125123

126124
#define KVM_CAP_PMU_VALID_MASK KVM_PMU_CAP_DISABLE
@@ -1308,9 +1306,6 @@ EXPORT_SYMBOL_GPL(kvm_emulate_xsetbv);
13081306

13091307
bool __kvm_is_valid_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
13101308
{
1311-
if (cr4 & cr4_reserved_bits)
1312-
return false;
1313-
13141309
if (cr4 & vcpu->arch.cr4_guest_rsvd_bits)
13151310
return false;
13161311

@@ -9797,10 +9792,6 @@ int kvm_x86_vendor_init(struct kvm_x86_init_ops *ops)
97979792
if (!kvm_cpu_cap_has(X86_FEATURE_XSAVES))
97989793
kvm_caps.supported_xss = 0;
97999794

9800-
#define __kvm_cpu_cap_has(UNUSED_, f) kvm_cpu_cap_has(f)
9801-
cr4_reserved_bits = __cr4_reserved_bits(__kvm_cpu_cap_has, UNUSED_);
9802-
#undef __kvm_cpu_cap_has
9803-
98049795
if (kvm_caps.has_tsc_control) {
98059796
/*
98069797
* Make sure the user can only configure tsc_khz values that

0 commit comments

Comments
 (0)