]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
KVM: arm64: Ensure I-cache isolation between vcpus of a same VM
authorMarc Zyngier <maz@kernel.org>
Wed, 3 Mar 2021 16:45:05 +0000 (16:45 +0000)
committerSeth Forshee <seth.forshee@canonical.com>
Wed, 17 Mar 2021 18:49:05 +0000 (13:49 -0500)
BugLink: https://bugs.launchpad.net/bugs/1919492
commit 01dc9262ff5797b675c32c0c6bc682777d23de05 upstream.

It recently became apparent that the ARMv8 architecture has interesting
rules regarding attributes being used when fetching instructions
if the MMU is off at Stage-1.

In this situation, the CPU is allowed to fetch from the PoC and
allocate into the I-cache (unless the memory is mapped with
the XN attribute at Stage-2).

If we transpose this to vcpus sharing a single physical CPU,
it is possible for a vcpu running with its MMU off to influence
another vcpu running with its MMU on, as the latter is expected to
fetch from the PoU (and self-patching code doesn't flush below that
level).

In order to solve this, reuse the vcpu-private TLB invalidation
code to apply the same policy to the I-cache, nuking it every time
the vcpu runs on a physical CPU that ran another vcpu of the same
VM in the past.

This involve renaming __kvm_tlb_flush_local_vmid() to
__kvm_flush_cpu_context(), and inserting a local i-cache invalidation
there.

Cc: stable@vger.kernel.org
Signed-off-by: Marc Zyngier <maz@kernel.org>
Acked-by: Will Deacon <will@kernel.org>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Link: https://lore.kernel.org/r/20210303164505.68492-1-maz@kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
arch/arm64/include/asm/kvm_asm.h
arch/arm64/kvm/arm.c
arch/arm64/kvm/hyp/nvhe/hyp-main.c
arch/arm64/kvm/hyp/nvhe/tlb.c
arch/arm64/kvm/hyp/vhe/tlb.c

index 8a33d83ea843a4af0a8641f1715cacf454ab2eea..3398477c891d53da4a073c2a66670179d1c5ee24 100644 (file)
@@ -47,7 +47,7 @@
 #define __KVM_HOST_SMCCC_FUNC___kvm_flush_vm_context           2
 #define __KVM_HOST_SMCCC_FUNC___kvm_tlb_flush_vmid_ipa         3
 #define __KVM_HOST_SMCCC_FUNC___kvm_tlb_flush_vmid             4
-#define __KVM_HOST_SMCCC_FUNC___kvm_tlb_flush_local_vmid       5
+#define __KVM_HOST_SMCCC_FUNC___kvm_flush_cpu_context          5
 #define __KVM_HOST_SMCCC_FUNC___kvm_timer_set_cntvoff          6
 #define __KVM_HOST_SMCCC_FUNC___kvm_enable_ssbs                        7
 #define __KVM_HOST_SMCCC_FUNC___vgic_v3_get_ich_vtr_el2                8
@@ -183,10 +183,10 @@ DECLARE_KVM_HYP_SYM(__bp_harden_hyp_vecs);
 #define __bp_harden_hyp_vecs   CHOOSE_HYP_SYM(__bp_harden_hyp_vecs)
 
 extern void __kvm_flush_vm_context(void);
+extern void __kvm_flush_cpu_context(struct kvm_s2_mmu *mmu);
 extern void __kvm_tlb_flush_vmid_ipa(struct kvm_s2_mmu *mmu, phys_addr_t ipa,
                                     int level);
 extern void __kvm_tlb_flush_vmid(struct kvm_s2_mmu *mmu);
-extern void __kvm_tlb_flush_local_vmid(struct kvm_s2_mmu *mmu);
 
 extern void __kvm_timer_set_cntvoff(u64 cntvoff);
 
