lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250821210042.3451147-13-seanjc@google.com>
Date: Thu, 21 Aug 2025 14:00:38 -0700
From: Sean Christopherson <seanjc@...gle.com>
To: Marc Zyngier <maz@...nel.org>, Oliver Upton <oliver.upton@...ux.dev>
Cc: linux-arm-kernel@...ts.infradead.org, kvmarm@...ts.linux.dev, 
	linux-kernel@...r.kernel.org, Sean Christopherson <seanjc@...gle.com>, 
	James Houghton <jthoughton@...gle.com>
Subject: [RFC PATCH 12/16] KVM: arm64: Move VMA-related information into
 "struct kvm_page_fault"

Stash the "outputs" from parsing the VMA associated with an abort in
kvm_page_fault.  This will allow moving the mmap_lock-protected section to
a separate helper without needing a pile of out-parameters.

Deliberately place "pagesize" outside of the "vma" sub-structure, as KVM
manipulates (restricts) the pagesize based on other state, i.e. it's not a
strict representation of the VMA.

No functional change intended.

Signed-off-by: Sean Christopherson <seanjc@...gle.com>
---
 arch/arm64/include/asm/kvm_host.h |  9 +++++
 arch/arm64/kvm/mmu.c              | 67 +++++++++++++++----------------
 2 files changed, 41 insertions(+), 35 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index ec6473007fb9..4d131be08d8d 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -430,6 +430,15 @@ struct kvm_page_fault {
 	unsigned long hva;
 	kvm_pfn_t pfn;
 	struct page *page;
+
+	struct {
+		vm_flags_t vm_flags;
+		short pageshift;
+
+		bool is_cacheable;
+	} vma;
+
+	long pagesize;
 };
 
 /*
diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index b85968019dd4..aa6ee72bef51 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -1470,18 +1470,14 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)
 {
 	int ret = 0;
 	bool writable, force_pte = false;
-	bool is_vma_cacheable;
 	bool s2_force_noncacheable = false;
 	unsigned long mmu_seq;
 	struct kvm *kvm = vcpu->kvm;
 	struct vm_area_struct *vma;
-	short vma_shift;
 	void *memcache;
 	bool logging_active = memslot_is_logging(fault->slot);
-	long vma_pagesize;
 	enum kvm_pgtable_prot prot = KVM_PGTABLE_PROT_R;
 	struct kvm_pgtable *pgt;
-	vm_flags_t vm_flags;
 	enum kvm_pgtable_walk_flags flags = KVM_PGTABLE_WALK_HANDLE_FAULT | KVM_PGTABLE_WALK_SHARED;
 
 	VM_BUG_ON(fault->write && fault->exec);
@@ -1532,12 +1528,12 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)
 	 */
 	if (logging_active) {
 		force_pte = true;
-		vma_shift = PAGE_SHIFT;
+		fault->vma.pageshift = PAGE_SHIFT;
 	} else {
-		vma_shift = get_vma_page_shift(vma, fault->hva);
+		fault->vma.pageshift = get_vma_page_shift(vma, fault->hva);
 	}
 
-	switch (vma_shift) {
+	switch (fault->vma.pageshift) {
 #ifndef __PAGETABLE_PMD_FOLDED
 	case PUD_SHIFT:
 		if (fault_supports_stage2_huge_mapping(fault, PUD_SIZE))
@@ -1545,23 +1541,23 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)
 		fallthrough;
 #endif
 	case CONT_PMD_SHIFT:
-		vma_shift = PMD_SHIFT;
+		fault->vma.pageshift = PMD_SHIFT;
 		fallthrough;
 	case PMD_SHIFT:
 		if (fault_supports_stage2_huge_mapping(fault, PMD_SIZE))
 			break;
 		fallthrough;
 	case CONT_PTE_SHIFT:
-		vma_shift = PAGE_SHIFT;
+		fault->vma.pageshift = PAGE_SHIFT;
 		force_pte = true;
 		fallthrough;
 	case PAGE_SHIFT:
 		break;
 	default:
-		WARN_ONCE(1, "Unknown vma_shift %d", vma_shift);
+		WARN_ONCE(1, "Unknown VMA page shift %d", fault->vma.pageshift);
 	}
 
-	vma_pagesize = 1UL << vma_shift;
+	fault->pagesize = 1UL << fault->vma.pageshift;
 
 	if (fault->nested) {
 		unsigned long max_map_size;
@@ -1587,7 +1583,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)
 			max_map_size = PAGE_SIZE;
 
 		force_pte = (max_map_size == PAGE_SIZE);
-		vma_pagesize = min(vma_pagesize, (long)max_map_size);
+		fault->pagesize = min(fault->pagesize, (long)max_map_size);
 	}
 
 	/*
@@ -1595,16 +1591,15 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)
 	 * ensure we find the right PFN and lay down the mapping in the right
 	 * place.
 	 */
