linux-brain/arch/x86/kvm
Lai Jiangshan d28adaabbb KVM: X86: MMU: Use the correct inherited permissions to get shadow page
commit b1bd5cba3306691c771d558e94baa73e8b0b96b7 upstream.

When computing the access permissions of a shadow page, use the effective
permissions of the walk up to that point, i.e. the logic AND of its parents'
permissions.  Two guest PxE entries that point at the same table gfn need to
be shadowed with different shadow pages if their parents' permissions are
different.  KVM currently uses the effective permissions of the last
non-leaf entry for all non-leaf entries.  Because all non-leaf SPTEs have
full ("uwx") permissions, and the effective permissions are recorded only
in role.access and merged into the leaves, this can lead to incorrect
reuse of a shadow page and eventually to a missing guest protection page
fault.

For example, here is a shared pagetable:

   pgd[]   pud[]        pmd[]            virtual address pointers
                     /->pmd1(u--)->pte1(uw-)->page1 <- ptr1 (u--)
        /->pud1(uw-)--->pmd2(uw-)->pte2(uw-)->page2 <- ptr2 (uw-)
   pgd-|           (shared pmd[] as above)
        \->pud2(u--)--->pmd1(u--)->pte1(uw-)->page1 <- ptr3 (u--)
                     \->pmd2(uw-)->pte2(uw-)->page2 <- ptr4 (u--)

  pud1 and pud2 point to the same pmd table, so:
  - ptr1 and ptr3 points to the same page.
  - ptr2 and ptr4 points to the same page.

(pud1 and pud2 here are pud entries, while pmd1 and pmd2 here are pmd entries)

- First, the guest reads from ptr1 first and KVM prepares a shadow
  page table with role.access=u--, from ptr1's pud1 and ptr1's pmd1.
  "u--" comes from the effective permissions of pgd, pud1 and
  pmd1, which are stored in pt->access.  "u--" is used also to get
  the pagetable for pud1, instead of "uw-".

- Then the guest writes to ptr2 and KVM reuses pud1 which is present.
  The hypervisor set up a shadow page for ptr2 with pt->access is "uw-"
  even though the pud1 pmd (because of the incorrect argument to
  kvm_mmu_get_page in the previous step) has role.access="u--".

- Then the guest reads from ptr3.  The hypervisor reuses pud1's
  shadow pmd for pud2, because both use "u--" for their permissions.
  Thus, the shadow pmd already includes entries for both pmd1 and pmd2.

- At last, the guest writes to ptr4.  This causes no vmexit or pagefault,
  because pud1's shadow page structures included an "uw-" page even though
  its role.access was "u--".

Any kind of shared pagetable might have the similar problem when in
virtual machine without TDP enabled if the permissions are different
from different ancestors.

In order to fix the problem, we change pt->access to be an array, and
any access in it will not include permissions ANDed from child ptes.

The test code is: https://lore.kernel.org/kvm/20210603050537.19605-1-jiangshanlai@gmail.com/
Remember to test it with TDP disabled.

