On systems without DIC, KVM lazily grants execute permission to stage-2
translations after taking an instruction abort due to a permission
fault, allowing it to defer I-cache invalidations to the point they're
absolutely required.
If a data abort happens later down the line to such a translation, KVM
will not request execute permissions as part of the S2 relaxation on the
assumption that kvm_pgtable_stage2_relax_perms() does exactly what the
name implies and adds the requested permissions to the pre-existing
ones.
Avoid taking unintended execute permission faults by only preparing the
XN attribute if KVM_PGTABLE_PROT_X is set.
Fixes: 2608563b466b ("KVM: arm64: Add support for FEAT_XNX stage-2 permissions")
Signed-off-by: Oliver Upton <oupton@kernel.org>
Reviewed-by: Wei-Lin Chang <weilin.chang@arm.com>
Link: https://patch.msgid.link/20260701231620.3300204-3-oupton@kernel.org
Signed-off-by: Marc Zyngier <maz@kernel.org>
if (prot & KVM_PGTABLE_PROT_W)
set |= KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W;
- ret = stage2_set_xn_attr(prot, &xn);
- if (ret)
- return ret;
+ if (prot & KVM_PGTABLE_PROT_X) {
+ ret = stage2_set_xn_attr(prot, &xn);
+ if (ret)
+ return ret;
- set |= xn & KVM_PTE_LEAF_ATTR_HI_S2_XN;
- clr |= ~xn & KVM_PTE_LEAF_ATTR_HI_S2_XN;
+ set |= xn & KVM_PTE_LEAF_ATTR_HI_S2_XN;
+ clr |= ~xn & KVM_PTE_LEAF_ATTR_HI_S2_XN;
+ }
ret = stage2_update_leaf_attrs(pgt, addr, 1, set, clr, NULL, &level, flags);
if (!ret || ret == -EAGAIN)