From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-26.3 required=3.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, USER_AGENT_GIT,USER_IN_DEF_DKIM_WL autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 47884C433ED for ; Fri, 7 May 2021 17:00:08 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 18CF061460 for ; Fri, 7 May 2021 17:00:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S238486AbhEGRBE (ORCPT ); Fri, 7 May 2021 13:01:04 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33642 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S238462AbhEGRA7 (ORCPT ); Fri, 7 May 2021 13:00:59 -0400 Received: from mail-yb1-xb49.google.com (mail-yb1-xb49.google.com [IPv6:2607:f8b0:4864:20::b49]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 89457C06138A for ; Fri, 7 May 2021 09:59:58 -0700 (PDT) Received: by mail-yb1-xb49.google.com with SMTP id a3-20020a2580430000b02904f7a1a09012so10744898ybn.3 for ; Fri, 07 May 2021 09:59:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=reply-to:date:in-reply-to:message-id:mime-version:references :subject:from:to:cc; bh=nXbsQzZRKADxmz3jPQyGk2mwipulmK8ydHFPEpTQQXY=; b=cZAvPBhNqujbaGxJlK4D8mIW+Swf1BC4L7PwZB3GQ7JVWWxdeAIL3qOpHbD1N7+IDP tlcRAsw/mMjLviNrHz0tBXTi1JaNLfNk8c+7bk9+0nD6VUhcdBo88t7lHPuldYqc+OP0 U17N9Sf8vPB2ez0F3tKHgHTGKEuCK5D6KPo26i3BaiXYrC9bKDjH76kSLoXyWhJOB5BR Y0vh1d9xhzxQLAnuh6E9lnuowGCPTtBhYd5K7Nbu7a10Nq8InGHZVUwUzrTcxak9TjPW YCa1Cy35GJsLR09nU0UHI+GD9Vf3JnTOxzrSetvQ3vn0dWxX03VZvc2vsqlz2az75D6r LERw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:reply-to:date:in-reply-to:message-id :mime-version:references:subject:from:to:cc; bh=nXbsQzZRKADxmz3jPQyGk2mwipulmK8ydHFPEpTQQXY=; b=RsEKU0ehBvPj3maXx6s8RnIhxgPSBeqEyzFbO/KJCYWlhDcomuoGwaWe7Pbxl5xdfp IOBXCWU2INnO8288IkTjJN3D19P8w+c4i6UGZK/jGMIPQIHQmvVvONLgW+qiYUDNYbJJ Wmh3EzttRDNDTC8LW45VjRiJFfhm379k9mW9fXLFgRDt2JQBxnrkt5N8w/L48PtRZaQW w6flW5c6dLCE5PuNubPAtyi/opilh8Q5N4joNJVYvhe+K7c3nL8GDfJKtHqtEjUN/LgN HmJV9Q0O4Od+Z2BN27digM9hOW0ibJhfTBs8z7mXPEQkUSPE5qH2gTsKPoioWQJKG3wF Dn7Q== X-Gm-Message-State: AOAM531HJsxXKH2Yj2nEVRt3lB5UBRhyPWgUcx+Ogu+f6BXgOeMqfUIv fl72fMDqXSJx1+PyT96qKgyWZ174rnA= X-Google-Smtp-Source: ABdhPJxTl5XVJuekxZhnDVHK/OX5tlB0XW7XCBsx4xJY6H7vJRWejR56oTeCAQd64J3MY/dfJjlgiNulBOs= X-Received: from seanjc798194.pdx.corp.google.com ([2620:15c:f:10:7352:5279:7518:418f]) (user=seanjc job=sendgmr) by 2002:a25:30d5:: with SMTP id w204mr14454275ybw.416.1620406797719; Fri, 07 May 2021 09:59:57 -0700 (PDT) Reply-To: Sean Christopherson Date: Fri, 7 May 2021 09:59:47 -0700 In-Reply-To: <20210507165947.2502412-1-seanjc@google.com> Message-Id: <20210507165947.2502412-3-seanjc@google.com> Mime-Version: 1.0 References: <20210507165947.2502412-1-seanjc@google.com> X-Mailer: git-send-email 2.31.1.607.g51e8a6a459-goog Subject: [PATCH 2/2] KVM: x86: Allow userspace to update tracked sregs for protected guests From: Sean Christopherson To: Paolo Bonzini Cc: Sean Christopherson , Vitaly Kuznetsov , Wanpeng Li , Jim Mattson , Joerg Roedel , kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Peter Gonda , Maxim Levitsky Content-Type: text/plain; charset="UTF-8" Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Allow userspace to set CR0, CR4, CR8, and EFER via KVM_SET_SREGS for protected guests, e.g. for SEV-ES guests with an encrypted VMSA. KVM tracks the aforementioned registers by trapping guest writes, and also exposes the values to userspace via KVM_GET_SREGS. Skipping the regs in KVM_SET_SREGS prevents userspace from updating KVM's CPU model to match the known hardware state. Fixes: 5265713a0737 ("KVM: x86: Update __get_sregs() / __set_sregs() to support SEV-ES") Reported-by: Peter Gonda Cc: stable@vger.kernel.org Cc: Maxim Levitsky Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 73 ++++++++++++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 31 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 3bf52ba5f2bb..1b7d0e97c82b 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -9963,21 +9963,25 @@ static int __set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) if (kvm_set_apic_base(vcpu, &apic_base_msr)) goto out; - if (vcpu->arch.guest_state_protected) - goto skip_protected_regs; + if (!vcpu->arch.guest_state_protected) { + dt.size = sregs->idt.limit; + dt.address = sregs->idt.base; + static_call(kvm_x86_set_idt)(vcpu, &dt); + dt.size = sregs->gdt.limit; + dt.address = sregs->gdt.base; + static_call(kvm_x86_set_gdt)(vcpu, &dt); - dt.size = sregs->idt.limit; - dt.address = sregs->idt.base; - static_call(kvm_x86_set_idt)(vcpu, &dt); - dt.size = sregs->gdt.limit; - dt.address = sregs->gdt.base; - static_call(kvm_x86_set_gdt)(vcpu, &dt); - - vcpu->arch.cr2 = sregs->cr2; - mmu_reset_needed |= kvm_read_cr3(vcpu) != sregs->cr3; - vcpu->arch.cr3 = sregs->cr3; - kvm_register_mark_available(vcpu, VCPU_EXREG_CR3); + vcpu->arch.cr2 = sregs->cr2; + mmu_reset_needed |= kvm_read_cr3(vcpu) != sregs->cr3; + vcpu->arch.cr3 = sregs->cr3; + kvm_register_mark_available(vcpu, VCPU_EXREG_CR3); + } + /* + * Writes to CR0, CR4, CR8, and EFER are trapped (after the instruction + * completes) for SEV-EV guests, thus userspace is allowed to set them + * so that KVM's model can be updated to mirror hardware state. + */ kvm_set_cr8(vcpu, sregs->cr8); mmu_reset_needed |= vcpu->arch.efer != sregs->efer; @@ -9990,35 +9994,42 @@ static int __set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) mmu_reset_needed |= kvm_read_cr4(vcpu) != sregs->cr4; static_call(kvm_x86_set_cr4)(vcpu, sregs->cr4); - idx = srcu_read_lock(&vcpu->kvm->srcu); - if (is_pae_paging(vcpu)) { + /* + * PDPTEs, like regular PTEs, are always encrypted, thus reading them + * will return garbage. Shadow paging, including nested NPT, isn't + * compatible with protected guests, so ignoring the PDPTEs is a-ok. + */ + if (!vcpu->arch.guest_state_protected && is_pae_paging(vcpu)) { + idx = srcu_read_lock(&vcpu->kvm->srcu); load_pdptrs(vcpu, vcpu->arch.walk_mmu, kvm_read_cr3(vcpu)); + srcu_read_unlock(&vcpu->kvm->srcu, idx); + mmu_reset_needed = 1; } - srcu_read_unlock(&vcpu->kvm->srcu, idx); if (mmu_reset_needed) kvm_mmu_reset_context(vcpu); - kvm_set_segment(vcpu, &sregs->cs, VCPU_SREG_CS); - kvm_set_segment(vcpu, &sregs->ds, VCPU_SREG_DS); - kvm_set_segment(vcpu, &sregs->es, VCPU_SREG_ES); - kvm_set_segment(vcpu, &sregs->fs, VCPU_SREG_FS); - kvm_set_segment(vcpu, &sregs->gs, VCPU_SREG_GS); - kvm_set_segment(vcpu, &sregs->ss, VCPU_SREG_SS); + if (!vcpu->arch.guest_state_protected) { + kvm_set_segment(vcpu, &sregs->cs, VCPU_SREG_CS); + kvm_set_segment(vcpu, &sregs->ds, VCPU_SREG_DS); + kvm_set_segment(vcpu, &sregs->es, VCPU_SREG_ES); + kvm_set_segment(vcpu, &sregs->fs, VCPU_SREG_FS); + kvm_set_segment(vcpu, &sregs->gs, VCPU_SREG_GS); + kvm_set_segment(vcpu, &sregs->ss, VCPU_SREG_SS); - kvm_set_segment(vcpu, &sregs->tr, VCPU_SREG_TR); - kvm_set_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR); + kvm_set_segment(vcpu, &sregs->tr, VCPU_SREG_TR); + kvm_set_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR); - update_cr8_intercept(vcpu); + update_cr8_intercept(vcpu); - /* Older userspace won't unhalt the vcpu on reset. */ - if (kvm_vcpu_is_bsp(vcpu) && kvm_rip_read(vcpu) == 0xfff0 && - sregs->cs.selector == 0xf000 && sregs->cs.base == 0xffff0000 && - !is_protmode(vcpu)) - vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE; + /* Older userspace won't unhalt the vcpu on reset. */ + if (kvm_vcpu_is_bsp(vcpu) && kvm_rip_read(vcpu) == 0xfff0 && + sregs->cs.selector == 0xf000 && + sregs->cs.base == 0xffff0000 && !is_protmode(vcpu)) + vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE; + } -skip_protected_regs: max_bits = KVM_NR_INTERRUPTS; pending_vec = find_first_bit( (const unsigned long *)sregs->interrupt_bitmap, max_bits); -- 2.31.1.607.g51e8a6a459-goog