From c61ef850bb45ae2fa7f28fae9469b58e4d2c3e5d Mon Sep 17 00:00:00 2001 From: Andrew Honig Date: Wed, 10 Jan 2018 10:12:03 -0800 Subject: [PATCH] KVM: x86: Add memory barrier on vmcs field lookup This adds a memory barrier when performing a lookup into the vmcs_field_to_offset_table. This is related to CVE-2017-5753. This particularly scenario would involve an L1 hypervisor using vmread/vmwrite to try execute a variant 1 side channel leak on the host. In general variant 1 relies on a bounds check that gets bypassed speculatively. However it requires a fairly specific code pattern to actually be useful for an exploit, which is why most bounds check do not require speculation barrier. It requires two memory references close to each other. One that is out of bounds and attacker controlled and one where the memory address is based on the memory read in the first access. The first memory reference is a read of the memory that the attacker wants to leak and the second references creates side channel in the cache where the line accessed represents the data to be leaked. This code has that pattern because a potentially very large value for field could be used in the vmcs_to_offset_table lookup which will be put into f. Then very shortly thereafter and potentially still in the speculation window will be dereferenced in the vmcs_to_field_offset function. OraBug: 27380809 Signed-off-by: Andrew Honig Reviewed-by: Jim Mattson Cc: stable@vger.kernel.org Signed-off-by: Paolo Bonzini (cherry picked from commit 75f139aaf896d6fdeec2e468ddfa4b2fe469bf40) [The upstream commit used asm('lfence') but we already have the osb() macro so changed that out] Reviewed-by: Boris.Ostrovsky Signed-off-by: Konrad Rzeszutek Wilk --- arch/x86/kvm/vmx.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index f0c9ff45fd663..8aa10dd99157b 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -773,8 +773,12 @@ static inline short vmcs_field_to_offset(unsigned long field) { BUILD_BUG_ON(ARRAY_SIZE(vmcs_field_to_offset_table) > SHRT_MAX); - if (field >= ARRAY_SIZE(vmcs_field_to_offset_table) || - vmcs_field_to_offset_table[field] == 0) + if (field >= ARRAY_SIZE(vmcs_field_to_offset_table)) + return -ENOENT; + + osb(); + + if (vmcs_field_to_offset_table[field] == 0) return -ENOENT; return vmcs_field_to_offset_table[field]; -- 2.50.1