From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from userp1040.oracle.com ([156.151.31.81]:23091 "EHLO userp1040.oracle.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1422648AbcFCViB (ORCPT ); Fri, 3 Jun 2016 17:38:01 -0400 From: Sasha Levin To: stable@vger.kernel.org, stable-commits@vger.kernel.org Cc: Marc Zyngier , Christoffer Dall , Sasha Levin Subject: [added to the 4.1 stable tree] arm/arm64: KVM: Enforce Break-Before-Make on Stage-2 page tables Date: Fri, 3 Jun 2016 17:35:31 -0400 Message-Id: <1464989831-16666-36-git-send-email-sasha.levin@oracle.com> In-Reply-To: <1464989831-16666-1-git-send-email-sasha.levin@oracle.com> References: <1464989831-16666-1-git-send-email-sasha.levin@oracle.com> Sender: stable-owner@vger.kernel.org List-ID: From: Marc Zyngier This patch has been added to the 4.1 stable tree. If you have any objections, please let us know. =============== [ Upstream commit d4b9e0790aa764c0b01e18d4e8d33e93ba36d51f ] The ARM architecture mandates that when changing a page table entry from a valid entry to another valid entry, an invalid entry is first written, TLB invalidated, and only then the new entry being written. The current code doesn't respect this, directly writing the new entry and only then invalidating TLBs. Let's fix it up. Cc: Reported-by: Christoffer Dall Signed-off-by: Marc Zyngier Signed-off-by: Christoffer Dall Signed-off-by: Sasha Levin --- arch/arm/kvm/mmu.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c index da09ddc..691ea94 100644 --- a/arch/arm/kvm/mmu.c +++ b/arch/arm/kvm/mmu.c @@ -886,11 +886,14 @@ static int stage2_set_pmd_huge(struct kvm *kvm, struct kvm_mmu_memory_cache VM_BUG_ON(pmd_present(*pmd) && pmd_pfn(*pmd) != pmd_pfn(*new_pmd)); old_pmd = *pmd; - kvm_set_pmd(pmd, *new_pmd); - if (pmd_present(old_pmd)) + if (pmd_present(old_pmd)) { + pmd_clear(pmd); kvm_tlb_flush_vmid_ipa(kvm, addr); - else + } else { get_page(virt_to_page(pmd)); + } + + kvm_set_pmd(pmd, *new_pmd); return 0; } @@ -939,12 +942,14 @@ static int stage2_set_pte(struct kvm *kvm, struct kvm_mmu_memory_cache *cache, /* Create 2nd stage page table mapping - Level 3 */ old_pte = *pte; - kvm_set_pte(pte, *new_pte); - if (pte_present(old_pte)) + if (pte_present(old_pte)) { + kvm_set_pte(pte, __pte(0)); kvm_tlb_flush_vmid_ipa(kvm, addr); - else + } else { get_page(virt_to_page(pte)); + } + kvm_set_pte(pte, *new_pte); return 0; } -- 2.5.0