Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2] KVM: arm64: Reject guest_memfd memslots when the VM has MTE
@ 2026-07-20 13:09 Alexandru Elisei
  2026-07-20 15:20 ` Fuad Tabba
  2026-07-20 15:46 ` Marc Zyngier
  0 siblings, 2 replies; 4+ messages in thread
From: Alexandru Elisei @ 2026-07-20 13:09 UTC (permalink / raw)
  To: maz, oupton, joey.gouly, seiden, suzuki.poulose, yuzenghui,
	linux-arm-kernel, kvmarm, catalin.marinas, will
  Cc: steven.price, fuad.tabba

The user cannot use MTE on VMAs created by mapping a guest_memfd file,
as arch_calc_vm_flag_bits() does not set VM_MTE_ALLOWED.

When creating a guest_memfd backed memslot,
kvm_arch_prepare_memory_region() rejects the memslot if MTE is enabled for
the VM and if guest_memfd has been mapped in a VMA that intersects the
memslot.

However, the documentation for KVM_SET_USER_MEMORY_REGION2 explicitly
states that the only condition for userspace_addr is for it to be a legal
userspace address, but the mapping is not required to be valid nor
populated at memslot creation.

If userspace sets userspace_addr to an address that hasn't been mapped, or
if userspace_addr belongs to a VMA that isn't backed by the guest_memfd
file, or if the VMA doesn't intersect the memslot, memslot creation is
successful and KVM ends up with a VM with MTE and guest_memfd-backed
memslots.

The same happens if the order is reversed: when userspace enables MTE, KVM
does not check if memslots backed by guest_memfd are already present.

Fix both issues by rejecting guest_memfd-backed memslots when MTE is
enabled, and by reject MTE when guest_memfd-backed memslots are already
present.

Fixes: 32e200bd6e44 ("KVM: arm64: Enable support for guest_memfd backed memory")
Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
---

v1 can be found at [1].

Changes in v2:

* Added the Fixes tag (Fuad)
* Split the condition in kvm_arch_prepare_memory_region() (Fuad)
* Added the check in kvm_vm_ioctl_enable_cap() (Fuad)

Tested by using Fuad's patches to add guest_memfd support for kvmtool at [2],
with the following changes:

	diff --git a/arm64/kvm.c b/arm64/kvm.c
	index 36b3284e4a92..de83b5d7e517 100644
	--- a/arm64/kvm.c
	+++ b/arm64/kvm.c
	@@ -125,10 +125,12 @@ static void kvm__arch_enable_mte(struct kvm *kvm)
			return;
		}

	+       /*
		if (kvm->cfg.arch.guest_memfd) {
			pr_debug("MTE is incompatible with guest_memfd");
			return;
		}
	+       */

		if (kvm->cfg.arch.mte_disabled) {
			pr_debug("MTE disabled by user");
	diff --git a/kvm.c b/kvm.c
	index 96583f916442..cc8628b558ea 100644
	--- a/kvm.c
	+++ b/kvm.c
	@@ -332,8 +332,15 @@ int kvm__register_mem(struct kvm *kvm, u64 guest_phys, u64 size,
					.guest_memfd_offset     = guest_memfd_offset,
				};

	+                       if (munmap(userspace_addr, size) < 0)
	+                               die_perror("munmap hack");
	+
				ret = ioctl(kvm->vm_fd, KVM_SET_USER_MEMORY_REGION2,
					    &mem2);
	+
	+                       if (mmap(userspace_addr, size, PROT_RW, MAP_SHARED | MAP_FIXED,
	+                           guest_memfd, guest_memfd_offset) == MAP_FAILED)
	+                               die_perror("mmap hack");
			} else {
				struct kvm_userspace_memory_region mem = {
					.slot                   = slot,

(indentation is weird on purpose so git doesn't get confused). That's to
test that the user can create a guest_memfd memslot after MTE has been
enabled for the VM. Without this patch, I was able to create a VM with MTE
and guest_memfd backed ram (the guest reported MTE as enabled, but I didn't
test that it actually worked). With this patch, creating a VM with MTE is
rejected.

To test that KVM rejects enabling MTE *after* creating a guest_memfd backed
memslot, I modified kvmtool to enable MTE *after* creating the memslot.
Same situation: without this patch, KVM allows that, with this patch, KVM
rejects enabling MTE.

[1] https://lore.kernel.org/kvmarm/20260714110756.116950-1-alexandru.elisei@arm.com/
[2] https://lore.kernel.org/kvmarm/20260712142536.1391557-1-fuad.tabba@linux.dev/

 arch/arm64/kvm/arm.c | 25 +++++++++++++++++++------
 arch/arm64/kvm/mmu.c |  4 ++++
 2 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 50adfff75be8..9a6c72a18672 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -149,14 +149,27 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
 		set_bit(KVM_ARCH_FLAG_RETURN_NISV_IO_ABORT_TO_USER,
 			&kvm->arch.flags);
 		break;
-	case KVM_CAP_ARM_MTE:
-		mutex_lock(&kvm->lock);
-		if (system_supports_mte() && !kvm->created_vcpus) {
-			r = 0;
-			set_bit(KVM_ARCH_FLAG_MTE_ENABLED, &kvm->arch.flags);
+	case KVM_CAP_ARM_MTE: {
+		struct kvm_memory_slot *memslot;
+		int bkt;
+
+		guard(mutex)(&kvm->lock);
+		if (!system_supports_mte() || kvm->created_vcpus)
+			break;
+
+		r = 0;
+		guard(mutex)(&kvm->slots_lock);
+		kvm_for_each_memslot(memslot, bkt, kvm_memslots(kvm)) {
+			if (kvm_slot_has_gmem(memslot)) {
+				r = -EINVAL;
+				break;
+			}
 		}
-		mutex_unlock(&kvm->lock);
+		if (r == 0)
+			set_bit(KVM_ARCH_FLAG_MTE_ENABLED, &kvm->arch.flags);
 		break;
+
+	}
 	case KVM_CAP_ARM_SYSTEM_SUSPEND:
 		r = 0;
 		set_bit(KVM_ARCH_FLAG_SYSTEM_SUSPEND_ENABLED, &kvm->arch.flags);
diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index 6c941aaa10c6..2d95203386ba 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -2652,6 +2652,10 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
 	if (kvm_slot_has_gmem(new) && !kvm_memslot_is_gmem_only(new))
 		return -EINVAL;
 
+	/* guest_memfd is incompatible with MTE. */
+	if (kvm_slot_has_gmem(new) && kvm_has_mte(kvm))
+		return -EINVAL;
+
 	hva = new->userspace_addr;
 	reg_end = hva + (new->npages << PAGE_SHIFT);
 

base-commit: 1590cf0329716306e948a8fc29f1d3ee87d3989f
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-07-21  9:11 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-20 13:09 [PATCH v2] KVM: arm64: Reject guest_memfd memslots when the VM has MTE Alexandru Elisei
2026-07-20 15:20 ` Fuad Tabba
2026-07-20 15:46 ` Marc Zyngier
2026-07-21  9:10   ` Alexandru Elisei

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox