]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
KVM: arm64: Always check the state from hyp_ack_unshare()
authorQuentin Perret <qperret@google.com>
Thu, 28 Nov 2024 15:44:06 +0000 (15:44 +0000)
committerOliver Upton <oliver.upton@linux.dev>
Wed, 18 Dec 2024 21:21:37 +0000 (13:21 -0800)
There are multiple pKVM memory transitions where the state of a page is
not cross-checked from the completer's PoV for performance reasons.
For example, if a page is PKVM_PAGE_OWNED from the initiator's PoV,
we should be guaranteed by construction that it is PKVM_NOPAGE for
everybody else, hence allowing us to save a page-table lookup.

When it was introduced, hyp_ack_unshare() followed that logic and bailed
out without checking the PKVM_PAGE_SHARED_BORROWED state in the
hypervisor's stage-1. This was correct as we could safely assume that
all host-initiated shares were directed at the hypervisor at the time.
But with the introduction of other types of shares (e.g. for FF-A or
non-protected guests), it is now very much required to cross check this
state to prevent the host from running __pkvm_host_unshare_hyp() on a
page shared with TZ or a non-protected guest.

Thankfully, if an attacker were to try this, the hyp_unmap() call from
hyp_complete_unshare() would fail, hence causing to WARN() from
__do_unshare() with the host lock held, which is fatal. But this is
fragile at best, and can hardly be considered a security measure.

Let's just do the right thing and always check the state from
hyp_ack_unshare().

Signed-off-by: Quentin Perret <qperret@google.com>
Acked-by: Will Deacon <will@kernel.org>
Link: https://lore.kernel.org/r/20241128154406.602875-1-qperret@google.com
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
arch/arm64/kvm/hyp/nvhe/mem_protect.c

index caba3e4bd09e8405a4138a8d61c59375187550e0..e75374d682f45b3409ddf213c86c93a257d13cee 100644 (file)
@@ -783,9 +783,6 @@ static int hyp_ack_unshare(u64 addr, const struct pkvm_mem_transition *tx)
        if (tx->initiator.id == PKVM_ID_HOST && hyp_page_count((void *)addr))
                return -EBUSY;
 
-       if (__hyp_ack_skip_pgtable_check(tx))
-               return 0;
-
        return __hyp_check_page_state_range(addr, size,
                                            PKVM_PAGE_SHARED_BORROWED);
 }