index fe60d25c000e4f7148fd36e762932f4e923745f4..b25b4c19feebcaa61e6202ca5385981571be36c5 100644 (file)
@@ -385,11 +385,16 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
        last_ran = this_cpu_ptr(mmu->last_vcpu_ran);
 
        /*
+        * We guarantee that both TLBs and I-cache are private to each
+        * vcpu. If detecting that a vcpu from the same VM has
+        * previously run on the same physical CPU, call into the
+        * hypervisor code to nuke the relevant contexts.
+        *
         * We might get preempted before the vCPU actually runs, but
         * over-invalidation doesn't affect correctness.
         */
        if (*last_ran != vcpu->vcpu_id) {
-               kvm_call_hyp(__kvm_tlb_flush_local_vmid, mmu);
+               kvm_call_hyp(__kvm_flush_cpu_context, mmu);
                *last_ran = vcpu->vcpu_id;
        }
 
index a906f9e2ff34fba2d5588263b1f024e23b09963d..1b8ef37bf8054d506767a561e399b46b1f8b7d86 100644 (file)
@@ -46,11 +46,11 @@ static void handle___kvm_tlb_flush_vmid(struct kvm_cpu_context *host_ctxt)
        __kvm_tlb_flush_vmid(kern_hyp_va(mmu));
 }
 
-static void handle___kvm_tlb_flush_local_vmid(struct kvm_cpu_context *host_ctxt)
+static void handle___kvm_flush_cpu_context(struct kvm_cpu_context *host_ctxt)
 {
        DECLARE_REG(struct kvm_s2_mmu *, mmu, host_ctxt, 1);
 
-       __kvm_tlb_flush_local_vmid(kern_hyp_va(mmu));
+       __kvm_flush_cpu_context(kern_hyp_va(mmu));
 }
 
 static void handle___kvm_timer_set_cntvoff(struct kvm_cpu_context *host_ctxt)
@@ -115,7 +115,7 @@ static const hcall_t *host_hcall[] = {
        HANDLE_FUNC(__kvm_flush_vm_context),
        HANDLE_FUNC(__kvm_tlb_flush_vmid_ipa),
        HANDLE_FUNC(__kvm_tlb_flush_vmid),
-       HANDLE_FUNC(__kvm_tlb_flush_local_vmid),
+       HANDLE_FUNC(__kvm_flush_cpu_context),
        HANDLE_FUNC(__kvm_timer_set_cntvoff),
        HANDLE_FUNC(__kvm_enable_ssbs),
        HANDLE_FUNC(__vgic_v3_get_ich_vtr_el2),
index fbde89a2c6e838d0ad9cbcb9029130b789bf2360..229b06748c20849df4b85c6d656eea2f3403853d 100644 (file)
@@ -123,7 +123,7 @@ void __kvm_tlb_flush_vmid(struct kvm_s2_mmu *mmu)
        __tlb_switch_to_host(&cxt);
 }
 
-void __kvm_tlb_flush_local_vmid(struct kvm_s2_mmu *mmu)
+void __kvm_flush_cpu_context(struct kvm_s2_mmu *mmu)
 {
        struct tlb_inv_context cxt;
 
@@ -131,6 +131,7 @@ void __kvm_tlb_flush_local_vmid(struct kvm_s2_mmu *mmu)
        __tlb_switch_to_guest(mmu, &cxt);
 
        __tlbi(vmalle1);
+       asm volatile("ic iallu");
        dsb(nsh);
        isb();
 
index fd7895945bbc6f22b5c687220781a177e7af709a..66f17349f0c36923266b60ca03318e4729d7b1f7 100644 (file)
@@ -127,7 +127,7 @@ void __kvm_tlb_flush_vmid(struct kvm_s2_mmu *mmu)
        __tlb_switch_to_host(&cxt);
 }
 
-void __kvm_tlb_flush_local_vmid(struct kvm_s2_mmu *mmu)
+void __kvm_flush_cpu_context(struct kvm_s2_mmu *mmu)
 {
        struct tlb_inv_context cxt;
 
@@ -135,6 +135,7 @@ void __kvm_tlb_flush_local_vmid(struct kvm_s2_mmu *mmu)
        __tlb_switch_to_guest(mmu, &cxt);
 
        __tlbi(vmalle1);
+       asm volatile("ic iallu");
        dsb(nsh);
        isb();