Received: by 2002:a05:7412:b10a:b0:f3:1519:9f41 with SMTP id az10csp1404912rdb; Fri, 1 Dec 2023 16:05:08 -0800 (PST) X-Google-Smtp-Source: AGHT+IGTEjKIU2swX+SP9WeODIBM0hYe6UZNuWyX5idS9PdtW51BNDkz/jUP9bUucUh1z1/Orz0L X-Received: by 2002:a05:6a21:6da5:b0:18f:afc:4e02 with SMTP id wl37-20020a056a216da500b0018f0afc4e02mr313900pzb.125.1701475508745; Fri, 01 Dec 2023 16:05:08 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1701475508; cv=none; d=google.com; s=arc-20160816; b=LcC8oZVXWJPFHa3SKKaZS8uvyfB5nnCK3MKbRO9gv3O9pFRMgrVXCABXAsp0mWyKuH ROhYJmfR2lmb6jsAPyQv/3YMx6ZO8XPVgmBsLqQXXWJYQav85f4ez6qiBTvPHmtB8GAC 1uj27QNAl28ShhJetridZy31Ti9z40eX+c84hFeUfNH7iE6lXm4AKplKFXXf7ndDyZis 2gGQA3sF71aJDVzPqX7V8bvSs51akRS5+kkHfYJg5fg6b5qnA0aNzhFHpod1vr8cykMt QV46ty9NEuTWHwsPPuJ0Defv+RmYCdr0E879bnezmZf5KE6cJjODODKby3ehvrDy1KJ0 HLpg== 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=cEYLtrPOOaLARZLa9sm17PRst0mFxCm8VxSITDHXjiU=; fh=gm96CM+cG0KJxn7vnhn0c1c98ILNP1HHUrKfrGecw3M=; b=IXyODzNoCcPxcCG51m+a5Ve2v2HJQYiP6pCthdtUYW2Q8W0SIMdjBv6MJzSlPq1HnX 2V8mRpoq55BiKSEuxk4WMEg5v3EiRtF8U/UTqmt8l+/3qOM9A4qJr7s+twglP+A3DdsV tpT4aB596MykyIC1DTy5Y3rY/sSGmiSlfMQgYAEJfANQCQ5gtSZxhfUhqTFNcjlEbiwn AkrK9UVRC4G93kSG7XuNZoikTY9wCooK2bEnC+uaVHjVXEHwCsokXPncLexrWJu9QxA7 7TKPD5MfaB4nuBUgxefME16nL6IDcXODNEEloeqUU0jKPm5gy3qZrcc5tNzTclSyomq+ ArLA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20230601 header.b=ff6gIBR0; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.33 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Return-Path: Received: from lipwig.vger.email (lipwig.vger.email. [23.128.96.33]) by mx.google.com with ESMTPS id b1-20020a056a000a8100b006c4d54dd60fsi4147608pfl.298.2023.12.01.16.05.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 01 Dec 2023 16:05:08 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.33 as permitted sender) client-ip=23.128.96.33; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20230601 header.b=ff6gIBR0; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.33 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 (depot.vger.email [IPv6:2620:137:e000::3:0]) by lipwig.vger.email (Postfix) with ESMTP id 7DC6181CFF0A; Fri, 1 Dec 2023 16:05:05 -0800 (PST) X-Virus-Status: Clean X-Virus-Scanned: clamav-milter 0.103.11 at lipwig.vger.email Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1441991AbjLBAEu (ORCPT + 99 others); Fri, 1 Dec 2023 19:04:50 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56716 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1441952AbjLBAEi (ORCPT ); Fri, 1 Dec 2023 19:04:38 -0500 Received: from mail-pf1-x449.google.com (mail-pf1-x449.google.com [IPv6:2607:f8b0:4864:20::449]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A97DD1730 for ; Fri, 1 Dec 2023 16:04:34 -0800 (PST) Received: by mail-pf1-x449.google.com with SMTP id d2e1a72fcca58-6ce0af61329so1029775b3a.0 for ; Fri, 01 Dec 2023 16:04:34 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1701475474; x=1702080274; 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=cEYLtrPOOaLARZLa9sm17PRst0mFxCm8VxSITDHXjiU=; b=ff6gIBR0nJl/TcrVfSxlLtpdWHgtC7Zs8m0uZi3JAGIEJJnNcKnBSgt2qnvDzFjy/t jIvNwvUR5WFm+7vbghQik0QqmoIB4wg55tA94AcESIejyLJxGb77sX74QgTX2/2hd0C7 3egr+xlAX09PoJpL1eSjuZEWKkf5nd7mGWwOF+jgCt5gEEFYrQmZMy5zbmH4N/Zoq/au O6z1NvkCL668eY1raLGDtLfWD2UQ624JXWE1SMFZbNfFRIFG/54iYJISWdqLz7ymJ/Vp BB7kpuyGGM7alkCxeqKwjmr/g7cLHBQ3PN1R5tbrj7tdIucmxzC5itAIWTEP1JLaXTGj MZfQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1701475474; x=1702080274; 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=cEYLtrPOOaLARZLa9sm17PRst0mFxCm8VxSITDHXjiU=; b=wL0U/TfVHC1iAjSuJuMUcemLfpQTapAe2FXdihH4X9QR7BAEGmWRIw5JzSBKPo7BX3 fnB8p/kYpwLOqS+2yg0uE76GbyBBg+w2/yHQzQHA7O9OFRcUSngIty+c/13OXANPClUK /J7dGez51uydqHYawiZZDiijR/8XQvVdLXabnNCoUNp9idIisdSGuI6/4Wo6jsP4JWrr c7S4GyhC2iF8EVvMZogqHwBUx8Y8szoL7oQgmmIz+Huyawx0mOig42aY5ZiouqTz4tUa 0bIcvpMbvy87u/lXv0S/oMJ0WmLXXIfDJx09E3M/kkQHLYXUIvHxyzf7HfZXRuEmaCgz mMZg== X-Gm-Message-State: AOJu0YysFT1Zh8N70K4+D43lOMEs7YWmKt1CowjVBWynXDTDiKR3T00u sToRVHwBXxzK1WyrhPvEhnMi63Wy8dg= X-Received: from zagreus.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:5c37]) (user=seanjc job=sendgmr) by 2002:a05:6a00:3a03:b0:6cd:810:3875 with SMTP id fj3-20020a056a003a0300b006cd08103875mr4972590pfb.5.1701475474054; Fri, 01 Dec 2023 16:04:34 -0800 (PST) Reply-To: Sean Christopherson Date: Fri, 1 Dec 2023 16:03:56 -0800 In-Reply-To: <20231202000417.922113-1-seanjc@google.com> Mime-Version: 1.0 References: <20231202000417.922113-1-seanjc@google.com> X-Mailer: git-send-email 2.43.0.rc2.451.g8631bc7472-goog Message-ID: <20231202000417.922113-8-seanjc@google.com> Subject: [PATCH v9 07/28] KVM: x86/pmu: Prioritize VMX interception over #GP on RDPMC due to bad index From: Sean Christopherson To: Sean Christopherson , Paolo Bonzini Cc: kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Kan Liang , Dapeng Mi , Jim Mattson , Jinrong Liang , Aaron Lewis , Like Xu Content-Type: text/plain; charset="UTF-8" X-Spam-Status: No, score=-8.4 required=5.0 tests=DKIMWL_WL_MED,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE, 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 lipwig.vger.email Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-Greylist: Sender passed SPF test, not delayed by milter-greylist-4.6.4 (lipwig.vger.email [0.0.0.0]); Fri, 01 Dec 2023 16:05:05 -0800 (PST) Apply the pre-intercepts RDPMC validity check only to AMD, and rename all relevant functions to make it as clear as possible that the check is not a standard PMC index check. On Intel, the basic rule is that only invalid opcodes and privilege/permission/mode checks have priority over VM-Exit, i.e. RDPMC with an invalid index should VM-Exit, not #GP. While the SDM doesn't explicitly call out RDPMC, it _does_ explicitly use RDMSR of a non-existent MSR as an example where VM-Exit has priority over #GP, and RDPMC is effectively just a variation of RDMSR. Manually testing on various Intel CPUs confirms this behavior, and the inverted priority was introduced for SVM compatibility, i.e. was not an intentional change for Intel PMUs. On AMD, *all* exceptions on RDPMC have priority over VM-Exit. Check for a NULL kvm_pmu_ops.check_rdpmc_early instead of using a RET0 static call so as to provide a convenient location to document the difference between Intel and AMD, and to again try to make it as obvious as possible that the early check is a one-off thing, not a generic "is this PMC valid?" helper. Fixes: 8061252ee0d2 ("KVM: SVM: Add intercept checks for remaining twobyte instructions") Cc: Jim Mattson Signed-off-by: Sean Christopherson --- arch/x86/include/asm/kvm-x86-pmu-ops.h | 2 +- arch/x86/kvm/emulate.c | 2 +- arch/x86/kvm/kvm_emulate.h | 2 +- arch/x86/kvm/pmu.c | 16 +++++++++++++--- arch/x86/kvm/pmu.h | 4 ++-- arch/x86/kvm/svm/pmu.c | 9 ++++++--- arch/x86/kvm/vmx/pmu_intel.c | 12 ------------ arch/x86/kvm/x86.c | 9 +++------ 8 files changed, 27 insertions(+), 29 deletions(-) diff --git a/arch/x86/include/asm/kvm-x86-pmu-ops.h b/arch/x86/include/asm/kvm-x86-pmu-ops.h index d7eebee4450c..f0cd48222133 100644 --- a/arch/x86/include/asm/kvm-x86-pmu-ops.h +++ b/arch/x86/include/asm/kvm-x86-pmu-ops.h @@ -15,7 +15,7 @@ BUILD_BUG_ON(1) KVM_X86_PMU_OP(pmc_idx_to_pmc) KVM_X86_PMU_OP(rdpmc_ecx_to_pmc) KVM_X86_PMU_OP(msr_idx_to_pmc) -KVM_X86_PMU_OP(is_valid_rdpmc_ecx) +KVM_X86_PMU_OP_OPTIONAL(check_rdpmc_early) KVM_X86_PMU_OP(is_valid_msr) KVM_X86_PMU_OP(get_msr) KVM_X86_PMU_OP(set_msr) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index e223043ef5b2..695ab5b6055c 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -3962,7 +3962,7 @@ static int check_rdpmc(struct x86_emulate_ctxt *ctxt) * protected mode. */ if ((!(cr4 & X86_CR4_PCE) && ctxt->ops->cpl(ctxt)) || - ctxt->ops->check_pmc(ctxt, rcx)) + ctxt->ops->check_rdpmc_early(ctxt, rcx)) return emulate_gp(ctxt, 0); return X86EMUL_CONTINUE; diff --git a/arch/x86/kvm/kvm_emulate.h b/arch/x86/kvm/kvm_emulate.h index e6d149825169..4351149484fb 100644 --- a/arch/x86/kvm/kvm_emulate.h +++ b/arch/x86/kvm/kvm_emulate.h @@ -208,7 +208,7 @@ struct x86_emulate_ops { int (*set_msr_with_filter)(struct x86_emulate_ctxt *ctxt, u32 msr_index, u64 data); int (*get_msr_with_filter)(struct x86_emulate_ctxt *ctxt, u32 msr_index, u64 *pdata); int (*get_msr)(struct x86_emulate_ctxt *ctxt, u32 msr_index, u64 *pdata); - int (*check_pmc)(struct x86_emulate_ctxt *ctxt, u32 pmc); + int (*check_rdpmc_early)(struct x86_emulate_ctxt *ctxt, u32 pmc); int (*read_pmc)(struct x86_emulate_ctxt *ctxt, u32 pmc, u64 *pdata); void (*halt)(struct x86_emulate_ctxt *ctxt); void (*wbinvd)(struct x86_emulate_ctxt *ctxt); diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index 30945fea6988..0b0d804ee239 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -524,10 +524,20 @@ void kvm_pmu_handle_event(struct kvm_vcpu *vcpu) kvm_pmu_cleanup(vcpu); } -/* check if idx is a valid index to access PMU */ -bool kvm_pmu_is_valid_rdpmc_ecx(struct kvm_vcpu *vcpu, unsigned int idx) +int kvm_pmu_check_rdpmc_early(struct kvm_vcpu *vcpu, unsigned int idx) { - return static_call(kvm_x86_pmu_is_valid_rdpmc_ecx)(vcpu, idx); + /* + * On Intel, VMX interception has priority over RDPMC exceptions that + * aren't already handled by the emulator, i.e. there are no additional + * check needed for Intel PMUs. + * + * On AMD, _all_ exceptions on RDPMC have priority over SVM intercepts, + * i.e. an invalid PMC results in a #GP, not #VMEXIT. + */ + if (!kvm_pmu_ops.check_rdpmc_early) + return 0; + + return static_call(kvm_x86_pmu_check_rdpmc_early)(vcpu, idx); } bool is_vmware_backdoor_pmc(u32 pmc_idx) diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h index 87ecf22f5b25..51bbb01b21c8 100644 --- a/arch/x86/kvm/pmu.h +++ b/arch/x86/kvm/pmu.h @@ -23,7 +23,7 @@ struct kvm_pmu_ops { struct kvm_pmc *(*rdpmc_ecx_to_pmc)(struct kvm_vcpu *vcpu, unsigned int idx, u64 *mask); struct kvm_pmc *(*msr_idx_to_pmc)(struct kvm_vcpu *vcpu, u32 msr); - bool (*is_valid_rdpmc_ecx)(struct kvm_vcpu *vcpu, unsigned int idx); + int (*check_rdpmc_early)(struct kvm_vcpu *vcpu, unsigned int idx); bool (*is_valid_msr)(struct kvm_vcpu *vcpu, u32 msr); int (*get_msr)(struct kvm_vcpu *vcpu, struct msr_data *msr_info); int (*set_msr)(struct kvm_vcpu *vcpu, struct msr_data *msr_info); @@ -215,7 +215,7 @@ static inline bool pmc_is_globally_enabled(struct kvm_pmc *pmc) void kvm_pmu_deliver_pmi(struct kvm_vcpu *vcpu); void kvm_pmu_handle_event(struct kvm_vcpu *vcpu); int kvm_pmu_rdpmc(struct kvm_vcpu *vcpu, unsigned pmc, u64 *data); -bool kvm_pmu_is_valid_rdpmc_ecx(struct kvm_vcpu *vcpu, unsigned int idx); +int kvm_pmu_check_rdpmc_early(struct kvm_vcpu *vcpu, unsigned int idx); bool kvm_pmu_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr); int kvm_pmu_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info); int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info); diff --git a/arch/x86/kvm/svm/pmu.c b/arch/x86/kvm/svm/pmu.c index 1fafc46f61c9..e886300f0f97 100644 --- a/arch/x86/kvm/svm/pmu.c +++ b/arch/x86/kvm/svm/pmu.c @@ -73,11 +73,14 @@ static inline struct kvm_pmc *get_gp_pmc_amd(struct kvm_pmu *pmu, u32 msr, return amd_pmc_idx_to_pmc(pmu, idx); } -static bool amd_is_valid_rdpmc_ecx(struct kvm_vcpu *vcpu, unsigned int idx) +static int amd_check_rdpmc_early(struct kvm_vcpu *vcpu, unsigned int idx) { struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); - return idx < pmu->nr_arch_gp_counters; + if (idx >= pmu->nr_arch_gp_counters) + return -EINVAL; + + return 0; } /* idx is the ECX register of RDPMC instruction */ @@ -229,7 +232,7 @@ struct kvm_pmu_ops amd_pmu_ops __initdata = { .pmc_idx_to_pmc = amd_pmc_idx_to_pmc, .rdpmc_ecx_to_pmc = amd_rdpmc_ecx_to_pmc, .msr_idx_to_pmc = amd_msr_idx_to_pmc, - .is_valid_rdpmc_ecx = amd_is_valid_rdpmc_ecx, + .check_rdpmc_early = amd_check_rdpmc_early, .is_valid_msr = amd_is_valid_msr, .get_msr = amd_pmu_get_msr, .set_msr = amd_pmu_set_msr, diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index ec4feaef3d55..1b1f888ad32b 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -55,17 +55,6 @@ static struct kvm_pmc *intel_pmc_idx_to_pmc(struct kvm_pmu *pmu, int pmc_idx) } } -static bool intel_is_valid_rdpmc_ecx(struct kvm_vcpu *vcpu, unsigned int idx) -{ - struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); - bool fixed = idx & (1u << 30); - - idx &= ~(3u << 30); - - return fixed ? idx < pmu->nr_arch_fixed_counters - : idx < pmu->nr_arch_gp_counters; -} - static struct kvm_pmc *intel_rdpmc_ecx_to_pmc(struct kvm_vcpu *vcpu, unsigned int idx, u64 *mask) { @@ -718,7 +707,6 @@ struct kvm_pmu_ops intel_pmu_ops __initdata = { .pmc_idx_to_pmc = intel_pmc_idx_to_pmc, .rdpmc_ecx_to_pmc = intel_rdpmc_ecx_to_pmc, .msr_idx_to_pmc = intel_msr_idx_to_pmc, - .is_valid_rdpmc_ecx = intel_is_valid_rdpmc_ecx, .is_valid_msr = intel_is_valid_msr, .get_msr = intel_pmu_get_msr, .set_msr = intel_pmu_set_msr, diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index d19bbca6a44c..17ffadc61a45 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -8348,12 +8348,9 @@ static int emulator_get_msr(struct x86_emulate_ctxt *ctxt, return kvm_get_msr(emul_to_vcpu(ctxt), msr_index, pdata); } -static int emulator_check_pmc(struct x86_emulate_ctxt *ctxt, - u32 pmc) +static int emulator_check_rdpmc_early(struct x86_emulate_ctxt *ctxt, u32 pmc) { - if (kvm_pmu_is_valid_rdpmc_ecx(emul_to_vcpu(ctxt), pmc)) - return 0; - return -EINVAL; + return kvm_pmu_check_rdpmc_early(emul_to_vcpu(ctxt), pmc); } static int emulator_read_pmc(struct x86_emulate_ctxt *ctxt, @@ -8485,7 +8482,7 @@ static const struct x86_emulate_ops emulate_ops = { .set_msr_with_filter = emulator_set_msr_with_filter, .get_msr_with_filter = emulator_get_msr_with_filter, .get_msr = emulator_get_msr, - .check_pmc = emulator_check_pmc, + .check_rdpmc_early = emulator_check_rdpmc_early, .read_pmc = emulator_read_pmc, .halt = emulator_halt, .wbinvd = emulator_wbinvd, -- 2.43.0.rc2.451.g8631bc7472-goog