From patchwork Fri Aug 6 00:09:39 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Kuppuswamy Sathyanarayanan X-Patchwork-Id: 12422365 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=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT 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 D8888C432BE for ; Fri, 6 Aug 2021 00:10:08 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id BCB4C610FB for ; Fri, 6 Aug 2021 00:10:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S242711AbhHFAKT (ORCPT ); Thu, 5 Aug 2021 20:10:19 -0400 Received: from mga04.intel.com ([192.55.52.120]:45281 "EHLO mga04.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S242703AbhHFAKR (ORCPT ); Thu, 5 Aug 2021 20:10:17 -0400 X-IronPort-AV: E=McAfee;i="6200,9189,10067"; a="212422358" X-IronPort-AV: E=Sophos;i="5.84,299,1620716400"; d="scan'208";a="212422358" Received: from orsmga003.jf.intel.com ([10.7.209.27]) by fmsmga104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Aug 2021 17:10:02 -0700 X-IronPort-AV: E=Sophos;i="5.84,299,1620716400"; d="scan'208";a="420562704" Received: from rmgular-mobl2.amr.corp.intel.com (HELO skuppusw-desk1.amr.corp.intel.com) ([10.251.138.25]) by orsmga003-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Aug 2021 17:10:00 -0700 From: Kuppuswamy Sathyanarayanan To: Thomas Gleixner , Ingo Molnar , Borislav Petkov , Peter Zijlstra , Andy Lutomirski , Hans de Goede , Mark Gross , Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko Cc: Peter H Anvin , Dave Hansen , Tony Luck , Dan Williams , Andi Kleen , Kirill Shutemov , Sean Christopherson , Kuppuswamy Sathyanarayanan , x86@kernel.org, linux-kernel@vger.kernel.org, platform-driver-x86@vger.kernel.org, bpf@vger.kernel.org, netdev@vger.kernel.org Subject: [PATCH v4 1/7] x86/tdx: Add tdg_debug_enabled() interface Date: Thu, 5 Aug 2021 17:09:39 -0700 Message-Id: <20210806000946.2951441-2-sathyanarayanan.kuppuswamy@linux.intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210806000946.2951441-1-sathyanarayanan.kuppuswamy@linux.intel.com> References: <20210806000946.2951441-1-sathyanarayanan.kuppuswamy@linux.intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org A guest TD is defined as debuggable if its ATTRIBUTES.DEBUG bit is 1. In this mode, the host VMM can use Intel TDX functions to access secret TD state that is not accessible for non-debuggable TDs. A debuggable TD is, by nature, untrusted. Since the TD’s ATTRIBUTES are included in the TDG.MR.REPORT, the TD’s debuggability state can be known to any third party to which the TD attests. TD Attributes are initialized during TD INIT call. For more details about debug features, check Intel Trust Domain Extensions (Intel TDX) Module Architecture specification, sec 13.3. Add a new interface to detect the TDX debug mode. This will be used by follow-on patches. Examples of its usage are, when adding command line debug options to disable TDX features like driver or port filter, tdg_debug_enabled() is used to make sure it is used only in debug mode. https://software.intel.com/content/dam/develop/external/us/en/documents/tdx-module-1eas-v0.85.039.pdf Reviewed-by: Tony Luck Reviewed-by: Andi Kleen Signed-off-by: Kuppuswamy Sathyanarayanan --- arch/x86/include/asm/tdx.h | 2 ++ arch/x86/kernel/tdx.c | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h index dd5459ece9aa..50693bd6f0dd 100644 --- a/arch/x86/include/asm/tdx.h +++ b/arch/x86/include/asm/tdx.h @@ -69,6 +69,8 @@ enum tdx_map_type { extern unsigned int tdg_disable_prot; +bool tdg_debug_enabled(void); + void __init tdx_early_init(void); bool tdx_prot_guest_has(unsigned long flag); diff --git a/arch/x86/kernel/tdx.c b/arch/x86/kernel/tdx.c index bfa168f3f09c..c71049cd2255 100644 --- a/arch/x86/kernel/tdx.c +++ b/arch/x86/kernel/tdx.c @@ -135,6 +135,11 @@ phys_addr_t tdg_shared_mask(void) return 1ULL << (td_info.gpa_width - 1); } +bool tdg_debug_enabled(void) +{ + return td_info.attributes & BIT(0); +} + static void tdg_get_info(void) { u64 ret; From patchwork Fri Aug 6 00:09:40 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kuppuswamy Sathyanarayanan X-Patchwork-Id: 12422363 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=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham 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 13C14C43216 for ; Fri, 6 Aug 2021 00:10:09 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id E8E1161151 for ; Fri, 6 Aug 2021 00:10:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S242723AbhHFAKU (ORCPT ); Thu, 5 Aug 2021 20:10:20 -0400 Received: from mga04.intel.com ([192.55.52.120]:45281 "EHLO mga04.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S242710AbhHFAKT (ORCPT ); Thu, 5 Aug 2021 20:10:19 -0400 X-IronPort-AV: E=McAfee;i="6200,9189,10067"; a="212422364" X-IronPort-AV: E=Sophos;i="5.84,299,1620716400"; d="scan'208";a="212422364" Received: from orsmga003.jf.intel.com ([10.7.209.27]) by fmsmga104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Aug 2021 17:10:04 -0700 X-IronPort-AV: E=Sophos;i="5.84,299,1620716400"; d="scan'208";a="420562710" Received: from rmgular-mobl2.amr.corp.intel.com (HELO skuppusw-desk1.amr.corp.intel.com) ([10.251.138.25]) by orsmga003-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Aug 2021 17:10:02 -0700 From: Kuppuswamy Sathyanarayanan To: Thomas Gleixner , Ingo Molnar , Borislav Petkov , Peter Zijlstra , Andy Lutomirski , Hans de Goede , Mark Gross , Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko Cc: Peter H Anvin , Dave Hansen , Tony Luck , Dan Williams , Andi Kleen , Kirill Shutemov , Sean Christopherson , Kuppuswamy Sathyanarayanan , x86@kernel.org, linux-kernel@vger.kernel.org, platform-driver-x86@vger.kernel.org, bpf@vger.kernel.org, netdev@vger.kernel.org Subject: [PATCH v4 2/7] x86/tdx: Add TDREPORT TDX Module call support Date: Thu, 5 Aug 2021 17:09:40 -0700 Message-Id: <20210806000946.2951441-3-sathyanarayanan.kuppuswamy@linux.intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210806000946.2951441-1-sathyanarayanan.kuppuswamy@linux.intel.com> References: <20210806000946.2951441-1-sathyanarayanan.kuppuswamy@linux.intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org The TDX Guest-Host Communication Interface (GHCI) includes a module call (TDREPORT TDCALL) that a guest can make to acquire a copy of the attestation data that it needs to verify its trustworthiness. Add a wrapper function tdx_mcall_tdreport() that makes the module call to get this data. See GHCI section 2.4.5 "TDCALL [TDG.MR.REPORT] leaf" for additional details. [Xiaoyao: Proposed error code fix] Reviewed-by: Tony Luck Reviewed-by: Andi Kleen Signed-off-by: Kuppuswamy Sathyanarayanan --- Changes since v3 * Rebased on top of Tom Lendacky's protected guest changes (https://lore.kernel.org/patchwork/cover/1468760/) Changes since v2: * Included TDCALL_SUCCESS case check in tdx_mcall_tdreport(). arch/x86/include/asm/tdx.h | 2 ++ arch/x86/kernel/tdx.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h index 50693bd6f0dd..6e6abd2b0894 100644 --- a/arch/x86/include/asm/tdx.h +++ b/arch/x86/include/asm/tdx.h @@ -95,6 +95,8 @@ extern phys_addr_t tdg_shared_mask(void); extern int tdx_hcall_gpa_intent(phys_addr_t gpa, int numpages, enum tdx_map_type map_type); +int tdx_mcall_tdreport(u64 data, u64 reportdata); + /* * To support I/O port access in decompressor or early kernel init * code, since #VE exception handler cannot be used, use paravirt diff --git a/arch/x86/kernel/tdx.c b/arch/x86/kernel/tdx.c index c71049cd2255..5eed2e660546 100644 --- a/arch/x86/kernel/tdx.c +++ b/arch/x86/kernel/tdx.c @@ -22,6 +22,7 @@ /* TDX Module call Leaf IDs */ #define TDINFO 1 #define TDGETVEINFO 3 +#define TDREPORT 4 #define TDACCEPTPAGE 6 /* TDX hypercall Leaf IDs */ @@ -30,6 +31,9 @@ /* TDX Module call error codes */ #define TDX_PAGE_ALREADY_ACCEPTED 0x00000b0a00000000 #define TDCALL_RETURN_CODE_MASK 0xFFFFFFFF00000000 +#define TDCALL_OPERAND_BUSY 0x8000020000000000 +#define TDCALL_INVALID_OPERAND 0x8000000000000000 +#define TDCALL_SUCCESS 0x0 #define TDCALL_RETURN_CODE(a) ((a) & TDCALL_RETURN_CODE_MASK) #define VE_IS_IO_OUT(exit_qual) (((exit_qual) & 8) ? 0 : 1) @@ -140,6 +144,35 @@ bool tdg_debug_enabled(void) return td_info.attributes & BIT(0); } +/* + * tdx_mcall_tdreport() - Generate TDREPORT_STRUCT using TDCALL. + * + * @data : Physical address of 1024B aligned data to store + * TDREPORT_STRUCT. + * @reportdata : Physical address of 64B aligned report data + * + * return 0 on success or failure error number. + */ +int tdx_mcall_tdreport(u64 data, u64 reportdata) +{ + u64 ret; + + if (!data || !reportdata || !prot_guest_has(PATTR_GUEST_TDX)) + return -EINVAL; + + ret = __trace_tdx_module_call(TDREPORT, data, reportdata, 0, 0, NULL); + + if (ret == TDCALL_SUCCESS) + return 0; + else if (TDCALL_RETURN_CODE(ret) == TDCALL_INVALID_OPERAND) + return -EINVAL; + else if (TDCALL_RETURN_CODE(ret) == TDCALL_OPERAND_BUSY) + return -EBUSY; + + return -EIO; +} +EXPORT_SYMBOL_GPL(tdx_mcall_tdreport); + static void tdg_get_info(void) { u64 ret; From patchwork Fri Aug 6 00:09:41 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kuppuswamy Sathyanarayanan X-Patchwork-Id: 12422375 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=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham 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 CEE44C4338F for ; Fri, 6 Aug 2021 00:10:38 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B3DB661052 for ; Fri, 6 Aug 2021 00:10:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S242702AbhHFAKq (ORCPT ); Thu, 5 Aug 2021 20:10:46 -0400 Received: from mga04.intel.com ([192.55.52.120]:45281 "EHLO mga04.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S242724AbhHFAKU (ORCPT ); Thu, 5 Aug 2021 20:10:20 -0400 X-IronPort-AV: E=McAfee;i="6200,9189,10067"; a="212422372" X-IronPort-AV: E=Sophos;i="5.84,299,1620716400"; d="scan'208";a="212422372" Received: from orsmga003.jf.intel.com ([10.7.209.27]) by fmsmga104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Aug 2021 17:10:05 -0700 X-IronPort-AV: E=Sophos;i="5.84,299,1620716400"; d="scan'208";a="420562717" Received: from rmgular-mobl2.amr.corp.intel.com (HELO skuppusw-desk1.amr.corp.intel.com) ([10.251.138.25]) by orsmga003-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Aug 2021 17:10:03 -0700 From: Kuppuswamy Sathyanarayanan To: Thomas Gleixner , Ingo Molnar , Borislav Petkov , Peter Zijlstra , Andy Lutomirski , Hans de Goede , Mark Gross , Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko Cc: Peter H Anvin , Dave Hansen , Tony Luck , Dan Williams , Andi Kleen , Kirill Shutemov , Sean Christopherson , Kuppuswamy Sathyanarayanan , x86@kernel.org, linux-kernel@vger.kernel.org, platform-driver-x86@vger.kernel.org, bpf@vger.kernel.org, netdev@vger.kernel.org Subject: [PATCH v4 3/7] x86/tdx: Add GetQuote TDX hypercall support Date: Thu, 5 Aug 2021 17:09:41 -0700 Message-Id: <20210806000946.2951441-4-sathyanarayanan.kuppuswamy@linux.intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210806000946.2951441-1-sathyanarayanan.kuppuswamy@linux.intel.com> References: <20210806000946.2951441-1-sathyanarayanan.kuppuswamy@linux.intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org The second stage in the attestation process is for the guest to request the VMM generate and sign a quote based on the TDREPORT acquired earlier. Add tdx_hcall_get_quote() helper function to implement the GetQuote hypercall. More details about the GetQuote TDVMCALL are in the Guest-Host Communication Interface (GHCI) Specification, sec 3.3, titled "TDG.VP.VMCALL". This will be used by the TD attestation driver in follow-on patches. Reviewed-by: Tony Luck Reviewed-by: Andi Kleen Signed-off-by: Kuppuswamy Sathyanarayanan --- Changes since v3 * Rebased on top of Tom Lendacky's protected guest changes (https://lore.kernel.org/patchwork/cover/1468760/) Change since v2: * Included TDVMCALL_SUCCESS case check in tdx_hcall_get_quote(). arch/x86/include/asm/tdx.h | 2 ++ arch/x86/kernel/tdx.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h index 6e6abd2b0894..34d14766b3bc 100644 --- a/arch/x86/include/asm/tdx.h +++ b/arch/x86/include/asm/tdx.h @@ -97,6 +97,8 @@ extern int tdx_hcall_gpa_intent(phys_addr_t gpa, int numpages, int tdx_mcall_tdreport(u64 data, u64 reportdata); +int tdx_hcall_get_quote(u64 data); + /* * To support I/O port access in decompressor or early kernel init * code, since #VE exception handler cannot be used, use paravirt diff --git a/arch/x86/kernel/tdx.c b/arch/x86/kernel/tdx.c index 5eed2e660546..203ddc4c8412 100644 --- a/arch/x86/kernel/tdx.c +++ b/arch/x86/kernel/tdx.c @@ -27,6 +27,7 @@ /* TDX hypercall Leaf IDs */ #define TDVMCALL_MAP_GPA 0x10001 +#define TDVMCALL_GET_QUOTE 0x10002 /* TDX Module call error codes */ #define TDX_PAGE_ALREADY_ACCEPTED 0x00000b0a00000000 @@ -36,6 +37,11 @@ #define TDCALL_SUCCESS 0x0 #define TDCALL_RETURN_CODE(a) ((a) & TDCALL_RETURN_CODE_MASK) +/* TDX hypercall error codes */ +#define TDVMCALL_SUCCESS 0x0 +#define TDVMCALL_INVALID_OPERAND 0x8000000000000000 +#define TDVMCALL_TDREPORT_FAILED 0x8000000000000001 + #define VE_IS_IO_OUT(exit_qual) (((exit_qual) & 8) ? 0 : 1) #define VE_GET_IO_SIZE(exit_qual) (((exit_qual) & 7) + 1) #define VE_GET_PORT_NUM(exit_qual) ((exit_qual) >> 16) @@ -173,6 +179,34 @@ int tdx_mcall_tdreport(u64 data, u64 reportdata) } EXPORT_SYMBOL_GPL(tdx_mcall_tdreport); +/* + * tdx_hcall_get_quote() - Generate TDQUOTE using TDREPORT_STRUCT. + * + * @data : Physical address of 4KB GPA memory which contains + * TDREPORT_STRUCT. + * + * return 0 on success or failure error number. + */ +int tdx_hcall_get_quote(u64 data) +{ + u64 ret; + + if (!data || !prot_guest_has(PATTR_GUEST_TDX)) + return -EINVAL; + + ret = _trace_tdx_hypercall(TDVMCALL_GET_QUOTE, data, 0, 0, 0, NULL); + + if (ret == TDVMCALL_SUCCESS) + return 0; + else if (ret == TDVMCALL_INVALID_OPERAND) + return -EINVAL; + else if (ret == TDVMCALL_TDREPORT_FAILED) + return -EBUSY; + + return -EIO; +} +EXPORT_SYMBOL_GPL(tdx_hcall_get_quote); + static void tdg_get_info(void) { u64 ret; From patchwork Fri Aug 6 00:09:42 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kuppuswamy Sathyanarayanan X-Patchwork-Id: 12422373 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=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham 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 E05FCC4320A for ; Fri, 6 Aug 2021 00:10:32 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id C8BF8606A5 for ; Fri, 6 Aug 2021 00:10:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S242942AbhHFAKn (ORCPT ); Thu, 5 Aug 2021 20:10:43 -0400 Received: from mga04.intel.com ([192.55.52.120]:45289 "EHLO mga04.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S242730AbhHFAKV (ORCPT ); Thu, 5 Aug 2021 20:10:21 -0400 X-IronPort-AV: E=McAfee;i="6200,9189,10067"; a="212422375" X-IronPort-AV: E=Sophos;i="5.84,299,1620716400"; d="scan'208";a="212422375" Received: from orsmga003.jf.intel.com ([10.7.209.27]) by fmsmga104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Aug 2021 17:10:07 -0700 X-IronPort-AV: E=Sophos;i="5.84,299,1620716400"; d="scan'208";a="420562724" Received: from rmgular-mobl2.amr.corp.intel.com (HELO skuppusw-desk1.amr.corp.intel.com) ([10.251.138.25]) by orsmga003-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Aug 2021 17:10:05 -0700 From: Kuppuswamy Sathyanarayanan To: Thomas Gleixner , Ingo Molnar , Borislav Petkov , Peter Zijlstra , Andy Lutomirski , Hans de Goede , Mark Gross , Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko Cc: Peter H Anvin , Dave Hansen , Tony Luck , Dan Williams , Andi Kleen , Kirill Shutemov , Sean Christopherson , Kuppuswamy Sathyanarayanan , x86@kernel.org, linux-kernel@vger.kernel.org, platform-driver-x86@vger.kernel.org, bpf@vger.kernel.org, netdev@vger.kernel.org Subject: [PATCH v4 4/7] x86/tdx: Add SetupEventNotifyInterrupt TDX hypercall support Date: Thu, 5 Aug 2021 17:09:42 -0700 Message-Id: <20210806000946.2951441-5-sathyanarayanan.kuppuswamy@linux.intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210806000946.2951441-1-sathyanarayanan.kuppuswamy@linux.intel.com> References: <20210806000946.2951441-1-sathyanarayanan.kuppuswamy@linux.intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org SetupEventNotifyInterrupt TDX hypercall is used by guest TD to specify which interrupt vector to use as an event-notify vector to the VMM. Such registered vector is also used by Host VMM to notify about completion of GetQuote requests to the Guest TD. Add tdx_hcall_set_notify_intr() helper function to implement the SetupEventNotifyInterrupt hypercall. This will be used by the TD quote driver. Details about the SetupEventNotifyInterrupt TDVMCALL can be found in TDX Guest-Host Communication Interface (GHCI) Specification, sec 3.5 "TDG.VP.VMCALL". Reviewed-by: Tony Luck Reviewed-by: Andi Kleen Signed-off-by: Kuppuswamy Sathyanarayanan --- Change since v3: * None Change since v2: * Included TDVMCALL_SUCCESS case check in tdx_hcall_set_notify_intr(). arch/x86/kernel/tdx.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/arch/x86/kernel/tdx.c b/arch/x86/kernel/tdx.c index 203ddc4c8412..9fca354e014c 100644 --- a/arch/x86/kernel/tdx.c +++ b/arch/x86/kernel/tdx.c @@ -28,6 +28,7 @@ /* TDX hypercall Leaf IDs */ #define TDVMCALL_MAP_GPA 0x10001 #define TDVMCALL_GET_QUOTE 0x10002 +#define TDVMCALL_SETUP_NOTIFY_INTR 0x10004 /* TDX Module call error codes */ #define TDX_PAGE_ALREADY_ACCEPTED 0x00000b0a00000000 @@ -207,6 +208,32 @@ int tdx_hcall_get_quote(u64 data) } EXPORT_SYMBOL_GPL(tdx_hcall_get_quote); +/* + * tdx_hcall_set_notify_intr() - Setup Event Notify Interrupt Vector. + * + * @vector : Vector address to be used for notification. + * + * return 0 on success or failure error number. + */ +int tdx_hcall_set_notify_intr(u8 vector) +{ + u64 ret; + + /* Minimum vector value allowed is 32 */ + if (vector < 32) + return -EINVAL; + + ret = _trace_tdx_hypercall(TDVMCALL_SETUP_NOTIFY_INTR, vector, 0, 0, 0, + NULL); + + if (ret == TDVMCALL_SUCCESS) + return 0; + else if (ret == TDCALL_INVALID_OPERAND) + return -EINVAL; + + return -EIO; +} + static void tdg_get_info(void) { u64 ret; From patchwork Fri Aug 6 00:09:43 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kuppuswamy Sathyanarayanan X-Patchwork-Id: 12422367 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=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham 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 5D373C4320A for ; Fri, 6 Aug 2021 00:10:16 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3BB0661154 for ; Fri, 6 Aug 2021 00:10:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S242762AbhHFAK2 (ORCPT ); Thu, 5 Aug 2021 20:10:28 -0400 Received: from mga04.intel.com ([192.55.52.120]:45292 "EHLO mga04.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S242777AbhHFAKX (ORCPT ); Thu, 5 Aug 2021 20:10:23 -0400 X-IronPort-AV: E=McAfee;i="6200,9189,10067"; a="212422379" X-IronPort-AV: E=Sophos;i="5.84,299,1620716400"; d="scan'208";a="212422379" Received: from orsmga003.jf.intel.com ([10.7.209.27]) by fmsmga104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Aug 2021 17:10:08 -0700 X-IronPort-AV: E=Sophos;i="5.84,299,1620716400"; d="scan'208";a="420562732" Received: from rmgular-mobl2.amr.corp.intel.com (HELO skuppusw-desk1.amr.corp.intel.com) ([10.251.138.25]) by orsmga003-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Aug 2021 17:10:07 -0700 From: Kuppuswamy Sathyanarayanan To: Thomas Gleixner , Ingo Molnar , Borislav Petkov , Peter Zijlstra , Andy Lutomirski , Hans de Goede , Mark Gross , Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko Cc: Peter H Anvin , Dave Hansen , Tony Luck , Dan Williams , Andi Kleen , Kirill Shutemov , Sean Christopherson , Kuppuswamy Sathyanarayanan , x86@kernel.org, linux-kernel@vger.kernel.org, platform-driver-x86@vger.kernel.org, bpf@vger.kernel.org, netdev@vger.kernel.org Subject: [PATCH v4 5/7] x86/tdx: Add TDX Guest event notify interrupt vector support Date: Thu, 5 Aug 2021 17:09:43 -0700 Message-Id: <20210806000946.2951441-6-sathyanarayanan.kuppuswamy@linux.intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210806000946.2951441-1-sathyanarayanan.kuppuswamy@linux.intel.com> References: <20210806000946.2951441-1-sathyanarayanan.kuppuswamy@linux.intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org Allocate 0xec IRQ vector address for TDX guest to receive the event completion notification from VMM. Since this vector address will be sent to VMM via hypercall, allocate a fixed address and move LOCAL_TIMER_VECTOR vector address by 1 byte. Also add related IDT handler to process the notification event. It will be mainly used by attestation driver to receive Quote event completion notification from host. Add support to track the notification event status via /proc/interrupts. Reviewed-by: Tony Luck Reviewed-by: Andi Kleen Signed-off-by: Kuppuswamy Sathyanarayanan --- Changes since v3: * None arch/x86/include/asm/hardirq.h | 1 + arch/x86/include/asm/idtentry.h | 4 +++ arch/x86/include/asm/irq_vectors.h | 7 ++++- arch/x86/include/asm/tdx.h | 2 ++ arch/x86/kernel/irq.c | 7 +++++ arch/x86/kernel/tdx.c | 41 ++++++++++++++++++++++++++++++ 6 files changed, 61 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/asm/hardirq.h b/arch/x86/include/asm/hardirq.h index 07d79fa9c5c6..40d0534e7d82 100644 --- a/arch/x86/include/asm/hardirq.h +++ b/arch/x86/include/asm/hardirq.h @@ -46,6 +46,7 @@ typedef struct { #endif #if IS_ENABLED(CONFIG_INTEL_TDX_GUEST) unsigned int tdg_ve_count; + unsigned int irq_tdg_event_notify_count; #endif } ____cacheline_aligned irq_cpustat_t; diff --git a/arch/x86/include/asm/idtentry.h b/arch/x86/include/asm/idtentry.h index 8ccc81d653b3..6f3472a88e9c 100644 --- a/arch/x86/include/asm/idtentry.h +++ b/arch/x86/include/asm/idtentry.h @@ -693,6 +693,10 @@ DECLARE_IDTENTRY_SYSVEC(HYPERVISOR_CALLBACK_VECTOR, sysvec_xen_hvm_callback); DECLARE_IDTENTRY_SYSVEC(HYPERVISOR_CALLBACK_VECTOR, sysvec_kvm_asyncpf_interrupt); #endif +#ifdef CONFIG_INTEL_TDX_GUEST +DECLARE_IDTENTRY_SYSVEC(TDX_GUEST_EVENT_NOTIFY_VECTOR, sysvec_tdg_event_notify); +#endif + #undef X86_TRAP_OTHER #endif diff --git a/arch/x86/include/asm/irq_vectors.h b/arch/x86/include/asm/irq_vectors.h index 43dcb9284208..82ac0c0a34b1 100644 --- a/arch/x86/include/asm/irq_vectors.h +++ b/arch/x86/include/asm/irq_vectors.h @@ -104,7 +104,12 @@ #define HYPERV_STIMER0_VECTOR 0xed #endif -#define LOCAL_TIMER_VECTOR 0xec +#if IS_ENABLED(CONFIG_INTEL_TDX_GUEST) +/* Vector on which TDX Guest event notification is delivered */ +#define TDX_GUEST_EVENT_NOTIFY_VECTOR 0xec +#endif + +#define LOCAL_TIMER_VECTOR 0xeb #define NR_VECTORS 256 diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h index 34d14766b3bc..74c930869ee4 100644 --- a/arch/x86/include/asm/tdx.h +++ b/arch/x86/include/asm/tdx.h @@ -99,6 +99,8 @@ int tdx_mcall_tdreport(u64 data, u64 reportdata); int tdx_hcall_get_quote(u64 data); +extern void (*tdg_event_notify_handler)(void); + /* * To support I/O port access in decompressor or early kernel init * code, since #VE exception handler cannot be used, use paravirt diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c index 669869bd46ec..a4fe53c8c18f 100644 --- a/arch/x86/kernel/irq.c +++ b/arch/x86/kernel/irq.c @@ -182,11 +182,18 @@ int arch_show_interrupts(struct seq_file *p, int prec) irq_stats(j)->kvm_posted_intr_wakeup_ipis); seq_puts(p, " Posted-interrupt wakeup event\n"); #endif + #if IS_ENABLED(CONFIG_INTEL_TDX_GUEST) seq_printf(p, "%*s: ", prec, "TGV"); for_each_online_cpu(j) seq_printf(p, "%10u ", irq_stats(j)->tdg_ve_count); seq_puts(p, " TDX Guest VE event\n"); + + seq_printf(p, "%*s: ", prec, "TGN"); + for_each_online_cpu(j) + seq_printf(p, "%10u ", + irq_stats(j)->irq_tdg_event_notify_count); + seq_puts(p, " TDX Guest event notification\n"); #endif return 0; } diff --git a/arch/x86/kernel/tdx.c b/arch/x86/kernel/tdx.c index 9fca354e014c..1276027daa1c 100644 --- a/arch/x86/kernel/tdx.c +++ b/arch/x86/kernel/tdx.c @@ -9,6 +9,11 @@ #include #include +#include +#include +#include +#include +#include #include #include #include @@ -55,6 +60,14 @@ static struct { unsigned int tdg_disable_prot = -1; +/* + * Currently it will be used only by the attestation + * driver. So, race condition with read/write operation + * is not considered. + */ +void (*tdg_event_notify_handler)(void); +EXPORT_SYMBOL_GPL(tdg_event_notify_handler); + /* * Wrapper for standard use of __tdx_hypercall with BUG_ON() check * for TDCALL error. @@ -151,6 +164,28 @@ bool tdg_debug_enabled(void) return td_info.attributes & BIT(0); } +/* TDX guest event notification handler */ +DEFINE_IDTENTRY_SYSVEC(sysvec_tdg_event_notify) +{ + struct pt_regs *old_regs = set_irq_regs(regs); + + inc_irq_stat(irq_tdg_event_notify_count); + + if (tdg_event_notify_handler) + tdg_event_notify_handler(); + + /* + * The hypervisor requires that the APIC EOI should be acked. + * If the APIC EOI is not acked, the APIC ISR bit for the + * TDX_GUEST_EVENT_NOTIFY_VECTOR will not be cleared and then it + * will block the interrupt whose vector is lower than + * TDX_GUEST_EVENT_NOTIFY_VECTOR. + */ + ack_APIC_irq(); + + set_irq_regs(old_regs); +} + /* * tdx_mcall_tdreport() - Generate TDREPORT_STRUCT using TDCALL. * @@ -686,5 +721,11 @@ void __init tdx_early_init(void) add_taint(TAINT_CONF_NO_LOCKDOWN, LOCKDEP_STILL_OK); } + alloc_intr_gate(TDX_GUEST_EVENT_NOTIFY_VECTOR, + asm_sysvec_tdg_event_notify); + + if (tdx_hcall_set_notify_intr(TDX_GUEST_EVENT_NOTIFY_VECTOR)) + pr_warn("Setting event notification interrupt failed\n"); + pr_info("Guest initialized\n"); } From patchwork Fri Aug 6 00:09:44 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Kuppuswamy Sathyanarayanan X-Patchwork-Id: 12422369 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=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT 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 6CF99C432BE for ; Fri, 6 Aug 2021 00:10:17 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 4F2D1606A5 for ; Fri, 6 Aug 2021 00:10:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S242857AbhHFAKa (ORCPT ); Thu, 5 Aug 2021 20:10:30 -0400 Received: from mga04.intel.com ([192.55.52.120]:45294 "EHLO mga04.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S242813AbhHFAKZ (ORCPT ); Thu, 5 Aug 2021 20:10:25 -0400 X-IronPort-AV: E=McAfee;i="6200,9189,10067"; a="212422382" X-IronPort-AV: E=Sophos;i="5.84,299,1620716400"; d="scan'208";a="212422382" Received: from orsmga003.jf.intel.com ([10.7.209.27]) by fmsmga104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Aug 2021 17:10:10 -0700 X-IronPort-AV: E=Sophos;i="5.84,299,1620716400"; d="scan'208";a="420562739" Received: from rmgular-mobl2.amr.corp.intel.com (HELO skuppusw-desk1.amr.corp.intel.com) ([10.251.138.25]) by orsmga003-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Aug 2021 17:10:08 -0700 From: Kuppuswamy Sathyanarayanan To: Thomas Gleixner , Ingo Molnar , Borislav Petkov , Peter Zijlstra , Andy Lutomirski , Hans de Goede , Mark Gross , Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko Cc: Peter H Anvin , Dave Hansen , Tony Luck , Dan Williams , Andi Kleen , Kirill Shutemov , Sean Christopherson , Kuppuswamy Sathyanarayanan , x86@kernel.org, linux-kernel@vger.kernel.org, platform-driver-x86@vger.kernel.org, bpf@vger.kernel.org, netdev@vger.kernel.org Subject: [PATCH v4 6/7] platform/x86: intel_tdx_attest: Add TDX Guest attestation interface driver Date: Thu, 5 Aug 2021 17:09:44 -0700 Message-Id: <20210806000946.2951441-7-sathyanarayanan.kuppuswamy@linux.intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210806000946.2951441-1-sathyanarayanan.kuppuswamy@linux.intel.com> References: <20210806000946.2951441-1-sathyanarayanan.kuppuswamy@linux.intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org TDX guest supports encrypted disk as root or secondary drives. Decryption keys required to access such drives are usually maintained by 3rd party key servers. Attestation is required by 3rd party key servers to get the key for an encrypted disk volume, or possibly other encrypted services. Attestation is used to prove to the key server that the TD guest is running in a valid TD and the kernel and virtual BIOS and other environment are secure. During the boot process various components before the kernel accumulate hashes in the TDX module, which can then combined into a report. This would typically include a hash of the bios, bios configuration, boot loader, command line, kernel, initrd. After checking the hashes the key server will securely release the keys. The actual details of the attestation protocol depend on the particular key server configuration, but some parts are common and need to communicate with the TDX module. This communication is implemented in the attestation driver. The supported steps are: 1. TD guest generates the TDREPORT that contains version information about the Intel TDX module, measurement of the TD, along with a TD-specified nonce.   2. TD guest shares the TDREPORT with TD host via GetQuote hypercall which is used by the host to generate a quote via quoting enclave (QE).   3. Quote generation completion notification is sent to TD OS via callback interrupt vector configured by TD using SetupEventNotifyInterrupt hypercall.   4. After receiving the generated TDQUOTE, a remote verifier can be used to verify the quote and confirm the trustworthiness of the TD. Attestation agent uses IOCTLs implemented by the attestation driver to complete the various steps of the attestation process. Also note that, explicit access permissions are not enforced in this driver because the quote and measurements are not a secret. However the access permissions of the device node can be used to set any desired access policy. The udev default is usually root access only. TDX_CMD_GEN_QUOTE IOCTL can be used to create an computation on the host, but TDX assumes that the host is able to deal with malicious guest flooding it anyways. The interaction with the TDX module is like a RPM protocol here. There are several operations (get tdreport, get quote) that need to input a blob, and then output another blob. It was considered to use a sysfs interface for this, but it doesn't fit well into the standard sysfs model for configuring values. It would be possible to do read/write on files, but it would need multiple file descriptors, which would be somewhat messy. ioctls seems to be the best fitting and simplest model here. There is one ioctl per operation, that takes the input blob and returns the output blob, and as well as auxiliary ioctls to return the blob lengths. The ioctls are documented in the header file.  Reviewed-by: Tony Luck Reviewed-by: Andi Kleen Acked-by: Hans de Goede Signed-off-by: Kuppuswamy Sathyanarayanan --- Changes since v3: * Moved attestation driver under drivers/platform/x86/intel/. * No functional changes. Changes since v2: * Removed MMIO reference in Kconfig help text. * Added support for GetQuote completion timeout. * Moved quote and report data memory allocation logic to module init code. * Removed tdg_attest_open() and tdg_attest_release(). * Removed MODULE_VERSION as per Dan's suggestion. * Added check for put_user() return value in TDX_CMD_GET_QUOTE_SIZE case. * Modified TDX_CMD_GEN_QUOTE IOCTL to depend on TDREPORT data instead of report data. * Added tdg_attest_init() and tdg_attest_exit(). * Instead of using set_memory_{de/en}crypted() for sharing/unsharing guest pages, modified the driver to use dma_alloc APIs. drivers/platform/x86/intel/Kconfig | 1 + drivers/platform/x86/intel/Makefile | 1 + drivers/platform/x86/intel/tdx/Kconfig | 13 ++ drivers/platform/x86/intel/tdx/Makefile | 3 + .../platform/x86/intel/tdx/intel_tdx_attest.c | 212 ++++++++++++++++++ include/uapi/misc/tdx.h | 37 +++ 6 files changed, 267 insertions(+) create mode 100644 drivers/platform/x86/intel/tdx/Kconfig create mode 100644 drivers/platform/x86/intel/tdx/Makefile create mode 100644 drivers/platform/x86/intel/tdx/intel_tdx_attest.c create mode 100644 include/uapi/misc/tdx.h diff --git a/drivers/platform/x86/intel/Kconfig b/drivers/platform/x86/intel/Kconfig index f2eef337eb98..9ceebafea348 100644 --- a/drivers/platform/x86/intel/Kconfig +++ b/drivers/platform/x86/intel/Kconfig @@ -18,5 +18,6 @@ if X86_PLATFORM_DRIVERS_INTEL source "drivers/platform/x86/intel/int33fe/Kconfig" source "drivers/platform/x86/intel/int3472/Kconfig" +source "drivers/platform/x86/intel/tdx/Kconfig" endif # X86_PLATFORM_DRIVERS_INTEL diff --git a/drivers/platform/x86/intel/Makefile b/drivers/platform/x86/intel/Makefile index 0653055942d5..e2c2484089a0 100644 --- a/drivers/platform/x86/intel/Makefile +++ b/drivers/platform/x86/intel/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_INTEL_CHT_INT33FE) += int33fe/ obj-$(CONFIG_INTEL_SKL_INT3472) += int3472/ +obj-$(CONFIG_INTEL_TDX_GUEST) += tdx/ diff --git a/drivers/platform/x86/intel/tdx/Kconfig b/drivers/platform/x86/intel/tdx/Kconfig new file mode 100644 index 000000000000..853e3a34c889 --- /dev/null +++ b/drivers/platform/x86/intel/tdx/Kconfig @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# X86 TDX Platform Specific Drivers +# + +config INTEL_TDX_ATTESTATION + tristate "Intel TDX attestation driver" + depends on INTEL_TDX_GUEST + help + The TDX attestation driver provides IOCTL interfaces to the user to + request TDREPORT from the TDX module or request quote from the VMM + or to get quote buffer size. It is mainly used to get secure disk + decryption keys from the key server. diff --git a/drivers/platform/x86/intel/tdx/Makefile b/drivers/platform/x86/intel/tdx/Makefile new file mode 100644 index 000000000000..124d6b7b20a0 --- /dev/null +++ b/drivers/platform/x86/intel/tdx/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-$(CONFIG_INTEL_TDX_ATTESTATION) += intel_tdx_attest.o diff --git a/drivers/platform/x86/intel/tdx/intel_tdx_attest.c b/drivers/platform/x86/intel/tdx/intel_tdx_attest.c new file mode 100644 index 000000000000..9dbb253df6ae --- /dev/null +++ b/drivers/platform/x86/intel/tdx/intel_tdx_attest.c @@ -0,0 +1,212 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * intel_tdx_attest.c - TDX guest attestation interface driver. + * + * Implements user interface to trigger attestation process and + * read the TD Quote result. + * + * Copyright (C) 2020 Intel Corporation + * + * Author: + * Kuppuswamy Sathyanarayanan + */ + +#define pr_fmt(fmt) "x86/tdx: attest: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Used in Quote memory allocation */ +#define QUOTE_SIZE (2 * PAGE_SIZE) +/* Get Quote timeout in msec */ +#define GET_QUOTE_TIMEOUT (5000) + +/* Mutex to synchronize attestation requests */ +static DEFINE_MUTEX(attestation_lock); +/* Completion object to track attestation status */ +static DECLARE_COMPLETION(attestation_done); +/* Buffer used to copy report data in attestation handler */ +static u8 report_data[TDX_REPORT_DATA_LEN]; +/* Data pointer used to get TD Quote data in attestation handler */ +static void *tdquote_data; +/* Data pointer used to get TDREPORT data in attestation handler */ +static void *tdreport_data; +/* DMA handle used to allocate and free tdquote DMA buffer */ +dma_addr_t tdquote_dma_handle; + +static void attestation_callback_handler(void) +{ + complete(&attestation_done); +} + +static long tdg_attest_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + void __user *argp = (void __user *)arg; + long ret = 0; + + mutex_lock(&attestation_lock); + + switch (cmd) { + case TDX_CMD_GET_TDREPORT: + if (copy_from_user(report_data, argp, TDX_REPORT_DATA_LEN)) { + ret = -EFAULT; + break; + } + + /* Generate TDREPORT_STRUCT */ + if (tdx_mcall_tdreport(virt_to_phys(tdreport_data), + virt_to_phys(report_data))) { + ret = -EIO; + break; + } + + if (copy_to_user(argp, tdreport_data, TDX_TDREPORT_LEN)) + ret = -EFAULT; + break; + case TDX_CMD_GEN_QUOTE: + /* Copy TDREPORT data from user buffer */ + if (copy_from_user(tdquote_data, argp, TDX_TDREPORT_LEN)) { + ret = -EFAULT; + break; + } + + /* Submit GetQuote Request */ + if (tdx_hcall_get_quote(virt_to_phys(tdquote_data))) { + ret = -EIO; + break; + } + + /* Wait for attestation completion */ + ret = wait_for_completion_interruptible_timeout( + &attestation_done, + msecs_to_jiffies(GET_QUOTE_TIMEOUT)); + if (ret <= 0) { + ret = -EIO; + break; + } + + if (copy_to_user(argp, tdquote_data, QUOTE_SIZE)) + ret = -EFAULT; + + break; + case TDX_CMD_GET_QUOTE_SIZE: + ret = put_user(QUOTE_SIZE, (u64 __user *)argp); + break; + default: + pr_err("cmd %d not supported\n", cmd); + break; + } + + mutex_unlock(&attestation_lock); + + return ret; +} + +static const struct file_operations tdg_attest_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = tdg_attest_ioctl, + .llseek = no_llseek, +}; + +static struct miscdevice tdg_attest_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "tdx-attest", + .fops = &tdg_attest_fops, +}; + +static int __init tdg_attest_init(void) +{ + dma_addr_t handle; + long ret = 0; + + ret = misc_register(&tdg_attest_device); + if (ret) { + pr_err("misc device registration failed\n"); + return ret; + } + + /* + * tdreport_data needs to be 64-byte aligned. + * Full page alignment is more than enough. + */ + tdreport_data = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 0); + if (!tdreport_data) { + ret = -ENOMEM; + goto failed; + } + + ret = dma_set_coherent_mask(tdg_attest_device.this_device, + DMA_BIT_MASK(64)); + if (ret) { + pr_err("dma set coherent mask failed\n"); + goto failed; + } + + /* Allocate DMA buffer to get TDQUOTE data from the VMM */ + tdquote_data = dma_alloc_coherent(tdg_attest_device.this_device, + QUOTE_SIZE, &handle, + GFP_KERNEL | __GFP_ZERO); + if (!tdquote_data) { + ret = -ENOMEM; + goto failed; + } + + tdquote_dma_handle = handle; + + /* + * Currently tdg_event_notify_handler is only used in attestation + * driver. But, WRITE_ONCE is used as benign data race notice. + */ + WRITE_ONCE(tdg_event_notify_handler, attestation_callback_handler); + + pr_debug("module initialization success\n"); + + return 0; + +failed: + if (tdreport_data) + free_pages((unsigned long)tdreport_data, 0); + + misc_deregister(&tdg_attest_device); + + pr_debug("module initialization failed\n"); + + return ret; +} + +static void __exit tdg_attest_exit(void) +{ + mutex_lock(&attestation_lock); + + dma_free_coherent(tdg_attest_device.this_device, QUOTE_SIZE, + tdquote_data, tdquote_dma_handle); + free_pages((unsigned long)tdreport_data, 0); + misc_deregister(&tdg_attest_device); + /* + * Currently tdg_event_notify_handler is only used in attestation + * driver. But, WRITE_ONCE is used as benign data race notice. + */ + WRITE_ONCE(tdg_event_notify_handler, NULL); + mutex_unlock(&attestation_lock); + pr_debug("module is successfully removed\n"); +} + +module_init(tdg_attest_init); +module_exit(tdg_attest_exit); + +MODULE_AUTHOR("Kuppuswamy Sathyanarayanan "); +MODULE_DESCRIPTION("TDX attestation driver"); +MODULE_LICENSE("GPL"); diff --git a/include/uapi/misc/tdx.h b/include/uapi/misc/tdx.h new file mode 100644 index 000000000000..da4b3866ea1b --- /dev/null +++ b/include/uapi/misc/tdx.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI_MISC_TDX_H +#define _UAPI_MISC_TDX_H + +#include +#include + +/* Input report data length for TDX_CMD_GET_TDREPORT IOCTL request */ +#define TDX_REPORT_DATA_LEN 64 + +/* Output TD report data length after TDX_CMD_GET_TDREPORT IOCTL execution */ +#define TDX_TDREPORT_LEN 1024 + +/* + * TDX_CMD_GET_TDREPORT IOCTL is used to get TDREPORT data from the TDX + * Module. Users should pass report data of size TDX_REPORT_DATA_LEN bytes + * via user input buffer of size TDX_TDREPORT_LEN. Once IOCTL is successful + * TDREPORT data is copied to the user buffer. + */ +#define TDX_CMD_GET_TDREPORT _IOWR('T', 0x01, __u64) + +/* + * TDX_CMD_GEN_QUOTE IOCTL is used to request TD QUOTE from the VMM. User + * should pass TD report data of size TDX_TDREPORT_LEN bytes via user input + * buffer of quote size. Once IOCTL is successful quote data is copied back to + * the user buffer. + */ +#define TDX_CMD_GEN_QUOTE _IOR('T', 0x02, __u64) + +/* + * TDX_CMD_GET_QUOTE_SIZE IOCTL is used to get the TD Quote size info in bytes. + * This will be used for determining the input buffer allocation size when + * using TDX_CMD_GEN_QUOTE IOCTL. + */ +#define TDX_CMD_GET_QUOTE_SIZE _IOR('T', 0x03, __u64) + +#endif /* _UAPI_MISC_TDX_H */ From patchwork Fri Aug 6 00:09:45 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kuppuswamy Sathyanarayanan X-Patchwork-Id: 12422371 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=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham 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 D344FC4338F for ; Fri, 6 Aug 2021 00:10:31 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id BA778606A5 for ; Fri, 6 Aug 2021 00:10:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S242927AbhHFAKi (ORCPT ); Thu, 5 Aug 2021 20:10:38 -0400 Received: from mga04.intel.com ([192.55.52.120]:45295 "EHLO mga04.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240392AbhHFAK0 (ORCPT ); Thu, 5 Aug 2021 20:10:26 -0400 X-IronPort-AV: E=McAfee;i="6200,9189,10067"; a="212422385" X-IronPort-AV: E=Sophos;i="5.84,299,1620716400"; d="scan'208";a="212422385" Received: from orsmga003.jf.intel.com ([10.7.209.27]) by fmsmga104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Aug 2021 17:10:11 -0700 X-IronPort-AV: E=Sophos;i="5.84,299,1620716400"; d="scan'208";a="420562748" Received: from rmgular-mobl2.amr.corp.intel.com (HELO skuppusw-desk1.amr.corp.intel.com) ([10.251.138.25]) by orsmga003-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Aug 2021 17:10:10 -0700 From: Kuppuswamy Sathyanarayanan To: Thomas Gleixner , Ingo Molnar , Borislav Petkov , Peter Zijlstra , Andy Lutomirski , Hans de Goede , Mark Gross , Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko Cc: Peter H Anvin , Dave Hansen , Tony Luck , Dan Williams , Andi Kleen , Kirill Shutemov , Sean Christopherson , Kuppuswamy Sathyanarayanan , x86@kernel.org, linux-kernel@vger.kernel.org, platform-driver-x86@vger.kernel.org, bpf@vger.kernel.org, netdev@vger.kernel.org Subject: [PATCH v4 7/7] tools/tdx: Add a sample attestation user app Date: Thu, 5 Aug 2021 17:09:45 -0700 Message-Id: <20210806000946.2951441-8-sathyanarayanan.kuppuswamy@linux.intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210806000946.2951441-1-sathyanarayanan.kuppuswamy@linux.intel.com> References: <20210806000946.2951441-1-sathyanarayanan.kuppuswamy@linux.intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org This application uses the misc device /dev/tdx-attest to get TDREPORT from the TDX Module or request quote from the VMM. It tests following attestation features: - Get report using TDX_CMD_GET_TDREPORT IOCTL. - Using report data request quote from VMM using TDX_CMD_GEN_QUOTE IOCTL. - Get the quote size using TDX_CMD_GET_QUOTE_SIZE IOCTL. Reviewed-by: Tony Luck Reviewed-by: Andi Kleen Signed-off-by: Kuppuswamy Sathyanarayanan --- tools/Makefile | 13 +- tools/tdx/Makefile | 19 +++ tools/tdx/attest/.gitignore | 2 + tools/tdx/attest/Makefile | 24 +++ tools/tdx/attest/tdx-attest-test.c | 232 +++++++++++++++++++++++++++++ 5 files changed, 284 insertions(+), 6 deletions(-) create mode 100644 tools/tdx/Makefile create mode 100644 tools/tdx/attest/.gitignore create mode 100644 tools/tdx/attest/Makefile create mode 100644 tools/tdx/attest/tdx-attest-test.c diff --git a/tools/Makefile b/tools/Makefile index 7e9d34ddd74c..5d68084511cb 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -30,6 +30,7 @@ help: @echo ' selftests - various kernel selftests' @echo ' bootconfig - boot config tool' @echo ' spi - spi tools' + @echo ' tdx - TDX related test tools' @echo ' tmon - thermal monitoring and tuning tool' @echo ' tracing - misc tracing tools' @echo ' turbostat - Intel CPU idle stats and freq reporting tool' @@ -65,7 +66,7 @@ acpi: FORCE cpupower: FORCE $(call descend,power/$@) -cgroup firewire hv guest bootconfig spi usb virtio vm bpf iio gpio objtool leds wmi pci firmware debugging tracing: FORCE +cgroup firewire hv guest bootconfig spi usb virtio vm bpf iio gpio objtool leds wmi pci firmware debugging tracing tdx: FORCE $(call descend,$@) bpf/%: FORCE @@ -104,7 +105,7 @@ all: acpi cgroup cpupower gpio hv firewire liblockdep \ perf selftests bootconfig spi turbostat usb \ virtio vm bpf x86_energy_perf_policy \ tmon freefall iio objtool kvm_stat wmi \ - pci debugging tracing + pci debugging tracing tdx acpi_install: $(call descend,power/$(@:_install=),install) @@ -112,7 +113,7 @@ acpi_install: cpupower_install: $(call descend,power/$(@:_install=),install) -cgroup_install firewire_install gpio_install hv_install iio_install perf_install bootconfig_install spi_install usb_install virtio_install vm_install bpf_install objtool_install wmi_install pci_install debugging_install tracing_install: +cgroup_install firewire_install gpio_install hv_install iio_install perf_install bootconfig_install spi_install usb_install virtio_install vm_install bpf_install objtool_install wmi_install pci_install debugging_install tracing_install tdx_install: $(call descend,$(@:_install=),install) liblockdep_install: @@ -139,7 +140,7 @@ install: acpi_install cgroup_install cpupower_install gpio_install \ virtio_install vm_install bpf_install x86_energy_perf_policy_install \ tmon_install freefall_install objtool_install kvm_stat_install \ wmi_install pci_install debugging_install intel-speed-select_install \ - tracing_install + tracing_install tdx_install acpi_clean: $(call descend,power/acpi,clean) @@ -147,7 +148,7 @@ acpi_clean: cpupower_clean: $(call descend,power/cpupower,clean) -cgroup_clean hv_clean firewire_clean bootconfig_clean spi_clean usb_clean virtio_clean vm_clean wmi_clean bpf_clean iio_clean gpio_clean objtool_clean leds_clean pci_clean firmware_clean debugging_clean tracing_clean: +cgroup_clean hv_clean firewire_clean bootconfig_clean spi_clean usb_clean virtio_clean vm_clean wmi_clean bpf_clean iio_clean gpio_clean objtool_clean leds_clean pci_clean firmware_clean debugging_clean tracing_clean tdx_clean: $(call descend,$(@:_clean=),clean) liblockdep_clean: @@ -186,6 +187,6 @@ clean: acpi_clean cgroup_clean cpupower_clean hv_clean firewire_clean \ vm_clean bpf_clean iio_clean x86_energy_perf_policy_clean tmon_clean \ freefall_clean build_clean libbpf_clean libsubcmd_clean liblockdep_clean \ gpio_clean objtool_clean leds_clean wmi_clean pci_clean firmware_clean debugging_clean \ - intel-speed-select_clean tracing_clean + intel-speed-select_clean tracing_clean tdx_clean .PHONY: FORCE diff --git a/tools/tdx/Makefile b/tools/tdx/Makefile new file mode 100644 index 000000000000..e2564557d463 --- /dev/null +++ b/tools/tdx/Makefile @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0 +include ../scripts/Makefile.include + +all: attest + +clean: attest_clean + +install: attest_install + +attest: + $(call descend,attest) + +attest_install: + $(call descend,attest,install) + +attest_clean: + $(call descend,attest,clean) + +.PHONY: all install clean attest latency_install latency_clean diff --git a/tools/tdx/attest/.gitignore b/tools/tdx/attest/.gitignore new file mode 100644 index 000000000000..5f819a8a6c49 --- /dev/null +++ b/tools/tdx/attest/.gitignore @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +tdx-attest-test diff --git a/tools/tdx/attest/Makefile b/tools/tdx/attest/Makefile new file mode 100644 index 000000000000..bf47ba718386 --- /dev/null +++ b/tools/tdx/attest/Makefile @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: GPL-2.0 +# Makefile for vm tools +# +VAR_CFLAGS := $(shell pkg-config --cflags libtracefs 2>/dev/null) +VAR_LDLIBS := $(shell pkg-config --libs libtracefs 2>/dev/null) + +TARGETS = tdx-attest-test +CFLAGS = -static -Wall -Wextra -g -O2 $(VAR_CFLAGS) +LDFLAGS = -lpthread $(VAR_LDLIBS) + +all: $(TARGETS) + +%: %.c + $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) + +clean: + $(RM) tdx-attest-test + +prefix ?= /usr/local +sbindir ?= ${prefix}/sbin + +install: all + install -d $(DESTDIR)$(sbindir) + install -m 755 -p $(TARGETS) $(DESTDIR)$(sbindir) diff --git a/tools/tdx/attest/tdx-attest-test.c b/tools/tdx/attest/tdx-attest-test.c new file mode 100644 index 000000000000..cff33c3a0c32 --- /dev/null +++ b/tools/tdx/attest/tdx-attest-test.c @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * tdx-attest-test.c - utility to test TDX attestation feature. + * + * Copyright (C) 2020 - 2021 Intel Corporation. All rights reserved. + * + * Author: Kuppuswamy Sathyanarayanan + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* uintmax_t */ +#include +#include /* sysconf */ +#include + +#include "../../../include/uapi/misc/tdx.h" + +#define devname "/dev/tdx-attest" + +#define HEX_DUMP_SIZE 16 +#define MAX_ROW_SIZE 70 + +#define ATTESTATION_TEST_BIN_VERSION "0.1" + +struct tdx_attest_args { + bool is_dump_data; + bool is_get_tdreport; + bool is_get_quote_size; + bool is_gen_quote; + bool debug_mode; + char *out_file; +}; + +static void print_hex_dump(const char *title, const char *prefix_str, + const void *buf, int len) +{ + const __u8 *ptr = buf; + int i, rowsize = HEX_DUMP_SIZE; + + if (!len || !buf) + return; + + printf("\t\t%s", title); + + for (i = 0; i < len; i++) { + if (!(i % rowsize)) + printf("\n%s%.8x:", prefix_str, i); + printf(" %.2x", ptr[i]); + } + + printf("\n"); +} + +static void gen_report_data(__u8 *report_data, bool dump_data) +{ + int i; + + srand(time(NULL)); + + for (i = 0; i < TDX_REPORT_DATA_LEN; i++) + report_data[i] = rand(); + + if (dump_data) + print_hex_dump("\n\t\tTDX report data\n", " ", + report_data, TDX_REPORT_DATA_LEN); +} + +static int get_tdreport(int devfd, bool dump_data, __u8 *report_data) +{ + __u8 tdrdata[TDX_TDREPORT_LEN] = {0}; + int ret; + + if (!report_data) + report_data = tdrdata; + + gen_report_data(report_data, dump_data); + + ret = ioctl(devfd, TDX_CMD_GET_TDREPORT, report_data); + if (ret) { + printf("TDX_CMD_GET_TDREPORT ioctl() %d failed\n", ret); + return -EIO; + } + + if (dump_data) + print_hex_dump("\n\t\tTDX tdreport data\n", " ", report_data, + TDX_TDREPORT_LEN); + + return 0; +} + +static __u64 get_quote_size(int devfd) +{ + int ret; + __u64 quote_size; + + ret = ioctl(devfd, TDX_CMD_GET_QUOTE_SIZE, "e_size); + if (ret) { + printf("TDX_CMD_GET_QUOTE_SIZE ioctl() %d failed\n", ret); + return -EIO; + } + + printf("Quote size: %lld\n", quote_size); + + return quote_size; +} + +static int gen_quote(int devfd, bool dump_data) +{ + __u8 *quote_data; + __u64 quote_size; + int ret; + + quote_size = get_quote_size(devfd); + + quote_data = malloc(sizeof(char) * quote_size); + if (!quote_data) { + printf("%s queue data alloc failed\n", devname); + return -ENOMEM; + } + + ret = get_tdreport(devfd, dump_data, quote_data); + if (ret) { + printf("TDX_CMD_GET_TDREPORT ioctl() %d failed\n", ret); + goto done; + } + + ret = ioctl(devfd, TDX_CMD_GEN_QUOTE, quote_data); + if (ret) { + printf("TDX_CMD_GEN_QUOTE ioctl() %d failed\n", ret); + goto done; + } + + print_hex_dump("\n\t\tTDX Quote data\n", " ", quote_data, + quote_size); + +done: + free(quote_data); + + return ret; +} + +static void usage(void) +{ + puts("\nUsage:\n"); + puts("tdx_attest [options] \n"); + + puts("Attestation device test utility."); + + puts("\nOptions:\n"); + puts(" -d, --dump Dump tdreport/tdquote data"); + puts(" -r, --get-tdreport Get TDREPORT data"); + puts(" -g, --gen-quote Generate TDQUOTE"); + puts(" -s, --get-quote-size Get TDQUOTE size"); +} + +int main(int argc, char **argv) +{ + int ret, devfd; + struct tdx_attest_args args = {0}; + + static const struct option longopts[] = { + { "dump", no_argument, NULL, 'd' }, + { "get-tdreport", required_argument, NULL, 'r' }, + { "gen-quote", required_argument, NULL, 'g' }, + { "gen-quote-size", required_argument, NULL, 's' }, + { "version", no_argument, NULL, 'V' }, + { NULL, 0, NULL, 0 } + }; + + while ((ret = getopt_long(argc, argv, "hdrgsV", longopts, + NULL)) != -1) { + switch (ret) { + case 'd': + args.is_dump_data = true; + break; + case 'r': + args.is_get_tdreport = true; + break; + case 'g': + args.is_gen_quote = true; + break; + case 's': + args.is_get_quote_size = true; + break; + case 'h': + usage(); + return 0; + case 'V': + printf("Version: %s\n", ATTESTATION_TEST_BIN_VERSION); + return 0; + default: + printf("Invalid options\n"); + usage(); + return -EINVAL; + } + } + + devfd = open(devname, O_RDWR | O_SYNC); + if (devfd < 0) { + printf("%s open() failed\n", devname); + return -ENODEV; + } + + if (args.is_get_quote_size) + get_quote_size(devfd); + + if (args.is_get_tdreport) + get_tdreport(devfd, args.is_dump_data, NULL); + + if (args.is_gen_quote) + gen_quote(devfd, args.is_dump_data); + + close(devfd); + + return 0; +}