[PATCH v1 03/10] KVM: arm64: nv: Don't loop on AT S12E{0,1}{R,W} with an invalid VTCR_EL2

Fuad Tabba fuad.tabba at linux.dev
Mon Sep 28 08:25:00 PDT 2026


When KVM walks an L1 guest's stage-2 tables, a positive return means
the walk faulted with the syndrome in out->esr, and a negative one
means KVM couldn't complete it and the caller has to retry. The
VTCR_EL2.T0SZ and SL0 checks return -EFAULT for what is the guest's
own misconfiguration: an invalid SL0 is a stage-2 level 0 Translation
fault (AArch64_S2InvalidSL()), and so is an out of range T0SZ that the
implementation doesn't clamp (AArch64_S2TxSZFaults()).

An L1 guest that programs either value therefore executes
AT S12E{0,1}{R,W} forever, since the AT is never retired, and on an L2
abort KVM injects the fault and then returns -EFAULT from KVM_RUN. The
T0SZ check also left the syndrome unset, so where a fault was reported
at all, on an L2 abort or in PAR_EL1 after a stage-1 AT, it was an
Address size fault.

Return 1 with a level 0 Translation fault from both checks, as the walk
does for the guest's other stage-2 faults.

Fixes: fd276e71d1e7b ("KVM: arm64: nv: Handle shadow stage 2 page faults")
Fixes: 92c6443222ca4 ("KVM: arm64: Propagate PTW errors up to AT emulation")
Signed-off-by: Fuad Tabba <fuad.tabba at linux.dev>
---
 arch/arm64/kvm/nested.c | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c
index 98c1f8c193319..a67be19e73250 100644
--- a/arch/arm64/kvm/nested.c
+++ b/arch/arm64/kvm/nested.c
@@ -275,13 +275,10 @@ static int walk_nested_s2_pgd(struct kvm_vcpu *vcpu, phys_addr_t ipa,
 
 	stride = wi->pgshift - 3;
 	input_size = get_ia_size(wi);
-	if (input_size > 48 || input_size < 25)
-		return -EFAULT;
-
-	ret = check_base_s2_limits(vcpu, wi, level, input_size, stride);
-	if (ret) {
+	if (input_size > 48 || input_size < 25 ||
+	    check_base_s2_limits(vcpu, wi, level, input_size, stride)) {
 		out->esr = compute_fsc(0, ESR_ELx_FSC_FAULT);
-		return ret;
+		return 1;
 	}
 
 	base_lower_bound = 3 + input_size - ((3 - level) * stride +
-- 
2.39.5




More information about the linux-arm-kernel mailing list