Skip to content

Commit d483bf6

Browse files
Maxim Levitskygregkh
authored andcommitted
KVM: x86: model canonical checks more precisely
[ Upstream commit 9245fd6 ] As a result of a recent investigation, it was determined that x86 CPUs which support 5-level paging, don't always respect CR4.LA57 when doing canonical checks. In particular: 1. MSRs which contain a linear address, allow full 57-bitcanonical address regardless of CR4.LA57 state. For example: MSR_KERNEL_GS_BASE. 2. All hidden segment bases and GDT/IDT bases also behave like MSRs. This means that full 57-bit canonical address can be loaded to them regardless of CR4.LA57, both using MSRS (e.g GS_BASE) and instructions (e.g LGDT). 3. TLB invalidation instructions also allow the user to use full 57-bit address regardless of the CR4.LA57. Finally, it must be noted that the CPU doesn't prevent the user from disabling 5-level paging, even when the full 57-bit canonical address is present in one of the registers mentioned above (e.g GDT base). In fact, this can happen without any userspace help, when the CPU enters SMM mode - some MSRs, for example MSR_KERNEL_GS_BASE are left to contain a non-canonical address in regard to the new mode. Since most of the affected MSRs and all segment bases can be read and written freely by the guest without any KVM intervention, this patch makes the emulator closely follow hardware behavior, which means that the emulator doesn't take in the account the guest CPUID support for 5-level paging, and only takes in the account the host CPU support. Signed-off-by: Maxim Levitsky <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Sean Christopherson <[email protected]> Stable-dep-of: fa787ac ("KVM: x86/hyper-v: Skip non-canonical addresses during PV TLB flush") Signed-off-by: Sasha Levin <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent c0c82c2 commit d483bf6

File tree

7 files changed

+66
-22
lines changed

7 files changed

+66
-22
lines changed