The problem had existed long before the commit 41074d07c7 ("KVM: MMU:
Fix inherited permissions for emulated guest pte updates"), and it
is hard to find which is the culprit.  So there is no fixes tag here.

Signed-off-by: Lai Jiangshan <laijs@linux.alibaba.com>
Message-Id: <20210603052455.21023-1-jiangshanlai@gmail.com>
Cc: stable@vger.kernel.org
Fixes: cea0f0e7ea ("[PATCH] KVM: MMU: Shadow page table caching")
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
[OP: - apply arch/x86/kvm/mmu/* changes to arch/x86/kvm
     - apply documentation changes to Documentation/virt/kvm/mmu.txt
     - adjusted context in arch/x86/kvm/paging_tmpl.h]
Signed-off-by: Ovidiu Panait <ovidiu.panait@windriver.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-08-15 13:08:04 +02:00
..
vmx KVM: nVMX: Ensure 64-bit shift when checking VMFUNC bitmap 2021-07-14 16:53:23 +02:00
cpuid.c KVM: x86: Use guest MAXPHYADDR from CPUID.0x8000_0008 iff TDP is enabled 2021-07-20 16:10:40 +02:00
cpuid.h KVM: x86: reinstate vendor-agnostic check on SPEC_CTRL cpuid bits 2021-01-06 14:48:36 +01:00
debugfs.c KVM: no need to check return value of debugfs_create functions 2019-08-05 12:55:49 +02:00
emulate.c KVM: x86: Update emulator context mode if SYSENTER xfers to 64-bit mode 2021-02-10 09:25:31 +01:00
hyperv.c KVM: x86: Protect kvm_hv_msr_[get|set]_crash_data() from Spectre-v1/L1TF attacks 2020-02-11 04:35:38 -08:00
hyperv.h treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 499 2019-06-19 17:09:53 +02:00
i8254.c kvm: x86: Add memcg accounting to KVM allocations 2019-02-20 22:48:30 +01:00
i8254.h License cleanup: add SPDX GPL-2.0 license identifier to files with no license 2017-11-02 11:10:55 +01:00
i8259.c KVM: x86: Refactor picdev_write() to prevent Spectre-v1/L1TF attacks 2020-02-11 04:35:37 -08:00
ioapic.c x86/kvm: fix vcpu-id indexed array sizes 2021-08-04 12:27:37 +02:00
ioapic.h x86/kvm: fix vcpu-id indexed array sizes 2021-08-04 12:27:37 +02:00
irq_comm.c KVM: x86: don't notify userspace IOAPIC on edge-triggered interrupt EOI 2020-02-28 17:22:22 +01:00
irq.c KVM: x86: Fix split-irqchip vs interrupt injection window request 2020-12-02 08:49:46 +01:00
irq.h KVM/arm updates for 5.3 2019-07-11 15:14:16 +02:00
Kconfig kvm: x86: add host poll control msrs 2019-06-18 11:43:46 +02:00
kvm_cache_regs.h KVM: x86: Mark CR4.TSD as being possibly owned by the guest 2020-07-16 08:16:44 +02:00
lapic.c kvm: LAPIC: Restore guard to prevent illegal APIC register access 2021-06-23 14:41:23 +02:00
lapic.h KVM: SVM: Fix potential wrong physical id in avic_handle_ldr_update 2019-10-22 18:47:50 +02:00
Makefile KVM: x86: fix TRACE_INCLUDE_PATH and remove -I. header search paths 2019-01-25 19:12:37 +01:00
mmu_audit.c treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 499 2019-06-19 17:09:53 +02:00
mmu.c KVM: x86/mmu: Fix per-cpu counter corruption on 32-bit builds 2021-08-12 13:21:03 +02:00
mmu.h KVM: x86: fix shift out of bounds reported by UBSAN 2021-01-12 20:16:25 +01:00
mmutrace.h KVM: x86: fix incorrect comparison in trace event 2020-10-01 13:17:35 +02:00
mtrr.c KVM: x86: Protect MSR-based index computations in fixed_msr_to_seg_unit() from Spectre-v1/L1TF attacks 2020-02-11 04:35:39 -08:00
page_track.c treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 499 2019-06-19 17:09:53 +02:00
paging_tmpl.h KVM: X86: MMU: Use the correct inherited permissions to get shadow page 2021-08-15 13:08:04 +02:00
pmu_amd.c treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 499 2019-06-19 17:09:53 +02:00
pmu.c KVM: x86: Add fixed counters to PMU filter 2019-07-20 09:00:48 +02:00
pmu.h KVM: x86: Protect MSR-based index computations in pmu.h from Spectre-v1/L1TF attacks 2020-02-11 04:35:38 -08:00
svm.c KVM: SVM: Fix off-by-one indexing when nullifying last used SEV VMCB 2021-08-15 13:08:02 +02:00
trace.h KVM: x86: Ensure liveliness of nested VM-Enter fail tracepoint message 2021-06-16 11:59:44 +02:00
tss.h License cleanup: add SPDX GPL-2.0 license identifier to files with no license 2017-11-02 11:10:55 +01:00
x86.c KVM: x86: accept userspace interrupt only if no event is injected 2021-08-12 13:21:03 +02:00
x86.h kvm: x86: replace kvm_spec_ctrl_test_value with runtime test on the host 2021-03-04 10:26:09 +01:00