From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pj1-f73.google.com (mail-pj1-f73.google.com [209.85.216.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7670C349B19 for ; Wed, 18 Feb 2026 20:56:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.73 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771448188; cv=none; b=HW3fa3XWvONJDSZPmi7EcYHvuTgLN6cIx7xgdCGHHyl+6Yp4fvbcrrfV0s3KKRAy9qlFUvVPCruv8GB3+k+r/QBsbhZzzBfGa0Tw1QolKxyFfEkZyrbV9YVSW71juHWuqVs1yh7l7K4YAoH69QKiDGkfoIcFoaUmortlOgoI7gk= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771448188; c=relaxed/simple; bh=az8pKqGTqLPKEg70OjYkXanOeX00kgot4vjebxI5Rd0=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=uz3V4xwRsdBASaPiEeZxAkkcYym/w5jpsAaxADV95i9pvYydtelhzmUkmTOgUuryKly7nGRtI11PEmvOCcXEh64eidZrJajbAeUXcw5GUw1vDbKdDXC691iwTC51+r52JPNchObP6QH+494nwBGLk6vYqa8/HO++3gJDMvhZWoY= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--seanjc.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=m2hSGXQJ; arc=none smtp.client-ip=209.85.216.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--seanjc.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="m2hSGXQJ" Received: by mail-pj1-f73.google.com with SMTP id 98e67ed59e1d1-354c0eb08ceso1290586a91.1 for ; Wed, 18 Feb 2026 12:56:27 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1771448187; x=1772052987; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=Gre4sWSuNgzzkfFkiG0uuZShlGPNxvNAn5AYWvywWnE=; b=m2hSGXQJAlWbaUHKBljsoI8geiuHAv/HbSleOzF1KSGwv8+2HDC5213DKovJXr0bjI PM2XXLGc36moABtRJS04JGuV8mObZ4am2fhZ1wq+mFzRIwW9VfzC50BrEBb810OVOQ+r 0PgbMxsciyHJVXEIUL7DboLv7upKETDj3NHqop6WDwLCUyxrBefnuLLkSbpUSsfa2JqV 9NgBFJ054kFVcAhH2/pB2T2SjJEGi+R8U+uDVRq50kqY+dLjUjyjNYgTmLABPJwx0bCm brA7WgABuBjTxe2j0XUJq0JSYJawoA16bXzT6RFjWkq0hh5NtasYuohtH1OdX7gTgci5 +HGA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1771448187; x=1772052987; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=Gre4sWSuNgzzkfFkiG0uuZShlGPNxvNAn5AYWvywWnE=; b=AszDrWdePrX2ONQPyGuYj+g/rRyMfnj3mG+BV5ess21rzibvXSkafXsiqr07YlTt67 TEtsQMAxClq1OVMnIkukebl9grCfkSwwWKtQiNY1HyIXIWPt01Ca2rhlCwK43WDk2g+Z MZYJ0YgOit6bsIV72Zg7yTEZ6It28c49FIYak5nAab7UlK4GieSasHjxgsX3eeChNKuM 3hbsTY6mcZi3Ls3ke2m5Tc0EkV9Z8zFYuMkOK8+1w81DW2n/plXaJ+QdL/MD7i66tID7 3BL78NSU9FoXwGkqVB3cC9Q8uTi8qbxMucNVoEzjtkrAxgoQP3apejNcFfSkfLfSPtNN ZINQ== X-Forwarded-Encrypted: i=1; AJvYcCVRc0FgwrrRC9dc8jVyDmW1eMAcldAU2zp7TV+WH1U/hTEEoefdjQS+7ju2n8OJzqPWS1X2BNS0aSqk/xk=@vger.kernel.org X-Gm-Message-State: AOJu0Yxg73kJEUnvUljHndZGYqJLy8iFh96TIIf0o/Mo6Gl/9DYwQA2e c6fYtQ7P5/1uhZZku9nJTfXzKAyPyFiPCmhXly+MXf2YxkiNGMAAxmnbNJRXqnXHU73sWpUAp94 VwCPryA== X-Received: from pjzb12.prod.google.com ([2002:a17:90a:e38c:b0:353:454:939c]) (user=seanjc job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90b:5704:b0:356:4c1f:98d4 with SMTP id 98e67ed59e1d1-358890dda32mr2710883a91.13.1771448186543; Wed, 18 Feb 2026 12:56:26 -0800 (PST) Date: Wed, 18 Feb 2026 12:56:25 -0800 In-Reply-To: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <67a2f20537354628bcb835586a7c6255@huawei.com> Message-ID: Subject: Re: Re: [BUG REPORT] USE_AFTER_FREE in complete_emulated_mmio found by KASAN/Syzkaller fuzz test (v5.10.0) From: Sean Christopherson To: Zhangjiaji Cc: Paolo Bonzini , "kvm@vger.kernel.org" , "linux-kernel@vger.kernel.org" , "Wangqinxiao (Tom)" , zhangyashu , "wangyanan (Y)" Content-Type: text/plain; charset="us-ascii" On Tue, Feb 10, 2026, Sean Christopherson wrote: > On Tue, Feb 10, 2026, Zhangjiaji wrote: > > > I think there's a not-completely-awful solution buried in this gigantic cesspool. > > > The only time KVM uses on-stack variables is for qword or smaller accesses, i.e. > > > 8 bytes in size or less. For larger fragments, e.g. AVX to/from MMIO, the target > > > value will always be an operand in the emulator context. And so rather than > > > disallow stack variables, for "small" fragments, we can rework the handling to > > > copy the value to/from each fragment on-demand instead of stashing a pointer to > > > the value. > > > > Since we can store the frag->val in struct kvm_mmio_fragment, > > why not just point frag->data to it? This Way we can save a lot code about > > (frag->data == NULL). > > It's not quite that simple, because we need to handle reads as well. > > > Though this patch will block any read-into-stack calls, we can add a special path > > in function emulator_read_write handling feasible read-into-stack calls -- the > > target is released just after emulator_read_write returns. > > > > --- > > arch/x86/kvm/x86.c | 9 ++++++++- > > include/linux/kvm_host.h | 3 ++- > > 2 files changed, 10 insertions(+), 2 deletions(-) > > > > diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c > > index 72d37c8930ad..12d53d441a39 100644 > > --- a/arch/x86/kvm/x86.c > > +++ b/arch/x86/kvm/x86.c > > @@ -8197,7 +8197,14 @@ static int emulator_read_write_onepage(unsigned long addr, void *val, > > WARN_ON(vcpu->mmio_nr_fragments >= KVM_MAX_MMIO_FRAGMENTS); > > frag = &vcpu->mmio_fragments[vcpu->mmio_nr_fragments++]; > > frag->gpa = gpa; > > - frag->data = val; > > + if (bytes > 8u || ! write) { > > + if (WARN_ON_ONCE(object_is_on_stack(val))) > > This is user-triggerable, e.g. em_popa(), em_pop_sreg(), emulate_iret_real(), > em_ret_near_imm(), em_ret_far(), and em_ret(). *sigh* And I was wrong. I finally sat down to write some comments for all of this, and realized that reads _never_ pass an on-stack @val to emulator_read_write_onepage(), because read_emulated() always buffers reads through ctxt->mem_read. So not only is my fancy, complex code unnecessary, it's actively broken. If a read splits a page boundary, and the first page is NOT emulated MMIO, trying to fulfill the read on-demand falls apart because the @val points at the start of the operand (technically its cache "entry"). I'm sure that's a solvable problem, but I don't see any point in manufacturing a problem in the first place. I need to write a changelog, but as Yashu suggested, the fix can more simply be: -- From: Sean Christopherson Date: Tue, 10 Feb 2026 09:45:37 -0800 Subject: [PATCH 01/14] KVM: x86: Use scratch field in MMIO fragment to hold small write values Fixes: f78146b0f923 ("KVM: Fix page-crossing MMIO") Suggested-by: Yashu Zhang Reported-by: Yashu Zhang Closes: https://lore.kernel.org/all/369eaaa2b3c1425c85e8477066391bc7@huawei.com Cc: stable@vger.kernel.org Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 14 +++++++++++++- include/linux/kvm_host.h | 3 ++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index db3f393192d9..ff3a6f86973f 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -8226,7 +8226,13 @@ static int emulator_read_write_onepage(unsigned long addr, void *val, WARN_ON(vcpu->mmio_nr_fragments >= KVM_MAX_MMIO_FRAGMENTS); frag = &vcpu->mmio_fragments[vcpu->mmio_nr_fragments++]; frag->gpa = gpa; - frag->data = val; + if (write && bytes <= 8u) { + frag->val = 0; + frag->data = &frag->val; + memcpy(&frag->val, val, bytes); + } else { + frag->data = val; + } frag->len = bytes; return X86EMUL_CONTINUE; } @@ -8241,6 +8247,9 @@ static int emulator_read_write(struct x86_emulate_ctxt *ctxt, gpa_t gpa; int rc; + if (WARN_ON_ONCE((bytes > 8u || !ops->write) && object_is_on_stack(val))) + return X86EMUL_UNHANDLEABLE; + if (ops->read_write_prepare && ops->read_write_prepare(vcpu, val, bytes)) return X86EMUL_CONTINUE; @@ -11847,6 +11856,9 @@ static int complete_emulated_mmio(struct kvm_vcpu *vcpu) frag++; vcpu->mmio_cur_fragment++; } else { + if (WARN_ON_ONCE(frag->data == &frag->val)) + return -EIO; + /* Go forward to the next mmio piece. */ frag->data += len; frag->gpa += len; diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 2c7d76262898..0bb2a34fb93d 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -320,7 +320,8 @@ static inline bool kvm_vcpu_can_poll(ktime_t cur, ktime_t stop) struct kvm_mmio_fragment { gpa_t gpa; void *data; - unsigned len; + u64 val; + unsigned int len; }; struct kvm_vcpu { base-commit: 183bb0ce8c77b0fd1fb25874112bc8751a461e49 --