Message ID | 20230210003148.2646712-6-seanjc@google.com |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:eb09:0:0:0:0:0 with SMTP id s9csp660635wrn; Thu, 9 Feb 2023 16:33:42 -0800 (PST) X-Google-Smtp-Source: AK7set97wkpQwPKfzDxACRs36FNmIEhyZn/qa+mFwzz23D3jEmv7BrBzk+MOVjWPzw7EXv3vuvxk X-Received: by 2002:a17:906:eb03:b0:889:1734:566a with SMTP id mb3-20020a170906eb0300b008891734566amr12757483ejb.76.1675989222516; Thu, 09 Feb 2023 16:33:42 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1675989222; cv=none; d=google.com; s=arc-20160816; b=ebNZhsDpSPKF742id6RrtLBlbcpAyycFaI5+frAZ3eXF2mGuPrHhJwzrAhDcs0lm9K Xg+Snv62uSozKnw3w8L36u7xeDBt0bAzqZMJ8xun3Ho5cQDFuv2p6a/a3KNq/c/TYv2K aW2iKaM/5AD5a40kCopQeClpxEtFRvxQtek5CgeRXtPhhTg/J4lNH6PjM+3kLhKrxd00 1/PjdQlPxWUCNUunXH7CGtRMx8Nm6oV3MG0sdo2u/mTPcxWO5DhtEsTe5YnNGus7MvaE KXsXHaEi2kTuz6NQfXsDkmD5XuddeWZ39PAkCiNqDq031C51CIAnw2bH35CkWvzLk1hF L4tw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:reply-to:dkim-signature; bh=00HAzMjPVYVZpNNjib7OPhFskVadeKfZTgeX842t58U=; b=fOoCRqQj6lpXn7RjTEvQBdMWhpeDG/W/D1Y1bE90O2bisiZzQ21AR857AjTNR2zGvx pS+tVBys5PIQALMzil0JolWTxT0RLyEDGyPaOfXa5vR+dW9nkU80XaU9KoYQDJzITP5x Vp2luX8/dCWvMozT+jhsc2/is6K5kzSa30IcGlNGuqPhQ+7izEesqdDs3HdV83H5sj/O O9XsFv8SSUU8AwRKXVQGIavxHV9Dgj5WDhJt7Q9g/ZZWu6mZyGwuvBEtjXfh4WeHxcY1 gE5KmSct28Bvo+rV0yqJbWHj4ceFLfZbOVbZO6JBHp04FZT5ThHkc8ROhnQYW3JWKraz qEXQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=aBtzaPE8; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id ep11-20020a1709069b4b00b008a6109abff5si3587772ejc.815.2023.02.09.16.33.18; Thu, 09 Feb 2023 16:33:42 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=aBtzaPE8; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230198AbjBJAcX (ORCPT <rfc822;ybw1215001957@gmail.com> + 99 others); Thu, 9 Feb 2023 19:32:23 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53022 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230174AbjBJAcQ (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Thu, 9 Feb 2023 19:32:16 -0500 Received: from mail-pj1-x1049.google.com (mail-pj1-x1049.google.com [IPv6:2607:f8b0:4864:20::1049]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7A26F4E52D for <linux-kernel@vger.kernel.org>; Thu, 9 Feb 2023 16:32:00 -0800 (PST) Received: by mail-pj1-x1049.google.com with SMTP id l22-20020a17090aaa9600b00230aa3c1350so1596225pjq.2 for <linux-kernel@vger.kernel.org>; Thu, 09 Feb 2023 16:32:00 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; 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=00HAzMjPVYVZpNNjib7OPhFskVadeKfZTgeX842t58U=; b=aBtzaPE8mYEmKnAgTm5Kax34YIZeL7JG4RKNgQ8x0KfDYjrvnvQ33kpzNnCl3AZjFx q0YvA0dhIK66QCU2byQQpwLdRR2uvjOsa1tMsA0sdVAGPUxLfrLlfF5LDa3auEb01hKT lZJJqZrfdgikkQzecg4RtA2RbUg3AP2vbP6d5pSW1Oy0oFdX2ZSj7jPuGBOmpAaC72BA H3hPZkLs9AnDnvU7c9BO0Tg+B7NscWiAXdFyL800DZcdLES2IuiEUiScFXp0CEnwejaI nMb/yCangz2qqeh+CQdL6qbm8lQC0stog6QULX5eBG4GEdzcuUFMcJ1B44nbvA24hpHy MY7A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; 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=00HAzMjPVYVZpNNjib7OPhFskVadeKfZTgeX842t58U=; b=wdpfv3fYHeENaTnvV76RFN1o6DghiitH1fHZlE1icNCGjcu8PSUj2Byp7MUrO8hc1c 74fQHEH6qVpPyIxvWAhAF88qXGI2RTjBb5Ez3Gk7/WaHCpDvq35BoSbswdNJB0uVeJaD SrGVeYqxC+nTGjU0gXRDQqXXbB8u5AhnPo/QameUmrJxyKtpi7DvbXpwoFina26Pb389 pqsvoU3bt8myqUxcWIULVh8cSqaATBKrgPgq3FnTpt9IL+d/7KgQ4t40BjAoS1vht28T HmIpcju3+SJUOoT+MyFsuIHpEFVMybxkaE5EJr7hy4UMUYSExjmjtbgXKupzvFKdGbMa /7bA== X-Gm-Message-State: AO0yUKWk7f+vFNtf5Q58DLmrpIOpm/iYepDF3bMCS3Cw05Js+TqdcOnu cNpJYsFNQ0ytQVnVSRiHOqJ99DTCmO0= X-Received: from zagreus.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:5c37]) (user=seanjc job=sendgmr) by 2002:a62:3181:0:b0:58d:8d29:399c with SMTP id x123-20020a623181000000b0058d8d29399cmr2696005pfx.44.1675989119771; Thu, 09 Feb 2023 16:31:59 -0800 (PST) Reply-To: Sean Christopherson <seanjc@google.com> Date: Fri, 10 Feb 2023 00:31:32 +0000 In-Reply-To: <20230210003148.2646712-1-seanjc@google.com> Mime-Version: 1.0 References: <20230210003148.2646712-1-seanjc@google.com> X-Mailer: git-send-email 2.39.1.581.gbfd45094c4-goog Message-ID: <20230210003148.2646712-6-seanjc@google.com> Subject: [PATCH v2 05/21] KVM: x86: Disallow writes to immutable feature MSRs after KVM_RUN From: Sean Christopherson <seanjc@google.com> To: Sean Christopherson <seanjc@google.com>, Paolo Bonzini <pbonzini@redhat.com> Cc: kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Xiaoyao Li <xiaoyao.li@intel.com>, Like Xu <like.xu.linux@gmail.com> Content-Type: text/plain; charset="UTF-8" X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,USER_IN_DEF_DKIM_WL autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: <linux-kernel.vger.kernel.org> X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1757402075073762362?= X-GMAIL-MSGID: =?utf-8?q?1757402075073762362?= |
Series |
KVM: x86: Disallow writes to feature MSRs post-KVM_RUN
|
|
Commit Message
Sean Christopherson
Feb. 10, 2023, 12:31 a.m. UTC
Disallow writes to feature MSRs after KVM_RUN to prevent userspace from
changing the vCPU model after running the vCPU. Similar to guest CPUID,
KVM uses feature MSRs to configure intercepts, determine what operations
are/aren't allowed, etc. Changing the capabilities while the vCPU is
active will at best yield unpredictable guest behavior, and at worst
could be dangerous to KVM.
Allow writing the current value, e.g. so that userspace can blindly set
all MSRs when emulating RESET, and unconditionally allow writes to
MSR_IA32_UCODE_REV so that userspace can emulate patch loads.
Special case the VMX MSRs to keep the generic list small, i.e. so that
KVM can do a linear walk of the generic list without incurring meaningful
overhead.
Cc: Like Xu <like.xu.linux@gmail.com>
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
arch/x86/kvm/x86.c | 36 ++++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
Comments
On Fri, Feb 10, 2023 at 12:31:32AM +0000, Sean Christopherson wrote: > Disallow writes to feature MSRs after KVM_RUN to prevent userspace from > changing the vCPU model after running the vCPU. Similar to guest CPUID, > KVM uses feature MSRs to configure intercepts, determine what operations > are/aren't allowed, etc. Changing the capabilities while the vCPU is > active will at best yield unpredictable guest behavior, and at worst > could be dangerous to KVM. > > Allow writing the current value, e.g. so that userspace can blindly set > all MSRs when emulating RESET, and unconditionally allow writes to > MSR_IA32_UCODE_REV so that userspace can emulate patch loads. > > Special case the VMX MSRs to keep the generic list small, i.e. so that > KVM can do a linear walk of the generic list without incurring meaningful > overhead. > > Cc: Like Xu <like.xu.linux@gmail.com> > Signed-off-by: Sean Christopherson <seanjc@google.com> > --- > arch/x86/kvm/x86.c | 36 ++++++++++++++++++++++++++++++++++++ > 1 file changed, 36 insertions(+) > > diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c > index 7b73a0b45041..186cb6a81643 100644 > --- a/arch/x86/kvm/x86.c > +++ b/arch/x86/kvm/x86.c > @@ -1554,6 +1554,25 @@ static u32 msr_based_features[ARRAY_SIZE(msr_based_features_all_except_vmx) + > (KVM_LAST_EMULATED_VMX_MSR - KVM_FIRST_EMULATED_VMX_MSR + 1)]; > static unsigned int num_msr_based_features; > > +/* > + * All feature MSRs except uCode revID, which tracks the currently loaded uCode > + * patch, are immutable once the vCPU model is defined. > + */ > +static bool kvm_is_immutable_feature_msr(u32 msr) > +{ > + int i; > + > + if (msr >= KVM_FIRST_EMULATED_VMX_MSR && msr <= KVM_LAST_EMULATED_VMX_MSR) > + return true; > + > + for (i = 0; i < ARRAY_SIZE(msr_based_features_all_except_vmx); i++) { > + if (msr == msr_based_features_all_except_vmx[i]) > + return msr != MSR_IA32_UCODE_REV; > + } > + > + return false; > +} > + > /* > * Some IA32_ARCH_CAPABILITIES bits have dependencies on MSRs that KVM > * does not yet virtualize. These include: > @@ -2168,6 +2187,23 @@ static int do_get_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data) > > static int do_set_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data) > { > + u64 val; > + > + /* > + * Disallow writes to immutable feature MSRs after KVM_RUN. KVM does > + * not support modifying the guest vCPU model on the fly, e.g. changing > + * the nVMX capabilities while L2 is running is nonsensical. Ignore > + * writes of the same value, e.g. to allow userspace to blindly stuff > + * all MSRs when emulating RESET. > + */ > + if (vcpu->arch.last_vmentry_cpu != -1 && Use kvm_vcpu_has_run(vcpu) here? B.R. Yu
On Fri, Feb 10, 2023, Yu Zhang wrote: > On Fri, Feb 10, 2023 at 12:31:32AM +0000, Sean Christopherson wrote: > > @@ -2168,6 +2187,23 @@ static int do_get_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data) > > > > static int do_set_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data) > > { > > + u64 val; > > + > > + /* > > + * Disallow writes to immutable feature MSRs after KVM_RUN. KVM does > > + * not support modifying the guest vCPU model on the fly, e.g. changing > > + * the nVMX capabilities while L2 is running is nonsensical. Ignore > > + * writes of the same value, e.g. to allow userspace to blindly stuff > > + * all MSRs when emulating RESET. > > + */ > > + if (vcpu->arch.last_vmentry_cpu != -1 && > > Use kvm_vcpu_has_run(vcpu) here? /facepalm Yes, that was the entire point of adding the helper. Thanks!
Maybe be more clearer in the title to reflect what the patch really does KVM: x86: Disallow writes to immutable feature MSRs from user space after KVM_RUN On 2/10/2023 8:31 AM, Sean Christopherson wrote: > Disallow writes to feature MSRs after KVM_RUN to prevent userspace from > changing the vCPU model after running the vCPU. Similar to guest CPUID, > KVM uses feature MSRs to configure intercepts, determine what operations > are/aren't allowed, etc. Changing the capabilities while the vCPU is > active will at best yield unpredictable guest behavior, and at worst > could be dangerous to KVM. > > Allow writing the current value, e.g. so that userspace can blindly set > all MSRs when emulating RESET, and unconditionally allow writes to > MSR_IA32_UCODE_REV so that userspace can emulate patch loads. > > Special case the VMX MSRs to keep the generic list small, i.e. so that > KVM can do a linear walk of the generic list without incurring meaningful > overhead. > > Cc: Like Xu <like.xu.linux@gmail.com> > Signed-off-by: Sean Christopherson <seanjc@google.com> > --- > arch/x86/kvm/x86.c | 36 ++++++++++++++++++++++++++++++++++++ > 1 file changed, 36 insertions(+) > > diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c > index 7b73a0b45041..186cb6a81643 100644 > --- a/arch/x86/kvm/x86.c > +++ b/arch/x86/kvm/x86.c > @@ -1554,6 +1554,25 @@ static u32 msr_based_features[ARRAY_SIZE(msr_based_features_all_except_vmx) + > (KVM_LAST_EMULATED_VMX_MSR - KVM_FIRST_EMULATED_VMX_MSR + 1)]; > static unsigned int num_msr_based_features; > > +/* > + * All feature MSRs except uCode revID, which tracks the currently loaded uCode > + * patch, are immutable once the vCPU model is defined. > + */ > +static bool kvm_is_immutable_feature_msr(u32 msr) > +{ > + int i; > + > + if (msr >= KVM_FIRST_EMULATED_VMX_MSR && msr <= KVM_LAST_EMULATED_VMX_MSR) > + return true; > + > + for (i = 0; i < ARRAY_SIZE(msr_based_features_all_except_vmx); i++) { > + if (msr == msr_based_features_all_except_vmx[i]) > + return msr != MSR_IA32_UCODE_REV; > + } > + > + return false; > +} > + > /* > * Some IA32_ARCH_CAPABILITIES bits have dependencies on MSRs that KVM > * does not yet virtualize. These include: > @@ -2168,6 +2187,23 @@ static int do_get_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data) > > static int do_set_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data) > { > + u64 val; > + > + /* > + * Disallow writes to immutable feature MSRs after KVM_RUN. KVM does > + * not support modifying the guest vCPU model on the fly, e.g. changing > + * the nVMX capabilities while L2 is running is nonsensical. Ignore > + * writes of the same value, e.g. to allow userspace to blindly stuff > + * all MSRs when emulating RESET. > + */ > + if (vcpu->arch.last_vmentry_cpu != -1 && after this replaced with the helper, Reviewed-by: Xiaoyao Li <xiaoyao.li@intel.com> > + kvm_is_immutable_feature_msr(index)) { > + if (do_get_msr(vcpu, index, &val) || *data != val) > + return -EINVAL; > + > + return 0; > + } > + > return kvm_set_msr_ignored_check(vcpu, index, *data, true); > } >
On 10/2/2023 8:31 am, Sean Christopherson wrote: > Disallow writes to feature MSRs after KVM_RUN to prevent userspace from > changing the vCPU model after running the vCPU. Similar to guest CPUID, > KVM uses feature MSRs to configure intercepts, determine what operations > are/aren't allowed, etc. Changing the capabilities while the vCPU is > active will at best yield unpredictable guest behavior, and at worst > could be dangerous to KVM. > > Allow writing the current value, e.g. so that userspace can blindly set > all MSRs when emulating RESET, and unconditionally allow writes to > MSR_IA32_UCODE_REV so that userspace can emulate patch loads. > > Special case the VMX MSRs to keep the generic list small, i.e. so that > KVM can do a linear walk of the generic list without incurring meaningful > overhead. > > Cc: Like Xu <like.xu.linux@gmail.com> > Signed-off-by: Sean Christopherson <seanjc@google.com> > --- > arch/x86/kvm/x86.c | 36 ++++++++++++++++++++++++++++++++++++ > 1 file changed, 36 insertions(+) > > diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c > index 7b73a0b45041..186cb6a81643 100644 > --- a/arch/x86/kvm/x86.c > +++ b/arch/x86/kvm/x86.c > @@ -1554,6 +1554,25 @@ static u32 msr_based_features[ARRAY_SIZE(msr_based_features_all_except_vmx) + > (KVM_LAST_EMULATED_VMX_MSR - KVM_FIRST_EMULATED_VMX_MSR + 1)]; > static unsigned int num_msr_based_features; > > +/* > + * All feature MSRs except uCode revID, which tracks the currently loaded uCode > + * patch, are immutable once the vCPU model is defined. > + */ > +static bool kvm_is_immutable_feature_msr(u32 msr) > +{ > + int i; > + > + if (msr >= KVM_FIRST_EMULATED_VMX_MSR && msr <= KVM_LAST_EMULATED_VMX_MSR) > + return true; > + > + for (i = 0; i < ARRAY_SIZE(msr_based_features_all_except_vmx); i++) { > + if (msr == msr_based_features_all_except_vmx[i]) > + return msr != MSR_IA32_UCODE_REV; > + } > + > + return false; > +} > + > /* > * Some IA32_ARCH_CAPABILITIES bits have dependencies on MSRs that KVM > * does not yet virtualize. These include: > @@ -2168,6 +2187,23 @@ static int do_get_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data) > > static int do_set_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data) > { > + u64 val; > + > + /* > + * Disallow writes to immutable feature MSRs after KVM_RUN. KVM does > + * not support modifying the guest vCPU model on the fly, e.g. changing > + * the nVMX capabilities while L2 is running is nonsensical. Ignore > + * writes of the same value, e.g. to allow userspace to blindly stuff > + * all MSRs when emulating RESET. > + */ > + if (vcpu->arch.last_vmentry_cpu != -1 && Three concerns on my mind (to help you think more if any): - why not using kvm->created_vcpus; - how about different vcpu models of the same guest have different feature_msr values; (although they are not altered after the first run, cases (selftests) may be needed to show that it is dangerous for KVM); - the relative time to set "vcpu->arch.last_vmentry_cpu = vcpu->cpu" is still too late, since part of the guest code (an attack window) has already been executed on first run of kvm_x86_vcpu_run() which may run for a long time; > + kvm_is_immutable_feature_msr(index)) { > + if (do_get_msr(vcpu, index, &val) || *data != val) > + return -EINVAL; > + > + return 0; > + } > + > return kvm_set_msr_ignored_check(vcpu, index, *data, true); > } >
On Tue, Feb 14, 2023, Like Xu wrote: > On 10/2/2023 8:31 am, Sean Christopherson wrote: > > @@ -2168,6 +2187,23 @@ static int do_get_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data) > > static int do_set_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data) > > { > > + u64 val; > > + > > + /* > > + * Disallow writes to immutable feature MSRs after KVM_RUN. KVM does > > + * not support modifying the guest vCPU model on the fly, e.g. changing > > + * the nVMX capabilities while L2 is running is nonsensical. Ignore > > + * writes of the same value, e.g. to allow userspace to blindly stuff > > + * all MSRs when emulating RESET. > > + */ > > + if (vcpu->arch.last_vmentry_cpu != -1 && > > Three concerns on my mind (to help you think more if any): > - why not using kvm->created_vcpus; Because this is a vCPU scoped ioctl(). > - how about different vcpu models of the same guest have different > feature_msr values; KVM shouldn't care. If KVM does care, then that's a completely orthogonal bug that needs to be fixed separately. > (although they are not altered after the first run, cases (selftests) may be > needed to > show that it is dangerous for KVM); > > - the relative time to set "vcpu->arch.last_vmentry_cpu = vcpu->cpu" is > still too late, > since part of the guest code (an attack window) has already been executed on first > run of kvm_x86_vcpu_run() which may run for a long time; Again, this is a vCPU scoped ioctl. The task doing KVM_RUN holds vcpu->mutex so there is no race.
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 7b73a0b45041..186cb6a81643 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1554,6 +1554,25 @@ static u32 msr_based_features[ARRAY_SIZE(msr_based_features_all_except_vmx) + (KVM_LAST_EMULATED_VMX_MSR - KVM_FIRST_EMULATED_VMX_MSR + 1)]; static unsigned int num_msr_based_features; +/* + * All feature MSRs except uCode revID, which tracks the currently loaded uCode + * patch, are immutable once the vCPU model is defined. + */ +static bool kvm_is_immutable_feature_msr(u32 msr) +{ + int i; + + if (msr >= KVM_FIRST_EMULATED_VMX_MSR && msr <= KVM_LAST_EMULATED_VMX_MSR) + return true; + + for (i = 0; i < ARRAY_SIZE(msr_based_features_all_except_vmx); i++) { + if (msr == msr_based_features_all_except_vmx[i]) + return msr != MSR_IA32_UCODE_REV; + } + + return false; +} + /* * Some IA32_ARCH_CAPABILITIES bits have dependencies on MSRs that KVM * does not yet virtualize. These include: @@ -2168,6 +2187,23 @@ static int do_get_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data) static int do_set_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data) { + u64 val; + + /* + * Disallow writes to immutable feature MSRs after KVM_RUN. KVM does + * not support modifying the guest vCPU model on the fly, e.g. changing + * the nVMX capabilities while L2 is running is nonsensical. Ignore + * writes of the same value, e.g. to allow userspace to blindly stuff + * all MSRs when emulating RESET. + */ + if (vcpu->arch.last_vmentry_cpu != -1 && + kvm_is_immutable_feature_msr(index)) { + if (do_get_msr(vcpu, index, &val) || *data != val) + return -EINVAL; + + return 0; + } + return kvm_set_msr_ignored_check(vcpu, index, *data, true); }