Message ID | 20221028141220.29217-2-kirill.shutemov@linux.intel.com |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:6687:0:0:0:0:0 with SMTP id l7csp861713wru; Fri, 28 Oct 2022 07:25:05 -0700 (PDT) X-Google-Smtp-Source: AMsMyM5o0r0IQxQcOPUOXbB86fWdZ5Ps1sP4rO/FZ2pLt+MNBqn7ziJniejGNkKg+U7cQuA4zwu0 X-Received: by 2002:a17:907:7b94:b0:731:1b11:c241 with SMTP id ne20-20020a1709077b9400b007311b11c241mr48426751ejc.676.1666967105178; Fri, 28 Oct 2022 07:25:05 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1666967105; cv=none; d=google.com; s=arc-20160816; b=KU/fTuSUmsHdD7q+RwuRdVLUpqEdG3q3AtRg6s8BVGZhUnfjlrVnlseArpXUcWAOTD LgQvXlGx01UFr3lDUSOLzPpZARjDHhIcL2lb8wUFZwoFEdUROrBzfLuRkUTkFz9361Kz s7LvGnQlkqQPV75edsvP/EREF1+cg7ddjXc2+1ncUS6Xt146bZ3+iTgl/4/9KSsNkd1G VETzx2oCjmb0/XGTI7qp64iuV1ILuQ++9wCIIafxhOi872dy+DczovvYARMPY466yk5P w1L6SX+hg0mLtbPMDCOhPQAOS8Qy8ExBi/9pqpmQn9fDAKPlWkGsI0vZKRfiAUu08No/ P2ZQ== 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=6+BI5gFuARNnfrOfgAJOyB2COcE79FhOkcvsrPjwD+0=; b=0ysGBGQI0jn1PetYmb0nmLmHWiWMlY0xAvsKqj/GCDoTjF38V4cdwo17HH6sSaQN8Q y4P94jG0OdchQ9rFlPmDRzqgZHclHq2Db+FAqqBUDW8Elx+Gbv+LukmHQ1/jo5XpyUR/ Bb6n/Dk3c4vLwKeFKU6LqUiFKe4fve/gmnPIWIuEqfXiPgGzjs3LaGBJ/evqJDQjg+qF eEd5TE5s4V/E+JAESvWSsR00wy1d0kl84s3K0GN3ILYmlbDDMtlYARFVWJzv+1TuBthF cxYjAJ8cEqcZhYTL6fmGCJkHaU4JfnDWGoN+vwRaLDRDFGFuK8jK3dGRVyznd5lHmomU vQJw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@intel.com header.s=Intel header.b=NSSmMzr4; 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 sh10-20020a1709076e8a00b007a39ad3da43si4747486ejc.714.2022.10.28.07.24.40; Fri, 28 Oct 2022 07:25:05 -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=NSSmMzr4; 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 S230183AbiJ1OMl (ORCPT <rfc822;chrisfriedt@gmail.com> + 99 others); Fri, 28 Oct 2022 10:12:41 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35662 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230016AbiJ1OMb (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Fri, 28 Oct 2022 10:12:31 -0400 Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 490E21C811D for <linux-kernel@vger.kernel.org>; Fri, 28 Oct 2022 07:12:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1666966351; x=1698502351; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=JE7pYb0iyhrn1PbMnI0l9LTThn2Yh8uAqjKnOua3gYk=; b=NSSmMzr4mzNYR7nqtwRMQpvl6iYJ4VHaMRd5o5RUvlXn+cLLhoLn+OdQ 5ms7PN77qol8nDP7rpyj3HLqidAA+qMoFu676Va60G3DNb0TQYXmTB7yt cY5DchAbZtbXlta0NUqrV+bHyiVrypbUeFUXaUFUPFMX6Xw+lIs2O33dR Jtb1LQiDI3oWPdHjz1QZ+p2NBXR1gyVzl/MSWLGhfOXbcFAGRu6iBgI0X JZpexYsq7zdEQi2dwFi8sl4h1adToh4JQGepGwLzeT57mNI6EOkpX6t5L n75l7WUr08mTWr76iR3r+TnID/BcaV2oddar2BLB1y509dQEKW0hwyakU Q==; X-IronPort-AV: E=McAfee;i="6500,9779,10513"; a="335142691" X-IronPort-AV: E=Sophos;i="5.95,221,1661842800"; d="scan'208";a="335142691" Received: from orsmga003.jf.intel.com ([10.7.209.27]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Oct 2022 07:12:29 -0700 X-IronPort-AV: E=McAfee;i="6500,9779,10513"; a="583936260" X-IronPort-AV: E=Sophos;i="5.95,221,1661842800"; d="scan'208";a="583936260" Received: from snehalde-mobl1.ger.corp.intel.com (HELO box.shutemov.name) ([10.252.46.229]) by orsmga003-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Oct 2022 07:12:24 -0700 Received: by box.shutemov.name (Postfix, from userid 1000) id 13F0A104D5B; Fri, 28 Oct 2022 17:12:22 +0300 (+03) From: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com> To: tglx@linutronix.de, mingo@redhat.com, bp@alien8.de, dave.hansen@intel.com, luto@kernel.org, peterz@infradead.org Cc: sathyanarayanan.kuppuswamy@linux.intel.com, ak@linux.intel.com, dan.j.williams@intel.com, david@redhat.com, hpa@zytor.com, seanjc@google.com, thomas.lendacky@amd.com, elena.reshetova@intel.com, x86@kernel.org, linux-kernel@vger.kernel.org, "Kirill A . Shutemov" <kirill.shutemov@linux.intel.com> Subject: [PATCH 1/2] x86/tdx: Extract GET_INFO call from get_cc_mask() Date: Fri, 28 Oct 2022 17:12:19 +0300 Message-Id: <20221028141220.29217-2-kirill.shutemov@linux.intel.com> X-Mailer: git-send-email 2.38.0 In-Reply-To: <20221028141220.29217-1-kirill.shutemov@linux.intel.com> References: <20221028141220.29217-1-kirill.shutemov@linux.intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-7.5 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_EF,RCVD_IN_DNSWL_HI, RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL,SPF_HELO_NONE,SPF_NONE 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?1747941699220761531?= X-GMAIL-MSGID: =?utf-8?q?1747941699220761531?= |
Series |
x86/tdx: Enforce no #VE on private memory accesses
|
|
Commit Message
Kirill A. Shutemov
Oct. 28, 2022, 2:12 p.m. UTC
From: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com> TDCALL [TDG.VP.INFO] is used to get details like gpa_width, TD attributes, etc. So far only gpa_width was needed to enumerate the shared bit, but upcoming changes will need TD attributes too. Extract GET_INFO call out of get_cc_mask() into a separate helper and save attributes. Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com> Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> --- arch/x86/coco/tdx/tdx.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-)
Comments
On 10/28/22 07:12, Kirill A. Shutemov wrote: > + * information, TD attributes etc. More details about the ABI can be > + * found in TDX Guest-Host-Communication Interface (GHCI), section > + * 2.4.2 TDCALL [TDG.VP.INFO]. Folks, I thought we agreed long ago to stop putting section numbers in these comments because they're not stable. Am I remembering this wrong?
I looked at this a bit more closely. The code is just bonkers now. It
can't go in like this.
tdx_parse_tdinfo() stashes two global variables. Then, about three
lines later in the function, it calls get_cc_mask() which just returns
one of those variables, modulo a little masking.
Ditto for the td_attr. It's stashed in a global variable and then read
one time.
There is *ZERO* reason to store 'td_attr'. There's also zero reason to
have 'gpa_width' as a global variable. It's only used *ONE* *TIME* from
the scope of *ONE* *FUNCTION*.
Even the comment is bonkers:
/*
* Initializes gpa_width and td_attr. Must be called before
* get_cc_mask() or attribute checks.
*/
tdx_parse_tdinfo();
Comments are great. But comments that are only there because the code
is obtuse are not. I changed it to:
tdx_parse_tdinfo(&cc_mask);
It doesn't even need a comment now. Why? Because it's obvious from the
naming and calling convention that it initializes cc_mask and what the
ordering dependency is. Plus, even *if* I missed the call, or screwed
up the order, the compiler would tell me that I'm a dolt.
The whole global variable thing actually makes the code objectively
worse in almost every possible way.
Can you please take a look through this and make sure I didn't botch
anything:
> https://git.kernel.org/pub/scm/linux/kernel/git/daveh/devel.git/log/?h=tdxbadve
The end result is about 50 lines less than what was there before. Most
of it is comment removal but the code is simpler too.
Acks and Tested-by's would be appreciated.
On Fri, Oct 28, 2022 at 04:27:10PM -0700, Dave Hansen wrote: > I looked at this a bit more closely. The code is just bonkers now. It > can't go in like this. > > tdx_parse_tdinfo() stashes two global variables. Then, about three > lines later in the function, it calls get_cc_mask() which just returns > one of those variables, modulo a little masking. > > Ditto for the td_attr. It's stashed in a global variable and then read > one time. > > There is *ZERO* reason to store 'td_attr'. There's also zero reason to > have 'gpa_width' as a global variable. It's only used *ONE* *TIME* from > the scope of *ONE* *FUNCTION*. > > Even the comment is bonkers: > > /* > * Initializes gpa_width and td_attr. Must be called before > * get_cc_mask() or attribute checks. > */ > tdx_parse_tdinfo(); > > Comments are great. But comments that are only there because the code > is obtuse are not. I changed it to: > > tdx_parse_tdinfo(&cc_mask); > > It doesn't even need a comment now. Why? Because it's obvious from the > naming and calling convention that it initializes cc_mask and what the > ordering dependency is. Plus, even *if* I missed the call, or screwed > up the order, the compiler would tell me that I'm a dolt. > > The whole global variable thing actually makes the code objectively > worse in almost every possible way. I agree. Sorry about that. We have more code in our tree that want to check attributes. And it is after initialization, so the code structure derived from there. But, yes, I should have rework it before sending upstream. > Can you please take a look through this and make sure I didn't botch > anything: > > > https://git.kernel.org/pub/scm/linux/kernel/git/daveh/devel.git/log/?h=tdxbadve > > The end result is about 50 lines less than what was there before. Most > of it is comment removal but the code is simpler too. > > Acks and Tested-by's would be appreciated. Looks good and works fine: Acked-and-Tested-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
On Sat, Oct 29, 2022 at 02:59:51AM +0300, Kirill A. Shutemov wrote: > > Can you please take a look through this and make sure I didn't botch > > anything: > > > > > https://git.kernel.org/pub/scm/linux/kernel/git/daveh/devel.git/log/?h=tdxbadve > > > > The end result is about 50 lines less than what was there before. Most > > of it is comment removal but the code is simpler too. > > > > Acks and Tested-by's would be appreciated. One thing that I must bring up is that it seems that there's no way to get the panic message to user. I tried to convinced myself that it is qemu misconfiguration on my part or some race, but no: it is just too early for earlyprintk. We only get earlyprintk working after parse_early_options() which happens well after tdx_early_init(). Moving panic() after earlyprintk working is not good idea as it exposes kernel more: by the time we already have full #VE handler. We can move it earlier into decompresser which has different earlyprintk implementation. Not sure if it worth this. What do you think? "tdx: Guest detected" printed from the same tdx_early_init() is visible if boot goes far enough to initialize console (early or not) as printk adds the message to the buffer, but no so luck for panic().
On 10/30/22 21:12, Kirill A. Shutemov wrote: > On Sat, Oct 29, 2022 at 02:59:51AM +0300, Kirill A. Shutemov wrote: >>> Can you please take a look through this and make sure I didn't botch >>> anything: >>> >>>> https://git.kernel.org/pub/scm/linux/kernel/git/daveh/devel.git/log/?h=tdxbadve >>> >>> The end result is about 50 lines less than what was there before. Most >>> of it is comment removal but the code is simpler too. >>> >>> Acks and Tested-by's would be appreciated. > > One thing that I must bring up is that it seems that there's no way to get > the panic message to user. I tried to convinced myself that it is qemu > misconfiguration on my part or some race, but no: it is just too early for > earlyprintk. > > We only get earlyprintk working after parse_early_options() which happens > well after tdx_early_init(). > > Moving panic() after earlyprintk working is not good idea as it exposes > kernel more: by the time we already have full #VE handler. How about we soften the panic() to a pr_err() if it's a debug guest? The first thing a user is going to do if they get an early boot failure is flip the debug switch and try it again. That gets us safe, well-defined behavior when we need security and also lets us figure out what went wrong. Also, did anyone ever actually implement that TDX earlyprintk simple console thing? A TDCALL up to the host with some characters in a register or two is as dirt simple of a console as you can get. It would be very easy to improve the user experience here if there were a: tdx_puts("uh oh"); interface. It's a shame if it didn't get done by now. I asked for it years ago. And, yeah, I know it wouldn't help us in this precise situation because earlyprintk doesn't work yet. But, it *would* be one of those really, really early bitbanging-style consoles that _could_ be in use very, very early if the printk() infrastructure could take advantage of it. > We can move it earlier into decompresser which has different earlyprintk > implementation. Not sure if it worth this. What do you think? There's the puts()/printf() gunk that's really early like in validate_cpu(). Is that what you were thinking of?
On Mon, Oct 31, 2022 at 09:42:15AM -0700, Dave Hansen wrote: > On 10/30/22 21:12, Kirill A. Shutemov wrote: > > On Sat, Oct 29, 2022 at 02:59:51AM +0300, Kirill A. Shutemov wrote: > >>> Can you please take a look through this and make sure I didn't botch > >>> anything: > >>> > >>>> https://git.kernel.org/pub/scm/linux/kernel/git/daveh/devel.git/log/?h=tdxbadve > >>> > >>> The end result is about 50 lines less than what was there before. Most > >>> of it is comment removal but the code is simpler too. > >>> > >>> Acks and Tested-by's would be appreciated. > > > > One thing that I must bring up is that it seems that there's no way to get > > the panic message to user. I tried to convinced myself that it is qemu > > misconfiguration on my part or some race, but no: it is just too early for > > earlyprintk. > > > > We only get earlyprintk working after parse_early_options() which happens > > well after tdx_early_init(). > > > > Moving panic() after earlyprintk working is not good idea as it exposes > > kernel more: by the time we already have full #VE handler. > > How about we soften the panic() to a pr_err() if it's a debug guest? The plan is to have pr_warn() + check in handle_mmio(), as I mentioned before. But pr_err() also works. > The first thing a user is going to do if they get an early boot failure > is flip the debug switch and try it again. That gets us safe, > well-defined behavior when we need security and also lets us figure out > what went wrong. > > Also, did anyone ever actually implement that TDX earlyprintk simple > console thing? A TDCALL up to the host with some characters in a > register or two is as dirt simple of a console as you can get. It would > be very easy to improve the user experience here if there were a: > > tdx_puts("uh oh"); > > interface. It's a shame if it didn't get done by now. I asked for it > years ago. There's nothing like this, unfortunately. There's ReportFatalError TDVMCALL that intended for the task, but it only takes an error code as input which is useless here. Nobody will decode it. > And, yeah, I know it wouldn't help us in this precise situation because > earlyprintk doesn't work yet. But, it *would* be one of those really, > really early bitbanging-style consoles that _could_ be in use very, very > early if the printk() infrastructure could take advantage of it. > > > We can move it earlier into decompresser which has different earlyprintk > > implementation. Not sure if it worth this. What do you think? > > There's the puts()/printf() gunk that's really early like in > validate_cpu(). Is that what you were thinking of? More like error() in arch/x86/boot/compressed/kaslr.c.
sted-by's would be appreciated. > One thing that I must bring up is that it seems that there's no way to get > the panic message to user. I tried to convinced myself that it is qemu > misconfiguration on my part or some race, but no: it is just too early for > earlyprintk. > > We only get earlyprintk working after parse_early_options() which happens > well after tdx_early_init(). > > Moving panic() after earlyprintk working is not good idea as it exposes > kernel more: by the time we already have full #VE handler. It should be fine to move since there is no user land at this point (the attack requires user land) > > We can move it earlier into decompresser which has different earlyprintk > implementation. Not sure if it worth this. What do you think? That would make uncompressed kernels unsafe. -Andi
On 10/31/22 12:27, Andi Kleen wrote: >> Moving panic() after earlyprintk working is not good idea as it exposes >> kernel more: by the time we already have full #VE handler. > > It should be fine to move since there is no user land at this point (the > attack requires user land) Maybe I'm misunderstanding the exposure. A normal MMIO #VE goes something like this: 1. %rax points to some MMIO 2. Kernel executes: mov (%rax),%rbx, trying to read MMIO 3. #VE handler is triggered 4. Handler emulates the 'mov' with instruction decoding 5. Handler asks the VMM what the value of %rax should be 6. Handler puts VMM value in %rax 7. Return from #VE I think the attack scenario subverts a normal MMIO to the following (changes from the normal flow are marked with *): *1. %rax points to some private kernel memory, VMM removes Secure-EPT entry for that memory. 2. Kernel executes: mov (%rax),%rbx as part of normal kernel execution, not an MMIO read. 3. #VE handler is triggered, assuming a MMIO read 4. Handler emulates the 'mov' with instruction decoding 5. Handler asks the VMM what the value of %rax should be *6. Handler puts (malicious) VMM value in %rax 7. Return from #VE *8. Now the guest kernel is running with an attacker-controlled %rax This effectively gives the attacker the ability to override the contents of a memory read. Am I misunderstanding the attack scenario? I don't see guest userspace needing to be involved at all.
On Mon, Oct 31, 2022 at 12:44:15PM -0700, Dave Hansen wrote: > On 10/31/22 12:27, Andi Kleen wrote: > >> Moving panic() after earlyprintk working is not good idea as it exposes > >> kernel more: by the time we already have full #VE handler. > > > > It should be fine to move since there is no user land at this point (the > > attack requires user land) > > Maybe I'm misunderstanding the exposure. A normal MMIO #VE goes > something like this: > > 1. %rax points to some MMIO > 2. Kernel executes: mov (%rax),%rbx, trying to read MMIO > 3. #VE handler is triggered > 4. Handler emulates the 'mov' with instruction decoding > 5. Handler asks the VMM what the value of %rax should be > 6. Handler puts VMM value in %rax > 7. Return from #VE > > I think the attack scenario subverts a normal MMIO to the following > (changes from the normal flow are marked with *): > > *1. %rax points to some private kernel memory, VMM removes > Secure-EPT entry for that memory. > 2. Kernel executes: mov (%rax),%rbx as part of normal kernel > execution, not an MMIO read. > 3. #VE handler is triggered, assuming a MMIO read > 4. Handler emulates the 'mov' with instruction decoding > 5. Handler asks the VMM what the value of %rax should be > *6. Handler puts (malicious) VMM value in %rax > 7. Return from #VE > *8. Now the guest kernel is running with an attacker-controlled > %rax > > This effectively gives the attacker the ability to override the contents > of a memory read. > > Am I misunderstanding the attack scenario? I don't see guest userspace > needing to be involved at all. Looks correct to me. I think Andi refers to attack against syscall gap that also addressed by the patch.
diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c index 928dcf7a20d9..343d60853b71 100644 --- a/arch/x86/coco/tdx/tdx.c +++ b/arch/x86/coco/tdx/tdx.c @@ -34,6 +34,12 @@ #define VE_GET_PORT_NUM(e) ((e) >> 16) #define VE_IS_IO_STRING(e) ((e) & BIT(4)) +/* Caches GPA width from TDG.VP.INFO TDCALL */ +static unsigned int gpa_width __ro_after_init; + +/* Caches TD Attributes from TDG.VP.INFO TDCALL */ +static u64 td_attr __ro_after_init; + /* * Wrapper for standard use of __tdx_hypercall with no output aside from * return code. @@ -98,17 +104,16 @@ static inline void tdx_module_call(u64 fn, u64 rcx, u64 rdx, u64 r8, u64 r9, panic("TDCALL %lld failed (Buggy TDX module!)\n", fn); } -static u64 get_cc_mask(void) +static void tdx_parse_tdinfo(void) { struct tdx_module_output out; - unsigned int gpa_width; /* * TDINFO TDX module call is used to get the TD execution environment * information like GPA width, number of available vcpus, debug mode - * information, etc. More details about the ABI can be found in TDX - * Guest-Host-Communication Interface (GHCI), section 2.4.2 TDCALL - * [TDG.VP.INFO]. + * information, TD attributes etc. More details about the ABI can be + * found in TDX Guest-Host-Communication Interface (GHCI), section + * 2.4.2 TDCALL [TDG.VP.INFO]. * * The GPA width that comes out of this call is critical. TDX guests * can not meaningfully run without it. @@ -116,7 +121,11 @@ static u64 get_cc_mask(void) tdx_module_call(TDX_GET_INFO, 0, 0, 0, 0, &out); gpa_width = out.rcx & GENMASK(5, 0); + td_attr = out.rdx; +} +static u64 get_cc_mask(void) +{ /* * The highest bit of a guest physical address is the "sharing" bit. * Set it for shared pages and clear it for private pages. @@ -755,6 +764,12 @@ void __init tdx_early_init(void) if (memcmp(TDX_IDENT, sig, sizeof(sig))) return; + /* + * Initializes gpa_width and td_attr. Must be called before + * get_cc_mask() or attribute checks. + */ + tdx_parse_tdinfo(); + setup_force_cpu_cap(X86_FEATURE_TDX_GUEST); cc_set_vendor(CC_VENDOR_INTEL);