From nobody Wed Apr 15 16:24:10 2026 Received: from mail-pl1-f202.google.com (mail-pl1-f202.google.com [209.85.214.202]) (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 A6A842C028B for ; Wed, 4 Mar 2026 00:22:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772583749; cv=none; b=rKawugpB84bwXXn08f5X2O+KmXlPHedb6kfO/2F53+wAriJGTIT6wthPOcsM8DUCJK1BQZKlkqsPrwn7MVqfxA44LdqQk4ZVtoyqWesZ6VfNIj+pG6nUccwEqMPv6bBHGrzqbFk+idEOfPHncJEQx3UY9Q75GYzlPRFiBRsbU4E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772583749; c=relaxed/simple; bh=Ck6UOjQ5l9IPeUj0AuHo5TInOYDQijB57LOwr0XEFvg=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=DXWQbo7t85gEWHna5Iwa+ZtYSI8Qr+/I7mi3H2cCbbuBqtrhOXTWiwk4BmfibN3dC+ePYrLWqqBYIxj0JYFSZEvni2zxMbjg2TPdJaSm+9k0ZkdUXuGfWXxGb9Ai/8w2+4puv040UqmsBC0cCZ8lsysQHifLI2HXoUzrHACKjqg= 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=sdpjFRaD; arc=none smtp.client-ip=209.85.214.202 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="sdpjFRaD" Received: by mail-pl1-f202.google.com with SMTP id d9443c01a7336-2ae48a21d12so21288155ad.1 for ; Tue, 03 Mar 2026 16:22:28 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1772583748; x=1773188548; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:reply-to:from:to:cc:subject:date:message-id:reply-to; bh=MgLfV/AlTi0QspD6Lj2GwHa9tuqm7EnMjJUIM2Fpook=; b=sdpjFRaDiCgJ4VvI3tMHTr3RSuLAdLcAA8ppnyiTmS8AMVesQzx84jMWmEXlev+47Z FShlA15Z6gTfSdJfoRvvugRjazdc7kY4IY6SpQbCOFs59BnBhagek4jIJ4mSfZ4mT9kB SR8LgKMztSh4w1S0XdQpg3zsJgakjbRlxUUcrXXGYfexvu0E/cBTKJGze/ERAjuajMVP wVJnJuON1aFN0x0fcjS46Mfj9SIMuGQA/b+taxChN6pGqyy7SX/LcR723jd6DKWdIPmG dJtcWj0AuJlrHTJgDtobZWCUuI8k47p6/5LzRyNctCed1GLI0F0BsYo7cbxnZDmn131u /Eug== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1772583748; x=1773188548; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:reply-to:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=MgLfV/AlTi0QspD6Lj2GwHa9tuqm7EnMjJUIM2Fpook=; b=BjN+gxqNk+9hB0qPMgvR0AVxflt1KQYUJpRjzWlV3UIdDzhECFOa/vBKvZqYVd/YoZ I/941huRsvIj28ZVWA1XTYqoNerPgplvDeoK4XThnMXPW7mx1DQphnRhm8SK+qV/Wy98 bHIQns6gNBFyY+BKQZ4xYAIu7bHiLRO/TQNK32k+SaEiImhrTvw3lbuWdwrpv2sLC5E9 Oag7e5t+nqARHjVzNO5btzPvCfsNGubp2pGM+xvhPdZQLhgoV5GoilHihZsPdnJLvCrI JuaBgCO8UTWrdk7ORFnHmyMUpw4kHUhX5Evr9LeXWLvkygNBODL7x2f9F5fEClYTW803 wLyA== X-Forwarded-Encrypted: i=1; AJvYcCU9amSDek3sHi4Z/q4M5XTfj5h9Gx2IHUAUgOHD7a5NfTg9gBWHWbUhK3d0Fql0rDaZIvQPd4HCR3KFb1s=@vger.kernel.org X-Gm-Message-State: AOJu0Yx8wMt4DR2sS/OsDCmbbeiH6MemQ5UkI7jm9WTyMu+JNYMKY50y qAaVEguxKmhqywBcRP4waYyTkiA8tL+fvcPlAQ+AdSknhzPhP+bb3Uqp0uKBUAmtoxSHWwFQdG5 UW7KUqQ== X-Received: from pltg3.prod.google.com ([2002:a17:902:6b43:b0:2a9:5a6e:3616]) (user=seanjc job=prod-delivery.src-stubby-dispatcher) by 2002:a17:902:e888:b0:2ae:48a0:33e3 with SMTP id d9443c01a7336-2ae6ab782d2mr2333325ad.45.1772583747859; Tue, 03 Mar 2026 16:22:27 -0800 (PST) Reply-To: Sean Christopherson Date: Tue, 3 Mar 2026 16:22:22 -0800 In-Reply-To: <20260304002223.1105129-1-seanjc@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260304002223.1105129-1-seanjc@google.com> X-Mailer: git-send-email 2.53.0.473.g4a7958ca14-goog Message-ID: <20260304002223.1105129-2-seanjc@google.com> Subject: [PATCH v5 1/2] KVM: nSVM: Raise #UD if unhandled VMMCALL isn't intercepted by L1 From: Sean Christopherson To: Vitaly Kuznetsov , Sean Christopherson , Paolo Bonzini Cc: kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Kevin Cheng Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Kevin Cheng Explicitly synthesize a #UD for VMMCALL if L2 is active, L1 does NOT want to intercept VMMCALL, nested_svm_l2_tlb_flush_enabled() is true, and the hypercall is something other than one of the supported Hyper-V hypercalls. When all of the above conditions are met, KVM will intercept VMMCALL but never forward it to L1, i.e. will let L2 make hypercalls as if it were L1. The TLFS says a whole lot of nothing about this scenario, so go with the architectural behavior, which says that VMMCALL #UDs if it's not intercepted. Opportunistically do a 2-for-1 stub trade by stub-ifying the new API instead of the helpers it uses. The last remaining "single" stub will soon be dropped as well. Suggested-by: Sean Christopherson Fixes: 3f4a812edf5c ("KVM: nSVM: hyper-v: Enable L2 TLB flush") Cc: Vitaly Kuznetsov Cc: stable@vger.kernel.org Signed-off-by: Kevin Cheng Link: https://patch.msgid.link/20260228033328.2285047-5-chengkev@google.com [sean: rewrite changelog and comment, tag for stable, remove defunct stubs] Signed-off-by: Sean Christopherson Reviewed-by: Vitaly Kuznetsov Reviewed-by: Yosry Ahmed --- arch/x86/kvm/hyperv.h | 8 -------- arch/x86/kvm/svm/hyperv.h | 11 +++++++++++ arch/x86/kvm/svm/nested.c | 4 +--- arch/x86/kvm/svm/svm.c | 19 ++++++++++++++++++- 4 files changed, 30 insertions(+), 12 deletions(-) diff --git a/arch/x86/kvm/hyperv.h b/arch/x86/kvm/hyperv.h index 6ce160ffa678..6301f79fcbae 100644 --- a/arch/x86/kvm/hyperv.h +++ b/arch/x86/kvm/hyperv.h @@ -305,14 +305,6 @@ static inline bool kvm_hv_has_stimer_pending(struct kv= m_vcpu *vcpu) { return false; } -static inline bool kvm_hv_is_tlb_flush_hcall(struct kvm_vcpu *vcpu) -{ - return false; -} -static inline bool guest_hv_cpuid_has_l2_tlb_flush(struct kvm_vcpu *vcpu) -{ - return false; -} static inline int kvm_hv_verify_vp_assist(struct kvm_vcpu *vcpu) { return 0; diff --git a/arch/x86/kvm/svm/hyperv.h b/arch/x86/kvm/svm/hyperv.h index d3f8bfc05832..9af03970d40c 100644 --- a/arch/x86/kvm/svm/hyperv.h +++ b/arch/x86/kvm/svm/hyperv.h @@ -41,6 +41,13 @@ static inline bool nested_svm_l2_tlb_flush_enabled(struc= t kvm_vcpu *vcpu) return hv_vcpu->vp_assist_page.nested_control.features.directhypercall; } =20 +static inline bool nested_svm_is_l2_tlb_flush_hcall(struct kvm_vcpu *vcpu) +{ + return guest_hv_cpuid_has_l2_tlb_flush(vcpu) && + nested_svm_l2_tlb_flush_enabled(vcpu) && + kvm_hv_is_tlb_flush_hcall(vcpu); +} + void svm_hv_inject_synthetic_vmexit_post_tlb_flush(struct kvm_vcpu *vcpu); #else /* CONFIG_KVM_HYPERV */ static inline void nested_svm_hv_update_vm_vp_ids(struct kvm_vcpu *vcpu) {} @@ -48,6 +55,10 @@ static inline bool nested_svm_l2_tlb_flush_enabled(struc= t kvm_vcpu *vcpu) { return false; } +static inline bool nested_svm_is_l2_tlb_flush_hcall(struct kvm_vcpu *vcpu) +{ + return false; +} static inline void svm_hv_inject_synthetic_vmexit_post_tlb_flush(struct kv= m_vcpu *vcpu) {} #endif /* CONFIG_KVM_HYPERV */ =20 diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c index 53ab6ce3cc26..750bf93c5341 100644 --- a/arch/x86/kvm/svm/nested.c +++ b/arch/x86/kvm/svm/nested.c @@ -1674,9 +1674,7 @@ int nested_svm_exit_special(struct vcpu_svm *svm) } case SVM_EXIT_VMMCALL: /* Hyper-V L2 TLB flush hypercall is handled by L0 */ - if (guest_hv_cpuid_has_l2_tlb_flush(vcpu) && - nested_svm_l2_tlb_flush_enabled(vcpu) && - kvm_hv_is_tlb_flush_hcall(vcpu)) + if (nested_svm_is_l2_tlb_flush_hcall(vcpu)) return NESTED_EXIT_HOST; break; default: diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 8f8bc863e214..38a2fad81ad8 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -52,6 +52,7 @@ #include "svm.h" #include "svm_ops.h" =20 +#include "hyperv.h" #include "kvm_onhyperv.h" #include "svm_onhyperv.h" =20 @@ -3228,6 +3229,22 @@ static int bus_lock_exit(struct kvm_vcpu *vcpu) return 0; } =20 +static int vmmcall_interception(struct kvm_vcpu *vcpu) +{ + /* + * Inject a #UD if L2 is active and the VMMCALL isn't a Hyper-V TLB + * hypercall, as VMMCALL #UDs if it's not intercepted, and this path is + * reachable if and only if L1 doesn't want to intercept VMMCALL or has + * enabled L0 (KVM) handling of Hyper-V L2 TLB flush hypercalls. + */ + if (is_guest_mode(vcpu) && !nested_svm_is_l2_tlb_flush_hcall(vcpu)) { + kvm_queue_exception(vcpu, UD_VECTOR); + return 1; + } + + return kvm_emulate_hypercall(vcpu); +} + static int (*const svm_exit_handlers[])(struct kvm_vcpu *vcpu) =3D { [SVM_EXIT_READ_CR0] =3D cr_interception, [SVM_EXIT_READ_CR3] =3D cr_interception, @@ -3278,7 +3295,7 @@ static int (*const svm_exit_handlers[])(struct kvm_vc= pu *vcpu) =3D { [SVM_EXIT_TASK_SWITCH] =3D task_switch_interception, [SVM_EXIT_SHUTDOWN] =3D shutdown_interception, [SVM_EXIT_VMRUN] =3D vmrun_interception, - [SVM_EXIT_VMMCALL] =3D kvm_emulate_hypercall, + [SVM_EXIT_VMMCALL] =3D vmmcall_interception, [SVM_EXIT_VMLOAD] =3D vmload_interception, [SVM_EXIT_VMSAVE] =3D vmsave_interception, [SVM_EXIT_STGI] =3D stgi_interception, --=20 2.53.0.473.g4a7958ca14-goog From nobody Wed Apr 15 16:24:10 2026 Received: from mail-pg1-f202.google.com (mail-pg1-f202.google.com [209.85.215.202]) (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 CE6FC2EFDAF for ; Wed, 4 Mar 2026 00:22:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772583751; cv=none; b=O2/3UDkf8OzE8o14uYrynarxoXCCP/SvPjj7fVO9QG8ZPo+8ELWoKsSBVLwRmI/yx2wg0VshFrYnsAY55tTHn1oLQS3HY/oYeig4SE7UfSkzKv/5P5TzZYWCI3x8CVwQ+hqzyTOnnCxS8z1rkEVb5MBOjKP9R0TXrWSKemJhxiI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772583751; c=relaxed/simple; bh=NPX7a4G73+QzySINrUOAjawzHqN9/zKfXL/heyEw3GA=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=Qfdi85ZQEkXDGAzFmZVGiNi63nMpds2BiaCSSpqFb5+XsKnfhVeN/Hc2g7jmOP0+vd2vaCmBZmt+Ftt45wG0WUZ5yZy3S8P6juGehMXSP85hwfAwqlk0y99gEJqhn4ZAwf17skVjusvIiDEiQCRVPMtineqH0xOoMULHZbLY+T0= 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=bXhmFLjX; arc=none smtp.client-ip=209.85.215.202 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="bXhmFLjX" Received: by mail-pg1-f202.google.com with SMTP id 41be03b00d2f7-c70f2120583so3532993a12.3 for ; Tue, 03 Mar 2026 16:22:30 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1772583750; x=1773188550; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:reply-to:from:to:cc:subject:date:message-id:reply-to; bh=kDpA+UvHfqu2KXcEE0BeLwUh8qWoHNo3iiEgddOUlSA=; b=bXhmFLjXMt+jLLcLnKC2YEU2Gnh2U1iyyAa8t65BE5dhOjbRzMMY4b344ChMsOSfMO tFq3Ef2v6rhqpSYBBVRwc9ecplKQ+pHU7e/593QMeaZnY1bFUbI7YVNhbo2DOr+DyvCv e3Gj4L/Hhpb0rmfr/aT3HazUyTYD2Ot00x/vzpod9/SZzPAkjA1/YRqFtEZm1Nvd/RTn 5gl8H/PLZTFwJwxKvp8veQCsl4l/oADvwgex0MYsdDJPJerU76UFrL1j8Eh8RHPIdEWQ 2/3MWAwNSo7elG1HRt9ILmL0LSkZ0iQGN+AfWJFOj5+RvOEjxPZp9EsYu4JsjFgDYhOZ ZdRg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1772583750; x=1773188550; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:reply-to:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=kDpA+UvHfqu2KXcEE0BeLwUh8qWoHNo3iiEgddOUlSA=; b=do414Cw2L1H+x0o9ucDUxUh0FdWnk+Qpe39zRFgyykF5Mo15fVAm33drRi6D3Dh1p5 GhugN5AoeV9w10l+8miUuC/OuaTC5t1BHuSsoE2pxI+9Mhi95sLxRTvqqnzi/GqF9f/V mwf1LNH/MIzWCREZsAFF7u0Fh6tIR0cLwf2k5RNNAzJghDOJfTqYa7cKRXdX6g4dU3I7 nUsC7z28n1G4fS/cAvOwLrEhp5+sfJMWJz2kvPzkAn6iFcI4kkdprzPglcM4lpfxR6Y+ 5AP+wLRTgvUW1NfjY5v9YgXypeg4ecaulHsIjpIFbiNNQqOecU9WMprc1RkQzLvxWH7x SQ4g== X-Forwarded-Encrypted: i=1; AJvYcCV150KYM49LMVjDAX6wOe3mTjEv+TSPdj1bTIjdrTooDEgYRZhm5n4lMpJKkD4p+JeGqm5E+hmjv7EkCYU=@vger.kernel.org X-Gm-Message-State: AOJu0Yx+oZrR9g9Y+lRB6LtB1rd+Owsn8H3tERYUT56IXhNu+pPe3oJD 6pw+xypUUGJZ7dvLh+PIEGtf3X6qv3JSiGo6mJtRYVzOhojsizPp1sc8zc6figCwqK/Kwi4ydbz yWklpfg== X-Received: from pgpc1.prod.google.com ([2002:a63:a441:0:b0:bc0:ea34:538]) (user=seanjc job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a21:4598:b0:395:cb87:dd6b with SMTP id adf61e73a8af0-3982ded303emr99556637.28.1772583749893; Tue, 03 Mar 2026 16:22:29 -0800 (PST) Reply-To: Sean Christopherson Date: Tue, 3 Mar 2026 16:22:23 -0800 In-Reply-To: <20260304002223.1105129-1-seanjc@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260304002223.1105129-1-seanjc@google.com> X-Mailer: git-send-email 2.53.0.473.g4a7958ca14-goog Message-ID: <20260304002223.1105129-3-seanjc@google.com> Subject: [PATCH v5 2/2] KVM: nSVM: Always intercept VMMCALL when L2 is active From: Sean Christopherson To: Vitaly Kuznetsov , Sean Christopherson , Paolo Bonzini Cc: kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Kevin Cheng Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Always intercept VMMCALL now that KVM properly synthesizes a #UD as appropriate, i.e. when L1 doesn't want to intercept VMMCALL, to avoid putting L2 into an infinite #UD loop if KVM_X86_QUIRK_FIX_HYPERCALL_INSN is enabled. By letting L2 execute VMMCALL natively and thus #UD, for all intents and purposes KVM morphs the VMMCALL intercept into a #UD intercept (KVM always intercepts #UD). When the hypercall quirk is enabled, KVM "emulates" VMMCALL in response to the #UD by trying to fixup the opcode to the "right" vendor, then restarts the guest, without skipping the VMMCALL. As a result, the guest sees an endless stream of #UDs since it's already executing the correct vendor hypercall instruction, i.e. the emulator doesn't anticipate that the #UD could be due to lack of interception, as opposed to a truly undefined opcode. Fixes: 0d945bd93511 ("KVM: SVM: Don't allow nested guest to VMMCALL into ho= st") Cc: stable@vger.kernel.org Signed-off-by: Sean Christopherson Reviewed-by: Vitaly Kuznetsov Reviewed-by: Yosry Ahmed --- arch/x86/kvm/svm/hyperv.h | 4 ---- arch/x86/kvm/svm/nested.c | 7 ------- 2 files changed, 11 deletions(-) diff --git a/arch/x86/kvm/svm/hyperv.h b/arch/x86/kvm/svm/hyperv.h index 9af03970d40c..f70d076911a6 100644 --- a/arch/x86/kvm/svm/hyperv.h +++ b/arch/x86/kvm/svm/hyperv.h @@ -51,10 +51,6 @@ static inline bool nested_svm_is_l2_tlb_flush_hcall(stru= ct kvm_vcpu *vcpu) void svm_hv_inject_synthetic_vmexit_post_tlb_flush(struct kvm_vcpu *vcpu); #else /* CONFIG_KVM_HYPERV */ static inline void nested_svm_hv_update_vm_vp_ids(struct kvm_vcpu *vcpu) {} -static inline bool nested_svm_l2_tlb_flush_enabled(struct kvm_vcpu *vcpu) -{ - return false; -} static inline bool nested_svm_is_l2_tlb_flush_hcall(struct kvm_vcpu *vcpu) { return false; diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c index 750bf93c5341..2ac28d2c34ca 100644 --- a/arch/x86/kvm/svm/nested.c +++ b/arch/x86/kvm/svm/nested.c @@ -156,13 +156,6 @@ void recalc_intercepts(struct vcpu_svm *svm) vmcb_clr_intercept(c, INTERCEPT_VINTR); } =20 - /* - * We want to see VMMCALLs from a nested guest only when Hyper-V L2 TLB - * flush feature is enabled. - */ - if (!nested_svm_l2_tlb_flush_enabled(&svm->vcpu)) - vmcb_clr_intercept(c, INTERCEPT_VMMCALL); - for (i =3D 0; i < MAX_INTERCEPT; i++) c->intercepts[i] |=3D g->intercepts[i]; =20 --=20 2.53.0.473.g4a7958ca14-goog