[PATCHv2,2/3] x86/tdx: Fix race between set_memory_encrypted() and load_unaligned_zeropad()
Message ID | 20230526120225.31936-3-kirill.shutemov@linux.intel.com |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:994d:0:b0:3d9:f83d:47d9 with SMTP id k13csp422786vqr; Fri, 26 May 2023 05:13:15 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ6tvpkEvm0cxh6H1L7dTaUdVLQFDmK2pCHyambr7gEs6n8RI7se1hq/88sw6lM/MtL5scD9 X-Received: by 2002:a05:6a20:7350:b0:10f:6529:543b with SMTP id v16-20020a056a20735000b0010f6529543bmr2468516pzc.3.1685103194691; Fri, 26 May 2023 05:13:14 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1685103194; cv=none; d=google.com; s=arc-20160816; b=KirUn0fw+RfLt3kCj/+621nwiwfn/ssHJu5XRb98hWDamlkMzIa6+v0gNQ397oGoN1 Kt42y3y5fGHfd0pUcI0jULO55kWXF4kAbYJlyCpSKC4WxNPLXGdBsgcWvPEaSk+Nlb12 gWhGDMiO9tF48mVZ62wYyMQfH41hOzVIRY2rayBmVplALo0Z8AcgHpfKbft7+Ak8BJBJ tURmfjy4CIVY8nB7AMC6Eok/JNUene/YCgdI+XsKyHENwKfbZdkEy3yNyNSffaJqDIJx 5DJr+EkVNAoQ9Y44rottZGE5luHV1f55FvYfELWuTCFPd0JWqlkUwpOkzHMiSa+h5+JO xzwQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=Xhf5WcGABMs7mmpnznluCBlSm8NKMmeeWNE3BOkq6ls=; b=VfL6wvmHr6582Ksk2lFCrd9oxR/VwWCmcEMhlc5Qnowm310IqJLNB3v7UcKRCNu5T2 IL7xv+hTTsTn3lnWX2CzfFu0mhoWZDoDIaSd4pQiwJfnLLnoHTpabm5vKvYLUp2cVS9k +3b9trrIKrBzgznpztlFclQ3Rj4n7TpnaWa+H8DSIM5BXSn3DCK7LMJwD1K+OuFinebQ Y1B1ZR9U8eoMI94qo9CSzdUjfTGNCidXcMO6DE/igncacbMOpwFvDFG3HNlCKzjVNkmy pni9je6QKLWDYLknGBWsaKfBsTIomlOKaRQuJsIVoD4FJ4khwGVb2viFiR0rPGlEgrCs wS9w== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@intel.com header.s=Intel header.b=JwmBl1k4; 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=NONE sp=NONE dis=NONE) header.from=intel.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id 7-20020a621807000000b0063d45a6d0e5si2293986pfy.17.2023.05.26.05.13.02; Fri, 26 May 2023 05:13:14 -0700 (PDT) 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=@intel.com header.s=Intel header.b=JwmBl1k4; 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=NONE sp=NONE dis=NONE) header.from=intel.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231447AbjEZMDR (ORCPT <rfc822;zhanglyra.2023@gmail.com> + 99 others); Fri, 26 May 2023 08:03:17 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46488 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231679AbjEZMDO (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Fri, 26 May 2023 08:03:14 -0400 Received: from mga14.intel.com (mga14.intel.com [192.55.52.115]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1D2DFE46; Fri, 26 May 2023 05:02:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1685102579; x=1716638579; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=rT7cwEP37q2mK0/mhhF1SbjEW1zoGpi7jl7FkWAvvT4=; b=JwmBl1k464CcRfIFxUknh6/UqKNaTJZoAOxw/kF+yZ8hT5Zn3DNx+7jv Csb8x0YI5kFU/swerh+pdXuyRMYuFnX4zSLx55sLOHnluzVCAPQXW/gLc iCRaw1mcr2xxlecRqIu7lD5H2YvGYP38mvIYDY5uGpHqCkCRI5ywca0bi SdttbM3FdD3fJO6WzxrZ2rar8eRjYYZ+1Llp1uhlQz95q9UUWT2TXSjn9 YWhl1O1kcI+EqusRgdxJaFvdkNQEY+YhXjZgMf5drrjQYTyKWh+AxwRlU oLzfqm655ljtwyNxgMC/SD1ORwjDeUNRiQZvx0txeK7BNdbJYHfkCZ6u1 g==; X-IronPort-AV: E=McAfee;i="6600,9927,10721"; a="354201705" X-IronPort-AV: E=Sophos;i="6.00,194,1681196400"; d="scan'208";a="354201705" Received: from orsmga008.jf.intel.com ([10.7.209.65]) by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 26 May 2023 05:02:38 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10721"; a="735987427" X-IronPort-AV: E=Sophos;i="6.00,194,1681196400"; d="scan'208";a="735987427" Received: from fgarrona-mobl.ger.corp.intel.com (HELO box.shutemov.name) ([10.251.208.169]) by orsmga008-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 26 May 2023 05:02:34 -0700 Received: by box.shutemov.name (Postfix, from userid 1000) id 3C48510DC17; Fri, 26 May 2023 15:02:32 +0300 (+03) From: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com> To: dave.hansen@intel.com, tglx@linutronix.de, mingo@redhat.com, bp@alien8.de Cc: decui@microsoft.com, rick.p.edgecombe@intel.com, sathyanarayanan.kuppuswamy@linux.intel.com, seanjc@google.com, thomas.lendacky@amd.com, x86@kernel.org, linux-kernel@vger.kernel.org, "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>, stable@vger.kernel.org Subject: [PATCHv2 2/3] x86/tdx: Fix race between set_memory_encrypted() and load_unaligned_zeropad() Date: Fri, 26 May 2023 15:02:24 +0300 Message-Id: <20230526120225.31936-3-kirill.shutemov@linux.intel.com> X-Mailer: git-send-email 2.39.3 In-Reply-To: <20230526120225.31936-1-kirill.shutemov@linux.intel.com> References: <20230526120225.31936-1-kirill.shutemov@linux.intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-4.3 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_EF,RCVD_IN_DNSWL_MED,SPF_HELO_NONE, SPF_NONE,T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED autolearn=ham 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?1766958767741341171?= X-GMAIL-MSGID: =?utf-8?q?1766958767741341171?= |
Series |
x86/tdx: Fix one more load_unaligned_zeropad() issue
|
|
Commit Message
Kirill A. Shutemov
May 26, 2023, 12:02 p.m. UTC
Touching privately mapped GPA that is not properly converted to private
with MapGPA and accepted leads to unrecoverable exit to VMM.
load_unaligned_zeropad() can touch memory that is not owned by the
caller, but just happened to next after the owned memory.
This load_unaligned_zeropad() behaviour makes it important when kernel
asks VMM to convert a GPA from shared to private or back. Kernel must
never have a page mapped into direct mapping (and aliases) as private
when the GPA is already converted to shared or when GPA is not yet
converted to private.
guest.enc_status_change_prepare() called before adjusting direct mapping
and therefore it is responsible for converting the memory to private.
guest.enc_status_change_finish() called after adjusting direct mapping
and it converts the memory to shared.
It is okay to have a shared mapping of memory that is not converted
properly. handle_mmio() knows how to deal with load_unaligned_zeropad()
stepping on it.
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Fixes: 7dbde7631629 ("x86/mm/cpa: Add support for TDX shared memory")
Cc: stable@vger.kernel.org
---
arch/x86/coco/tdx/tdx.c | 56 ++++++++++++++++++++++++++++++++++++++---
1 file changed, 53 insertions(+), 3 deletions(-)
Comments
On 5/26/23 5:02 AM, Kirill A. Shutemov wrote: > Touching privately mapped GPA that is not properly converted to private > with MapGPA and accepted leads to unrecoverable exit to VMM. > > load_unaligned_zeropad() can touch memory that is not owned by the > caller, but just happened to next after the owned memory. /s/to/to be ? > This load_unaligned_zeropad() behaviour makes it important when kernel > asks VMM to convert a GPA from shared to private or back. Kernel must > never have a page mapped into direct mapping (and aliases) as private > when the GPA is already converted to shared or when GPA is not yet > converted to private. I am wondering whether this issue exist in the AMD code? IMO, you can add some info on the window in set_memory_encrypted() where this race exists. > > guest.enc_status_change_prepare() called before adjusting direct mapping > and therefore it is responsible for converting the memory to private. > > guest.enc_status_change_finish() called after adjusting direct mapping > and it converts the memory to shared. > > It is okay to have a shared mapping of memory that is not converted > properly. handle_mmio() knows how to deal with load_unaligned_zeropad() > stepping on it. > > Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> > Fixes: 7dbde7631629 ("x86/mm/cpa: Add support for TDX shared memory") > Cc: stable@vger.kernel.org > --- > arch/x86/coco/tdx/tdx.c | 56 ++++++++++++++++++++++++++++++++++++++--- > 1 file changed, 53 insertions(+), 3 deletions(-) > > diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c > index e146b599260f..59cc13e41aa6 100644 > --- a/arch/x86/coco/tdx/tdx.c > +++ b/arch/x86/coco/tdx/tdx.c > @@ -840,6 +840,30 @@ static bool tdx_enc_status_changed(unsigned long vaddr, int numpages, bool enc) > return true; > } > > +static bool tdx_enc_status_change_prepare(unsigned long vaddr, int numpages, > + bool enc) > +{ > + /* > + * Only handle shared->private conversion here. > + * See the comment in tdx_early_init(). > + */ > + if (enc) > + return tdx_enc_status_changed(vaddr, numpages, enc); > + return true; > +} > + > +static bool tdx_enc_status_change_finish(unsigned long vaddr, int numpages, > + bool enc) > +{ > + /* > + * Only handle private->shared conversion here. > + * See the comment in tdx_early_init(). > + */ > + if (!enc) > + return tdx_enc_status_changed(vaddr, numpages, enc); > + return true; > +} > + > void __init tdx_early_init(void) > { > u64 cc_mask; > @@ -867,9 +891,35 @@ void __init tdx_early_init(void) > */ > physical_mask &= cc_mask - 1; > > - x86_platform.guest.enc_cache_flush_required = tdx_cache_flush_required; > - x86_platform.guest.enc_tlb_flush_required = tdx_tlb_flush_required; I think you don't need to change the order here. > - x86_platform.guest.enc_status_change_finish = tdx_enc_status_changed; > + /* > + * Touching privately mapped GPA that is not properly converted to > + * private with MapGPA and accepted leads to unrecoverable exit > + * to VMM. > + * > + * load_unaligned_zeropad() can touch memory that is not owned by > + * the caller, but just happened to next after the owned memory. > + * This load_unaligned_zeropad() behaviour makes it important when > + * kernel asks VMM to convert a GPA from shared to private or back. > + * Kernel must never have a page mapped into direct mapping (and > + * aliases) as private when the GPA is already converted to shared or > + * when GPA is not yet converted to private. > + * > + * guest.enc_status_change_prepare() called before adjusting direct > + * mapping and therefore it is responsible for converting the memory > + * to private. > + * > + * guest.enc_status_change_finish() called after adjusting direct > + * mapping and it converts the memory to shared. > + * > + * It is okay to have a shared mapping of memory that is not converted > + * properly. handle_mmio() knows how to deal with load_unaligned_zeropad() > + * stepping on it. > + */ > + x86_platform.guest.enc_status_change_prepare = tdx_enc_status_change_prepare; > + x86_platform.guest.enc_status_change_finish = tdx_enc_status_change_finish; > + > + x86_platform.guest.enc_cache_flush_required = tdx_cache_flush_required; > + x86_platform.guest.enc_tlb_flush_required = tdx_tlb_flush_required; > > pr_info("Guest detected\n"); > }
On Fri, May 26, 2023 at 03:10:56PM -0700, Sathyanarayanan Kuppuswamy wrote: > > > On 5/26/23 5:02 AM, Kirill A. Shutemov wrote: > > Touching privately mapped GPA that is not properly converted to private > > with MapGPA and accepted leads to unrecoverable exit to VMM. > > > > load_unaligned_zeropad() can touch memory that is not owned by the > > caller, but just happened to next after the owned memory. > > /s/to/to be ? Yep, my bad. > > This load_unaligned_zeropad() behaviour makes it important when kernel > > asks VMM to convert a GPA from shared to private or back. Kernel must > > never have a page mapped into direct mapping (and aliases) as private > > when the GPA is already converted to shared or when GPA is not yet > > converted to private. > > I am wondering whether this issue exist in the AMD code? > > IMO, you can add some info on the window in set_memory_encrypted() > where this race exists. I don't think AMD affected by load_unaligned_zeropad() the same way as Intel does. But I'm not sure. Tom, do you have any comments? > > > > > guest.enc_status_change_prepare() called before adjusting direct mapping > > and therefore it is responsible for converting the memory to private. > > > > guest.enc_status_change_finish() called after adjusting direct mapping > > and it converts the memory to shared. > > > > It is okay to have a shared mapping of memory that is not converted > > properly. handle_mmio() knows how to deal with load_unaligned_zeropad() > > stepping on it. > > > > > Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> > > Fixes: 7dbde7631629 ("x86/mm/cpa: Add support for TDX shared memory") > > Cc: stable@vger.kernel.org > > --- > > arch/x86/coco/tdx/tdx.c | 56 ++++++++++++++++++++++++++++++++++++++--- > > 1 file changed, 53 insertions(+), 3 deletions(-) > > > > diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c > > index e146b599260f..59cc13e41aa6 100644 > > --- a/arch/x86/coco/tdx/tdx.c > > +++ b/arch/x86/coco/tdx/tdx.c > > @@ -840,6 +840,30 @@ static bool tdx_enc_status_changed(unsigned long vaddr, int numpages, bool enc) > > return true; > > } > > > > +static bool tdx_enc_status_change_prepare(unsigned long vaddr, int numpages, > > + bool enc) > > +{ > > + /* > > + * Only handle shared->private conversion here. > > + * See the comment in tdx_early_init(). > > + */ > > + if (enc) > > + return tdx_enc_status_changed(vaddr, numpages, enc); > > + return true; > > +} > > + > > +static bool tdx_enc_status_change_finish(unsigned long vaddr, int numpages, > > + bool enc) > > +{ > > + /* > > + * Only handle private->shared conversion here. > > + * See the comment in tdx_early_init(). > > + */ > > + if (!enc) > > + return tdx_enc_status_changed(vaddr, numpages, enc); > > + return true; > > +} > > + > > void __init tdx_early_init(void) > > { > > u64 cc_mask; > > @@ -867,9 +891,35 @@ void __init tdx_early_init(void) > > */ > > physical_mask &= cc_mask - 1; > > > > - x86_platform.guest.enc_cache_flush_required = tdx_cache_flush_required; > > - x86_platform.guest.enc_tlb_flush_required = tdx_tlb_flush_required; > > I think you don't need to change the order here. I wanted to emphasise that the comment is for _prepare/_finish callbacks and I hoped re-order would help with this. > > - x86_platform.guest.enc_status_change_finish = tdx_enc_status_changed; > > + /* > > + * Touching privately mapped GPA that is not properly converted to > > + * private with MapGPA and accepted leads to unrecoverable exit > > + * to VMM. > > + * > > + * load_unaligned_zeropad() can touch memory that is not owned by > > + * the caller, but just happened to next after the owned memory. > > + * This load_unaligned_zeropad() behaviour makes it important when > > + * kernel asks VMM to convert a GPA from shared to private or back. > > + * Kernel must never have a page mapped into direct mapping (and > > + * aliases) as private when the GPA is already converted to shared or > > + * when GPA is not yet converted to private. > > + * > > + * guest.enc_status_change_prepare() called before adjusting direct > > + * mapping and therefore it is responsible for converting the memory > > + * to private. > > + * > > + * guest.enc_status_change_finish() called after adjusting direct > > + * mapping and it converts the memory to shared. > > + * > > + * It is okay to have a shared mapping of memory that is not converted > > + * properly. handle_mmio() knows how to deal with load_unaligned_zeropad() > > + * stepping on it. > > + */ > > + x86_platform.guest.enc_status_change_prepare = tdx_enc_status_change_prepare; > > + x86_platform.guest.enc_status_change_finish = tdx_enc_status_change_finish; > > + > > + x86_platform.guest.enc_cache_flush_required = tdx_cache_flush_required; > > + x86_platform.guest.enc_tlb_flush_required = tdx_tlb_flush_required; > > > > pr_info("Guest detected\n"); > > } > > -- > Sathyanarayanan Kuppuswamy > Linux Kernel Developer
On 5/29/23 19:57, Kirill A. Shutemov wrote: > On Fri, May 26, 2023 at 03:10:56PM -0700, Sathyanarayanan Kuppuswamy wrote: >> >> >> On 5/26/23 5:02 AM, Kirill A. Shutemov wrote: >>> Touching privately mapped GPA that is not properly converted to private >>> with MapGPA and accepted leads to unrecoverable exit to VMM. >>> >>> load_unaligned_zeropad() can touch memory that is not owned by the >>> caller, but just happened to next after the owned memory. >> >> /s/to/to be ? > > Yep, my bad. > >>> This load_unaligned_zeropad() behaviour makes it important when kernel >>> asks VMM to convert a GPA from shared to private or back. Kernel must >>> never have a page mapped into direct mapping (and aliases) as private >>> when the GPA is already converted to shared or when GPA is not yet >>> converted to private. >> >> I am wondering whether this issue exist in the AMD code? >> >> IMO, you can add some info on the window in set_memory_encrypted() >> where this race exists. > > I don't think AMD affected by load_unaligned_zeropad() the same way as > Intel does. But I'm not sure. > > Tom, do you have any comments? Right, shouldn't be an issue for SNP. Thanks, Tom > >> >>> >>> guest.enc_status_change_prepare() called before adjusting direct mapping >>> and therefore it is responsible for converting the memory to private. >>> >>> guest.enc_status_change_finish() called after adjusting direct mapping >>> and it converts the memory to shared. >>> >>> It is okay to have a shared mapping of memory that is not converted >>> properly. handle_mmio() knows how to deal with load_unaligned_zeropad() >>> stepping on it. >> >>> >>> Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> >>> Fixes: 7dbde7631629 ("x86/mm/cpa: Add support for TDX shared memory") >>> Cc: stable@vger.kernel.org >>> --- >>> arch/x86/coco/tdx/tdx.c | 56 ++++++++++++++++++++++++++++++++++++++--- >>> 1 file changed, 53 insertions(+), 3 deletions(-) >>> >>> diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c >>> index e146b599260f..59cc13e41aa6 100644 >>> --- a/arch/x86/coco/tdx/tdx.c >>> +++ b/arch/x86/coco/tdx/tdx.c >>> @@ -840,6 +840,30 @@ static bool tdx_enc_status_changed(unsigned long vaddr, int numpages, bool enc) >>> return true; >>> } >>> >>> +static bool tdx_enc_status_change_prepare(unsigned long vaddr, int numpages, >>> + bool enc) >>> +{ >>> + /* >>> + * Only handle shared->private conversion here. >>> + * See the comment in tdx_early_init(). >>> + */ >>> + if (enc) >>> + return tdx_enc_status_changed(vaddr, numpages, enc); >>> + return true; >>> +} >>> + >>> +static bool tdx_enc_status_change_finish(unsigned long vaddr, int numpages, >>> + bool enc) >>> +{ >>> + /* >>> + * Only handle private->shared conversion here. >>> + * See the comment in tdx_early_init(). >>> + */ >>> + if (!enc) >>> + return tdx_enc_status_changed(vaddr, numpages, enc); >>> + return true; >>> +} >>> + >>> void __init tdx_early_init(void) >>> { >>> u64 cc_mask; >>> @@ -867,9 +891,35 @@ void __init tdx_early_init(void) >>> */ >>> physical_mask &= cc_mask - 1; >>> >>> - x86_platform.guest.enc_cache_flush_required = tdx_cache_flush_required; >>> - x86_platform.guest.enc_tlb_flush_required = tdx_tlb_flush_required; >> >> I think you don't need to change the order here. > > I wanted to emphasise that the comment is for _prepare/_finish callbacks > and I hoped re-order would help with this. > >>> - x86_platform.guest.enc_status_change_finish = tdx_enc_status_changed; >>> + /* >>> + * Touching privately mapped GPA that is not properly converted to >>> + * private with MapGPA and accepted leads to unrecoverable exit >>> + * to VMM. >>> + * >>> + * load_unaligned_zeropad() can touch memory that is not owned by >>> + * the caller, but just happened to next after the owned memory. >>> + * This load_unaligned_zeropad() behaviour makes it important when >>> + * kernel asks VMM to convert a GPA from shared to private or back. >>> + * Kernel must never have a page mapped into direct mapping (and >>> + * aliases) as private when the GPA is already converted to shared or >>> + * when GPA is not yet converted to private. >>> + * >>> + * guest.enc_status_change_prepare() called before adjusting direct >>> + * mapping and therefore it is responsible for converting the memory >>> + * to private. >>> + * >>> + * guest.enc_status_change_finish() called after adjusting direct >>> + * mapping and it converts the memory to shared. >>> + * >>> + * It is okay to have a shared mapping of memory that is not converted >>> + * properly. handle_mmio() knows how to deal with load_unaligned_zeropad() >>> + * stepping on it. >>> + */ >>> + x86_platform.guest.enc_status_change_prepare = tdx_enc_status_change_prepare; >>> + x86_platform.guest.enc_status_change_finish = tdx_enc_status_change_finish; >>> + >>> + x86_platform.guest.enc_cache_flush_required = tdx_cache_flush_required; >>> + x86_platform.guest.enc_tlb_flush_required = tdx_tlb_flush_required; >>> >>> pr_info("Guest detected\n"); >>> } >> >> -- >> Sathyanarayanan Kuppuswamy >> Linux Kernel Developer >
Hi, On 5/30/23 5:57 AM, Tom Lendacky wrote: > On 5/29/23 19:57, Kirill A. Shutemov wrote: >> On Fri, May 26, 2023 at 03:10:56PM -0700, Sathyanarayanan Kuppuswamy wrote: >>> >>> >>> On 5/26/23 5:02 AM, Kirill A. Shutemov wrote: >>>> Touching privately mapped GPA that is not properly converted to private >>>> with MapGPA and accepted leads to unrecoverable exit to VMM. >>>> >>>> load_unaligned_zeropad() can touch memory that is not owned by the >>>> caller, but just happened to next after the owned memory. >>> >>> /s/to/to be ? >> >> Yep, my bad. >> >>>> This load_unaligned_zeropad() behaviour makes it important when kernel >>>> asks VMM to convert a GPA from shared to private or back. Kernel must >>>> never have a page mapped into direct mapping (and aliases) as private >>>> when the GPA is already converted to shared or when GPA is not yet >>>> converted to private. >>> >>> I am wondering whether this issue exist in the AMD code? >>> >>> IMO, you can add some info on the window in set_memory_encrypted() >>> where this race exists. >> >> I don't think AMD affected by load_unaligned_zeropad() the same way as >> Intel does. But I'm not sure. >> >> Tom, do you have any comments? > > Right, shouldn't be an issue for SNP. Thanks for confirming. > > Thanks, > Tom > >> >>> >>>> >>>> guest.enc_status_change_prepare() called before adjusting direct mapping >>>> and therefore it is responsible for converting the memory to private. >>>> >>>> guest.enc_status_change_finish() called after adjusting direct mapping >>>> and it converts the memory to shared. >>>> >>>> It is okay to have a shared mapping of memory that is not converted >>>> properly. handle_mmio() knows how to deal with load_unaligned_zeropad() >>>> stepping on it. >>> >>>> Rest looks good to me. Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com> >>>> Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> >>>> Fixes: 7dbde7631629 ("x86/mm/cpa: Add support for TDX shared memory") >>>> Cc: stable@vger.kernel.org >>>> --- >>>> arch/x86/coco/tdx/tdx.c | 56 ++++++++++++++++++++++++++++++++++++++--- >>>> 1 file changed, 53 insertions(+), 3 deletions(-) >>>> >>>> diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c >>>> index e146b599260f..59cc13e41aa6 100644 >>>> --- a/arch/x86/coco/tdx/tdx.c >>>> +++ b/arch/x86/coco/tdx/tdx.c >>>> @@ -840,6 +840,30 @@ static bool tdx_enc_status_changed(unsigned long vaddr, int numpages, bool enc) >>>> return true; >>>> } >>>> +static bool tdx_enc_status_change_prepare(unsigned long vaddr, int numpages, >>>> + bool enc) >>>> +{ >>>> + /* >>>> + * Only handle shared->private conversion here. >>>> + * See the comment in tdx_early_init(). >>>> + */ >>>> + if (enc) >>>> + return tdx_enc_status_changed(vaddr, numpages, enc); >>>> + return true; >>>> +} >>>> + >>>> +static bool tdx_enc_status_change_finish(unsigned long vaddr, int numpages, >>>> + bool enc) >>>> +{ >>>> + /* >>>> + * Only handle private->shared conversion here. >>>> + * See the comment in tdx_early_init(). >>>> + */ >>>> + if (!enc) >>>> + return tdx_enc_status_changed(vaddr, numpages, enc); >>>> + return true; >>>> +} >>>> + >>>> void __init tdx_early_init(void) >>>> { >>>> u64 cc_mask; >>>> @@ -867,9 +891,35 @@ void __init tdx_early_init(void) >>>> */ >>>> physical_mask &= cc_mask - 1; >>>> - x86_platform.guest.enc_cache_flush_required = tdx_cache_flush_required; >>>> - x86_platform.guest.enc_tlb_flush_required = tdx_tlb_flush_required; >>> >>> I think you don't need to change the order here. >> >> I wanted to emphasise that the comment is for _prepare/_finish callbacks >> and I hoped re-order would help with this. >> >>>> - x86_platform.guest.enc_status_change_finish = tdx_enc_status_changed; >>>> + /* >>>> + * Touching privately mapped GPA that is not properly converted to >>>> + * private with MapGPA and accepted leads to unrecoverable exit >>>> + * to VMM. >>>> + * >>>> + * load_unaligned_zeropad() can touch memory that is not owned by >>>> + * the caller, but just happened to next after the owned memory. >>>> + * This load_unaligned_zeropad() behaviour makes it important when >>>> + * kernel asks VMM to convert a GPA from shared to private or back. >>>> + * Kernel must never have a page mapped into direct mapping (and >>>> + * aliases) as private when the GPA is already converted to shared or >>>> + * when GPA is not yet converted to private. >>>> + * >>>> + * guest.enc_status_change_prepare() called before adjusting direct >>>> + * mapping and therefore it is responsible for converting the memory >>>> + * to private. >>>> + * >>>> + * guest.enc_status_change_finish() called after adjusting direct >>>> + * mapping and it converts the memory to shared. >>>> + * >>>> + * It is okay to have a shared mapping of memory that is not converted >>>> + * properly. handle_mmio() knows how to deal with load_unaligned_zeropad() >>>> + * stepping on it. >>>> + */ >>>> + x86_platform.guest.enc_status_change_prepare = tdx_enc_status_change_prepare; >>>> + x86_platform.guest.enc_status_change_finish = tdx_enc_status_change_finish; >>>> + >>>> + x86_platform.guest.enc_cache_flush_required = tdx_cache_flush_required; >>>> + x86_platform.guest.enc_tlb_flush_required = tdx_tlb_flush_required; >>>> pr_info("Guest detected\n"); >>>> } >>> >>> -- >>> Sathyanarayanan Kuppuswamy >>> Linux Kernel Developer >>
From: Sathyanarayanan Kuppuswamy <sathyanarayanan.kuppuswamy@linux.intel.com> Sent: Tuesday, May 30, 2023 6:22 AM > > Hi, > > On 5/30/23 5:57 AM, Tom Lendacky wrote: > > On 5/29/23 19:57, Kirill A. Shutemov wrote: > >> On Fri, May 26, 2023 at 03:10:56PM -0700, Sathyanarayanan Kuppuswamy wrote: > >>> > >>> > >>> On 5/26/23 5:02 AM, Kirill A. Shutemov wrote: > >>>> Touching privately mapped GPA that is not properly converted to private > >>>> with MapGPA and accepted leads to unrecoverable exit to VMM. > >>>> > >>>> load_unaligned_zeropad() can touch memory that is not owned by the > >>>> caller, but just happened to next after the owned memory. > >>> > >>> /s/to/to be ? > >> > >> Yep, my bad. > >> > >>>> This load_unaligned_zeropad() behaviour makes it important when kernel > >>>> asks VMM to convert a GPA from shared to private or back. Kernel must > >>>> never have a page mapped into direct mapping (and aliases) as private > >>>> when the GPA is already converted to shared or when GPA is not yet > >>>> converted to private. > >>> > >>> I am wondering whether this issue exist in the AMD code? > >>> > >>> IMO, you can add some info on the window in set_memory_encrypted() > >>> where this race exists. > >> > >> I don't think AMD affected by load_unaligned_zeropad() the same way as > >> Intel does. But I'm not sure. > >> > >> Tom, do you have any comments? > > > > Right, shouldn't be an issue for SNP. > > Thanks for confirming. > Tom -- For my education, could you elaborate on why this problem can't occur in an SEV-SNP guest? There's still a window where the direct map PTE and the RMP as maintained by the hypervisor are out-of-sync. If load_unaligned_zeropad() does a read using the direct map PTE during this out-of-sync window, isn't that going to trap to the hypervisor? How is the scenario is handled from there to provide the zeros to load_unaligned_zeropad()? I need to make sure Hyper-V is doing whatever is needed. :-) Thanks, Michael
On 5/31/23 15:00, Michael Kelley (LINUX) wrote: > From: Sathyanarayanan Kuppuswamy <sathyanarayanan.kuppuswamy@linux.intel.com> > Sent: Tuesday, May 30, 2023 6:22 AM >> >> Hi, >> >> On 5/30/23 5:57 AM, Tom Lendacky wrote: >>> On 5/29/23 19:57, Kirill A. Shutemov wrote: >>>> On Fri, May 26, 2023 at 03:10:56PM -0700, Sathyanarayanan Kuppuswamy wrote: >>>>> >>>>> >>>>> On 5/26/23 5:02 AM, Kirill A. Shutemov wrote: >>>>>> Touching privately mapped GPA that is not properly converted to private >>>>>> with MapGPA and accepted leads to unrecoverable exit to VMM. >>>>>> >>>>>> load_unaligned_zeropad() can touch memory that is not owned by the >>>>>> caller, but just happened to next after the owned memory. >>>>> >>>>> /s/to/to be ? >>>> >>>> Yep, my bad. >>>> >>>>>> This load_unaligned_zeropad() behaviour makes it important when kernel >>>>>> asks VMM to convert a GPA from shared to private or back. Kernel must >>>>>> never have a page mapped into direct mapping (and aliases) as private >>>>>> when the GPA is already converted to shared or when GPA is not yet >>>>>> converted to private. >>>>> >>>>> I am wondering whether this issue exist in the AMD code? >>>>> >>>>> IMO, you can add some info on the window in set_memory_encrypted() >>>>> where this race exists. >>>> >>>> I don't think AMD affected by load_unaligned_zeropad() the same way as >>>> Intel does. But I'm not sure. >>>> >>>> Tom, do you have any comments? >>> >>> Right, shouldn't be an issue for SNP. >> >> Thanks for confirming. >> > > Tom -- For my education, could you elaborate on why this problem can't > occur in an SEV-SNP guest? There's still a window where the direct map > PTE and the RMP as maintained by the hypervisor are out-of-sync. If > load_unaligned_zeropad() does a read using the direct map PTE during > this out-of-sync window, isn't that going to trap to the hypervisor? How > is the scenario is handled from there to provide the zeros to > load_unaligned_zeropad()? I need to make sure Hyper-V is doing whatever > is needed. :-) Ah, I think I misunderstood this when it was being talked about. The issue SNP would have would be between setting the c-bit but before the PVALIDATE is issued. Prior to the RMP being updated, referencing the page will generate an #NPF and automatically change the RMP over to private (in KVM). However, after the guest is resumed, the page will not have been validated resulting in a #VC with error code 0x404 being generated, causing the guest to terminate itself. I suppose, when a 0x404 error code is encountered by the #VC handler, it could call search_exception_tables() and call ex_handler_zeropad() for the EX_TYPE_ZEROPAD type (ex_handler_zeropad is currently static, though). Thanks, Tom > > Thanks, > > Michael > >
From: Tom Lendacky <thomas.lendacky@amd.com> Sent: Thursday, June 1, 2023 11:19 AM > > On 5/31/23 15:00, Michael Kelley (LINUX) wrote: > > From: Sathyanarayanan Kuppuswamy > <sathyanarayanan.kuppuswamy@linux.intel.com> > > Sent: Tuesday, May 30, 2023 6:22 AM > >> > >> Hi, > >> > >> On 5/30/23 5:57 AM, Tom Lendacky wrote: > >>> On 5/29/23 19:57, Kirill A. Shutemov wrote: > >>>> On Fri, May 26, 2023 at 03:10:56PM -0700, Sathyanarayanan Kuppuswamy > wrote: > >>>>> > >>>>> > >>>>> On 5/26/23 5:02 AM, Kirill A. Shutemov wrote: > >>>>>> Touching privately mapped GPA that is not properly converted to private > >>>>>> with MapGPA and accepted leads to unrecoverable exit to VMM. > >>>>>> > >>>>>> load_unaligned_zeropad() can touch memory that is not owned by the > >>>>>> caller, but just happened to next after the owned memory. > >>>>> > >>>>> /s/to/to be ? > >>>> > >>>> Yep, my bad. > >>>> > >>>>>> This load_unaligned_zeropad() behaviour makes it important when kernel > >>>>>> asks VMM to convert a GPA from shared to private or back. Kernel must > >>>>>> never have a page mapped into direct mapping (and aliases) as private > >>>>>> when the GPA is already converted to shared or when GPA is not yet > >>>>>> converted to private. > >>>>> > >>>>> I am wondering whether this issue exist in the AMD code? > >>>>> > >>>>> IMO, you can add some info on the window in set_memory_encrypted() > >>>>> where this race exists. > >>>> > >>>> I don't think AMD affected by load_unaligned_zeropad() the same way as > >>>> Intel does. But I'm not sure. > >>>> > >>>> Tom, do you have any comments? > >>> > >>> Right, shouldn't be an issue for SNP. > >> > >> Thanks for confirming. > >> > > > > Tom -- For my education, could you elaborate on why this problem can't > > occur in an SEV-SNP guest? There's still a window where the direct map > > PTE and the RMP as maintained by the hypervisor are out-of-sync. If > > load_unaligned_zeropad() does a read using the direct map PTE during > > this out-of-sync window, isn't that going to trap to the hypervisor? How > > is the scenario is handled from there to provide the zeros to > > load_unaligned_zeropad()? I need to make sure Hyper-V is doing whatever > > is needed. :-) > > Ah, I think I misunderstood this when it was being talked about. The issue > SNP would have would be between setting the c-bit but before the PVALIDATE > is issued. Prior to the RMP being updated, referencing the page will > generate an #NPF and automatically change the RMP over to private (in > KVM). However, after the guest is resumed, the page will not have been > validated resulting in a #VC with error code 0x404 being generated, > causing the guest to terminate itself. > > I suppose, when a 0x404 error code is encountered by the #VC handler, it > could call search_exception_tables() and call ex_handler_zeropad() for the > EX_TYPE_ZEROPAD type (ex_handler_zeropad is currently static, though). > Tom -- Does the above sequence *depend* on the hypervisor doing anything to make it work? I'm not clear on why KVM would automatically change the page over to private. If there's a dependency on the hypervisor doing something, then it seems like we'll need to standardize that "something" across hypervisors, lest we end up with per-hypervisor code in Linux to handle this scenario. And running SEV-SNP with multiple VMPLs probably makes it even more complicated. Kirill -- Same question about TDX. Does making load_unaligned_zeropad() work in a TDX VM depend on the hypervisor doing anything? Or is the behavior seen by the guest dependent only on architected behavior of the TDX processor? Looking at this problem from a slightly higher level, and thinking out loud a bit, load_unaligned_zeropad() functionality is provided only for certain architectures: x86/64, arm, arm64, and PowerPC 64 (little endian). There are fallbacks for architectures that don't support it. With two minor tweaks to Kconfig files, I've built x86 with load_unaligned_zeropad() disabled. Maybe with today's processors the performance benefits are past their prime, and running with it disabled in CoCo VMs is the better solution. Does anyone have a sense of whether the perf impact would be measureable? If doing the load_unaligned_zeropad() enable/disable at build time is too limiting, maybe it could be runtime based on whether page private/shared state is being enforced. I haven't looked at the details. Thoughts? Michael
On 6/2/23 11:11, Michael Kelley (LINUX) wrote: > From: Tom Lendacky <thomas.lendacky@amd.com> Sent: Thursday, June 1, 2023 11:19 AM >> >> On 5/31/23 15:00, Michael Kelley (LINUX) wrote: >>> From: Sathyanarayanan Kuppuswamy >> <sathyanarayanan.kuppuswamy@linux.intel.com> >>> Sent: Tuesday, May 30, 2023 6:22 AM >>>> >>>> Hi, >>>> >>>> On 5/30/23 5:57 AM, Tom Lendacky wrote: >>>>> On 5/29/23 19:57, Kirill A. Shutemov wrote: >>>>>> On Fri, May 26, 2023 at 03:10:56PM -0700, Sathyanarayanan Kuppuswamy >> wrote: >>>>>>> >>>>>>> >>>>>>> On 5/26/23 5:02 AM, Kirill A. Shutemov wrote: >>>>>>>> Touching privately mapped GPA that is not properly converted to private >>>>>>>> with MapGPA and accepted leads to unrecoverable exit to VMM. >>>>>>>> >>>>>>>> load_unaligned_zeropad() can touch memory that is not owned by the >>>>>>>> caller, but just happened to next after the owned memory. >>>>>>> >>>>>>> /s/to/to be ? >>>>>> >>>>>> Yep, my bad. >>>>>> >>>>>>>> This load_unaligned_zeropad() behaviour makes it important when kernel >>>>>>>> asks VMM to convert a GPA from shared to private or back. Kernel must >>>>>>>> never have a page mapped into direct mapping (and aliases) as private >>>>>>>> when the GPA is already converted to shared or when GPA is not yet >>>>>>>> converted to private. >>>>>>> >>>>>>> I am wondering whether this issue exist in the AMD code? >>>>>>> >>>>>>> IMO, you can add some info on the window in set_memory_encrypted() >>>>>>> where this race exists. >>>>>> >>>>>> I don't think AMD affected by load_unaligned_zeropad() the same way as >>>>>> Intel does. But I'm not sure. >>>>>> >>>>>> Tom, do you have any comments? >>>>> >>>>> Right, shouldn't be an issue for SNP. >>>> >>>> Thanks for confirming. >>>> >>> >>> Tom -- For my education, could you elaborate on why this problem can't >>> occur in an SEV-SNP guest? There's still a window where the direct map >>> PTE and the RMP as maintained by the hypervisor are out-of-sync. If >>> load_unaligned_zeropad() does a read using the direct map PTE during >>> this out-of-sync window, isn't that going to trap to the hypervisor? How >>> is the scenario is handled from there to provide the zeros to >>> load_unaligned_zeropad()? I need to make sure Hyper-V is doing whatever >>> is needed. :-) >> >> Ah, I think I misunderstood this when it was being talked about. The issue >> SNP would have would be between setting the c-bit but before the PVALIDATE >> is issued. Prior to the RMP being updated, referencing the page will >> generate an #NPF and automatically change the RMP over to private (in >> KVM). However, after the guest is resumed, the page will not have been >> validated resulting in a #VC with error code 0x404 being generated, >> causing the guest to terminate itself. >> >> I suppose, when a 0x404 error code is encountered by the #VC handler, it >> could call search_exception_tables() and call ex_handler_zeropad() for the >> EX_TYPE_ZEROPAD type (ex_handler_zeropad is currently static, though). >> > > Tom -- Does the above sequence *depend* on the hypervisor doing anything > to make it work? I'm not clear on why KVM would automatically change the > page over to private. If there's a dependency on the hypervisor doing > something, then it seems like we'll need to standardize that "something" > across hypervisors, lest we end up with per-hypervisor code in Linux to handle > this scenario. And running SEV-SNP with multiple VMPLs probably makes it > even more complicated. No, it doesn't depend on the hypervisor doing anything. If the RMP hasn't been updated, then a #VMEXIT(NPF) will be triggered (see APM vol 2, Table 15-39). The hypervisor is free to do what it wants with that, e.g. just resume the guest (and immediately take another #VMEXIT(NPF), possibly). Since it is a different thread/vCPU trying to access the memory than is changing the state of the memory, eventually the guest kernel thread that is changing the state of the memory will issue the page state change to the hypervisor and the other thread can continue. Thanks, Tom > > Kirill -- Same question about TDX. Does making load_unaligned_zeropad() > work in a TDX VM depend on the hypervisor doing anything? Or is the > behavior seen by the guest dependent only on architected behavior of > the TDX processor? > > Looking at this problem from a slightly higher level, and thinking out loud > a bit, load_unaligned_zeropad() functionality is provided only for certain > architectures: x86/64, arm, arm64, and PowerPC 64 (little endian). There are > fallbacks for architectures that don't support it. With two minor tweaks to > Kconfig files, I've built x86 with load_unaligned_zeropad() disabled. Maybe > with today's processors the performance benefits are past their prime, > and running with it disabled in CoCo VMs is the better solution. Does > anyone have a sense of whether the perf impact would be measureable? > > If doing the load_unaligned_zeropad() enable/disable at build time is too > limiting, maybe it could be runtime based on whether page private/shared > state is being enforced. I haven't looked at the details. > > Thoughts? > > Michael
On 6/2/23 09:11, Michael Kelley (LINUX) wrote: > Tom -- Does the above sequence *depend* on the hypervisor doing anything > to make it work? I'm not clear on why KVM would automatically change the > page over to private. If there's a dependency on the hypervisor doing > something, then it seems like we'll need to standardize that "something" > across hypervisors, lest we end up with per-hypervisor code in Linux to handle > this scenario. And running SEV-SNP with multiple VMPLs probably makes it > even more complicated. > > Kirill -- Same question about TDX. Does making load_unaligned_zeropad() > work in a TDX VM depend on the hypervisor doing anything? Or is the > behavior seen by the guest dependent only on architected behavior of > the TDX processor? No, there's no active help from the hypervisor here. Also, fwiw, the "architected behavior" here is really just the TDX module policy and _arguably_ the hardware Secure-EPT controlled by the TDX module.
On Fri, Jun 02, 2023 at 10:42:33AM -0700, Dave Hansen wrote: > On 6/2/23 09:11, Michael Kelley (LINUX) wrote: > > Tom -- Does the above sequence *depend* on the hypervisor doing anything > > to make it work? I'm not clear on why KVM would automatically change the > > page over to private. If there's a dependency on the hypervisor doing > > something, then it seems like we'll need to standardize that "something" > > across hypervisors, lest we end up with per-hypervisor code in Linux to handle > > this scenario. And running SEV-SNP with multiple VMPLs probably makes it > > even more complicated. > > > > Kirill -- Same question about TDX. Does making load_unaligned_zeropad() > > work in a TDX VM depend on the hypervisor doing anything? Or is the > > behavior seen by the guest dependent only on architected behavior of > > the TDX processor? > > No, there's no active help from the hypervisor here. > > Also, fwiw, the "architected behavior" here is really just the TDX > module policy and _arguably_ the hardware Secure-EPT controlled by the > TDX module. Right. There's nothing VMM can do to change behaviour here. VMM can remove private page, but it will lead to VM termination on access to the page, but VMM controls VM lifecycle anyway.
On 5/26/23 05:02, Kirill A. Shutemov wrote: > Touching privately mapped GPA that is not properly converted to private > with MapGPA and accepted leads to unrecoverable exit to VMM. > > load_unaligned_zeropad() can touch memory that is not owned by the > caller, but just happened to next after the owned memory. > This load_unaligned_zeropad() behaviour makes it important when kernel > asks VMM to convert a GPA from shared to private or back. Kernel must > never have a page mapped into direct mapping (and aliases) as private > when the GPA is already converted to shared or when GPA is not yet > converted to private. > > guest.enc_status_change_prepare() called before adjusting direct mapping > and therefore it is responsible for converting the memory to private. > > guest.enc_status_change_finish() called after adjusting direct mapping > and it converts the memory to shared. > > It is okay to have a shared mapping of memory that is not converted > properly. handle_mmio() knows how to deal with load_unaligned_zeropad() > stepping on it. Yeah, as other said, the changelog grammar here is a bit funky. Can you fix it up and resend, please?
diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c index e146b599260f..59cc13e41aa6 100644 --- a/arch/x86/coco/tdx/tdx.c +++ b/arch/x86/coco/tdx/tdx.c @@ -840,6 +840,30 @@ static bool tdx_enc_status_changed(unsigned long vaddr, int numpages, bool enc) return true; } +static bool tdx_enc_status_change_prepare(unsigned long vaddr, int numpages, + bool enc) +{ + /* + * Only handle shared->private conversion here. + * See the comment in tdx_early_init(). + */ + if (enc) + return tdx_enc_status_changed(vaddr, numpages, enc); + return true; +} + +static bool tdx_enc_status_change_finish(unsigned long vaddr, int numpages, + bool enc) +{ + /* + * Only handle private->shared conversion here. + * See the comment in tdx_early_init(). + */ + if (!enc) + return tdx_enc_status_changed(vaddr, numpages, enc); + return true; +} + void __init tdx_early_init(void) { u64 cc_mask; @@ -867,9 +891,35 @@ void __init tdx_early_init(void) */ physical_mask &= cc_mask - 1; - x86_platform.guest.enc_cache_flush_required = tdx_cache_flush_required; - x86_platform.guest.enc_tlb_flush_required = tdx_tlb_flush_required; - x86_platform.guest.enc_status_change_finish = tdx_enc_status_changed; + /* + * Touching privately mapped GPA that is not properly converted to + * private with MapGPA and accepted leads to unrecoverable exit + * to VMM. + * + * load_unaligned_zeropad() can touch memory that is not owned by + * the caller, but just happened to next after the owned memory. + * This load_unaligned_zeropad() behaviour makes it important when + * kernel asks VMM to convert a GPA from shared to private or back. + * Kernel must never have a page mapped into direct mapping (and + * aliases) as private when the GPA is already converted to shared or + * when GPA is not yet converted to private. + * + * guest.enc_status_change_prepare() called before adjusting direct + * mapping and therefore it is responsible for converting the memory + * to private. + * + * guest.enc_status_change_finish() called after adjusting direct + * mapping and it converts the memory to shared. + * + * It is okay to have a shared mapping of memory that is not converted + * properly. handle_mmio() knows how to deal with load_unaligned_zeropad() + * stepping on it. + */ + x86_platform.guest.enc_status_change_prepare = tdx_enc_status_change_prepare; + x86_platform.guest.enc_status_change_finish = tdx_enc_status_change_finish; + + x86_platform.guest.enc_cache_flush_required = tdx_cache_flush_required; + x86_platform.guest.enc_tlb_flush_required = tdx_tlb_flush_required; pr_info("Guest detected\n"); }