KVM: arm64: Honor UX/PX attributes for EL2 S1 mappings

Now that we potentially have two bits to deal with when setting
execution permissions, make sure we correctly handle them when both
when building the page tables and when reading back from them.

Reported-by: Alexandru Elisei <alexandru.elisei@arm.com>
Reviewed-by: Fuad Tabba <tabba@google.com>
Reviewed-by: Joey Gouly <joey.gouly@arm.com>
Tested-by: Fuad Tabba <tabba@google.com>
Link: https://patch.msgid.link/20251210173024.561160-7-maz@kernel.org
Signed-off-by: Marc Zyngier <maz@kernel.org>
This commit is contained in:
Marc Zyngier 2025-12-10 17:30:24 +00:00
parent 9d2de51825
commit 80cbfd7174
2 changed files with 24 additions and 12 deletions

View File

@ -87,15 +87,9 @@ typedef u64 kvm_pte_t;
#define KVM_PTE_LEAF_ATTR_HI_SW GENMASK(58, 55)
#define __KVM_PTE_LEAF_ATTR_HI_S1_XN BIT(54)
#define __KVM_PTE_LEAF_ATTR_HI_S1_UXN BIT(54)
#define __KVM_PTE_LEAF_ATTR_HI_S1_PXN BIT(53)
#define KVM_PTE_LEAF_ATTR_HI_S1_XN \
({ cpus_have_final_cap(ARM64_KVM_HVHE) ? \
(__KVM_PTE_LEAF_ATTR_HI_S1_UXN | \
__KVM_PTE_LEAF_ATTR_HI_S1_PXN) : \
__KVM_PTE_LEAF_ATTR_HI_S1_XN; })
#define KVM_PTE_LEAF_ATTR_HI_S1_XN BIT(54)
#define KVM_PTE_LEAF_ATTR_HI_S1_UXN BIT(54)
#define KVM_PTE_LEAF_ATTR_HI_S1_PXN BIT(53)
#define KVM_PTE_LEAF_ATTR_HI_S2_XN GENMASK(54, 53)

View File

@ -342,6 +342,9 @@ static int hyp_set_prot_attr(enum kvm_pgtable_prot prot, kvm_pte_t *ptep)
if (!(prot & KVM_PGTABLE_PROT_R))
return -EINVAL;
if (!cpus_have_final_cap(ARM64_KVM_HVHE))
prot &= ~KVM_PGTABLE_PROT_UX;
if (prot & KVM_PGTABLE_PROT_X) {
if (prot & KVM_PGTABLE_PROT_W)
return -EINVAL;
@ -351,8 +354,16 @@ static int hyp_set_prot_attr(enum kvm_pgtable_prot prot, kvm_pte_t *ptep)
if (system_supports_bti_kernel())
attr |= KVM_PTE_LEAF_ATTR_HI_S1_GP;
}
if (cpus_have_final_cap(ARM64_KVM_HVHE)) {
if (!(prot & KVM_PGTABLE_PROT_PX))
attr |= KVM_PTE_LEAF_ATTR_HI_S1_PXN;
if (!(prot & KVM_PGTABLE_PROT_UX))
attr |= KVM_PTE_LEAF_ATTR_HI_S1_UXN;
} else {
attr |= KVM_PTE_LEAF_ATTR_HI_S1_XN;
if (!(prot & KVM_PGTABLE_PROT_PX))
attr |= KVM_PTE_LEAF_ATTR_HI_S1_XN;
}
attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S1_AP, ap);
@ -373,8 +384,15 @@ enum kvm_pgtable_prot kvm_pgtable_hyp_pte_prot(kvm_pte_t pte)
if (!kvm_pte_valid(pte))
return prot;
if (!(pte & KVM_PTE_LEAF_ATTR_HI_S1_XN))
prot |= KVM_PGTABLE_PROT_X;
if (cpus_have_final_cap(ARM64_KVM_HVHE)) {
if (!(pte & KVM_PTE_LEAF_ATTR_HI_S1_PXN))
prot |= KVM_PGTABLE_PROT_PX;
if (!(pte & KVM_PTE_LEAF_ATTR_HI_S1_UXN))
prot |= KVM_PGTABLE_PROT_UX;
} else {
if (!(pte & KVM_PTE_LEAF_ATTR_HI_S1_XN))
prot |= KVM_PGTABLE_PROT_PX;
}
ap = FIELD_GET(KVM_PTE_LEAF_ATTR_LO_S1_AP, pte);
if (ap == KVM_PTE_LEAF_ATTR_LO_S1_AP_RO)