[PATCH v2 6/6] KVM: arm64: Honor UX/PX attributes for EL2 S1 mappings

Joey Gouly joey.gouly at arm.com
Fri Dec 12 08:00:42 PST 2025


On Thu, Dec 11, 2025 at 04:21:20PM +0000, Marc Zyngier wrote:
> On Thu, 11 Dec 2025 15:18:51 +0000,
> Joey Gouly <joey.gouly at arm.com> wrote:
> > 
> > Question,
> > 
> > On Wed, Dec 10, 2025 at 05:30:24PM +0000, Marc Zyngier wrote:
> > > 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 at arm.com>
> > > Signed-off-by: Marc Zyngier <maz at kernel.org>
> > > ---
> > >  arch/arm64/include/asm/kvm_pgtable.h | 12 +++---------
> > >  arch/arm64/kvm/hyp/pgtable.c         | 24 +++++++++++++++++++++---
> > >  2 files changed, 24 insertions(+), 12 deletions(-)
> > > 
> > > diff --git a/arch/arm64/include/asm/kvm_pgtable.h b/arch/arm64/include/asm/kvm_pgtable.h
> > > index be68b89692065..095e6b73740a6 100644
> > > --- a/arch/arm64/include/asm/kvm_pgtable.h
> > > +++ b/arch/arm64/include/asm/kvm_pgtable.h
> > > @@ -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)
> > >  
> > > diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c
> > > index e0bd6a0172729..97c0835d25590 100644
> > > --- a/arch/arm64/kvm/hyp/pgtable.c
> > > +++ b/arch/arm64/kvm/hyp/pgtable.c
> > > @@ -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;
> > 
> > Trying to understand this part. We don't consider KVM_PGTABLE_PROT_UX below
> > when !HVHE, and we don't set it in kvm_pgtable_hyp_pte_prot() when !HVHE
> > either, so can it ever actually be set?
> 
> Because KVM_PGTABLE_PROT_X, which is directly passed by the high-level
> code, is defined as such:
> 
> 	KVM_PGTABLE_PROT_X			= KVM_PGTABLE_PROT_PX	|
> 						  KVM_PGTABLE_PROT_UX,
> 

This was the main missing part!

> We *could* make that value dependent on HVHE, but since that's in an
> enum, it is pretty ugly to do (not impossible though).
> 
> But it is in the following code that this becomes useful...
> 
> >
> > Otherwise LGTM!
> > 
> > Thanks,
> > Joey
> > 
> > > +
> > >  	if (prot & KVM_PGTABLE_PROT_X) {
> > >  		if (prot & KVM_PGTABLE_PROT_W)
> > >  			return -EINVAL;
> 
> ... here. If you were passed UX (and only that), and that you're
> !HVHE, you won't have execution at all, and can allow writes.
> 
> Does that make sense?

Yes, thanks!

Reviewed-by: Joey Gouly <joey.gouly at arm.com>

> 
> 	M.
> 
> -- 
> Without deviation from the norm, progress is not possible.



More information about the linux-arm-kernel mailing list