summaryrefslogtreecommitdiffstats
path: root/arch/arm64/kvm/hyp/nvhe/mem_protect.c
diff options
context:
space:
mode:
authorQuentin Perret <qperret@google.com>2021-10-05 10:01:41 +0100
committerMarc Zyngier <maz@kernel.org>2021-10-05 13:02:54 +0100
commit1d58a17ef54599506d44c45ac95be27273a4d2b1 (patch)
tree10dbb0b3fb1a689c6c114e045fae8b9d621e9b41 /arch/arm64/kvm/hyp/nvhe/mem_protect.c
parente840f42a49925707fca90e6c7a4095118fdb8c4d (diff)
downloadlinux-stable-1d58a17ef54599506d44c45ac95be27273a4d2b1.tar.gz
linux-stable-1d58a17ef54599506d44c45ac95be27273a4d2b1.tar.bz2
linux-stable-1d58a17ef54599506d44c45ac95be27273a4d2b1.zip
KVM: arm64: Fix host stage-2 PGD refcount
The KVM page-table library refcounts the pages of concatenated stage-2 PGDs individually. However, when running KVM in protected mode, the host's stage-2 PGD is currently managed by EL2 as a single high-order compound page, which can cause the refcount of the tail pages to reach 0 when they shouldn't, hence corrupting the page-table. Fix this by introducing a new hyp_split_page() helper in the EL2 page allocator (matching the kernel's split_page() function), and make use of it from host_s2_zalloc_pages_exact(). Fixes: 1025c8c0c6ac ("KVM: arm64: Wrap the host with a stage 2") Acked-by: Will Deacon <will@kernel.org> Suggested-by: Will Deacon <will@kernel.org> Signed-off-by: Quentin Perret <qperret@google.com> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20211005090155.734578-5-qperret@google.com
Diffstat (limited to 'arch/arm64/kvm/hyp/nvhe/mem_protect.c')
-rw-r--r--arch/arm64/kvm/hyp/nvhe/mem_protect.c13
1 files changed, 12 insertions, 1 deletions
diff --git a/arch/arm64/kvm/hyp/nvhe/mem_protect.c b/arch/arm64/kvm/hyp/nvhe/mem_protect.c
index bacd493a4eac..34eeb524b686 100644
--- a/arch/arm64/kvm/hyp/nvhe/mem_protect.c
+++ b/arch/arm64/kvm/hyp/nvhe/mem_protect.c
@@ -35,7 +35,18 @@ const u8 pkvm_hyp_id = 1;
static void *host_s2_zalloc_pages_exact(size_t size)
{
- return hyp_alloc_pages(&host_s2_pool, get_order(size));
+ void *addr = hyp_alloc_pages(&host_s2_pool, get_order(size));
+
+ hyp_split_page(hyp_virt_to_page(addr));
+
+ /*
+ * The size of concatenated PGDs is always a power of two of PAGE_SIZE,
+ * so there should be no need to free any of the tail pages to make the
+ * allocation exact.
+ */
+ WARN_ON(size != (PAGE_SIZE << get_order(size)));
+
+ return addr;
}
static void *host_s2_zalloc_page(void *pool)