]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
KVM: arm64: nv: Inject SEA if kvm_translate_vncr() can't resolve PFN
authorOliver Upton <oupton@kernel.org>
Thu, 18 Jun 2026 23:42:03 +0000 (16:42 -0700)
committerMarc Zyngier <maz@kernel.org>
Mon, 22 Jun 2026 09:43:25 +0000 (10:43 +0100)
kvm_handle_vncr_abort() assumes that s1_walk_result conveys an abort
when kvm_translate_vncr() returns -EFAULT. This is not always the case
as it's possible to encounter 'late' failures on the output of S1
translation, e.g. a GFN outside of the memslots.

Fix it by preparing an external abort before returning from
kvm_translate_vncr(). Get rid of the BUG_ON() in the fault injection
path while at it.

Cc: stable@vger.kernel.org
Fixes: 2a359e072596 ("KVM: arm64: nv: Handle mapping of VNCR_EL2 at EL2")
Signed-off-by: Oliver Upton <oupton@kernel.org>
Link: https://patch.msgid.link/20260618234207.1063941-3-oupton@kernel.org
Signed-off-by: Marc Zyngier <maz@kernel.org>
arch/arm64/include/asm/kvm_nested.h
arch/arm64/kvm/at.c
arch/arm64/kvm/nested.c

index dc2957662ff204d43ba9ead49a2db01542bf4b5b..cbdaaa2a2903b6f33cba77f5260789e5fed53e19 100644 (file)
@@ -388,6 +388,14 @@ struct s1_walk_result {
        bool    failed;
 };
 
+static inline void fail_s1_walk(struct s1_walk_result *wr, u8 fst, bool s1ptw)
+{
+       wr->fst         = fst;
+       wr->ptw         = s1ptw;
+       wr->s2          = s1ptw;
+       wr->failed      = true;
+}
+
 int __kvm_translate_va(struct kvm_vcpu *vcpu, struct s1_walk_info *wi,
                       struct s1_walk_result *wr, u64 va);
 int __kvm_find_s1_desc_level(struct kvm_vcpu *vcpu, u64 va, u64 ipa,
index 30e6fa8ac07cf30be7e8a49275b0596a224ae44f..8263c648207b03893c0527524677bf1ebd767f03 100644 (file)
 #include <asm/kvm_mmu.h>
 #include <asm/lsui.h>
 
-static void fail_s1_walk(struct s1_walk_result *wr, u8 fst, bool s1ptw)
-{
-       wr->fst         = fst;
-       wr->ptw         = s1ptw;
-       wr->s2          = s1ptw;
-       wr->failed      = true;
-}
-
 #define S1_MMU_DISABLED                (-127)
 
 static int get_ia_size(struct s1_walk_info *wi)
index 903ccabca78c548b99f252e93628da25a9b696ea..53dea9c3f14f84af37b80d394eb34589055312f2 100644 (file)
@@ -1395,15 +1395,19 @@ static int kvm_translate_vncr(struct kvm_vcpu *vcpu, bool *is_gmem)
 
        gfn = vt->wr.pa >> PAGE_SHIFT;
        memslot = gfn_to_memslot(vcpu->kvm, gfn);
-       if (!memslot)
+       if (!memslot) {
+               fail_s1_walk(&vt->wr, ESR_ELx_FSC_EXTABT, false);
                return -EFAULT;
+       }
 
        *is_gmem = kvm_slot_has_gmem(memslot);
        if (!*is_gmem) {
                pfn = __kvm_faultin_pfn(memslot, gfn, write_fault ? FOLL_WRITE : 0,
                                        &writable, &page);
-               if (is_error_noslot_pfn(pfn))
+               if (is_error_noslot_pfn(pfn)) {
+                       fail_s1_walk(&vt->wr, ESR_ELx_FSC_EXTABT, false);
                        return -EFAULT;
+               }
        } else {
                ret = kvm_gmem_get_pfn(vcpu->kvm, memslot, gfn, &pfn, &page, NULL);
                if (ret) {
@@ -1530,8 +1534,6 @@ int kvm_handle_vncr_abort(struct kvm_vcpu *vcpu)
                         * Translation failed, inject the corresponding
                         * exception back to EL2.
                         */
-                       BUG_ON(!vt->wr.failed);
-
                        esr &= ~ESR_ELx_FSC;
                        esr |= FIELD_PREP(ESR_ELx_FSC, vt->wr.fst);