arch/x86/kvm/mmu/mmu.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6234,7 +6234,7 @@ void kvm_mmu_invalidate_addr(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
62346234
/* It's actually a GPA for vcpu->arch.guest_mmu. */
62356235
if (mmu != &vcpu->arch.guest_mmu) {
62366236
/* INVLPG on a non-canonical address is a NOP according to the SDM. */
6237-
if (is_noncanonical_address(addr, vcpu))
6237+
if (is_noncanonical_invlpg_address(addr, vcpu))
62386238
return;
62396239

62406240
kvm_x86_call(flush_tlb_gva)(vcpu, addr);

arch/x86/kvm/vmx/nested.c

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3020,8 +3020,8 @@ static int nested_vmx_check_host_state(struct kvm_vcpu *vcpu,
30203020
CC(!kvm_vcpu_is_legal_cr3(vcpu, vmcs12->host_cr3)))
30213021
return -EINVAL;
30223022

3023-
if (CC(is_noncanonical_address(vmcs12->host_ia32_sysenter_esp, vcpu)) ||
3024-
CC(is_noncanonical_address(vmcs12->host_ia32_sysenter_eip, vcpu)))
3023+
if (CC(is_noncanonical_msr_address(vmcs12->host_ia32_sysenter_esp, vcpu)) ||
3024+
CC(is_noncanonical_msr_address(vmcs12->host_ia32_sysenter_eip, vcpu)))
30253025
return -EINVAL;
30263026

30273027
if ((vmcs12->vm_exit_controls & VM_EXIT_LOAD_IA32_PAT) &&
@@ -3055,12 +3055,12 @@ static int nested_vmx_check_host_state(struct kvm_vcpu *vcpu,
30553055
CC(vmcs12->host_ss_selector == 0 && !ia32e))
30563056
return -EINVAL;
30573057

3058-
if (CC(is_noncanonical_address(vmcs12->host_fs_base, vcpu)) ||
3059-
CC(is_noncanonical_address(vmcs12->host_gs_base, vcpu)) ||
3060-
CC(is_noncanonical_address(vmcs12->host_gdtr_base, vcpu)) ||
3061-
CC(is_noncanonical_address(vmcs12->host_idtr_base, vcpu)) ||
3062-
CC(is_noncanonical_address(vmcs12->host_tr_base, vcpu)) ||
3063-
CC(is_noncanonical_address(vmcs12->host_rip, vcpu)))
3058+
if (CC(is_noncanonical_base_address(vmcs12->host_fs_base, vcpu)) ||
3059+
CC(is_noncanonical_base_address(vmcs12->host_gs_base, vcpu)) ||
3060+
CC(is_noncanonical_base_address(vmcs12->host_gdtr_base, vcpu)) ||
3061+
CC(is_noncanonical_base_address(vmcs12->host_idtr_base, vcpu)) ||
3062+
CC(is_noncanonical_base_address(vmcs12->host_tr_base, vcpu)) ||
3063+
CC(is_noncanonical_address(vmcs12->host_rip, vcpu, 0)))
30643064
return -EINVAL;
30653065

30663066
/*
@@ -3178,7 +3178,7 @@ static int nested_vmx_check_guest_state(struct kvm_vcpu *vcpu,
31783178
}
31793179

31803180
if ((vmcs12->vm_entry_controls & VM_ENTRY_LOAD_BNDCFGS) &&
3181-
(CC(is_noncanonical_address(vmcs12->guest_bndcfgs & PAGE_MASK, vcpu)) ||
3181+
(CC(is_noncanonical_msr_address(vmcs12->guest_bndcfgs & PAGE_MASK, vcpu)) ||
31823182
CC((vmcs12->guest_bndcfgs & MSR_IA32_BNDCFGS_RSVD))))
31833183
return -EINVAL;
31843184

@@ -5172,7 +5172,7 @@ int get_vmx_mem_address(struct kvm_vcpu *vcpu, unsigned long exit_qualification,
51725172
* non-canonical form. This is the only check on the memory
51735173
* destination for long mode!
51745174
*/
5175-
exn = is_noncanonical_address(*ret, vcpu);
5175+
exn = is_noncanonical_address(*ret, vcpu, 0);
51765176
} else {
51775177
/*
51785178
* When not in long mode, the virtual/linear address is
@@ -5983,7 +5983,7 @@ static int handle_invvpid(struct kvm_vcpu *vcpu)
59835983
* invalidation.
59845984
*/
59855985
if (!operand.vpid ||
5986-
is_noncanonical_address(operand.gla, vcpu))
5986+
is_noncanonical_invlpg_address(operand.gla, vcpu))
59875987
return nested_vmx_fail(vcpu,
59885988
VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID);
59895989
vpid_sync_vcpu_addr(vpid02, operand.gla);

arch/x86/kvm/vmx/pmu_intel.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
365365
}
366366
break;
367367
case MSR_IA32_DS_AREA:
368-
if (is_noncanonical_address(data, vcpu))
368+
if (is_noncanonical_msr_address(data, vcpu))
369369
return 1;
370370

371371
pmu->ds_area = data;

arch/x86/kvm/vmx/sgx.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ static int sgx_get_encls_gva(struct kvm_vcpu *vcpu, unsigned long offset,
3737
fault = true;
3838
} else if (likely(is_64_bit_mode(vcpu))) {
3939
*gva = vmx_get_untagged_addr(vcpu, *gva, 0);
40-
fault = is_noncanonical_address(*gva, vcpu);
40+
fault = is_noncanonical_address(*gva, vcpu, 0);
4141
} else {
4242
*gva &= 0xffffffff;
4343
fault = (s.unusable) ||

arch/x86/kvm/vmx/vmx.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2284,7 +2284,7 @@ int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
22842284
(!msr_info->host_initiated &&
22852285
!guest_cpuid_has(vcpu, X86_FEATURE_MPX)))
22862286
return 1;
2287-
if (is_noncanonical_address(data & PAGE_MASK, vcpu) ||
2287+
if (is_noncanonical_msr_address(data & PAGE_MASK, vcpu) ||
22882288
(data & MSR_IA32_BNDCFGS_RSVD))
22892289
return 1;
22902290

@@ -2449,7 +2449,7 @@ int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
24492449
index = msr_info->index - MSR_IA32_RTIT_ADDR0_A;
24502450
if (index >= 2 * vmx->pt_desc.num_address_ranges)
24512451
return 1;
2452-
if (is_noncanonical_address(data, vcpu))
2452+
if (is_noncanonical_msr_address(data, vcpu))
24532453
return 1;
24542454
if (index % 2)
24552455
vmx->pt_desc.guest.addr_b[index / 2] = data;

arch/x86/kvm/x86.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1845,7 +1845,7 @@ static int __kvm_set_msr(struct kvm_vcpu *vcpu, u32 index, u64 data,
18451845
case MSR_KERNEL_GS_BASE:
18461846
case MSR_CSTAR:
18471847
case MSR_LSTAR:
1848-
if (is_noncanonical_address(data, vcpu))
1848+
if (is_noncanonical_msr_address(data, vcpu))
18491849
return 1;
18501850
break;
18511851
case MSR_IA32_SYSENTER_EIP:
@@ -1862,7 +1862,7 @@ static int __kvm_set_msr(struct kvm_vcpu *vcpu, u32 index, u64 data,
18621862
* value, and that something deterministic happens if the guest
18631863
* invokes 64-bit SYSENTER.
18641864
*/
1865-
data = __canonical_address(data, vcpu_virt_addr_bits(vcpu));
1865+
data = __canonical_address(data, max_host_virt_addr_bits());
18661866
break;
18671867
case MSR_TSC_AUX:
18681868
if (!kvm_is_supported_user_return_msr(MSR_TSC_AUX))
@@ -8611,7 +8611,7 @@ static gva_t emulator_get_untagged_addr(struct x86_emulate_ctxt *ctxt,
86118611
static bool emulator_is_canonical_addr(struct x86_emulate_ctxt *ctxt,
86128612
gva_t addr, unsigned int flags)
86138613
{
8614-
return !is_noncanonical_address(addr, emul_to_vcpu(ctxt));
8614+
return !is_noncanonical_address(addr, emul_to_vcpu(ctxt), flags);
86158615
}
86168616

86178617
static const struct x86_emulate_ops emulate_ops = {
@@ -13763,7 +13763,7 @@ int kvm_handle_invpcid(struct kvm_vcpu *vcpu, unsigned long type, gva_t gva)
1376313763
* invalidation.
1376413764
*/
1376513765
if ((!pcid_enabled && (operand.pcid != 0)) ||
13766-
is_noncanonical_address(operand.gla, vcpu)) {
13766+
is_noncanonical_invlpg_address(operand.gla, vcpu)) {
1376713767
kvm_inject_gp(vcpu, 0);
1376813768
return 1;
1376913769
}

arch/x86/kvm/x86.h

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <asm/pvclock.h>
99
#include "kvm_cache_regs.h"
1010
#include "kvm_emulate.h"
11+
#include "cpuid.h"
1112

1213
struct kvm_caps {
1314
/* control of guest tsc rate supported? */
@@ -233,9 +234,52 @@ static inline u8 vcpu_virt_addr_bits(struct kvm_vcpu *vcpu)
233234
return kvm_is_cr4_bit_set(vcpu, X86_CR4_LA57) ? 57 : 48;
234235
}
235236

236-
static inline bool is_noncanonical_address(u64 la, struct kvm_vcpu *vcpu)
237+
static inline u8 max_host_virt_addr_bits(void)
237238
{
238-
return !__is_canonical_address(la, vcpu_virt_addr_bits(vcpu));
239+
return kvm_cpu_cap_has(X86_FEATURE_LA57) ? 57 : 48;
240+
}
241+
242+
/*
243+
* x86 MSRs which contain linear addresses, x86 hidden segment bases, and
244+
* IDT/GDT bases have static canonicality checks, the size of which depends
245+
* only on the CPU's support for 5-level paging, rather than on the state of
246+
* CR4.LA57. This applies to both WRMSR and to other instructions that set
247+
* their values, e.g. SGDT.
248+
*
249+
* KVM passes through most of these MSRS and also doesn't intercept the
250+
* instructions that set the hidden segment bases.
251+
*
252+
* Because of this, to be consistent with hardware, even if the guest doesn't
253+
* have LA57 enabled in its CPUID, perform canonicality checks based on *host*
254+
* support for 5 level paging.
255+
*
256+
* Finally, instructions which are related to MMU invalidation of a given
257+
* linear address, also have a similar static canonical check on address.
258+
* This allows for example to invalidate 5-level addresses of a guest from a
259+
* host which uses 4-level paging.
260+
*/
261+
static inline bool is_noncanonical_address(u64 la, struct kvm_vcpu *vcpu,
262+
unsigned int flags)
263+
{
264+
if (flags & (X86EMUL_F_INVLPG | X86EMUL_F_MSR | X86EMUL_F_DT_LOAD))
265+
return !__is_canonical_address(la, max_host_virt_addr_bits());
266+
else
267+
return !__is_canonical_address(la, vcpu_virt_addr_bits(vcpu));
268+
}
269+
270+
static inline bool is_noncanonical_msr_address(u64 la, struct kvm_vcpu *vcpu)
271+
{
272+
return is_noncanonical_address(la, vcpu, X86EMUL_F_MSR);
273+
}
274+
275+
static inline bool is_noncanonical_base_address(u64 la, struct kvm_vcpu *vcpu)
276+
{
277+
return is_noncanonical_address(la, vcpu, X86EMUL_F_DT_LOAD);
278+
}
279+
280+
static inline bool is_noncanonical_invlpg_address(u64 la, struct kvm_vcpu *vcpu)
281+
{
282+
return is_noncanonical_address(la, vcpu, X86EMUL_F_INVLPG);
239283
}
240284

241285
static inline void vcpu_cache_mmio_info(struct kvm_vcpu *vcpu,

0 commit comments

Comments
 (0)