Blame SOURCES/KVM-VMX-Don-t-use-vcpu-run-internal.ndata-as-an-arra.patch

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