From 675eb60668bb27ed652d97890e77c6685beafc95 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 16 Apr 2018 13:39:10 -0500 Subject: [PATCH 1/7] signal/arm/kvm: Use send_sig_mceerr mainline inclusion from mainline-v4.20-rc1 commit 795a83714526754a2b8089a0533bfef24287bcb9 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I82UA0 CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=795a83714526754a2b8089a0533bfef24287bcb9 -------------------------------- This simplifies the code making it clearer what is going on, and making the siginfo generation easier to maintain. Signed-off-by: "Eric W. Biederman" Signed-off-by: Ding Hui --- virt/kvm/arm/mmu.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/virt/kvm/arm/mmu.c b/virt/kvm/arm/mmu.c index 2c183030f32e..6cd2189f70dd 100644 --- a/virt/kvm/arm/mmu.c +++ b/virt/kvm/arm/mmu.c @@ -1627,20 +1627,14 @@ static void invalidate_icache_guest_page(kvm_pfn_t pfn, unsigned long size) static void kvm_send_hwpoison_signal(unsigned long address, struct vm_area_struct *vma) { - siginfo_t info; - - clear_siginfo(&info); - info.si_signo = SIGBUS; - info.si_errno = 0; - info.si_code = BUS_MCEERR_AR; - info.si_addr = (void __user *)address; + short lsb; if (is_vm_hugetlb_page(vma)) - info.si_addr_lsb = huge_page_shift(hstate_vma(vma)); + lsb = huge_page_shift(hstate_vma(vma)); else - info.si_addr_lsb = PAGE_SHIFT; + lsb = PAGE_SHIFT; - send_sig_info(SIGBUS, &info, current); + send_sig_mceerr(BUS_MCEERR_AR, (void __user *)address, lsb, current); } static bool fault_supports_stage2_huge_mapping(struct kvm_memory_slot *memslot, -- Gitee From 225be9a6abff4e1c88d9ad4314d2344c43245bc1 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 11 Dec 2019 16:56:48 +0000 Subject: [PATCH 2/7] KVM: arm/arm64: Properly handle faulting of device mappings mainline inclusion from mainline-v5.5-rc3 commit 6d674e28f642e3ff676fbae2d8d1b872814d32b6 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I82UA0 CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=6d674e28f642e3ff676fbae2d8d1b872814d32b6 -------------------------------- A device mapping is normally always mapped at Stage-2, since there is very little gain in having it faulted in. Nonetheless, it is possible to end-up in a situation where the device mapping has been removed from Stage-2 (userspace munmaped the VFIO region, and the MMU notifier did its job), but present in a userspace mapping (userpace has mapped it back at the same address). In such a situation, the device mapping will be demand-paged as the guest performs memory accesses. This requires to be careful when dealing with mapping size, cache management, and to handle potential execution of a device mapping. Reported-by: Alexandru Elisei Signed-off-by: Marc Zyngier Tested-by: Alexandru Elisei Reviewed-by: James Morse Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20191211165651.7889-2-maz@kernel.org Signed-off-by: Ding Hui --- virt/kvm/arm/mmu.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/virt/kvm/arm/mmu.c b/virt/kvm/arm/mmu.c index 6cd2189f70dd..1eab040de8a6 100644 --- a/virt/kvm/arm/mmu.c +++ b/virt/kvm/arm/mmu.c @@ -50,6 +50,11 @@ static unsigned long io_map_base; #define KVM_S2PTE_FLAG_IS_IOMAP (1UL << 0) #define KVM_S2_FLAG_LOGGING_ACTIVE (1UL << 1) +static bool is_iomap(unsigned long flags) +{ + return flags & KVM_S2PTE_FLAG_IS_IOMAP; +} + static bool memslot_is_logging(struct kvm_memory_slot *memslot) { return memslot->dirty_bitmap && !(memslot->flags & KVM_MEM_READONLY); @@ -1733,6 +1738,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, vma_pagesize = vma_kernel_pagesize(vma); if (logging_active || + (vma->vm_flags & VM_PFNMAP) || !fault_supports_stage2_huge_mapping(memslot, hva, vma_pagesize)) { force_pte = true; vma_pagesize = PAGE_SIZE; @@ -1802,6 +1808,9 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, writable = false; } + if (exec_fault && is_iomap(flags)) + return -ENOEXEC; + spin_lock(&kvm->mmu_lock); if (mmu_notifier_retry(kvm, mmu_seq)) goto out_unlock; @@ -1823,7 +1832,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, if (writable) kvm_set_pfn_dirty(pfn); - if (fault_status != FSC_PERM && !kvm_ncsnp_support) + if (fault_status != FSC_PERM && !kvm_ncsnp_support && !is_iomap(flags)) clean_dcache_guest_page(pfn, vma_pagesize); if (exec_fault) @@ -1993,9 +2002,8 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run) if (kvm_is_error_hva(hva) || (write_fault && !writable)) { if (is_iabt) { /* Prefetch Abort on I/O address */ - kvm_inject_pabt(vcpu, kvm_vcpu_get_hfar(vcpu)); - ret = 1; - goto out_unlock; + ret = -ENOEXEC; + goto out; } /* @@ -2037,6 +2045,11 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run) ret = user_mem_abort(vcpu, fault_ipa, memslot, hva, fault_status); if (ret == 0) ret = 1; +out: + if (ret == -ENOEXEC) { + kvm_inject_pabt(vcpu, kvm_vcpu_get_hfar(vcpu)); + ret = 1; + } out_unlock: srcu_read_unlock(&vcpu->kvm->srcu, idx); return ret; -- Gitee From aae84271a92c87dbf0df3ea14d209564db733d50 Mon Sep 17 00:00:00 2001 From: James Morse Date: Tue, 17 Dec 2019 12:38:09 +0000 Subject: [PATCH 3/7] KVM: arm/arm64: Re-check VMA on detecting a poisoned page mainline inclusion from mainline-v5.6-rc1 commit 1559b7583ff6ed018c5320d1503fa80b435775f0 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I82UA0 CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=1559b7583ff6ed018c5320d1503fa80b435775f0 -------------------------------- When we check for a poisoned page, we use the VMA to tell userspace about the looming disaster. But we pass a pointer to this VMA after having released the mmap_sem, which isn't a good idea. Instead, stash the shift value that goes with this pfn while we are holding the mmap_sem. Reported-by: Marc Zyngier Signed-off-by: James Morse Signed-off-by: Marc Zyngier Reviewed-by: Christoffer Dall Link: https://lore.kernel.org/r/20191211165651.7889-3-maz@kernel.org Link: https://lore.kernel.org/r/20191217123809.197392-1-james.morse@arm.com Signed-off-by: Ding Hui --- virt/kvm/arm/mmu.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/virt/kvm/arm/mmu.c b/virt/kvm/arm/mmu.c index 1eab040de8a6..39a719fa976b 100644 --- a/virt/kvm/arm/mmu.c +++ b/virt/kvm/arm/mmu.c @@ -1629,16 +1629,8 @@ static void invalidate_icache_guest_page(kvm_pfn_t pfn, unsigned long size) __invalidate_icache_guest_page(pfn, size); } -static void kvm_send_hwpoison_signal(unsigned long address, - struct vm_area_struct *vma) +static void kvm_send_hwpoison_signal(unsigned long address, short lsb) { - short lsb; - - if (is_vm_hugetlb_page(vma)) - lsb = huge_page_shift(hstate_vma(vma)); - else - lsb = PAGE_SHIFT; - send_sig_mceerr(BUS_MCEERR_AR, (void __user *)address, lsb, current); } @@ -1712,6 +1704,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, struct kvm *kvm = vcpu->kvm; struct kvm_mmu_memory_cache *memcache = &vcpu->arch.mmu_page_cache; struct vm_area_struct *vma; + short vma_shift; kvm_pfn_t pfn; pgprot_t mem_type = PAGE_S2; bool logging_active = memslot_is_logging(memslot); @@ -1736,7 +1729,12 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, return -EFAULT; } - vma_pagesize = vma_kernel_pagesize(vma); + if (is_vm_hugetlb_page(vma)) + vma_shift = huge_page_shift(hstate_vma(vma)); + else + vma_shift = PAGE_SHIFT; + + vma_pagesize = 1ULL << vma_shift; if (logging_active || (vma->vm_flags & VM_PFNMAP) || !fault_supports_stage2_huge_mapping(memslot, hva, vma_pagesize)) { @@ -1783,7 +1781,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, pfn = gfn_to_pfn_prot(kvm, gfn, write_fault, &writable); if (pfn == KVM_PFN_ERR_HWPOISON) { - kvm_send_hwpoison_signal(hva, vma); + kvm_send_hwpoison_signal(hva, vma_shift); return 0; } if (is_error_noslot_pfn(pfn)) -- Gitee From be99930d4798efe34a4bee0bb0f41b019f59e468 Mon Sep 17 00:00:00 2001 From: Alexandru Elisei Date: Thu, 10 Sep 2020 14:33:51 +0100 Subject: [PATCH 4/7] KVM: arm64: Try PMD block mappings if PUD mappings are not supported mainline inclusion from mainline-v5.10-rc1 commit 523b3999e5f620cb5ccce6a7ca2780a4cab579a2 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I82UA0 CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=523b3999e5f620cb5ccce6a7ca2780a4cab579a2 -------------------------------- When userspace uses hugetlbfs for the VM memory, user_mem_abort() tries to use the same block size to map the faulting IPA in stage 2. If stage 2 cannot the same block mapping because the block size doesn't fit in the memslot or the memslot is not properly aligned, user_mem_abort() will fall back to a page mapping, regardless of the block size. We can do better for PUD backed hugetlbfs by checking if a PMD block mapping is supported before deciding to use a page. vma_pagesize is an unsigned long, use 1UL instead of 1ULL when assigning its value. Signed-off-by: Alexandru Elisei Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20200910133351.118191-1-alexandru.elisei@arm.com [ dh: backport for "Enable PUD huge mappings only on 1620" ] Signed-off-by: Ding Hui --- virt/kvm/arm/mmu.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/virt/kvm/arm/mmu.c b/virt/kvm/arm/mmu.c index 39a719fa976b..130b7f4bd372 100644 --- a/virt/kvm/arm/mmu.c +++ b/virt/kvm/arm/mmu.c @@ -1734,14 +1734,25 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, else vma_shift = PAGE_SHIFT; - vma_pagesize = 1ULL << vma_shift; if (logging_active || - (vma->vm_flags & VM_PFNMAP) || - !fault_supports_stage2_huge_mapping(memslot, hva, vma_pagesize)) { + (vma->vm_flags & VM_PFNMAP)) { force_pte = true; - vma_pagesize = PAGE_SIZE; + vma_shift = PAGE_SHIFT; } + /* Only enable PUD_SIZE huge mapping on 1620 serial boards */ + if (vma_shift == PUD_SHIFT && + (!fault_supports_stage2_huge_mapping(memslot, hva, PUD_SIZE) || + !kvm_ncsnp_support)) + vma_shift = PMD_SHIFT; + + if (vma_shift == PMD_SHIFT && + !fault_supports_stage2_huge_mapping(memslot, hva, PMD_SIZE)) { + force_pte = true; + vma_shift = PAGE_SHIFT; + } + + vma_pagesize = 1UL << vma_shift; /* * The stage2 has a minimum of 2 level table (For arm64 see * kvm_arm_setup_stage2()). Hence, we are guaranteed that we can @@ -1751,14 +1762,9 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, */ if (vma_pagesize == PMD_SIZE || (vma_pagesize == PUD_SIZE && kvm_stage2_has_pmd(kvm))) - gfn = (fault_ipa & huge_page_mask(hstate_vma(vma))) >> PAGE_SHIFT; - - /* Only enable PUD_SIZE huge mapping on 1620 serial boards */ - if (vma_pagesize == PUD_SIZE && !kvm_ncsnp_support) { - vma_pagesize = PMD_SIZE; - gfn = (fault_ipa & PMD_MASK) >> PAGE_SHIFT; - } + fault_ipa &= ~(vma_pagesize - 1); + gfn = fault_ipa >> PAGE_SHIFT; up_read(¤t->mm->mmap_sem); /* We need minimum second+third level pages */ -- Gitee From 94d3e3715f08d9d26e12408eb574ec38e3b42606 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Mon, 26 Oct 2020 10:06:26 +1100 Subject: [PATCH 5/7] KVM: arm64: Use fallback mapping sizes for contiguous huge page sizes mainline inclusion from mainline-v5.10-rc2 commit 2f40c46021bbb3ecd5c5f05764ecccbc276bc690 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I82UA0 CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=2f40c46021bbb3ecd5c5f05764ecccbc276bc690 -------------------------------- Although huge pages can be created out of multiple contiguous PMDs or PTEs, the corresponding sizes are not supported at Stage-2 yet. Instead of failing the mapping, fall back to the nearer supported mapping size (CONT_PMD to PMD and CONT_PTE to PTE respectively). Suggested-by: Marc Zyngier Signed-off-by: Gavin Shan [maz: rewritten commit message] Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20201025230626.18501-1-gshan@redhat.com [ dh: Backport for getting rid of a1634a542f74 ("arm64/mm: Redefine CONT_{PTE, PMD}_SHIFT") ] Signed-off-by: Ding Hui --- virt/kvm/arm/mmu.c | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/virt/kvm/arm/mmu.c b/virt/kvm/arm/mmu.c index 130b7f4bd372..5811aca07d37 100644 --- a/virt/kvm/arm/mmu.c +++ b/virt/kvm/arm/mmu.c @@ -1692,6 +1692,12 @@ static bool fault_supports_stage2_huge_mapping(struct kvm_memory_slot *memslot, (hva & ~(map_size - 1)) + map_size <= uaddr_end; } +/** + * Backport for getting rid of a1634a542f74 ("arm64/mm: Redefine CONT_{PTE, PMD}_SHIFT") + */ +#define UMA_CONT_PMD_SHIFT ilog2(CONT_PMD_SIZE) +#define UMA_CONT_PTE_SHIFT ilog2(CONT_PTE_SIZE) + static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, struct kvm_memory_slot *memslot, unsigned long hva, unsigned long fault_status) @@ -1700,7 +1706,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, bool write_fault, writable, force_pte = false; bool exec_fault, needs_exec; unsigned long mmu_seq; - gfn_t gfn = fault_ipa >> PAGE_SHIFT; + gfn_t gfn; struct kvm *kvm = vcpu->kvm; struct kvm_mmu_memory_cache *memcache = &vcpu->arch.mmu_page_cache; struct vm_area_struct *vma; @@ -1740,16 +1746,27 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, vma_shift = PAGE_SHIFT; } - /* Only enable PUD_SIZE huge mapping on 1620 serial boards */ - if (vma_shift == PUD_SHIFT && - (!fault_supports_stage2_huge_mapping(memslot, hva, PUD_SIZE) || - !kvm_ncsnp_support)) - vma_shift = PMD_SHIFT; - - if (vma_shift == PMD_SHIFT && - !fault_supports_stage2_huge_mapping(memslot, hva, PMD_SIZE)) { - force_pte = true; + switch (vma_shift) { + case PUD_SHIFT: + /* Only enable PUD_SIZE huge mapping on 1620 serial boards */ + if (fault_supports_stage2_huge_mapping(memslot, hva, PUD_SIZE) && kvm_ncsnp_support) + break; + /* fallthrough */ + case UMA_CONT_PMD_SHIFT: + vma_shift = PMD_SHIFT; + /* fallthrough */ + case PMD_SHIFT: + if (fault_supports_stage2_huge_mapping(memslot, hva, PMD_SIZE)) + break; + /* fallthrough */ + case UMA_CONT_PTE_SHIFT: vma_shift = PAGE_SHIFT; + force_pte = true; + /* fallthrough */ + case PAGE_SHIFT: + break; + default: + WARN_ONCE(1, "Unknown vma_shift %d", vma_shift); } vma_pagesize = 1UL << vma_shift; -- Gitee From ba0786107473af7d6cb5a9bd59076c23ad012706 Mon Sep 17 00:00:00 2001 From: Santosh Shukla Date: Mon, 26 Oct 2020 16:54:07 +0530 Subject: [PATCH 6/7] KVM: arm64: Force PTE mapping on fault resulting in a device mapping mainline inclusion from mainline-v5.10-rc2 commit 91a2c34b7d6fadc9c5d9433c620ea4c32ee7cae8 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I82UA0 CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=91a2c34b7d6fadc9c5d9433c620ea4c32ee7cae8 -------------------------------- VFIO allows a device driver to resolve a fault by mapping a MMIO range. This can be subsequently result in user_mem_abort() to try and compute a huge mapping based on the MMIO pfn, which is a sure recipe for things to go wrong. Instead, force a PTE mapping when the pfn faulted in has a device mapping. Fixes: 6d674e28f642 ("KVM: arm/arm64: Properly handle faulting of device mappings") Suggested-by: Marc Zyngier Signed-off-by: Santosh Shukla [maz: rewritten commit message] Signed-off-by: Marc Zyngier Reviewed-by: Gavin Shan Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/1603711447-11998-2-git-send-email-sashukla@nvidia.com Signed-off-by: Ding Hui --- virt/kvm/arm/mmu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/virt/kvm/arm/mmu.c b/virt/kvm/arm/mmu.c index 5811aca07d37..fed60e0588d6 100644 --- a/virt/kvm/arm/mmu.c +++ b/virt/kvm/arm/mmu.c @@ -1813,6 +1813,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, if (kvm_is_device_pfn(pfn)) { mem_type = PAGE_S2_DEVICE; flags |= KVM_S2PTE_FLAG_IS_IOMAP; + force_pte = true; } else if (logging_active) { /* * Faults on pages in a memslot with logging enabled -- Gitee From eb1da6d026de1f14acc17222d5390711d912f1e6 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Tue, 3 Nov 2020 11:30:09 +1100 Subject: [PATCH 7/7] KVM: arm64: Fix build error in user_mem_abort() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mainline inclusion from mainline-v5.10-rc4 commit faf000397e7f103df9953a312e1df21df1dc797f category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I82UA0 CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=faf000397e7f103df9953a312e1df21df1dc797f -------------------------------- The PUD and PMD are folded into PGD when the following options are enabled. In that case, PUD_SHIFT is equal to PMD_SHIFT and we fail to build with the indicated errors: CONFIG_ARM64_VA_BITS_42=y CONFIG_ARM64_PAGE_SHIFT=16 CONFIG_PGTABLE_LEVELS=3 arch/arm64/kvm/mmu.c: In function ‘user_mem_abort’: arch/arm64/kvm/mmu.c:798:2: error: duplicate case value case PMD_SHIFT: ^~~~ arch/arm64/kvm/mmu.c:791:2: note: previously used here case PUD_SHIFT: ^~~~ This fixes the issue by skipping the check on PUD huge page when PUD and PMD are folded into PGD. Fixes: 2f40c46021bbb ("KVM: arm64: Use fallback mapping sizes for contiguous huge page sizes") Reported-by: Eric Auger Signed-off-by: Gavin Shan Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20201103003009.32955-1-gshan@redhat.com Signed-off-by: Ding Hui --- virt/kvm/arm/mmu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/virt/kvm/arm/mmu.c b/virt/kvm/arm/mmu.c index fed60e0588d6..1038443b8953 100644 --- a/virt/kvm/arm/mmu.c +++ b/virt/kvm/arm/mmu.c @@ -1747,11 +1747,13 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, } switch (vma_shift) { +#ifndef __PAGETABLE_PMD_FOLDED case PUD_SHIFT: /* Only enable PUD_SIZE huge mapping on 1620 serial boards */ if (fault_supports_stage2_huge_mapping(memslot, hva, PUD_SIZE) && kvm_ncsnp_support) break; /* fallthrough */ +#endif case UMA_CONT_PMD_SHIFT: vma_shift = PMD_SHIFT; /* fallthrough */ -- Gitee