The following commit has been merged into the x86/mm branch of tip: Commit-ID: 9e4ce48087db09c0788a02fb2fd19f24c7f81529 Gitweb: https://git.kernel.org/tip/9e4ce48087db09c0788a02fb2fd19f24c7f81529 Author: Kirill A. Shutemov <kirill.shutemov@xxxxxxxxxxxxxxx> AuthorDate: Wed, 09 Nov 2022 19:51:30 +03:00 Committer: Dave Hansen <dave.hansen@xxxxxxxxxxxxxxx> CommitterDate: Fri, 11 Nov 2022 13:28:07 -08:00 KVM: Serialize tagged address check against tagging enabling KVM forbids usage of tagged userspace addresses for memslots. It is done by checking if the address stays the same after untagging. It is works fine for ARM TBI, but it the check gets racy for LAM. TBI enabling happens per-thread, so nobody can enable tagging for the thread while the memslot gets added. LAM gets enabled per-process. If it gets enabled after the untagged_addr() check, but before access_ok() check the kernel can wrongly allow tagged userspace_addr. Use mmap lock to protect against parallel LAM enabling. Reported-by: Rick Edgecombe <rick.p.edgecombe@xxxxxxxxx> Signed-off-by: Kirill A. Shutemov <kirill.shutemov@xxxxxxxxxxxxxxx> Signed-off-by: Dave Hansen <dave.hansen@xxxxxxxxxxxxxxx> Link: https://lore.kernel.org/all/20221109165140.9137-7-kirill.shutemov%40linux.intel.com --- virt/kvm/kvm_main.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index d213990..8399aae 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -1943,12 +1943,22 @@ int __kvm_set_memory_region(struct kvm *kvm, return -EINVAL; if (mem->guest_phys_addr & (PAGE_SIZE - 1)) return -EINVAL; + + /* Serialize against tagging enabling */ + if (mmap_read_lock_killable(kvm->mm)) + return -EINTR; + /* We can read the guest memory with __xxx_user() later on. */ if ((mem->userspace_addr & (PAGE_SIZE - 1)) || (mem->userspace_addr != untagged_addr(kvm->mm, mem->userspace_addr)) || !access_ok((void __user *)(unsigned long)mem->userspace_addr, - mem->memory_size)) + mem->memory_size)) { + mmap_read_unlock(kvm->mm); return -EINVAL; + } + + mmap_read_unlock(kvm->mm); + if (as_id >= KVM_ADDRESS_SPACE_NUM || id >= KVM_MEM_SLOTS_NUM) return -EINVAL; if (mem->guest_phys_addr + mem->memory_size < mem->guest_phys_addr)