All of lore.kernel.org
 help / color / mirror / Atom feed
From: Sean Christopherson <seanjc@google.com>
To: Borislav Petkov <bp@alien8.de>
Cc: Andrew Morton <akpm@linux-foundation.org>,
	Nikola Ciprich <nikola.ciprich@linuxbox.cz>,
	 David Laight <david.laight.linux@gmail.com>,
	Rik van Riel <riel@surriel.com>,
	ljs@kernel.org,  linux-mm@kvack.org,
	linux-kernel@vger.kernel.org, david@kernel.org,
	 Mike Rapoport <rppt@kernel.org>,
	Dave Hansen <dave.hansen@linux.intel.com>,
	 Pedro Falcato <pfalcato@suse.de>,
	Kiryl Shutsemau <kas@kernel.org>,
	luizcap@redhat.com,  pbonzini@redhat.com,
	Tal Zussman <tz2294@columbia.edu>,
	 Matt Fleming <matt@readmodwrite.com>
Subject: Re: hunting memory corruption bug in 6.18.x
Date: Fri, 16 Oct 2026 08:16:26 -0700	[thread overview]
Message-ID: <atI_yuCc4BiweBQP@google.com> (raw)
In-Reply-To: <20261016054954.GEatG7AgMNFRkiTo1H@fat_crate.local>

On Thu, Oct 15, 2026, Borislav Petkov wrote:
> On Thu, Oct 15, 2026 at 09:18:32PM -0700, Andrew Morton wrote:
> > The corruption patterns strongly resemble AMD VMCB state, particularly
> > FS/GS segment data appearing at the expected VMCB offsets in unrelated
> > host memory.
> 
> Aha, ok.
> 
> > This suggests that a VMSAVE operation may have written to
> > an incorrect physical address.  Ordinary KVM performs VMLOAD/VMSAVE
> > without nested virtualization, so Boris's objection doesn't eliminate
> > this possibility.  However, the relevant assembly is essentially
> > unchanged between 6.18.55 and 7.3-rc6, and I haven't identified a newer
> > commit that convincingly explains why the corruption apparently stopped
> > reproducing.  The earlier candidate 55780d8a1dcc remains poorly
> > motivated without evidence of nested virtualization.
> > 
> > Two investigations look worthwhile.  First, test 6.18.55 with both the
> > KVM TLB-flush fix (26505e1b5b54)
> 
> Pff, we've been looking at that one recently too, trying to figure out whether
> it was really necessary.
> 
> > and tlbi=ipi;
> 
> Yeah, we checked that, it ain't that.
> 
> > the existing results don't conclusively establish whether that combination
> > was tested.  Second, examine the vmcore to determine whether the corrupted
> > host pages contain complete FS/GS state matching a legitimate VMCB, rather
> > than merely a few matching values.  If they do, inspect the VMCB's
> > VMLOAD/VMSAVE interception and virtualization-enable bits.  That could
> > establish whether a hardware VMSAVE was allowed to write to an unintended
> > physical page.  The successful 7.3-rc6/rc7 testing is encouraging, but it
> > doesn't yet prove that all the reported corruption symptoms share one cause
> > or have been fixed.
> 
> Hmm. I guess looking at and around VMSAVE handling wouldn't hurt...

@Nikola, as very long long-shot, can you try running with the below?  I don't
expect it to help or flag anything, but this is eerily similar to a known bug[*]
where KVM writes to user memory in the wrong address space (wrong process) when
tearing down a VM after migrating the VM.  But that bug (well, bugs) only affects
Intel, and I don't see any similar patterns on the AMD side.

[*] https://lore.kernel.org/all/20261001202234.3794060-1-seanjc@google.com

diff --git a/arch/x86/kvm/vmx/sgx.c b/arch/x86/kvm/vmx/sgx.c
index df1d0cf769475..fc0ae4727793b 100644
--- a/arch/x86/kvm/vmx/sgx.c
+++ b/arch/x86/kvm/vmx/sgx.c
@@ -63,7 +63,7 @@ static void sgx_handle_emulation_failure(struct kvm_vcpu *vcpu, u64 addr,
 static int sgx_read_hva(struct kvm_vcpu *vcpu, unsigned long hva, void *data,
 			unsigned int size)
 {
-	if (__copy_from_user(data, (void __user *)hva, size)) {
+	if (kvm_copy_from_user(vcpu->kvm, data, (void __user *)hva, size)) {
 		sgx_handle_emulation_failure(vcpu, hva, size);
 		return -EFAULT;
 	}
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index f65081330c8a4..2dec1463b596c 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -3902,16 +3902,16 @@ static int init_rmode_tss(struct kvm *kvm, void __user *ua)
 	int i;
 
 	for (i = 0; i < 3; i++) {
-		if (__copy_to_user(ua + PAGE_SIZE * i, zero_page, PAGE_SIZE))
+		if (kvm_copy_to_user(kvm, ua + PAGE_SIZE * i, zero_page, PAGE_SIZE))
 			return -EFAULT;
 	}
 
 	data = TSS_BASE_SIZE + TSS_REDIRECTION_SIZE;
-	if (__copy_to_user(ua + TSS_IOPB_BASE_OFFSET, &data, sizeof(u16)))
+	if (kvm_copy_to_user(kvm, ua + TSS_IOPB_BASE_OFFSET, &data, sizeof(u16)))
 		return -EFAULT;
 
 	data = ~0;
-	if (__copy_to_user(ua + RMODE_TSS_SIZE - 1, &data, sizeof(u8)))
+	if (kvm_copy_to_user(kvm, ua + RMODE_TSS_SIZE - 1, &data, sizeof(u8)))
 		return -EFAULT;
 
 	return 0;
@@ -3946,7 +3946,7 @@ static int init_rmode_identity_map(struct kvm *kvm)
 	for (i = 0; i < (PAGE_SIZE / sizeof(tmp)); i++) {
 		tmp = (i << 22) + (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER |
 			_PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_PSE);
-		if (__copy_to_user(uaddr + i * sizeof(tmp), &tmp, sizeof(tmp))) {
+		if (kvm_copy_to_user(kvm, uaddr + i * sizeof(tmp), &tmp, sizeof(tmp))) {
 			r = -EFAULT;
 			goto out;
 		}
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 3c4e2401de072..13f44961e6e7d 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -1341,13 +1341,35 @@ int kvm_write_guest_offset_cached(struct kvm *kvm, struct gfn_to_hva_cache *ghc,
 int kvm_gfn_to_hva_cache_init(struct kvm *kvm, struct gfn_to_hva_cache *ghc,
 			      gpa_t gpa, unsigned long len);
 
+static __always_inline __must_check bool kvm_can_do_uaccess(struct kvm *kvm)
+{
+	return !WARN_ON_ONCE(current->mm != kvm->mm ||
+			     !refcount_read(&kvm->users_count));
+}
+
+#define BUILD_KVM_COPY_USER_WRAPPER(fn, to_user, from_user)				\
+static __always_inline __must_check unsigned long kvm_##fn(struct kvm *kvm,		\
+							   void to_user *to,		\
+							   const void from_user *from,	\
+							   unsigned long n)		\
+{											\
+	if (!kvm_can_do_uaccess(kvm))							\
+		return n;								\
+											\
+	return __##fn(to, from, n);							\
+}
+BUILD_KVM_COPY_USER_WRAPPER(copy_from_user, , __user)
+BUILD_KVM_COPY_USER_WRAPPER(copy_from_user_inatomic, , __user)
+BUILD_KVM_COPY_USER_WRAPPER(copy_to_user, __user, )
+BUILD_KVM_COPY_USER_WRAPPER(copy_to_user_inatomic, __user, )
+
 #define __kvm_get_guest(kvm, gfn, offset, v)				\
 ({									\
 	unsigned long __addr = gfn_to_hva(kvm, gfn);			\
 	typeof(v) __user *__uaddr = (typeof(__uaddr))(__addr + offset);	\
 	int __ret = -EFAULT;						\
 									\
-	if (!kvm_is_error_hva(__addr))					\
+	if (!kvm_is_error_hva(__addr) && kvm_can_do_uaccess(kvm))	\
 		__ret = get_user(v, __uaddr);				\
 	__ret;								\
 })
@@ -1367,7 +1389,7 @@ int kvm_gfn_to_hva_cache_init(struct kvm *kvm, struct gfn_to_hva_cache *ghc,
 	typeof(v) __user *__uaddr = (typeof(__uaddr))(__addr + offset);	\
 	int __ret = -EFAULT;						\
 									\
-	if (!kvm_is_error_hva(__addr))					\
+	if (!kvm_is_error_hva(__addr) && kvm_can_do_uaccess(kvm))	\
 		__ret = put_user(v, __uaddr);				\
 	if (!__ret)							\
 		mark_page_dirty(kvm, gfn);				\
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index ba09b1dabc4b7..aa1564d41e7ff 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -3207,8 +3207,8 @@ static int next_segment(unsigned long len, int offset)
 }
 
 /* Copy @len bytes from guest memory at '(@gfn * PAGE_SIZE) + @offset' to @data */
-static int __kvm_read_guest_page(struct kvm_memory_slot *slot, gfn_t gfn,
-				 void *data, int offset, int len)
+static int __kvm_read_guest_page(struct kvm *kvm, struct kvm_memory_slot *slot,
+				 gfn_t gfn, void *data, int offset, int len)
 {
 	int r;
 	unsigned long addr;
@@ -3219,7 +3219,7 @@ static int __kvm_read_guest_page(struct kvm_memory_slot *slot, gfn_t gfn,
 	addr = gfn_to_hva_memslot_prot(slot, gfn, NULL);
 	if (kvm_is_error_hva(addr))
 		return -EFAULT;
-	r = __copy_from_user(data, (void __user *)addr + offset, len);
+	r = kvm_copy_from_user(kvm, data, (void __user *)addr + offset, len);
 	if (r)
 		return -EFAULT;
 	return 0;
@@ -3230,7 +3230,7 @@ int kvm_read_guest_page(struct kvm *kvm, gfn_t gfn, void *data, int offset,
 {
 	struct kvm_memory_slot *slot = gfn_to_memslot(kvm, gfn);
 
-	return __kvm_read_guest_page(slot, gfn, data, offset, len);
+	return __kvm_read_guest_page(kvm, slot, gfn, data, offset, len);
 }
 EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_read_guest_page);
 
@@ -3239,7 +3239,7 @@ int kvm_vcpu_read_guest_page(struct kvm_vcpu *vcpu, gfn_t gfn, void *data,
 {
 	struct kvm_memory_slot *slot = kvm_vcpu_gfn_to_memslot(vcpu, gfn);
 
-	return __kvm_read_guest_page(slot, gfn, data, offset, len);
+	return __kvm_read_guest_page(vcpu->kvm, slot, gfn, data, offset, len);
 }
 EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_vcpu_read_guest_page);
 
@@ -3283,8 +3283,8 @@ int kvm_vcpu_read_guest(struct kvm_vcpu *vcpu, gpa_t gpa, void *data, unsigned l
 }
 EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_vcpu_read_guest);
 
-static int __kvm_read_guest_atomic(struct kvm_memory_slot *slot, gfn_t gfn,
-			           void *data, int offset, unsigned long len)
+static int __kvm_read_guest_atomic(struct kvm *kvm, struct kvm_memory_slot *slot,
+				   gfn_t gfn, void *data, int offset, unsigned long len)
 {
 	int r;
 	unsigned long addr;
@@ -3296,7 +3296,7 @@ static int __kvm_read_guest_atomic(struct kvm_memory_slot *slot, gfn_t gfn,
 	if (kvm_is_error_hva(addr))
 		return -EFAULT;
 	pagefault_disable();
-	r = __copy_from_user_inatomic(data, (void __user *)addr + offset, len);
+	r = kvm_copy_from_user_inatomic(kvm, data, (void __user *)addr + offset, len);
 	pagefault_enable();
 	if (r)
 		return -EFAULT;
@@ -3310,7 +3310,7 @@ int kvm_vcpu_read_guest_atomic(struct kvm_vcpu *vcpu, gpa_t gpa,
 	struct kvm_memory_slot *slot = kvm_vcpu_gfn_to_memslot(vcpu, gfn);
 	int offset = offset_in_page(gpa);
 
-	return __kvm_read_guest_atomic(slot, gfn, data, offset, len);
+	return __kvm_read_guest_atomic(vcpu->kvm, slot, gfn, data, offset, len);
 }
 EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_vcpu_read_guest_atomic);
 
@@ -3328,7 +3328,7 @@ static int __kvm_write_guest_page(struct kvm *kvm,
 	addr = gfn_to_hva_memslot(memslot, gfn);
 	if (kvm_is_error_hva(addr))
 		return -EFAULT;
-	r = __copy_to_user((void __user *)addr + offset, data, len);
+	r = kvm_copy_to_user(kvm, (void __user *)addr + offset, data, len);
 	if (r)
 		return -EFAULT;
 	mark_page_dirty_in_slot(kvm, memslot, gfn);
@@ -3466,7 +3466,7 @@ int kvm_write_guest_offset_cached(struct kvm *kvm, struct gfn_to_hva_cache *ghc,
 	if (unlikely(!ghc->memslot))
 		return kvm_write_guest(kvm, gpa, data, len);
 
-	r = __copy_to_user((void __user *)ghc->hva + offset, data, len);
+	r = kvm_copy_to_user(kvm, (void __user *)ghc->hva + offset, data, len);
 	if (r)
 		return -EFAULT;
 	mark_page_dirty_in_slot(kvm, ghc->memslot, gpa >> PAGE_SHIFT);
@@ -3504,7 +3504,7 @@ int kvm_read_guest_offset_cached(struct kvm *kvm, struct gfn_to_hva_cache *ghc,
 	if (unlikely(!ghc->memslot))
 		return kvm_read_guest(kvm, gpa, data, len);
 
-	r = __copy_from_user(data, (void __user *)ghc->hva + offset, len);
+	r = kvm_copy_from_user(kvm, data, (void __user *)ghc->hva + offset, len);
 	if (r)
 		return -EFAULT;



  reply	other threads:[~2026-10-16 15:16 UTC|newest]

Thread overview: 43+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-25  8:48 hunting memory corruption bug in 6.18.x Nikola Ciprich
2026-09-25 10:05 ` Lorenzo Stoakes (ARM)
2026-09-25 12:13 ` Lorenzo Stoakes (ARM)
2026-09-26  5:58   ` Nikola Ciprich
2026-09-26  9:32     ` Lorenzo Stoakes (ARM)
2026-09-28  9:05       ` Nikola Ciprich
2026-09-29 19:11         ` Nikola Ciprich
2026-09-30  9:07           ` Lorenzo Stoakes (ARM)
2026-09-30 18:40             ` Nikola Ciprich
2026-10-01 19:40               ` Nikola Ciprich
2026-10-01 22:21                 ` David Laight
2026-10-02  9:50                 ` Lorenzo Stoakes (ARM)
2026-10-02 14:55                   ` Nikola Ciprich
2026-10-02 19:27                     ` Lorenzo Stoakes (ARM)
2026-10-04 18:40                       ` Nikola Ciprich
2026-10-05 11:25                         ` Rik van Riel
2026-10-05 19:02                           ` Nikola Ciprich
     [not found]                           ` <20261005132113.43548696@pumpkin>
2026-10-05 19:25                             ` Nikola Ciprich
2026-10-08 12:29                               ` Nikola Ciprich
2026-10-08 18:23                                 ` Borislav Petkov
2026-10-08 20:48                                   ` Nikola Ciprich
2026-10-09  8:00                                   ` David Laight
2026-10-12 11:43                                     ` Nikola Ciprich
2026-10-14 23:53                                       ` Borislav Petkov
2026-10-15  9:10                                         ` Nikola Ciprich
2026-10-15 22:11                                           ` Borislav Petkov
2026-10-14 23:57                                       ` Borislav Petkov
2026-10-15  9:14                                         ` Nikola Ciprich
2026-10-15 22:15                                           ` Borislav Petkov
2026-10-16  0:28                                         ` Andrew Morton
2026-10-16  3:12                                           ` Borislav Petkov
2026-10-16  4:18                                             ` Andrew Morton
2026-10-16  5:49                                               ` Borislav Petkov
2026-10-16 15:16                                                 ` Sean Christopherson [this message]
2026-10-02 22:02                     ` Borislav Petkov
2026-10-04 18:45                       ` Nikola Ciprich
2026-10-05 10:58                 ` Rik van Riel
2026-10-05 18:05                   ` Nikola Ciprich
2026-09-26 16:02 ` Luiz Capitulino
2026-09-28  8:47   ` Nikola Ciprich
2026-10-04 22:20 ` Rik van Riel
2026-10-05  9:31   ` Nikola Ciprich
2026-10-05  8:31 ` Lance Yang

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=atI_yuCc4BiweBQP@google.com \
    --to=seanjc@google.com \
    --cc=akpm@linux-foundation.org \
    --cc=bp@alien8.de \
    --cc=dave.hansen@linux.intel.com \
    --cc=david.laight.linux@gmail.com \
    --cc=david@kernel.org \
    --cc=kas@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=ljs@kernel.org \
    --cc=luizcap@redhat.com \
    --cc=matt@readmodwrite.com \
    --cc=nikola.ciprich@linuxbox.cz \
    --cc=pbonzini@redhat.com \
    --cc=pfalcato@suse.de \
    --cc=riel@surriel.com \
    --cc=rppt@kernel.org \
    --cc=tz2294@columbia.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.