-	if (vma_pagesize == PMD_SIZE || vma_pagesize == PUD_SIZE) {
-		fault->fault_ipa &= ~(vma_pagesize - 1);
-		fault->ipa &= ~(vma_pagesize - 1);
+	if (fault->pagesize == PMD_SIZE || fault->pagesize == PUD_SIZE) {
+		fault->fault_ipa &= ~(fault->pagesize - 1);
+		fault->ipa &= ~(fault->pagesize - 1);
 	}
 
 	fault->gfn = fault->ipa >> PAGE_SHIFT;
 
-	vm_flags = vma->vm_flags;
-
-	is_vma_cacheable = kvm_vma_is_cacheable(vma);
+	fault->vma.vm_flags = vma->vm_flags;
+	fault->vma.is_cacheable = kvm_vma_is_cacheable(vma);
 
 	/* Don't use the VMA after the unlock -- it may have vanished */
 	vma = NULL;
@@ -1624,7 +1619,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)
 				       fault->write ? FOLL_WRITE : 0,
 				       &writable, &fault->page);
 	if (fault->pfn == KVM_PFN_ERR_HWPOISON) {
-		kvm_send_hwpoison_signal(fault->hva, vma_shift);
+		kvm_send_hwpoison_signal(fault->hva, fault->vma.pageshift);
 		return 0;
 	}
 	if (is_error_noslot_pfn(fault->pfn))
@@ -1634,8 +1629,9 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)
 	 * Check if this is non-struct page memory PFN, and cannot support
 	 * CMOs. It could potentially be unsafe to access as cachable.
 	 */
-	if (vm_flags & (VM_PFNMAP | VM_MIXEDMAP) && !pfn_is_map_memory(fault->pfn)) {
-		if (is_vma_cacheable) {
+	if (fault->vma.vm_flags & (VM_PFNMAP | VM_MIXEDMAP) &&
+	    !pfn_is_map_memory(fault->pfn)) {
+		if (fault->vma.is_cacheable) {
 			/*
 			 * Whilst the VMA owner expects cacheable mapping to this
 			 * PFN, hardware also has to support the FWB and CACHE DIC
@@ -1653,9 +1649,9 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)
 		} else {
 			/*
 			 * If the page was identified as device early by looking at
-			 * the VMA flags, vma_pagesize is already representing the
+			 * the VMA flags, fualt->pagesize is already representing the
 			 * largest quantity we can map.  If instead it was mapped
-			 * via __kvm_faultin_pfn(), vma_pagesize is set to PAGE_SIZE
+			 * via __kvm_faultin_pfn(), fualt->pagesize is set to PAGE_SIZE
 			 * and must not be upgraded.
 			 *
 			 * In both cases, we don't let transparent_hugepage_adjust()
@@ -1704,22 +1700,22 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)
 	 * If we are not forced to use page mapping, check if we are
 	 * backed by a THP and thus use block mapping if possible.
 	 */
-	if (vma_pagesize == PAGE_SIZE && !(force_pte || s2_force_noncacheable)) {
+	if (fault->pagesize == PAGE_SIZE && !(force_pte || s2_force_noncacheable)) {
 		if (fault->is_perm && fault->granule > PAGE_SIZE)
-			vma_pagesize = fault->granule;
+			fault->pagesize = fault->granule;
 		else
-			vma_pagesize = transparent_hugepage_adjust(kvm, fault);
+			fault->pagesize = transparent_hugepage_adjust(kvm, fault);
 
-		if (vma_pagesize < 0) {
-			ret = vma_pagesize;
+		if (fault->pagesize < 0) {
+			ret = fault->pagesize;
 			goto out_unlock;
 		}
 	}
 
 	if (!fault->is_perm && !s2_force_noncacheable && kvm_has_mte(kvm)) {
 		/* Check the VMM hasn't introduced a new disallowed VMA */
-		if (vm_flags & VM_MTE_ALLOWED) {
-			sanitise_mte_tags(kvm, fault->pfn, vma_pagesize);
+		if (fault->vma.vm_flags & VM_MTE_ALLOWED) {
+			sanitise_mte_tags(kvm, fault->pfn, fault->pagesize);
 		} else {
 			ret = -EFAULT;
 			goto out_unlock;
@@ -1733,7 +1729,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)
 		prot |= KVM_PGTABLE_PROT_X;
 
 	if (s2_force_noncacheable) {
-		if (vm_flags & VM_ALLOW_ANY_UNCACHED)
+		if (fault->vma.vm_flags & VM_ALLOW_ANY_UNCACHED)
 			prot |= KVM_PGTABLE_PROT_NORMAL_NC;
 		else
 			prot |= KVM_PGTABLE_PROT_DEVICE;
@@ -1747,7 +1743,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)
 	 * permissions only if vma_pagesize equals fault->granule. Otherwise,
 	 * kvm_pgtable_stage2_map() should be called to change block size.
 	 */
-	if (fault->is_perm && vma_pagesize == fault->granule) {
+	if (fault->is_perm && fault->pagesize == fault->granule) {
 		/*
 		 * Drop the SW bits in favour of those stored in the
 		 * PTE, which will be preserved.
@@ -1755,9 +1751,10 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)
 		prot &= ~KVM_NV_GUEST_MAP_SZ;
 		ret = KVM_PGT_FN(kvm_pgtable_stage2_relax_perms)(pgt, fault->fault_ipa, prot, flags);
 	} else {
-		ret = KVM_PGT_FN(kvm_pgtable_stage2_map)(pgt, fault->fault_ipa, vma_pagesize,
-					     __pfn_to_phys(fault->pfn), prot,
-					     memcache, flags);
+		ret = KVM_PGT_FN(kvm_pgtable_stage2_map)(pgt, fault->fault_ipa,
+							 fault->pagesize,
+							 __pfn_to_phys(fault->pfn),
+							 prot, memcache, flags);
 	}
 
 out_unlock:
-- 
2.51.0.261.g7ce5a0a67e-goog


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