* [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; 3+ 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] 3+ messages in thread
* Re: [PATCH v2] KVM: arm64: Reject guest_memfd memslots when the VM has MTE
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
1 sibling, 0 replies; 3+ messages in thread
From: Fuad Tabba @ 2026-07-20 15:20 UTC (permalink / raw)
To: Alexandru Elisei
Cc: maz, oupton, joey.gouly, seiden, suzuki.poulose, yuzenghui,
linux-arm-kernel, kvmarm, catalin.marinas, will, steven.price
On Mon, 20 Jul 2026 at 14:10, Alexandru Elisei <alexandru.elisei@arm.com> wrote:
>
> 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>
Reviewed-by: Fuad Tabba <fuad.tabba@linux.dev>
Tested-by: Fuad Tabba < fuad.tabba@linux.dev>
Cheers,
/fuad
> ---
>
> 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 [flat|nested] 3+ messages in thread
* Re: [PATCH v2] KVM: arm64: Reject guest_memfd memslots when the VM has MTE
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
1 sibling, 0 replies; 3+ messages in thread
From: Marc Zyngier @ 2026-07-20 15:46 UTC (permalink / raw)
To: Alexandru Elisei
Cc: oupton, joey.gouly, seiden, suzuki.poulose, yuzenghui,
linux-arm-kernel, kvmarm, catalin.marinas, will, steven.price,
fuad.tabba
On Mon, 20 Jul 2026 14:09:42 +0100,
Alexandru Elisei <alexandru.elisei@arm.com> wrote:
>
> 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>
This looks reasonable to me, but you probably want to capture some of
that in the documentation one way or another, because this will leave
the amateur VMM author puzzled for a bit...
Thanks,
M.
--
Without deviation from the norm, progress is not possible.
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-07-20 15:46 UTC | newest]
Thread overview: 3+ 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
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.