]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
KVM: arm64: Honor UX/PX attributes for EL2 S1 mappings
authorMarc Zyngier <maz@kernel.org>
Wed, 10 Dec 2025 17:30:24 +0000 (17:30 +0000)
committerMarc Zyngier <maz@kernel.org>
Thu, 15 Jan 2026 10:58:21 +0000 (10:58 +0000)
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>
arch/arm64/include/asm/kvm_pgtable.h
arch/arm64/kvm/hyp/pgtable.c

index c0ad262a828902115e054c2cdfb4b1e66ea80b8f..56bd08be9630d45e2e833b1f7e9bdfc57a1456ed 100644 (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)
 
index a99a7d6e7d0c83135626c7bac3785567acea4e01..13e34d66b6a7e18bf24c3f81c375915e5bd837ba 100644 (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)