|
|
805d32 |
From c7abb35eaee2d418b6fa1d7e856d825a07fa1d7d Mon Sep 17 00:00:00 2001
|
|
|
805d32 |
From: Artem Savkov <asavkov@redhat.com>
|
|
|
805d32 |
Date: Tue, 11 May 2021 09:32:44 +0200
|
|
|
805d32 |
Subject: [RHEL8.4 KPATCH] KVM: VMX: Don't use vcpu->run->internal.ndata as an
|
|
|
805d32 |
array index
|
|
|
805d32 |
|
|
|
805d32 |
Kernels:
|
|
|
805d32 |
4.18.0-305.el8
|
|
|
805d32 |
|
|
|
805d32 |
Changes since last build:
|
|
|
805d32 |
arches: x86_64
|
|
|
805d32 |
vmx.o: changed function: vmx_handle_exit
|
|
|
805d32 |
---------------------------
|
|
|
805d32 |
|
|
|
805d32 |
Modifications: Jump label workarounds in vmcs_read(write)* functions.
|
|
|
805d32 |
Unfortunately changing these in vmx_flush_pml_buffer() results in
|
|
|
805d32 |
compiler changing its optimization decisions and affecting 3 unrelated
|
|
|
805d32 |
functions. I couldn't figure out a way to avoid this so those are added
|
|
|
805d32 |
to KPATCH_IGNORE_FUNCTION.
|
|
|
805d32 |
Specific compiler decisions leading to these changes:
|
|
|
805d32 |
- evmcs_read16 inlined into vmx_read_guest_seg_selector
|
|
|
805d32 |
- evmcs_touch_msr_bitmap inlined into pt_update_intercept_for_msr
|
|
|
805d32 |
- evmcs_write16 inlined into vmx_vcpu_reset
|
|
|
805d32 |
- evmcs_write64 inlined into vmx_vcpu_reset
|
|
|
805d32 |
|
|
|
805d32 |
commit b43ff8b994b47e64db6afe4ed8dbe638c49fd2cf
|
|
|
805d32 |
Author: Jon Maloy <jmaloy@redhat.com>
|
|
|
805d32 |
Date: Mon May 3 20:15:43 2021 -0400
|
|
|
805d32 |
|
|
|
805d32 |
KVM: VMX: Don't use vcpu->run->internal.ndata as an array index
|
|
|
805d32 |
|
|
|
805d32 |
Bugzilla: https://bugzilla.redhat.com/1954221
|
|
|
805d32 |
Upstream Status: Merged
|
|
|
805d32 |
Build Info: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=36611892
|
|
|
805d32 |
CVE: CVE-2021-3501
|
|
|
805d32 |
|
|
|
805d32 |
commit 04c4f2ee3f68c9a4bf1653d15f1a9a435ae33f7a
|
|
|
805d32 |
Author: Reiji Watanabe <reijiw@google.com>
|
|
|
805d32 |
Date: Tue Apr 13 15:47:40 2021 +0000
|
|
|
805d32 |
|
|
|
805d32 |
KVM: VMX: Don't use vcpu->run->internal.ndata as an array index
|
|
|
805d32 |
|
|
|
805d32 |
__vmx_handle_exit() uses vcpu->run->internal.ndata as an index for
|
|
|
805d32 |
an array access. Since vcpu->run is (can be) mapped to a user address
|
|
|
805d32 |
space with a writer permission, the 'ndata' could be updated by the
|
|
|
805d32 |
user process at anytime (the user process can set it to outside the
|
|
|
805d32 |
bounds of the array).
|
|
|
805d32 |
So, it is not safe that __vmx_handle_exit() uses the 'ndata' that way.
|
|
|
805d32 |
|
|
|
805d32 |
Fixes: 1aa561b1a4c0 ("kvm: x86: Add "last CPU" to some KVM_EXIT information")
|
|
|
805d32 |
Signed-off-by: Reiji Watanabe <reijiw@google.com>
|
|
|
805d32 |
Reviewed-by: Jim Mattson <jmattson@google.com>
|
|
|
805d32 |
Message-Id: <20210413154739.490299-1-reijiw@google.com>
|
|
|
805d32 |
Cc: stable@vger.kernel.org
|
|
|
805d32 |
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
|
|
|
805d32 |
|
|
|
805d32 |
Signed-off-by: Jon Maloy <jmaloy@redhat.com>
|
|
|
805d32 |
|
|
|
805d32 |
Signed-off-by: Artem Savkov <asavkov@redhat.com>
|
|
|
805d32 |
Acked-by: Joe Lawrence <joe.lawrence@redhat.com>
|
|
|
805d32 |
---
|
|
|
805d32 |
arch/x86/kvm/vmx/vmx.c | 56 +++++++++++++++++++++++++++++++++++-------
|
|
|
805d32 |
1 file changed, 47 insertions(+), 9 deletions(-)
|
|
|
805d32 |
|
|
|
805d32 |
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
|
|
|
805d32 |
index f6b70e177eef3..8dbf613e86cb8 100644
|
|
|
805d32 |
--- a/arch/x86/kvm/vmx/vmx.c
|
|
|
805d32 |
+++ b/arch/x86/kvm/vmx/vmx.c
|
|
|
805d32 |
@@ -62,6 +62,8 @@
|
|
|
805d32 |
#include "vmx.h"
|
|
|
805d32 |
#include "x86.h"
|
|
|
805d32 |
|
|
|
805d32 |
+#include "kpatch-macros.h"
|
|
|
805d32 |
+
|
|
|
805d32 |
MODULE_AUTHOR("Qumranet");
|
|
|
805d32 |
MODULE_LICENSE("GPL");
|
|
|
805d32 |
|
|
|
805d32 |
@@ -778,6 +780,7 @@ static u16 vmx_read_guest_seg_selector(struct vcpu_vmx *vmx, unsigned seg)
|
|
|
805d32 |
*p = vmcs_read16(kvm_vmx_segment_fields[seg].selector);
|
|
|
805d32 |
return *p;
|
|
|
805d32 |
}
|
|
|
805d32 |
+KPATCH_IGNORE_FUNCTION(vmx_read_guest_seg_selector);
|
|
|
805d32 |
|
|
|
805d32 |
static ulong vmx_read_guest_seg_base(struct vcpu_vmx *vmx, unsigned seg)
|
|
|
805d32 |
{
|
|
|
805d32 |
@@ -3866,6 +3869,7 @@ void pt_update_intercept_for_msr(struct kvm_vcpu *vcpu)
|
|
|
805d32 |
vmx_set_intercept_for_msr(vcpu, MSR_IA32_RTIT_ADDR0_B + i * 2, MSR_TYPE_RW, flag);
|
|
|
805d32 |
}
|
|
|
805d32 |
}
|
|
|
805d32 |
+KPATCH_IGNORE_FUNCTION(pt_update_intercept_for_msr);
|
|
|
805d32 |
|
|
|
805d32 |
static bool vmx_guest_apic_has_interrupt(struct kvm_vcpu *vcpu)
|
|
|
805d32 |
{
|
|
|
805d32 |
@@ -4473,6 +4477,7 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
|
|
|
805d32 |
if (init_event)
|
|
|
805d32 |
vmx_clear_hlt(vcpu);
|
|
|
805d32 |
}
|
|
|
805d32 |
+KPATCH_IGNORE_FUNCTION(vmx_vcpu_reset);
|
|
|
805d32 |
|
|
|
805d32 |
static void enable_irq_window(struct kvm_vcpu *vcpu)
|
|
|
805d32 |
{
|
|
|
805d32 |
@@ -5710,13 +5715,46 @@ static void vmx_destroy_pml_buffer(struct vcpu_vmx *vmx)
|
|
|
805d32 |
}
|
|
|
805d32 |
}
|
|
|
805d32 |
|
|
|
805d32 |
+static __always_inline void kpatch_vmcs_write16(unsigned long field, u16 value)
|
|
|
805d32 |
+{
|
|
|
805d32 |
+ vmcs_check16(field);
|
|
|
805d32 |
+ if (unlikely(static_key_enabled(&enable_evmcs)))
|
|
|
805d32 |
+ return evmcs_write16(field, value);
|
|
|
805d32 |
+
|
|
|
805d32 |
+ __vmcs_writel(field, value);
|
|
|
805d32 |
+}
|
|
|
805d32 |
+
|
|
|
805d32 |
+static __always_inline u16 kpatch_vmcs_read16(unsigned long field)
|
|
|
805d32 |
+{
|
|
|
805d32 |
+ vmcs_check16(field);
|
|
|
805d32 |
+ if (unlikely(static_key_enabled(&enable_evmcs)))
|
|
|
805d32 |
+ return evmcs_read16(field);
|
|
|
805d32 |
+ return __vmcs_readl(field);
|
|
|
805d32 |
+}
|
|
|
805d32 |
+
|
|
|
805d32 |
+static __always_inline u32 kpatch_vmcs_read32(unsigned long field)
|
|
|
805d32 |
+{
|
|
|
805d32 |
+ vmcs_check32(field);
|
|
|
805d32 |
+ if (unlikely(static_key_enabled(&enable_evmcs)))
|
|
|
805d32 |
+ return evmcs_read32(field);
|
|
|
805d32 |
+ return __vmcs_readl(field);
|
|
|
805d32 |
+}
|
|
|
805d32 |
+
|
|
|
805d32 |
+static __always_inline u64 kpatch_vmcs_read64(unsigned long field)
|
|
|
805d32 |
+{
|
|
|
805d32 |
+ vmcs_check64(field);
|
|
|
805d32 |
+ if (unlikely(static_key_enabled(&enable_evmcs)))
|
|
|
805d32 |
+ return evmcs_read64(field);
|
|
|
805d32 |
+ return __vmcs_readl(field);
|
|
|
805d32 |
+}
|
|
|
805d32 |
+
|
|
|
805d32 |
static void vmx_flush_pml_buffer(struct kvm_vcpu *vcpu)
|
|
|
805d32 |
{
|
|
|
805d32 |
struct vcpu_vmx *vmx = to_vmx(vcpu);
|
|
|
805d32 |
u64 *pml_buf;
|
|
|
805d32 |
u16 pml_idx;
|
|
|
805d32 |
|
|
|
805d32 |
- pml_idx = vmcs_read16(GUEST_PML_INDEX);
|
|
|
805d32 |
+ pml_idx = kpatch_vmcs_read16(GUEST_PML_INDEX);
|
|
|
805d32 |
|
|
|
805d32 |
/* Do nothing if PML buffer is empty */
|
|
|
805d32 |
if (pml_idx == (PML_ENTITY_NUM - 1))
|
|
|
805d32 |
@@ -5738,7 +5776,7 @@ static void vmx_flush_pml_buffer(struct kvm_vcpu *vcpu)
|
|
|
805d32 |
}
|
|
|
805d32 |
|
|
|
805d32 |
/* reset PML index */
|
|
|
805d32 |
- vmcs_write16(GUEST_PML_INDEX, PML_ENTITY_NUM - 1);
|
|
|
805d32 |
+ kpatch_vmcs_write16(GUEST_PML_INDEX, PML_ENTITY_NUM - 1);
|
|
|
805d32 |
}
|
|
|
805d32 |
|
|
|
805d32 |
/*
|
|
|
805d32 |
@@ -5988,7 +6026,7 @@ static int vmx_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath)
|
|
|
805d32 |
dump_vmcs();
|
|
|
805d32 |
vcpu->run->exit_reason = KVM_EXIT_FAIL_ENTRY;
|
|
|
805d32 |
vcpu->run->fail_entry.hardware_entry_failure_reason
|
|
|
805d32 |
- = vmcs_read32(VM_INSTRUCTION_ERROR);
|
|
|
805d32 |
+ = kpatch_vmcs_read32(VM_INSTRUCTION_ERROR);
|
|
|
805d32 |
vcpu->run->fail_entry.cpu = vcpu->arch.last_vmentry_cpu;
|
|
|
805d32 |
return 0;
|
|
|
805d32 |
}
|
|
|
805d32 |
@@ -6006,19 +6044,19 @@ static int vmx_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath)
|
|
|
805d32 |
exit_reason != EXIT_REASON_PML_FULL &&
|
|
|
805d32 |
exit_reason != EXIT_REASON_APIC_ACCESS &&
|
|
|
805d32 |
exit_reason != EXIT_REASON_TASK_SWITCH)) {
|
|
|
805d32 |
+ int ndata = 3;
|
|
|
805d32 |
+
|
|
|
805d32 |
vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
|
|
|
805d32 |
vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_DELIVERY_EV;
|
|
|
805d32 |
- vcpu->run->internal.ndata = 3;
|
|
|
805d32 |
vcpu->run->internal.data[0] = vectoring_info;
|
|
|
805d32 |
vcpu->run->internal.data[1] = exit_reason;
|
|
|
805d32 |
vcpu->run->internal.data[2] = vcpu->arch.exit_qualification;
|
|
|
805d32 |
if (exit_reason == EXIT_REASON_EPT_MISCONFIG) {
|
|
|
805d32 |
- vcpu->run->internal.ndata++;
|
|
|
805d32 |
- vcpu->run->internal.data[3] =
|
|
|
805d32 |
- vmcs_read64(GUEST_PHYSICAL_ADDRESS);
|
|
|
805d32 |
+ vcpu->run->internal.data[ndata++] =
|
|
|
805d32 |
+ kpatch_vmcs_read64(GUEST_PHYSICAL_ADDRESS);
|
|
|
805d32 |
}
|
|
|
805d32 |
- vcpu->run->internal.data[vcpu->run->internal.ndata++] =
|
|
|
805d32 |
- vcpu->arch.last_vmentry_cpu;
|
|
|
805d32 |
+ vcpu->run->internal.data[ndata++] = vcpu->arch.last_vmentry_cpu;
|
|
|
805d32 |
+ vcpu->run->internal.ndata = ndata;
|
|
|
805d32 |
return 0;
|
|
|
805d32 |
}
|
|
|
805d32 |
|
|
|
805d32 |
--
|
|
|
805d32 |
2.26.3
|
|
|
805d32 |
|