From patchwork Thu May 11 11:23:29 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 9721201 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 6395A60236 for ; Thu, 11 May 2017 11:23:51 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 61A8E20072 for ; Thu, 11 May 2017 11:23:51 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 5640128663; Thu, 11 May 2017 11:23:51 +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=-6.3 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI, RCVD_IN_SORBS_SPAM, T_DKIM_INVALID autolearn=unavailable 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 DECB120072 for ; Thu, 11 May 2017 11:23:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932268AbdEKLXi (ORCPT ); Thu, 11 May 2017 07:23:38 -0400 Received: from mail-wr0-f196.google.com ([209.85.128.196]:34889 "EHLO mail-wr0-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751975AbdEKLXg (ORCPT ); Thu, 11 May 2017 07:23:36 -0400 Received: by mail-wr0-f196.google.com with SMTP id g12so3083856wrg.2; Thu, 11 May 2017 04:23:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=CABD+YUwjJOr0nhaklFq2rmuVcexwn3l/Ej82q5vlnI=; b=lQflhvBdJ/uzCx3gkfQp4PGpU/CJ5vhpVWTl3hsuhShSEdVsQed+WK77voOwWanNA9 V4RBIJEDqdFZ6S5e7370MDQ8UPh/bu55TSRg8hNZiugD0TKrL1iouSZKWbImd8t8LQLO OabApYrnvk+gGLVtqamtCIuHa/6iLY4RJW7Phbp8IyXLTKZ+yWowymnvY+KzhjDBbtef W8bipg/A4uaq/XSWcHWMbtsYJRD3avOEcuwCMWKtVU5AiHcXtJD6iqTZOmbYoarljlbB YvdXqXS/P2Yu80PLJkaJnNkwOxlvVG7J+KDhHZxK7m7g8rDmqfeIERXg6OYstWEH/kl9 7Ehg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references; bh=CABD+YUwjJOr0nhaklFq2rmuVcexwn3l/Ej82q5vlnI=; b=trQN76yIb84H5gJT1FZkKKLSzcfDKqKbKXkJas0rZ8KcvjHz8j94rNM1AEN60i9eQw OqpTemqAUHayfPP5iPY7reGyTQiRI0U6gLcLfJFJAAQTHN+220Tat2zuWspm9dLWZgJ7 obK5h5CMDGe7H6giqyfndzBOk3TBmZOkOCeg1W8F65hxDtcGo45tGiacmDebalagtOH5 VeytZIX0pr1AAIU70wfPOIcXsAr4jVfi0xWJzal5ujjUy5ZcwfnDo1+ycrZ+3gNkH15I /X841oKBEASoaE4bTyEreDEhK2Zar/N4i5YPe4kEgO//z+R9RKOVnfHxXtQxml7xLWDm 9HLg== X-Gm-Message-State: AODbwcD808sEyzyNj8FhEWuSLk//vJakT6HtbTj8av5vIeXVJQwDqpDs zLbZES/VrAnSLg== X-Received: by 10.223.132.132 with SMTP id 4mr7555472wrg.31.1494501814518; Thu, 11 May 2017 04:23:34 -0700 (PDT) Received: from 640k.lan (94-39-157-43.adsl-ull.clienti.tiscali.it. [94.39.157.43]) by smtp.gmail.com with ESMTPSA id v69sm5425447wmv.3.2017.05.11.04.23.33 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 11 May 2017 04:23:33 -0700 (PDT) From: Paolo Bonzini To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: Peter Feiner , David Matlack , =?UTF-8?q?Radim=20Kr=C4=8Dm=C3=A1=C5=99?= , Xiao Guangrong , Wanpeng Li Subject: [PATCH 1/2] KVM: nVMX: fix EPT permissions as reported in exit qualification Date: Thu, 11 May 2017 13:23:29 +0200 Message-Id: <1494501810-11822-2-git-send-email-pbonzini@redhat.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1494501810-11822-1-git-send-email-pbonzini@redhat.com> References: <1494501810-11822-1-git-send-email-pbonzini@redhat.com> Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This fixes the new ept_access_test_read_only and ept_access_test_read_write testcases from vmx.flat. The problem is that gpte_access moves bits around to switch from EPT bit order (XWR) to ACC_*_MASK bit order (RWX). This results in an incorrect exit qualification. To fix this, make pt_access and pte_access operate on raw PTE values (only with NX flipped to mean "can execute") and call gpte_access at the end of the walk. This lets us use pte_access to compute the exit qualification with XWR bit order. Signed-off-by: Paolo Bonzini Reviewed-by: Xiao Guangrong --- arch/x86/kvm/paging_tmpl.h | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h index 56241746abbd..b0454c7e4cff 100644 --- a/arch/x86/kvm/paging_tmpl.h +++ b/arch/x86/kvm/paging_tmpl.h @@ -283,11 +283,13 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, pt_element_t pte; pt_element_t __user *uninitialized_var(ptep_user); gfn_t table_gfn; - unsigned index, pt_access, pte_access, accessed_dirty, pte_pkey; + u64 pt_access, pte_access; + unsigned index, accessed_dirty, pte_pkey; unsigned nested_access; gpa_t pte_gpa; bool have_ad; int offset; + u64 walk_nx_mask = 0; const int write_fault = access & PFERR_WRITE_MASK; const int user_fault = access & PFERR_USER_MASK; const int fetch_fault = access & PFERR_FETCH_MASK; @@ -302,6 +304,7 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, have_ad = PT_HAVE_ACCESSED_DIRTY(mmu); #if PTTYPE == 64 + walk_nx_mask = 1ULL << PT64_NX_SHIFT; if (walker->level == PT32E_ROOT_LEVEL) { pte = mmu->get_pdptr(vcpu, (addr >> 30) & 3); trace_kvm_mmu_paging_element(pte, walker->level); @@ -313,8 +316,6 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, walker->max_level = walker->level; ASSERT(!(is_long_mode(vcpu) && !is_pae(vcpu))); - accessed_dirty = have_ad ? PT_GUEST_ACCESSED_MASK : 0; - /* * FIXME: on Intel processors, loads of the PDPTE registers for PAE paging * by the MOV to CR instruction are treated as reads and do not cause the @@ -322,14 +323,14 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, */ nested_access = (have_ad ? PFERR_WRITE_MASK : 0) | PFERR_USER_MASK; - pt_access = pte_access = ACC_ALL; + pte_access = ~0; ++walker->level; do { gfn_t real_gfn; unsigned long host_addr; - pt_access &= pte_access; + pt_access = pte_access; --walker->level; index = PT_INDEX(addr, walker->level); @@ -371,6 +372,12 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, trace_kvm_mmu_paging_element(pte, walker->level); + /* + * Inverting the NX it lets us AND it like other + * permission bits. + */ + pte_access = pt_access & (pte ^ walk_nx_mask); + if (unlikely(!FNAME(is_present_gpte)(pte))) goto error; @@ -379,14 +386,16 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, goto error; } - accessed_dirty &= pte; - pte_access = pt_access & FNAME(gpte_access)(vcpu, pte); - walker->ptes[walker->level - 1] = pte; } while (!is_last_gpte(mmu, walker->level, pte)); pte_pkey = FNAME(gpte_pkeys)(vcpu, pte); - errcode = permission_fault(vcpu, mmu, pte_access, pte_pkey, access); + accessed_dirty = have_ad ? pte_access & PT_GUEST_ACCESSED_MASK : 0; + + /* Convert to ACC_*_MASK flags for struct guest_walker. */ + walker->pt_access = FNAME(gpte_access)(vcpu, pt_access ^ walk_nx_mask); + walker->pte_access = FNAME(gpte_access)(vcpu, pte_access ^ walk_nx_mask); + errcode = permission_fault(vcpu, mmu, walker->pte_access, pte_pkey, access); if (unlikely(errcode)) goto error; @@ -403,7 +412,7 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, walker->gfn = real_gpa >> PAGE_SHIFT; if (!write_fault) - FNAME(protect_clean_gpte)(mmu, &pte_access, pte); + FNAME(protect_clean_gpte)(mmu, &walker->pte_access, pte); else /* * On a write fault, fold the dirty bit into accessed_dirty. @@ -421,10 +430,8 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, goto retry_walk; } - walker->pt_access = pt_access; - walker->pte_access = pte_access; pgprintk("%s: pte %llx pte_access %x pt_access %x\n", - __func__, (u64)pte, pte_access, pt_access); + __func__, (u64)pte, walker->pte_access, walker->pt_access); return 1; error: @@ -452,7 +459,7 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, */ if (!(errcode & PFERR_RSVD_MASK)) { vcpu->arch.exit_qualification &= 0x187; - vcpu->arch.exit_qualification |= ((pt_access & pte) & 0x7) << 3; + vcpu->arch.exit_qualification |= (pte_access & 0x7) << 3; } #endif walker->fault.address = addr;