From patchwork Sat Jul 1 00:26:32 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Feiner X-Patchwork-Id: 9820647 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 3444E60375 for ; Sat, 1 Jul 2017 00:26:46 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2738026E1A for ; Sat, 1 Jul 2017 00:26:46 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 1BC7F27CF9; Sat, 1 Jul 2017 00:26:46 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9334E27F89 for ; Sat, 1 Jul 2017 00:26:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752074AbdGAA0m (ORCPT ); Fri, 30 Jun 2017 20:26:42 -0400 Received: from mail-pg0-f53.google.com ([74.125.83.53]:35935 "EHLO mail-pg0-f53.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752037AbdGAA0k (ORCPT ); Fri, 30 Jun 2017 20:26:40 -0400 Received: by mail-pg0-f53.google.com with SMTP id u62so70339497pgb.3 for ; Fri, 30 Jun 2017 17:26:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :in-reply-to:references; bh=F+V+9gzmJLQpn6uynvZcy/1Hlvm49JXTJHoVU7kKIdI=; b=ursYRtQxWl1/ilc/tRrqgHDNwQa9R1TVgXC6BaoiDdcmi5EiYP9iIVRsYAEF8gLBNo RSFOvGigOHtmq+lNElnv1F0f9zxF68tVGm9ILfPbpodTiEYN/1AxBCm+LKCxaCg3CTUy e+3Ul17szQPkYmxmZW4EQckPFO2u3x1eZsGWyRbmKtrV6mQzyt3d9z2Pp7hFSUdmkxVP cWCVPDOttLP2aPfiaQ4pTEkE8XWmQX3Gal6sD5y3umxomRl97sehkNiVIZnqyEcSUI8j 793xLG8hX7aF0xQEcOY9GCHtgXJkIEVo208Pw6hbfqZIKsAR9+T9t6GRwwXNhksNMb9T 13EQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:in-reply-to:references; bh=F+V+9gzmJLQpn6uynvZcy/1Hlvm49JXTJHoVU7kKIdI=; b=ug8iO+oH3FsO5WO2AbTUWz1V5NeRo41ufyH1qAIiouCVPyuN855HaVoSMr2M0HTSOx J0jW6JB92ftntSHVb979yOSDTwDMhn/9ivtcIHU/KTvnPxKeF2ZhpBEX0pMf96IXBP6K Tbt0C7jnJpjAe8mmCw2a43ixY47VyTkmrMnFfz6zl94nIIcVPTyFpSqk9sne1sVaQPax iGkoe5+pZlN4FMBbspwaOruv2GPScdVH6N12SciZuv04gAIqKxab531EewsiPEP/fWR5 W6cDYoxEyA+Xnb+Zlx2f47gihH3BDNCQUXSB7QcjFlaya9VNpX0dhpauM/yCQVUFyZw7 gM5Q== X-Gm-Message-State: AKS2vOxELXMJ3zilvArCwkGAvK8Qi85JXJd7pQk/dIOuAZi2BJU9pvjO Z78gtSHE9RGbxyGXDdYHgw== X-Received: by 10.99.181.7 with SMTP id y7mr2681309pge.212.1498868799513; Fri, 30 Jun 2017 17:26:39 -0700 (PDT) Received: from localhost ([2620:0:1009:3:4123:6f60:64cb:d807]) by smtp.gmail.com with ESMTPSA id y28sm19717816pfd.32.2017.06.30.17.26.38 (version=TLS1_2 cipher=AES128-SHA bits=128/128); Fri, 30 Jun 2017 17:26:38 -0700 (PDT) From: Peter Feiner To: kvm@vger.kernel.org Cc: Paolo Bonzini , David Matlack , Peter Feiner Subject: [PATCH 4/4] x86: kvm: mmu: use ept a/d in vmcs02 iff used in vmcs12 Date: Fri, 30 Jun 2017 17:26:32 -0700 Message-Id: <5bdf824538481ee2308354165e8ebe7b59b7b8a1.1498868316.git.pfeiner@google.com> X-Mailer: git-send-email 2.13.2.725.g09c95d1e9-goog In-Reply-To: References: In-Reply-To: References: Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP EPT A/D was enabled in the vmcs02 EPTP regardless of the vmcs12's EPTP value. The problem is that enabling A/D changes the behavior of L2's x86 page table walks as seen by L1. With A/D enabled, x86 page table walks are always treated as EPT writes. The EPT A/D emulation patch (XXX) tried to work around this problem by clearing the write bit in the exit qualification for EPT violations triggered by page walks. However, that fixup introduced the opposite bug: page-table walks that actually set x86 A/D bits were *missing* the write bit in the exit qualification. This patch fixes the problem by disabling EPT A/D in the shadow MMU when EPT A/D is disabled in vmcs12's EPTP. Signed-off-by: Peter Feiner --- arch/x86/kvm/mmu.c | 1 + arch/x86/kvm/vmx.c | 40 ++++++++++++++++++---------------------- 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index e814fb6248ac..d483f81699fe 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -4415,6 +4415,7 @@ void kvm_init_shadow_ept_mmu(struct kvm_vcpu *vcpu, bool execonly, context->root_level = context->shadow_root_level; context->root_hpa = INVALID_PAGE; context->direct_map = false; + context->base_role.ad_disabled = !accessed_dirty; update_permission_bitmask(vcpu, context, true); update_pkru_bitmask(vcpu, context, true); diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index e59b01a1d431..58137690d57d 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -910,8 +910,9 @@ static void nested_release_page_clean(struct page *page) kvm_release_page_clean(page); } +static bool nested_ept_ad_enabled(struct kvm_vcpu *vcpu); static unsigned long nested_ept_get_cr3(struct kvm_vcpu *vcpu); -static u64 construct_eptp(unsigned long root_hpa); +static u64 construct_eptp(struct kvm_vcpu *vcpu, unsigned long root_hpa); static bool vmx_xsaves_supported(void); static int vmx_set_tss_addr(struct kvm *kvm, unsigned int addr); static void vmx_set_segment(struct kvm_vcpu *vcpu, @@ -4013,7 +4014,7 @@ static inline void __vmx_flush_tlb(struct kvm_vcpu *vcpu, int vpid) if (enable_ept) { if (!VALID_PAGE(vcpu->arch.mmu.root_hpa)) return; - ept_sync_context(construct_eptp(vcpu->arch.mmu.root_hpa)); + ept_sync_context(construct_eptp(vcpu, vcpu->arch.mmu.root_hpa)); } else { vpid_sync_context(vpid); } @@ -4188,14 +4189,15 @@ static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) vmx->emulation_required = emulation_required(vcpu); } -static u64 construct_eptp(unsigned long root_hpa) +static u64 construct_eptp(struct kvm_vcpu *vcpu, unsigned long root_hpa) { u64 eptp; /* TODO write the value reading from MSR */ eptp = VMX_EPT_DEFAULT_MT | VMX_EPT_DEFAULT_GAW << VMX_EPT_GAW_EPTP_SHIFT; - if (enable_ept_ad_bits) + if (enable_ept_ad_bits && + (!is_guest_mode(vcpu) || nested_ept_ad_enabled(vcpu))) eptp |= VMX_EPT_AD_ENABLE_BIT; eptp |= (root_hpa & PAGE_MASK); @@ -4209,7 +4211,7 @@ static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) guest_cr3 = cr3; if (enable_ept) { - eptp = construct_eptp(cr3); + eptp = construct_eptp(vcpu, cr3); vmcs_write64(EPT_POINTER, eptp); if (is_paging(vcpu) || is_guest_mode(vcpu)) guest_cr3 = kvm_read_cr3(vcpu); @@ -6214,17 +6216,6 @@ static int handle_ept_violation(struct kvm_vcpu *vcpu) exit_qualification = vmcs_readl(EXIT_QUALIFICATION); - if (is_guest_mode(vcpu) - && !(exit_qualification & EPT_VIOLATION_GVA_TRANSLATED)) { - /* - * Fix up exit_qualification according to whether guest - * page table accesses are reads or writes. - */ - u64 eptp = nested_ept_get_cr3(vcpu); - if (!(eptp & VMX_EPT_AD_ENABLE_BIT)) - exit_qualification &= ~EPT_VIOLATION_ACC_WRITE; - } - /* * EPT violation happened while executing iret from NMI, * "blocked by NMI" bit has to be set before next VM entry. @@ -6447,7 +6438,7 @@ void vmx_enable_tdp(void) enable_ept_ad_bits ? VMX_EPT_DIRTY_BIT : 0ull, 0ull, VMX_EPT_EXECUTABLE_MASK, cpu_has_vmx_ept_execute_only() ? 0ull : VMX_EPT_READABLE_MASK, - enable_ept_ad_bits ? 0ull : VMX_EPT_RWX_MASK); + VMX_EPT_RWX_MASK); ept_set_mmio_spte_mask(); kvm_enable_tdp(); @@ -8358,7 +8349,7 @@ static int vmx_handle_exit(struct kvm_vcpu *vcpu) * mode as if vcpus is in root mode, the PML buffer must has been * flushed already. */ - if (enable_pml) + if (enable_pml && !is_guest_mode(vcpu)) vmx_flush_pml_buffer(vcpu); /* If guest state is invalid, start emulating */ @@ -9379,6 +9370,11 @@ static void nested_ept_inject_page_fault(struct kvm_vcpu *vcpu, vmcs12->guest_physical_address = fault->address; } +static bool nested_ept_ad_enabled(struct kvm_vcpu *vcpu) +{ + return nested_ept_get_cr3(vcpu) & VMX_EPT_AD_ENABLE_BIT; +} + /* Callbacks for nested_ept_init_mmu_context: */ static unsigned long nested_ept_get_cr3(struct kvm_vcpu *vcpu) @@ -9389,18 +9385,18 @@ static unsigned long nested_ept_get_cr3(struct kvm_vcpu *vcpu) static int nested_ept_init_mmu_context(struct kvm_vcpu *vcpu) { - u64 eptp; + bool wants_ad; WARN_ON(mmu_is_nested(vcpu)); - eptp = nested_ept_get_cr3(vcpu); - if ((eptp & VMX_EPT_AD_ENABLE_BIT) && !enable_ept_ad_bits) + wants_ad = nested_ept_ad_enabled(vcpu); + if (wants_ad && !enable_ept_ad_bits) return 1; kvm_mmu_unload(vcpu); kvm_init_shadow_ept_mmu(vcpu, to_vmx(vcpu)->nested.nested_vmx_ept_caps & VMX_EPT_EXECUTE_ONLY_BIT, - eptp & VMX_EPT_AD_ENABLE_BIT); + wants_ad); vcpu->arch.mmu.set_cr3 = vmx_set_cr3; vcpu->arch.mmu.get_cr3 = nested_ept_get_cr3; vcpu->arch.mmu.inject_page_fault = nested_ept_inject_page_fault;