From patchwork Thu Sep 24 14:58:29 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ross Philipson X-Patchwork-Id: 11797657 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B3F4A6CA for ; Thu, 24 Sep 2020 15:00:28 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 91879238A1 for ; Thu, 24 Sep 2020 15:00:28 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=oracle.com header.i=@oracle.com header.b="rrLFfCwG" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728224AbgIXPA2 (ORCPT ); Thu, 24 Sep 2020 11:00:28 -0400 Received: from aserp2120.oracle.com ([141.146.126.78]:57810 "EHLO aserp2120.oracle.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728164AbgIXPA2 (ORCPT ); Thu, 24 Sep 2020 11:00:28 -0400 Received: from pps.filterd (aserp2120.oracle.com [127.0.0.1]) by aserp2120.oracle.com (8.16.0.42/8.16.0.42) with SMTP id 08OExGKU057807; Thu, 24 Sep 2020 15:00:12 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=from : to : cc : subject : date : message-id : in-reply-to : references; s=corp-2020-01-29; bh=13WiYyuHylIHc8b1AvafzrXZ3VZ7lUwT8kAQzpDo+aw=; b=rrLFfCwGt5vfQPO5UdVtqNplwrSDc9m2VMX3H6bzqsDHY65IPQy0z8KC+A+pKcWKvSsP 1OO1N3aFtGDCNwi+N+NOe3csElclXxUIzyyHQhA4ZRu/bzVbDgrlpyxDksjmmG/iKHu3 JYfv0cdqfhXFgsOLcwsTGM+teyX4yG0//iUDm2i/MIoif6i+rHzgi/OWPbMSkDI3O93K ZiMNloK2NcnqBTG5MCzjF6r60TFFUchb4H1k9zVl6iqnQ/NikbQT/xg2uKJYqLMwBjuu vM+zpmqcNEp+FDI3bTG/k7VSAcN+U65qrxi948MAWfY5v1PpGt6hHyTKjeQjtk46vkkw AQ== Received: from aserp3030.oracle.com (aserp3030.oracle.com [141.146.126.71]) by aserp2120.oracle.com with ESMTP id 33q5rgq5k0-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Thu, 24 Sep 2020 15:00:12 +0000 Received: from pps.filterd (aserp3030.oracle.com [127.0.0.1]) by aserp3030.oracle.com (8.16.0.42/8.16.0.42) with SMTP id 08OEuTx5126380; Thu, 24 Sep 2020 14:58:12 GMT Received: from aserv0121.oracle.com (aserv0121.oracle.com [141.146.126.235]) by aserp3030.oracle.com with ESMTP id 33nujr18a4-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 24 Sep 2020 14:58:12 +0000 Received: from abhmp0014.oracle.com (abhmp0014.oracle.com [141.146.116.20]) by aserv0121.oracle.com (8.14.4/8.13.8) with ESMTP id 08OEw8fd022539; Thu, 24 Sep 2020 14:58:08 GMT Received: from disposition.us.oracle.com (/10.152.32.81) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Thu, 24 Sep 2020 07:58:08 -0700 From: Ross Philipson To: linux-kernel@vger.kernel.org, x86@kernel.org, iommu@lists.linux-foundation.org, linux-integrity@vger.kernel.org, linux-doc@vger.kernel.org Cc: ross.philipson@oracle.com, dpsmith@apertussolutions.com, tglx@linutronix.de, mingo@redhat.com, bp@alien8.de, hpa@zytor.com, luto@amacapital.net, trenchboot-devel@googlegroups.com Subject: [PATCH 01/13] x86: Secure Launch Kconfig Date: Thu, 24 Sep 2020 10:58:29 -0400 Message-Id: <1600959521-24158-2-git-send-email-ross.philipson@oracle.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1600959521-24158-1-git-send-email-ross.philipson@oracle.com> References: <1600959521-24158-1-git-send-email-ross.philipson@oracle.com> X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9753 signatures=668680 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 bulkscore=0 malwarescore=0 mlxlogscore=999 phishscore=0 adultscore=0 spamscore=0 suspectscore=0 mlxscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2006250000 definitions=main-2009240114 X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9753 signatures=668680 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 spamscore=0 impostorscore=0 clxscore=1015 suspectscore=0 phishscore=0 malwarescore=0 priorityscore=1501 mlxlogscore=999 adultscore=0 bulkscore=0 mlxscore=0 lowpriorityscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2006250000 definitions=main-2009240115 Precedence: bulk List-ID: X-Mailing-List: linux-integrity@vger.kernel.org Initial bits to bring in Secure Launch functionality. Add Kconfig options for compiling in/out the Secure Launch code. Signed-off-by: Ross Philipson --- arch/x86/Kconfig | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 7101ac6..8957981 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1968,6 +1968,42 @@ config EFI_MIXED If unsure, say N. +config SECURE_LAUNCH + bool "Secure Launch support" + default n + depends on X86_64 + help + The Secure Launch feature allows a kernel to be loaded + directly through an Intel TXT measured launch. Intel TXT + establishes a Dynamic Root of Trust for Measurement (DRTM) + where the CPU measures the kernel image. This feature then + continues the measurement chain over kernel configuration + information and init images. + +choice + prompt "Select Secure Launch Algorithm for TPM2" + depends on SECURE_LAUNCH + +config SECURE_LAUNCH_SHA1 + bool "Secure Launch TPM1 SHA1" + help + When using Secure Launch and TPM1 is present, use SHA1 hash + algorithm for measurements. + +config SECURE_LAUNCH_SHA256 + bool "Secure Launch TPM2 SHA256" + help + When using Secure Launch and TPM2 is present, use SHA256 hash + algorithm for measurements. + +config SECURE_LAUNCH_SHA512 + bool "Secure Launch TPM2 SHA512" + help + When using Secure Launch and TPM2 is present, use SHA512 hash + algorithm for measurements. + +endchoice + config SECCOMP def_bool y prompt "Enable seccomp to safely compute untrusted bytecode" From patchwork Thu Sep 24 14:58:30 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Ross Philipson X-Patchwork-Id: 11797659 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C92BE6CA for ; Thu, 24 Sep 2020 15:00:37 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 95DD82074B for ; Thu, 24 Sep 2020 15:00:37 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=oracle.com header.i=@oracle.com header.b="V6Y0XJNb" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728536AbgIXPAh (ORCPT ); Thu, 24 Sep 2020 11:00:37 -0400 Received: from aserp2120.oracle.com ([141.146.126.78]:57872 "EHLO aserp2120.oracle.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728522AbgIXPAf (ORCPT ); Thu, 24 Sep 2020 11:00:35 -0400 Received: from pps.filterd (aserp2120.oracle.com [127.0.0.1]) by aserp2120.oracle.com (8.16.0.42/8.16.0.42) with SMTP id 08OExMuU057870; Thu, 24 Sep 2020 15:00:13 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type : content-transfer-encoding; s=corp-2020-01-29; bh=yg4M06FIQJ2u5BXPw1XKsLXjtLOTZNeOwA/0MhZC+5I=; b=V6Y0XJNbInDYYuYExYE5nm5iEloc7qnPMzW66VFnn/iqTzeD1ycdb6783VP8uhGnQ56T wIduJWSSY0LK7UWYVTYE6NhCAcrk7ols4gLQs6kvoPVy2SOaxbQZFRhU/Ge0UY4v64Pk qfif7OAKHotFCRAzHkSj8TwB6AznMclRgfwcuWbTJRfiImmbXQSVj+pgQrfTP+U0rEcP 3dKvkYuZQK3S09ajQBWJLBgDyuLcWlXCjrEbAg6yth3/Xlo+kTx0AkLlWV8/DrAJIKuD JPhTA8jaG1KsIvW8r4uNht7o+N+za+BUr6vOHQlf/h5Uq1wUtSUEAw+OMyo4VAzgAjNF zg== Received: from userp3030.oracle.com (userp3030.oracle.com [156.151.31.80]) by aserp2120.oracle.com with ESMTP id 33q5rgq5k5-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Thu, 24 Sep 2020 15:00:13 +0000 Received: from pps.filterd (userp3030.oracle.com [127.0.0.1]) by userp3030.oracle.com (8.16.0.42/8.16.0.42) with SMTP id 08OEtT6r159274; Thu, 24 Sep 2020 14:58:12 GMT Received: from aserv0121.oracle.com (aserv0121.oracle.com [141.146.126.235]) by userp3030.oracle.com with ESMTP id 33nux2vwjb-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 24 Sep 2020 14:58:12 +0000 Received: from abhmp0014.oracle.com (abhmp0014.oracle.com [141.146.116.20]) by aserv0121.oracle.com (8.14.4/8.13.8) with ESMTP id 08OEw9OM022555; Thu, 24 Sep 2020 14:58:09 GMT Received: from disposition.us.oracle.com (/10.152.32.81) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Thu, 24 Sep 2020 07:58:09 -0700 From: Ross Philipson To: linux-kernel@vger.kernel.org, x86@kernel.org, iommu@lists.linux-foundation.org, linux-integrity@vger.kernel.org, linux-doc@vger.kernel.org Cc: ross.philipson@oracle.com, dpsmith@apertussolutions.com, tglx@linutronix.de, mingo@redhat.com, bp@alien8.de, hpa@zytor.com, luto@amacapital.net, trenchboot-devel@googlegroups.com Subject: [PATCH 02/13] x86: Secure Launch main header file Date: Thu, 24 Sep 2020 10:58:30 -0400 Message-Id: <1600959521-24158-3-git-send-email-ross.philipson@oracle.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1600959521-24158-1-git-send-email-ross.philipson@oracle.com> References: <1600959521-24158-1-git-send-email-ross.philipson@oracle.com> MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9753 signatures=668680 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 malwarescore=0 mlxscore=0 adultscore=0 bulkscore=0 mlxlogscore=999 phishscore=0 suspectscore=0 spamscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2006250000 definitions=main-2009240114 X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9753 signatures=668680 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 spamscore=0 impostorscore=0 clxscore=1015 suspectscore=0 phishscore=0 malwarescore=0 priorityscore=1501 mlxlogscore=999 adultscore=0 bulkscore=0 mlxscore=0 lowpriorityscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2006250000 definitions=main-2009240115 Precedence: bulk List-ID: X-Mailing-List: linux-integrity@vger.kernel.org Introduce the main Secure Launch header file used in the early SL stub and the early setup code. Signed-off-by: Ross Philipson --- include/linux/slaunch.h | 544 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 544 insertions(+) create mode 100644 include/linux/slaunch.h diff --git a/include/linux/slaunch.h b/include/linux/slaunch.h new file mode 100644 index 0000000..88adc69 --- /dev/null +++ b/include/linux/slaunch.h @@ -0,0 +1,544 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Main Secure Launch header file. + * + * Copyright (c) 2020, Oracle and/or its affiliates. + */ + +#ifndef _LINUX_SLAUNCH_H +#define _LINUX_SLAUNCH_H + +/* + * Secure Launch Defined State Flags + */ +#define SL_FLAG_ACTIVE 0x00000001 +#define SL_FLAG_ARCH_SKINIT 0x00000002 +#define SL_FLAG_ARCH_TXT 0x00000004 + +#ifdef CONFIG_SECURE_LAUNCH + +/* + * Secure Launch main definitions file. + * + * Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved. + */ + +#define __SL32_CS 0x0008 +#define __SL32_DS 0x0010 + +#define SL_CPU_AMD 1 +#define SL_CPU_INTEL 2 + +#define INTEL_CPUID_MFGID_EBX 0x756e6547 /* Genu */ +#define INTEL_CPUID_MFGID_EDX 0x49656e69 /* ineI */ +#define INTEL_CPUID_MFGID_ECX 0x6c65746e /* ntel */ + +#define AMD_CPUID_MFGID_EBX 0x68747541 /* Auth */ +#define AMD_CPUID_MFGID_EDX 0x69746e65 /* enti */ +#define AMD_CPUID_MFGID_ECX 0x444d4163 /* cAMD */ + +/* + * Intel Safer Mode Extensions (SMX) + * + * Intel SMX provides a programming interface to establish a Measured Launched + * Environment (MLE). The measurement and protection mechanisms supported by the + * capabilities of an Intel Trusted Execution Technology (TXT) platform. SMX is + * the processor’s programming interface in an Intel TXT platform. + * + * See Intel SDM Volume 2 - 6.1 "Safer Mode Extensions Reference" + */ + +/* + * SMX GETSEC Leaf Functions + */ +#define SMX_X86_GETSEC_SEXIT 5 +#define SMX_X86_GETSEC_SMCTRL 7 +#define SMX_X86_GETSEC_WAKEUP 8 + +/* + * Intel Trusted Execution Technology MMIO Registers Banks + */ +#define TXT_PUB_CONFIG_REGS_BASE 0xfed30000 +#define TXT_PRIV_CONFIG_REGS_BASE 0xfed20000 +#define TXT_NR_CONFIG_PAGES ((TXT_PUB_CONFIG_REGS_BASE - \ + TXT_PRIV_CONFIG_REGS_BASE) >> PAGE_SHIFT) + +/* + * Intel Trusted Execution Technology (TXT) Registers + */ +#define TXT_CR_STS 0x0000 +#define TXT_CR_ESTS 0x0008 +#define TXT_CR_ERRORCODE 0x0030 +#define TXT_CR_CMD_RESET 0x0038 +#define TXT_CR_CMD_CLOSE_PRIVATE 0x0048 +#define TXT_CR_DIDVID 0x0110 +#define TXT_CR_VER_EMIF 0x0200 +#define TXT_CR_CMD_UNLOCK_MEM_CONFIG 0x0218 +#define TXT_CR_SINIT_BASE 0x0270 +#define TXT_CR_SINIT_SIZE 0x0278 +#define TXT_CR_MLE_JOIN 0x0290 +#define TXT_CR_HEAP_BASE 0x0300 +#define TXT_CR_HEAP_SIZE 0x0308 +#define TXT_CR_SCRATCHPAD 0x0378 +#define TXT_CR_CMD_OPEN_LOCALITY1 0x0380 +#define TXT_CR_CMD_CLOSE_LOCALITY1 0x0388 +#define TXT_CR_CMD_OPEN_LOCALITY2 0x0390 +#define TXT_CR_CMD_CLOSE_LOCALITY2 0x0398 +#define TXT_CR_CMD_SECRETS 0x08e0 +#define TXT_CR_CMD_NO_SECRETS 0x08e8 +#define TXT_CR_E2STS 0x08f0 + +/* TXTCR_STS status bits */ +#define TXT_SENTER_DONE_STS (1<<0) +#define TXT_SEXIT_DONE_STS (1<<1) + +/* + * SINIT/MLE Capabilities Field Bit Definitions + */ +#define TXT_SINIT_MLE_CAP_WAKE_GETSEC 0 +#define TXT_SINIT_MLE_CAP_WAKE_MONITOR 1 + +/* + * OS/MLE Secure Launch Specific Definitions + */ +#define TXT_OS_MLE_STRUCT_VERSION 1 +#define TXT_OS_MLE_MAX_VARIABLE_MTRRS 32 + +/* + * TXT Heap Table Enumeration + */ +#define TXT_BIOS_DATA_TABLE 1 +#define TXT_OS_MLE_DATA_TABLE 2 +#define TXT_OS_SINIT_DATA_TABLE 3 +#define TXT_SINIT_MLE_DATA_TABLE 4 + +/* + * Secure Launch Defined Error Codes used in MLE-initiated TXT resets. + * + * TXT Specification + * Appendix I ACM Error Codes + */ +#define SL_ERROR_GENERIC 0xc0008001 +#define SL_ERROR_TPM_INIT 0xc0008002 +#define SL_ERROR_TPM_INVALID_LOG20 0xc0008003 +#define SL_ERROR_TPM_LOGGING_FAILED 0xc0008004 +#define SL_ERROR_TPM_GET_LOC 0xc0008005 +#define SL_ERROR_TPM_EXTEND 0xc0008006 +#define SL_ERROR_MTRR_INV_VCNT 0xc0008007 +#define SL_ERROR_MTRR_INV_DEF_TYPE 0xc0008008 +#define SL_ERROR_MTRR_INV_BASE 0xc0008009 +#define SL_ERROR_MTRR_INV_MASK 0xc000800a +#define SL_ERROR_MSR_INV_MISC_EN 0xc000800b +#define SL_ERROR_INV_AP_INTERRUPT 0xc000800c +#define SL_ERROR_RESERVE_AP_WAKE 0xc000800d +#define SL_ERROR_HEAP_WALK 0xc000800e +#define SL_ERROR_HEAP_MAP 0xc000800f +#define SL_ERROR_HEAP_MDR_VALS 0xc0008010 +#define SL_ERROR_HEAP_INVALID_DMAR 0xc0008011 +#define SL_ERROR_HEAP_DMAR_SIZE 0xc0008012 +#define SL_ERROR_HEAP_DMAR_MAP 0xc0008013 +#define SL_ERROR_HI_PMR_BASE 0xc0008014 +#define SL_ERROR_HI_PMR_SIZE 0xc0008015 +#define SL_ERROR_LO_PMR_BASE 0xc0008016 +#define SL_ERROR_LO_PMR_MLE 0xc0008017 +#define SL_ERROR_LO_PMR_INITRD 0xc0008018 +#define SL_ERROR_HEAP_ZERO_OFFSET 0xc0008019 +#define SL_ERROR_WAKE_BLOCK_TOO_SMALL 0xc000801a + +/* + * Secure Launch Defined Limits + */ +#define TXT_MAX_CPUS 512 +#define TXT_BOOT_STACK_SIZE 24 + +/* + * Secure Launch event log entry type. The TXT specification defines the + * base event value as 0x400 for DRTM values. + */ +#define TXT_EVTYPE_BASE 0x400 +#define TXT_EVTYPE_SLAUNCH (TXT_EVTYPE_BASE + 0x102) + +/* + * Measured Launch PCRs + */ +#define SL_IMAGE_PCR17 17 +#define SL_CONFIG_PCR18 18 + +/* + * MLE scratch area offsets + */ +#define SL_SCRATCH_AP_EBX 0 +#define SL_SCRATCH_AP_JMP_OFFSET 4 +#define SL_SCRATCH_AP_PAUSE 8 + +#ifndef __ASSEMBLY__ + +#include + +/* + * Secure Launch AP wakeup information fetched in SMP boot code. + */ +struct sl_ap_wake_info { + u32 ap_wake_block; + u32 ap_wake_block_size; + u32 ap_jmp_offset; +}; + +/* + * TXT heap extended data elements. + */ +struct txt_heap_ext_data_element { + u32 type; + u32 size; + /* Data */ +} __packed; + +#define TXT_HEAP_EXTDATA_TYPE_END 0 + +struct txt_heap_end_element { + u32 type; + u32 size; +} __packed; + +#define TXT_HEAP_EXTDATA_TYPE_TPM_EVENT_LOG_PTR 5 + +struct txt_heap_event_log_element { + u64 event_log_phys_addr; +} __packed; + +#define TXT_HEAP_EXTDATA_TYPE_EVENT_LOG_POINTER2_1 8 + +struct txt_heap_event_log_pointer2_1_element { + u64 phys_addr; + u32 allocated_event_container_size; + u32 first_record_offset; + u32 next_record_offset; +} __packed; + +/* + * Secure Launch defined MTRR saving structures + */ +struct txt_mtrr_pair { + u64 mtrr_physbase; + u64 mtrr_physmask; +} __packed; + +struct txt_mtrr_state { + u64 default_mem_type; + u64 mtrr_vcnt; + struct txt_mtrr_pair mtrr_pair[TXT_OS_MLE_MAX_VARIABLE_MTRRS]; +} __packed; + +/* + * Secure Launch defined OS/MLE TXT Heap table + */ +struct txt_os_mle_data { + u32 version; + u32 boot_params_addr; + u64 saved_misc_enable_msr; + struct txt_mtrr_state saved_bsp_mtrrs; + u32 ap_wake_block; + u32 ap_wake_block_size; + u64 evtlog_addr; + u32 evtlog_size; + u8 mle_scratch[64]; +} __packed; + +/* + * TXT specification defined BIOS data TXT Heap table + */ +struct txt_bios_data { + u32 version; /* Currently 5 for TPM 1.2 and 6 for TPM 2.0 */ + u32 bios_sinit_size; + u64 reserved1; + u64 reserved2; + u32 num_logical_procs; + /* Versions >= 5 with updates in version 6 */ + u32 sinit_flags; + u32 mle_flags; + /* Versions >= 4 */ + /* Ext Data Elements */ +} __packed; + +/* + * TXT specification defined OS/SINIT TXT Heap table + */ +struct txt_os_sinit_data { + u32 version; /* Currently 6 for TPM 1.2 and 7 for TPM 2.0 */ + u32 flags; + u64 mle_ptab; + u64 mle_size; + u64 mle_hdr_base; + u64 vtd_pmr_lo_base; + u64 vtd_pmr_lo_size; + u64 vtd_pmr_hi_base; + u64 vtd_pmr_hi_size; + u64 lcp_po_base; + u64 lcp_po_size; + u32 capabilities; + /* Version = 5 */ + u64 efi_rsdt_ptr; + /* Versions >= 6 */ + /* Ext Data Elements */ +} __packed; + +/* + * TXT specification defined SINIT/MLE TXT Heap table + */ +struct txt_sinit_mle_data { + u32 version; /* Current values are 6 through 9 */ + /* Versions <= 8 */ + u8 bios_acm_id[20]; + u32 edx_senter_flags; + u64 mseg_valid; + u8 sinit_hash[20]; + u8 mle_hash[20]; + u8 stm_hash[20]; + u8 lcp_policy_hash[20]; + u32 lcp_policy_control; + /* Versions >= 7 */ + u32 rlp_wakeup_addr; + u32 reserved; + u32 num_of_sinit_mdrs; + u32 sinit_mdrs_table_offset; + u32 sinit_vtd_dmar_table_size; + u32 sinit_vtd_dmar_table_offset; + /* Versions >= 8 */ + u32 processor_scrtm_status; + /* Versions >= 9 */ + /* Ext Data Elements */ +} __packed; + +/* + * TXT data reporting structure for memory types + */ +struct txt_sinit_memory_descriptor_record { + u64 address; + u64 length; + u8 type; + u8 reserved[7]; +} __packed; + +/* + * TXT data structure used by a responsive local processor (RLP) to start + * execution in response to a GETSEC[WAKEUP]. + */ +struct smx_rlp_mle_join { + u32 rlp_gdt_limit; + u32 rlp_gdt_base; + u32 rlp_seg_sel; /* cs (ds, es, ss are seg_sel+8) */ + u32 rlp_entry_point; /* phys addr */ +} __packed; + +/* + * TPM event log structures defined in both the TXT specification and + * the TCG documentation. + */ +#define TPM12_EVTLOG_SIGNATURE "TXT Event Container" + +struct tpm12_event_log_header { + char signature[20]; + char reserved[12]; + u8 container_ver_major; + u8 container_ver_minor; + u8 pcr_event_ver_major; + u8 pcr_event_ver_minor; + u32 container_size; + u32 pcr_events_offset; + u32 next_event_offset; + /* PCREvents[] */ +} __packed; + +struct tpm12_pcr_event { + u32 pcr_index; + u32 type; + u8 digest[20]; + u32 size; + /* Data[] */ +} __packed; + +#define TPM20_EVTLOG_SIGNATURE "Spec ID Event03" + +struct tpm20_ha { + u16 algorithm_id; + /* digest[AlgorithmID_DIGEST_SIZE] */ +} __packed; + +struct tpm20_digest_values { + u32 count; + /* TPMT_HA digests[count] */ +} __packed; + +struct tpm20_pcr_event_head { + u32 pcr_index; + u32 event_type; +} __packed; + +/* Variable size array of hashes in the tpm20_digest_values structure */ + +struct tpm20_pcr_event_tail { + u32 event_size; + /* Event[EventSize]; */ +} __packed; + +/* + * Functions to extract data from the Intel TXT Heap Memory. The layout + * of the heap is as follows: + * +----------------------------+ + * | Size Bios Data table (u64) | + * +----------------------------+ + * | Bios Data table | + * +----------------------------+ + * | Size OS MLE table (u64) | + * +----------------------------+ + * | OS MLE table | + * +--------------------------- + + * | Size OS SINIT table (u64) | + * +----------------------------+ + * | OS SINIT table | + * +----------------------------+ + * | Size SINIT MLE table (u64) | + * +----------------------------+ + * | SINIT MLE table | + * +----------------------------+ + * + * NOTE: the table size fields include the 8 byte size field itself. + */ +static inline u64 txt_bios_data_size(void *heap) +{ + return *((u64 *)heap); +} + +static inline void *txt_bios_data_start(void *heap) +{ + return heap + sizeof(u64); +} + +static inline u64 txt_os_mle_data_size(void *heap) +{ + return *((u64 *)(heap + txt_bios_data_size(heap))); +} + +static inline void *txt_os_mle_data_start(void *heap) +{ + return heap + txt_bios_data_size(heap) + sizeof(u64); +} + +static inline u64 txt_os_sinit_data_size(void *heap) +{ + return *((u64 *)(heap + txt_bios_data_size(heap) + + txt_os_mle_data_size(heap))); +} + +static inline void *txt_os_sinit_data_start(void *heap) +{ + return heap + txt_bios_data_size(heap) + + txt_os_mle_data_size(heap) + sizeof(u64); +} + +static inline u64 txt_sinit_mle_data_size(void *heap) +{ + return *((u64 *)(heap + txt_bios_data_size(heap) + + txt_os_mle_data_size(heap) + + txt_os_sinit_data_size(heap))); +} + +static inline void *txt_sinit_mle_data_start(void *heap) +{ + return heap + txt_bios_data_size(heap) + + txt_os_mle_data_size(heap) + + txt_sinit_mle_data_size(heap) + sizeof(u64); +} + +/* + * TPM event logging functions. + */ +static inline struct txt_heap_event_log_pointer2_1_element* +tpm20_find_log2_1_element(struct txt_os_sinit_data *os_sinit_data) +{ + struct txt_heap_ext_data_element *ext_elem; + + /* The extended element array as at the end of this table */ + ext_elem = (struct txt_heap_ext_data_element *) + ((u8 *)os_sinit_data + sizeof(struct txt_os_sinit_data)); + + while (ext_elem->type != TXT_HEAP_EXTDATA_TYPE_END) { + if (ext_elem->type == + TXT_HEAP_EXTDATA_TYPE_EVENT_LOG_POINTER2_1) { + return (struct txt_heap_event_log_pointer2_1_element *) + ((u8 *)ext_elem + + sizeof(struct txt_heap_ext_data_element)); + } + ext_elem = + (struct txt_heap_ext_data_element *) + ((u8 *)ext_elem + ext_elem->size); + } + + return NULL; +} + +static inline int tpm12_log_event(void *evtlog_base, + u32 event_size, void *event) +{ + struct tpm12_event_log_header *evtlog = + (struct tpm12_event_log_header *)evtlog_base; + + if (memcmp(evtlog->signature, TPM12_EVTLOG_SIGNATURE, + sizeof(TPM12_EVTLOG_SIGNATURE))) + return -EINVAL; + + if (evtlog->next_event_offset + event_size > evtlog->container_size) + return -E2BIG; + + memcpy(evtlog_base + evtlog->next_event_offset, event, event_size); + evtlog->next_event_offset += event_size; + + return 0; +} + +static inline int tpm20_log_event(struct txt_heap_event_log_pointer2_1_element *elem, + void *evtlog_base, + u32 event_size, void *event) +{ + struct tpm12_pcr_event *header = + (struct tpm12_pcr_event *)evtlog_base; + + /* Has to be at least big enough for the signature */ + if (header->size < sizeof(TPM20_EVTLOG_SIGNATURE)) + return -EINVAL; + + if (memcmp((u8 *)header + sizeof(struct tpm12_pcr_event), + TPM20_EVTLOG_SIGNATURE, sizeof(TPM20_EVTLOG_SIGNATURE))) + return -EINVAL; + + if (elem->next_record_offset + event_size > + elem->allocated_event_container_size) + return -E2BIG; + + memcpy(evtlog_base + elem->next_record_offset, event, event_size); + elem->next_record_offset += event_size; + + return 0; +} + +/* + * External functions + */ +extern void slaunch_setup(void); +extern u32 slaunch_get_flags(void); +extern struct sl_ap_wake_info *slaunch_get_ap_wake_info(void); +extern struct acpi_table_header *slaunch_get_dmar_table(struct acpi_table_header *dmar); +extern void slaunch_finalize(int do_sexit); + +#endif /* !__ASSEMBLY */ + +#else + +#define slaunch_setup() do { } while (0) +#define slaunch_get_flags() 0 +#define slaunch_get_dmar_table(d) (d) +#define slaunch_finalize(d) do { } while (0) + +#endif /* !CONFIG_SECURE_LAUNCH */ + +#endif /* _LINUX_SLAUNCH_H */ From patchwork Thu Sep 24 14:58:31 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ross Philipson X-Patchwork-Id: 11797641 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C7FB2139A for ; Thu, 24 Sep 2020 14:59:08 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A35D0238A1 for ; Thu, 24 Sep 2020 14:59:08 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=oracle.com header.i=@oracle.com header.b="kX6ueIyp" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728379AbgIXO6w (ORCPT ); Thu, 24 Sep 2020 10:58:52 -0400 Received: from aserp2120.oracle.com ([141.146.126.78]:55946 "EHLO aserp2120.oracle.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728417AbgIXO6m (ORCPT ); Thu, 24 Sep 2020 10:58:42 -0400 Received: from pps.filterd (aserp2120.oracle.com [127.0.0.1]) by aserp2120.oracle.com (8.16.0.42/8.16.0.42) with SMTP id 08OEtGnj037479; Thu, 24 Sep 2020 14:58:12 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=from : to : cc : subject : date : message-id : in-reply-to : references; s=corp-2020-01-29; bh=VJyk/H2s9dDWeqPz/Xhx7qOnjD9xCnM1/44obMCXtFQ=; b=kX6ueIyp4SVt52upchUJrxzu7FHQ0xT74oC3QL5lhVkRTFND6nN7NKypsp5fUsJDf9pk 958nmSRZVe9Uzex2aTzmQ57Zr83VBw8HEm0VZ7OSGJ2kRX4VuK1WxonM0IXjzUWoeBzi +uUwjKyxRVOC5rZnIgopDVYDLrOXjsyBYHDvF9PvwKIf+HO+wyf4srOQXCvON7UvG3iM EW5CVXAIx95W1opZCIZf9m0KhrjCqt8DPym2k6161BPygIbW8yKCdeGqbmL+F8nc+/Gz nDemT3/HIfxX4drL+lE+M0QtjKTHBDGBCuUIBDc9lcwiA7rrh/hMCFv4ev6p48dqQK0i xg== Received: from aserp3030.oracle.com (aserp3030.oracle.com [141.146.126.71]) by aserp2120.oracle.com with ESMTP id 33q5rgq57x-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Thu, 24 Sep 2020 14:58:12 +0000 Received: from pps.filterd (aserp3030.oracle.com [127.0.0.1]) by aserp3030.oracle.com (8.16.0.42/8.16.0.42) with SMTP id 08OEuTGG126226; Thu, 24 Sep 2020 14:58:12 GMT Received: from aserv0122.oracle.com (aserv0122.oracle.com [141.146.126.236]) by aserp3030.oracle.com with ESMTP id 33nujr18a6-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 24 Sep 2020 14:58:12 +0000 Received: from abhmp0014.oracle.com (abhmp0014.oracle.com [141.146.116.20]) by aserv0122.oracle.com (8.14.4/8.14.4) with ESMTP id 08OEwAkv002765; Thu, 24 Sep 2020 14:58:10 GMT Received: from disposition.us.oracle.com (/10.152.32.81) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Thu, 24 Sep 2020 07:58:10 -0700 From: Ross Philipson To: linux-kernel@vger.kernel.org, x86@kernel.org, iommu@lists.linux-foundation.org, linux-integrity@vger.kernel.org, linux-doc@vger.kernel.org Cc: ross.philipson@oracle.com, dpsmith@apertussolutions.com, tglx@linutronix.de, mingo@redhat.com, bp@alien8.de, hpa@zytor.com, luto@amacapital.net, trenchboot-devel@googlegroups.com Subject: [PATCH 03/13] x86: Add early SHA support for Secure Launch early measurements Date: Thu, 24 Sep 2020 10:58:31 -0400 Message-Id: <1600959521-24158-4-git-send-email-ross.philipson@oracle.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1600959521-24158-1-git-send-email-ross.philipson@oracle.com> References: <1600959521-24158-1-git-send-email-ross.philipson@oracle.com> X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9753 signatures=668680 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 bulkscore=0 malwarescore=0 mlxlogscore=999 phishscore=0 adultscore=0 spamscore=0 suspectscore=2 mlxscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2006250000 definitions=main-2009240114 X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9753 signatures=668680 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 spamscore=0 impostorscore=0 clxscore=1011 suspectscore=2 phishscore=0 malwarescore=0 priorityscore=1501 mlxlogscore=999 adultscore=0 bulkscore=0 mlxscore=0 lowpriorityscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2006250000 definitions=main-2009240114 Precedence: bulk List-ID: X-Mailing-List: linux-integrity@vger.kernel.org The SHA algorithms are necessary to measure configuration information into the TPM as early as possible before using the values. This implementation uses the established approach of #including the SHA libraries directly in the code since the compressed kernel is not uncompressed at this point. The SHA code here has its origins in the code from the main kernel. That code could not be pulled directly into the setup portion of the compressed kernel because of other dependencies it pulls in. The result is this is a modified copy of that code that still leverages the core SHA algorithms. Signed-off-by: Daniel P. Smith Signed-off-by: Ross Philipson --- arch/x86/boot/compressed/Makefile | 4 + arch/x86/boot/compressed/early_sha1.c | 104 ++++++++++++++++ arch/x86/boot/compressed/early_sha1.h | 17 +++ arch/x86/boot/compressed/early_sha256.c | 6 + arch/x86/boot/compressed/early_sha512.c | 6 + include/linux/sha512.h | 21 ++++ lib/sha1.c | 4 + lib/sha512.c | 209 ++++++++++++++++++++++++++++++++ 8 files changed, 371 insertions(+) create mode 100644 arch/x86/boot/compressed/early_sha1.c create mode 100644 arch/x86/boot/compressed/early_sha1.h create mode 100644 arch/x86/boot/compressed/early_sha256.c create mode 100644 arch/x86/boot/compressed/early_sha512.c create mode 100644 include/linux/sha512.h create mode 100644 lib/sha512.c diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index ff7894f..0fd84b9 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile @@ -96,6 +96,10 @@ vmlinux-objs-$(CONFIG_ACPI) += $(obj)/acpi.o vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_thunk_$(BITS).o efi-obj-$(CONFIG_EFI_STUB) = $(objtree)/drivers/firmware/efi/libstub/lib.a +vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o +vmlinux-objs-$(CONFIG_SECURE_LAUNCH_SHA256) += $(obj)/early_sha256.o +vmlinux-objs-$(CONFIG_SECURE_LAUNCH_SHA512) += $(obj)/early_sha512.o + # The compressed kernel is built with -fPIC/-fPIE so that a boot loader # can place it anywhere in memory and it will still run. However, since # it is executed as-is without any ELF relocation processing performed diff --git a/arch/x86/boot/compressed/early_sha1.c b/arch/x86/boot/compressed/early_sha1.c new file mode 100644 index 0000000..198c46d --- /dev/null +++ b/arch/x86/boot/compressed/early_sha1.c @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020, Oracle and/or its affiliates. + * Copyright (c) 2020 Apertus Solutions, LLC. + */ + +#include +#include +#include +#include +#include + +#include "early_sha1.h" + +#define SHA1_DISABLE_EXPORT +#include "../../../../lib/sha1.c" + +/* The SHA1 implementation in lib/sha1.c was written to get the workspace + * buffer as a parameter. This wrapper function provides a container + * around a temporary workspace that is cleared after the transform completes. + */ +static void __sha_transform(u32 *digest, const char *data) +{ + u32 ws[SHA1_WORKSPACE_WORDS]; + + sha1_transform(digest, data, ws); + + memset(ws, 0, sizeof(ws)); + /* + * As this is cryptographic code, prevent the memset 0 from being + * optimized out potentially leaving secrets in memory. + */ + wmb(); + +} + +void early_sha1_init(struct sha1_state *sctx) +{ + sha1_init(sctx->state); + sctx->count = 0; +} + +void early_sha1_update(struct sha1_state *sctx, + const u8 *data, + unsigned int len) +{ + unsigned int partial = sctx->count % SHA1_BLOCK_SIZE; + + sctx->count += len; + + if (likely((partial + len) >= SHA1_BLOCK_SIZE)) { + int blocks; + + if (partial) { + int p = SHA1_BLOCK_SIZE - partial; + + memcpy(sctx->buffer + partial, data, p); + data += p; + len -= p; + + __sha_transform(sctx->state, sctx->buffer); + } + + blocks = len / SHA1_BLOCK_SIZE; + len %= SHA1_BLOCK_SIZE; + + if (blocks) { + while (blocks--) { + __sha_transform(sctx->state, data); + data += SHA1_BLOCK_SIZE; + } + } + partial = 0; + } + + if (len) + memcpy(sctx->buffer + partial, data, len); +} + +void early_sha1_final(struct sha1_state *sctx, u8 *out) +{ + const int bit_offset = SHA1_BLOCK_SIZE - sizeof(__be64); + __be64 *bits = (__be64 *)(sctx->buffer + bit_offset); + __be32 *digest = (__be32 *)out; + unsigned int partial = sctx->count % SHA1_BLOCK_SIZE; + int i; + + sctx->buffer[partial++] = 0x80; + if (partial > bit_offset) { + memset(sctx->buffer + partial, 0x0, SHA1_BLOCK_SIZE - partial); + partial = 0; + + __sha_transform(sctx->state, sctx->buffer); + } + + memset(sctx->buffer + partial, 0x0, bit_offset - partial); + *bits = cpu_to_be64(sctx->count << 3); + __sha_transform(sctx->state, sctx->buffer); + + for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(__be32); i++) + put_unaligned_be32(sctx->state[i], digest++); + + *sctx = (struct sha1_state){}; +} diff --git a/arch/x86/boot/compressed/early_sha1.h b/arch/x86/boot/compressed/early_sha1.h new file mode 100644 index 0000000..8e19f13 --- /dev/null +++ b/arch/x86/boot/compressed/early_sha1.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. + */ + +#ifndef BOOT_COMPRESSED_EARLY_SHA1_H +#define BOOT_COMPRESSED_EARLY_SHA1_H + +#include + +void early_sha1_init(struct sha1_state *sctx); +void early_sha1_update(struct sha1_state *sctx, + const u8 *data, + unsigned int len); +void early_sha1_final(struct sha1_state *sctx, u8 *out); + +#endif /* BOOT_COMPRESSED_EARLY_SHA1_H */ diff --git a/arch/x86/boot/compressed/early_sha256.c b/arch/x86/boot/compressed/early_sha256.c new file mode 100644 index 0000000..20cdc43 --- /dev/null +++ b/arch/x86/boot/compressed/early_sha256.c @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 Apertus Solutions, LLC + */ + +#include "../../../../lib/crypto/sha256.c" diff --git a/arch/x86/boot/compressed/early_sha512.c b/arch/x86/boot/compressed/early_sha512.c new file mode 100644 index 0000000..d352c55 --- /dev/null +++ b/arch/x86/boot/compressed/early_sha512.c @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 Apertus Solutions, LLC + */ + +#include "../../../../lib/sha512.c" diff --git a/include/linux/sha512.h b/include/linux/sha512.h new file mode 100644 index 0000000..d562237 --- /dev/null +++ b/include/linux/sha512.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2020 Apertus Solutions, LLC + * + * Author: Daniel P. Smith + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#ifndef SHA512_H +#define SHA512_H + +#include +#include + +extern int sha512_init(struct sha512_state *sctx); +extern int sha512_update(struct sha512_state *sctx, const u8 *input, + unsigned int length); +extern int sha512_final(struct sha512_state *sctx, u8 *hash); + +#endif /* SHA512_H */ diff --git a/lib/sha1.c b/lib/sha1.c index 49257a9..f4efe6f 100644 --- a/lib/sha1.c +++ b/lib/sha1.c @@ -187,7 +187,9 @@ void sha1_transform(__u32 *digest, const char *data, __u32 *array) digest[3] += D; digest[4] += E; } +#ifndef SHA1_DISABLE_EXPORT EXPORT_SYMBOL(sha1_transform); +#endif /** * sha1_init - initialize the vectors for a SHA1 digest @@ -201,4 +203,6 @@ void sha1_init(__u32 *buf) buf[3] = 0x10325476; buf[4] = 0xc3d2e1f0; } +#ifndef SHA1_DISABLE_EXPORT EXPORT_SYMBOL(sha1_init); +#endif diff --git a/lib/sha512.c b/lib/sha512.c new file mode 100644 index 0000000..7f91d83 --- /dev/null +++ b/lib/sha512.c @@ -0,0 +1,209 @@ +/* SHA-512 code by Jean-Luc Cooke + * + * Copyright (c) Jean-Luc Cooke + * Copyright (c) Andrew McDonald + * Copyright (c) 2003 Kyle McMartin + * Copyright (C) 2015 Linaro Ltd + * Copyright (C) 2020 Apertus Solutions, LLC + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + */ +#include +#include +#include +#include + +#include + +static inline u64 Ch(u64 x, u64 y, u64 z) +{ + return z ^ (x & (y ^ z)); +} + +static inline u64 Maj(u64 x, u64 y, u64 z) +{ + return (x & y) | (z & (x | y)); +} + +static const u64 sha512_K[80] = { + 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, + 0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, + 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL, + 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, + 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, + 0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, + 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL, + 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, + 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, + 0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, + 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL, + 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, + 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, + 0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, + 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL, + 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, + 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, + 0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, + 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL, + 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, + 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, + 0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, + 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL, + 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, + 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, + 0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, + 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL, +}; + +#define e0(x) (ror64(x,28) ^ ror64(x,34) ^ ror64(x,39)) +#define e1(x) (ror64(x,14) ^ ror64(x,18) ^ ror64(x,41)) +#define s0(x) (ror64(x, 1) ^ ror64(x, 8) ^ (x >> 7)) +#define s1(x) (ror64(x,19) ^ ror64(x,61) ^ (x >> 6)) + +static inline void LOAD_OP(int I, u64 *W, const u8 *input) +{ + W[I] = get_unaligned_be64((__u64 *)input + I); +} + +static inline void BLEND_OP(int I, u64 *W) +{ + W[I & 15] += s1(W[(I-2) & 15]) + W[(I-7) & 15] + s0(W[(I-15) & 15]); +} + +static void sha512_transform(u64 *state, const u8 *input) +{ + u64 a, b, c, d, e, f, g, h, t1, t2; + + int i; + u64 W[16]; + + /* load the state into our registers */ + a=state[0]; b=state[1]; c=state[2]; d=state[3]; + e=state[4]; f=state[5]; g=state[6]; h=state[7]; + + /* now iterate */ + for (i=0; i<80; i+=8) { + if (!(i & 8)) { + int j; + + if (i < 16) { + /* load the input */ + for (j = 0; j < 16; j++) + LOAD_OP(i + j, W, input); + } else { + for (j = 0; j < 16; j++) { + BLEND_OP(i + j, W); + } + } + } + + t1 = h + e1(e) + Ch(e,f,g) + sha512_K[i ] + W[(i & 15)]; + t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; + t1 = g + e1(d) + Ch(d,e,f) + sha512_K[i+1] + W[(i & 15) + 1]; + t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; + t1 = f + e1(c) + Ch(c,d,e) + sha512_K[i+2] + W[(i & 15) + 2]; + t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; + t1 = e + e1(b) + Ch(b,c,d) + sha512_K[i+3] + W[(i & 15) + 3]; + t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; + t1 = d + e1(a) + Ch(a,b,c) + sha512_K[i+4] + W[(i & 15) + 4]; + t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; + t1 = c + e1(h) + Ch(h,a,b) + sha512_K[i+5] + W[(i & 15) + 5]; + t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; + t1 = b + e1(g) + Ch(g,h,a) + sha512_K[i+6] + W[(i & 15) + 6]; + t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; + t1 = a + e1(f) + Ch(f,g,h) + sha512_K[i+7] + W[(i & 15) + 7]; + t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; + } + + state[0] += a; state[1] += b; state[2] += c; state[3] += d; + state[4] += e; state[5] += f; state[6] += g; state[7] += h; + + /* erase our data */ + a = b = c = d = e = f = g = h = t1 = t2 = 0; +} + +int sha512_init(struct sha512_state *sctx) +{ + sctx->state[0] = SHA512_H0; + sctx->state[1] = SHA512_H1; + sctx->state[2] = SHA512_H2; + sctx->state[3] = SHA512_H3; + sctx->state[4] = SHA512_H4; + sctx->state[5] = SHA512_H5; + sctx->state[6] = SHA512_H6; + sctx->state[7] = SHA512_H7; + sctx->count[0] = sctx->count[1] = 0; + + return 0; +} + +int sha512_update(struct sha512_state *sctx, const u8 *data, unsigned int len) +{ + unsigned int partial = sctx->count[0] % SHA512_BLOCK_SIZE; + + sctx->count[0] += len; + if (sctx->count[0] < len) + sctx->count[1]++; + + if (likely((partial + len) >= SHA512_BLOCK_SIZE)) { + int blocks; + + if (partial) { + int p = SHA512_BLOCK_SIZE - partial; + + memcpy(sctx->buf + partial, data, p); + data += p; + len -= p; + + sha512_transform(sctx->state, sctx->buf); + } + + blocks = len / SHA512_BLOCK_SIZE; + len %= SHA512_BLOCK_SIZE; + + if (blocks) { + while (blocks--) { + sha512_transform(sctx->state, data); + data += SHA512_BLOCK_SIZE; + } + } + partial = 0; + } + if (len) + memcpy(sctx->buf + partial, data, len); + + return 0; +} + +int sha512_final(struct sha512_state *sctx, u8 *out) +{ + const int bit_offset = SHA512_BLOCK_SIZE - sizeof(__be64[2]); + __be64 *bits = (__be64 *)(sctx->buf + bit_offset); + __be64 *digest = (__be64 *)out; + unsigned int partial = sctx->count[0] % SHA512_BLOCK_SIZE; + unsigned int digest_size = SHA512_DIGEST_SIZE; + int i; + + sctx->buf[partial++] = 0x80; + if (partial > bit_offset) { + memset(sctx->buf + partial, 0x0, SHA512_BLOCK_SIZE - partial); + partial = 0; + + sha512_transform(sctx->state, sctx->buf); + } + + memset(sctx->buf + partial, 0x0, bit_offset - partial); + bits[0] = cpu_to_be64(sctx->count[1] << 3 | sctx->count[0] >> 61); + bits[1] = cpu_to_be64(sctx->count[0] << 3); + sha512_transform(sctx->state, sctx->buf); + + for (i = 0; digest_size > 0; i++, digest_size -= sizeof(__be64)) + put_unaligned_be64(sctx->state[i], digest++); + + *sctx = (struct sha512_state){}; + return 0; +} From patchwork Thu Sep 24 14:58:32 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Ross Philipson X-Patchwork-Id: 11797639 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 752C86CA for ; Thu, 24 Sep 2020 14:59:08 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 4127A23787 for ; Thu, 24 Sep 2020 14:59:08 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=oracle.com header.i=@oracle.com header.b="Xm/zkyJd" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728430AbgIXO6x (ORCPT ); Thu, 24 Sep 2020 10:58:53 -0400 Received: from aserp2130.oracle.com ([141.146.126.79]:57268 "EHLO aserp2130.oracle.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728407AbgIXO6o (ORCPT ); Thu, 24 Sep 2020 10:58:44 -0400 Received: from pps.filterd (aserp2130.oracle.com [127.0.0.1]) by aserp2130.oracle.com (8.16.0.42/8.16.0.42) with SMTP id 08OErXCk101477; Thu, 24 Sep 2020 14:58:14 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type : content-transfer-encoding; s=corp-2020-01-29; bh=SW4zrkSQwoEdLRCEgQ4sbnKb+1sGwz7LtQQgdwwQPMY=; b=Xm/zkyJdaioXa/mvDiV1Orqy22dUH3TrUqTa0QYLhfwAAh0LFhvUq4wNFp3dQsYErI86 4dXmxbAvRFdmPXROnZBrFInPDYmgwUEUB3wzOXqXOKeze4FlNRiqGIAFnWNbSkBnLJJ8 /wWMg3b6Y2n867N2XzDk7v/2uDDqeK3CRBsPqx6qvkoPK9mhlAI6/renhI2txN3yCwxP exNejxsbPEoFAvBf85fgbOTwocm1TrNc3Weqz0YHl1NM7EwnMqmBj4M7pwCpBW2hY33J XlaaJRyTmBiNaWBCFQGUOmycY4xerYc0UQh/tmWwYu+MHJGy+8G93k7dXyjBoG47kAav yA== Received: from userp3020.oracle.com (userp3020.oracle.com [156.151.31.79]) by aserp2130.oracle.com with ESMTP id 33qcpu5qc4-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Thu, 24 Sep 2020 14:58:13 +0000 Received: from pps.filterd (userp3020.oracle.com [127.0.0.1]) by userp3020.oracle.com (8.16.0.42/8.16.0.42) with SMTP id 08OEuUQB096519; Thu, 24 Sep 2020 14:58:13 GMT Received: from aserv0122.oracle.com (aserv0122.oracle.com [141.146.126.236]) by userp3020.oracle.com with ESMTP id 33nurw9x1u-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 24 Sep 2020 14:58:12 +0000 Received: from abhmp0014.oracle.com (abhmp0014.oracle.com [141.146.116.20]) by aserv0122.oracle.com (8.14.4/8.14.4) with ESMTP id 08OEwB9k002771; Thu, 24 Sep 2020 14:58:11 GMT Received: from disposition.us.oracle.com (/10.152.32.81) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Thu, 24 Sep 2020 07:58:11 -0700 From: Ross Philipson To: linux-kernel@vger.kernel.org, x86@kernel.org, iommu@lists.linux-foundation.org, linux-integrity@vger.kernel.org, linux-doc@vger.kernel.org Cc: ross.philipson@oracle.com, dpsmith@apertussolutions.com, tglx@linutronix.de, mingo@redhat.com, bp@alien8.de, hpa@zytor.com, luto@amacapital.net, trenchboot-devel@googlegroups.com Subject: [PATCH 04/13] x86: Add early TPM TIS/CRB interface support for Secure Launch Date: Thu, 24 Sep 2020 10:58:32 -0400 Message-Id: <1600959521-24158-5-git-send-email-ross.philipson@oracle.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1600959521-24158-1-git-send-email-ross.philipson@oracle.com> References: <1600959521-24158-1-git-send-email-ross.philipson@oracle.com> MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9753 signatures=668680 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 adultscore=0 malwarescore=0 phishscore=0 mlxlogscore=999 bulkscore=0 mlxscore=0 suspectscore=2 spamscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2006250000 definitions=main-2009240114 X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9753 signatures=668680 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 suspectscore=2 mlxlogscore=999 adultscore=0 bulkscore=0 mlxscore=0 lowpriorityscore=0 priorityscore=1501 phishscore=0 spamscore=0 malwarescore=0 clxscore=1015 impostorscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2006250000 definitions=main-2009240114 Precedence: bulk List-ID: X-Mailing-List: linux-integrity@vger.kernel.org From: "Daniel P. Smith" The Secure Launch capability that is part of the compressed kernel requires the ability to send measurements it takes to the TPM. This commit introduces the necessary code to communicate with the hardware interface of TPM devices. Signed-off-by: Daniel P. Smith Signed-off-by: Ross Philipson --- arch/x86/boot/compressed/Makefile | 2 + arch/x86/boot/compressed/tpm/crb.c | 304 ++++++++++++++++++++++++++++++ arch/x86/boot/compressed/tpm/crb.h | 20 ++ arch/x86/boot/compressed/tpm/tis.c | 215 +++++++++++++++++++++ arch/x86/boot/compressed/tpm/tis.h | 46 +++++ arch/x86/boot/compressed/tpm/tpm.h | 48 +++++ arch/x86/boot/compressed/tpm/tpm_buff.c | 121 ++++++++++++ arch/x86/boot/compressed/tpm/tpm_common.h | 127 +++++++++++++ arch/x86/boot/compressed/tpm/tpmbuff.h | 34 ++++ arch/x86/boot/compressed/tpm/tpmio.c | 51 +++++ 10 files changed, 968 insertions(+) create mode 100644 arch/x86/boot/compressed/tpm/crb.c create mode 100644 arch/x86/boot/compressed/tpm/crb.h create mode 100644 arch/x86/boot/compressed/tpm/tis.c create mode 100644 arch/x86/boot/compressed/tpm/tis.h create mode 100644 arch/x86/boot/compressed/tpm/tpm.h create mode 100644 arch/x86/boot/compressed/tpm/tpm_buff.c create mode 100644 arch/x86/boot/compressed/tpm/tpm_common.h create mode 100644 arch/x86/boot/compressed/tpm/tpmbuff.h create mode 100644 arch/x86/boot/compressed/tpm/tpmio.c diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index 0fd84b9..5515afa 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile @@ -99,6 +99,8 @@ efi-obj-$(CONFIG_EFI_STUB) = $(objtree)/drivers/firmware/efi/libstub/lib.a vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o vmlinux-objs-$(CONFIG_SECURE_LAUNCH_SHA256) += $(obj)/early_sha256.o vmlinux-objs-$(CONFIG_SECURE_LAUNCH_SHA512) += $(obj)/early_sha512.o +vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/tpm/tpmio.o $(obj)/tpm/tpm_buff.o \ + $(obj)/tpm/tis.o $(obj)/tpm/crb.o # The compressed kernel is built with -fPIC/-fPIE so that a boot loader # can place it anywhere in memory and it will still run. However, since diff --git a/arch/x86/boot/compressed/tpm/crb.c b/arch/x86/boot/compressed/tpm/crb.c new file mode 100644 index 0000000..05c4038 --- /dev/null +++ b/arch/x86/boot/compressed/tpm/crb.c @@ -0,0 +1,304 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 Apertus Solutions, LLC + * + * Author(s): + * Daniel P. Smith + */ + +#include +#include "tpm.h" +#include "tpmbuff.h" +#include "crb.h" +#include "tpm_common.h" + +#define TPM_LOC_STATE 0x0000 +#define TPM_LOC_CTRL 0x0008 +#define TPM_LOC_STS 0x000C +#define TPM_CRB_INTF_ID 0x0030 +#define TPM_CRB_CTRL_EXT 0x0038 +#define TPM_CRB_CTRL_REQ 0x0040 +#define TPM_CRB_CTRL_STS 0x0044 +#define TPM_CRB_CTRL_CANCEL 0x0048 +#define TPM_CRB_CTRL_START 0x004C +#define TPM_CRB_INT_ENABLE 0x0050 +#define TPM_CRB_INT_STS 0x0054 +#define TPM_CRB_CTRL_CMD_SIZE 0x0058 +#define TPM_CRB_CTRL_CMD_LADDR 0x005C +#define TPM_CRB_CTRL_CMD_HADDR 0x0060 +#define TPM_CRB_CTRL_RSP_SIZE 0x0064 +#define TPM_CRB_CTRL_RSP_ADDR 0x0068 +#define TPM_CRB_DATA_BUFFER 0x0080 + +#define REGISTER(l, r) (((l) << 12) | (r)) + +static u8 locality = TPM_NO_LOCALITY; + +struct tpm_loc_state { + union { + u8 val; + struct { + u8 tpm_established:1; + u8 loc_assigned:1; + u8 active_locality:3; + u8 _reserved:2; + u8 tpm_reg_valid_sts:1; + }; + }; +} __packed; + +struct tpm_loc_ctrl { + union { + u32 val; + struct { + u32 request_access:1; + u32 relinquish:1; + u32 seize:1; + u32 reset_establishment_bit:1; + u32 _reserved:28; + }; + }; +} __packed; + +struct tpm_loc_sts { + union { + u32 val; + struct { + u32 granted:1; + u32 beenSeized:1; + u32 _reserved:30; + }; + }; +} __packed; + +struct tpm_crb_ctrl_req { + union { + u32 val; + struct { + u32 cmd_ready:1; + u32 go_idle:1; + u32 _reserved:30; + }; + }; +} __packed; + +struct tpm_crb_ctrl_sts { + union { + u32 val; + struct { + u32 tpm_sts:1; + u32 tpm_idle:1; + u32 _reserved:30; + }; + }; +} __packed; + +struct tpm_crb_intf_id_ext { + union { + u32 val; + struct { + u32 vid:16; + u32 did:16; + }; + }; +} __packed; + +/* + * Durations derived from Table 15 of the PTP but is purely an artifact of this + * implementation + */ + +/* TPM Duration A: 20ms */ +static void duration_a(void) +{ + tpm_mdelay(20); +} + +/* TPM Duration B: 750ms */ +static void __maybe_unused duration_b(void) +{ + tpm_mdelay(750); +} + +/* TPM Duration C: 1000ms */ +static void __maybe_unused duration_c(void) +{ + tpm_mdelay(1000); +} + +static u8 is_idle(void) +{ + struct tpm_crb_ctrl_sts ctl_sts; + + ctl_sts.val = tpm_read32(REGISTER(locality, TPM_CRB_CTRL_STS)); + if (ctl_sts.tpm_idle == 1) + return 1; + + return 0; +} + +static u8 __maybe_unused is_ready(void) +{ + struct tpm_crb_ctrl_sts ctl_sts; + + ctl_sts.val = tpm_read32(REGISTER(locality, TPM_CRB_CTRL_STS)); + return ctl_sts.val == 0; +} + +static u8 is_cmd_exec(void) +{ + u32 ctrl_start; + + ctrl_start = tpm_read32(REGISTER(locality, TPM_CRB_CTRL_START)); + if (ctrl_start == 1) + return 1; + + return 0; +} + +static s8 cmd_ready(void) +{ + struct tpm_crb_ctrl_req ctl_req; + + if (is_idle()) { + ctl_req.cmd_ready = 1; + tpm_write32(ctl_req.val, REGISTER(locality, TPM_CRB_CTRL_REQ)); + tpm2_timeout_c(); + + if (is_idle()) + return -1; + } + + return 0; +} + +static void go_idle(void) +{ + struct tpm_crb_ctrl_req ctl_req; + + if (is_idle()) + return; + + ctl_req.go_idle = 1; + tpm_write32(ctl_req.val, REGISTER(locality, TPM_CRB_CTRL_REQ)); + + /* pause to give tpm time to complete the request */ + tpm2_timeout_c(); +} + +static void crb_relinquish_locality_internal(u16 l) +{ + struct tpm_loc_ctrl loc_ctrl; + + loc_ctrl.relinquish = 1; + + tpm_write32(loc_ctrl.val, REGISTER(l, TPM_LOC_CTRL)); +} + +u8 crb_request_locality(u8 l) +{ + struct tpm_loc_state loc_state; + struct tpm_loc_ctrl loc_ctrl; + struct tpm_loc_sts loc_sts; + + /* TPM_LOC_STATE is aliased across all localities */ + loc_state.val = tpm_read8(REGISTER(0, TPM_LOC_STATE)); + + if (loc_state.loc_assigned == 1) { + if (loc_state.active_locality == l) { + locality = l; + return locality; + } + + crb_relinquish_locality_internal(loc_state.loc_assigned); + } + + loc_ctrl.request_access = 1; + tpm_write32(loc_ctrl.val, REGISTER(l, TPM_LOC_CTRL)); + + loc_sts.val = tpm_read32(REGISTER(l, TPM_LOC_STS)); + if (loc_sts.granted != 1) { + locality = TPM_NO_LOCALITY; + return locality; + } + + locality = l; + return locality; +} + +void crb_relinquish_locality(void) +{ + crb_relinquish_locality_internal(locality); +} + +/* assumes cancel will succeed */ +static void cancel_send(void) +{ + if (is_cmd_exec()) { + tpm_write32(1, REGISTER(locality, TPM_CRB_CTRL_CANCEL)); + timeout_b(); + + tpm_write32(0, REGISTER(locality, TPM_CRB_CTRL_CANCEL)); + } +} + +size_t crb_send(struct tpmbuff *buf) +{ + u32 ctrl_start = 1; + + if (is_idle()) + return 0; + + tpm_write32(ctrl_start, REGISTER(locality, TPM_CRB_CTRL_START)); + + /* + * Most command sequences this code is interested with operates with + * 20/750 duration/timeout schedule + */ + duration_a(); + ctrl_start = tpm_read32(REGISTER(locality, TPM_CRB_CTRL_START)); + if (ctrl_start != 0) { + timeout_a(); + ctrl_start = tpm_read32(REGISTER(locality, TPM_CRB_CTRL_START)); + if (ctrl_start != 0) { + cancel_send(); + /* minimum response is header with cancel ord */ + return sizeof(struct tpm_header); + } + } + + return buf->len; +} + +size_t crb_recv(__attribute__((unused)) enum tpm_family family, + __attribute__((unused)) struct tpmbuff *buf) +{ + /* noop, currently send waits until execution is complete*/ + return 0; +} + +u8 crb_init(struct tpm *t) +{ + u8 i; + struct tpm_crb_intf_id_ext id; + + if (crb_request_locality(0) == TPM_NO_LOCALITY) + return 0; + + id.val = tpm_read32(REGISTER(0, TPM_CRB_INTF_ID + 4)); + t->vendor = ((id.vid & 0x00FF) << 8) | ((id.vid & 0xFF00) >> 8); + if ((t->vendor & 0xFFFF) == 0xFFFF) + return 0; + + /* have the tpm invalidate the buffer if left in completion state */ + go_idle(); + /* now move to ready state */ + cmd_ready(); + + t->ops.request_locality = crb_request_locality; + t->ops.relinquish_locality = crb_relinquish_locality; + t->ops.send = crb_send; + t->ops.recv = crb_recv; + + return 1; +} diff --git a/arch/x86/boot/compressed/tpm/crb.h b/arch/x86/boot/compressed/tpm/crb.h new file mode 100644 index 0000000..8ab162e --- /dev/null +++ b/arch/x86/boot/compressed/tpm/crb.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2020 Apertus Solutions, LLC + * + * Author(s): + * Daniel P. Smith + * + * The definitions in this header are extracted from the Trusted Computing + * Group's "TPM Main Specification", Parts 1-3. + * + */ + +#ifndef _CRB_H +#define _CRB_H + +#include "tpm.h" + +u8 crb_init(struct tpm *t); + +#endif diff --git a/arch/x86/boot/compressed/tpm/tis.c b/arch/x86/boot/compressed/tpm/tis.c new file mode 100644 index 0000000..bc67b23 --- /dev/null +++ b/arch/x86/boot/compressed/tpm/tis.c @@ -0,0 +1,215 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 Apertus Solutions, LLC + * + * Author(s): + * Daniel P. Smith + * + * The code in this file is based on the article "Writing a TPM Device Driver" + * published on http://ptgmedia.pearsoncmg.com. + * + */ + +#include +#include +#include "tpm.h" +#include "tpmbuff.h" +#include "tpm_common.h" +#include "tis.h" + +#define TPM_BURST_MIN_DELAY 100 /* 100us */ + +static u8 locality = TPM_NO_LOCALITY; + +static u32 burst_wait(void) +{ + u32 count = 0; + + while (count == 0) { + count = tpm_read8(STS(locality) + 1); + count += tpm_read8(STS(locality) + 2) << 8; + + /* Wait for FIFO to drain */ + if (count == 0) + tpm_udelay(TPM_BURST_MIN_DELAY); + } + + return count; +} + +void tis_relinquish_locality(void) +{ + if (locality < TPM_MAX_LOCALITY) + tpm_write8(ACCESS_RELINQUISH_LOCALITY, ACCESS(locality)); + + locality = TPM_NO_LOCALITY; +} + +u8 tis_request_locality(u8 l) +{ + if (l > TPM_MAX_LOCALITY) + return TPM_NO_LOCALITY; + + if (l == locality) + return locality; + + tis_relinquish_locality(); + + tpm_write8(ACCESS_REQUEST_USE, ACCESS(l)); + + /* wait for locality to be granted */ + if (tpm_read8(ACCESS(l)) & ACCESS_ACTIVE_LOCALITY) + locality = l; + + return locality; +} + +size_t tis_send(struct tpmbuff *buf) +{ + u8 status, *buf_ptr; + u32 burstcnt = 0; + u32 count = 0; + + if (locality > TPM_MAX_LOCALITY) + return 0; + + for (status = 0; (status & STS_COMMAND_READY) == 0; ) { + tpm_write8(STS_COMMAND_READY, STS(locality)); + status = tpm_read8(STS(locality)); + } + + buf_ptr = buf->head; + + /* send all but the last byte */ + while (count < (buf->len - 1)) { + burstcnt = burst_wait(); + for (; burstcnt > 0 && count < (buf->len - 1); burstcnt--) { + tpm_write8(buf_ptr[count], DATA_FIFO(locality)); + count++; + } + + /* check for overflow */ + for (status = 0; (status & STS_VALID) == 0; ) + status = tpm_read8(STS(locality)); + + if ((status & STS_DATA_EXPECT) == 0) + return 0; + } + + /* write last byte */ + tpm_write8(buf_ptr[buf->len - 1], DATA_FIFO(locality)); + count++; + + /* make sure it stuck */ + for (status = 0; (status & STS_VALID) == 0; ) + status = tpm_read8(STS(locality)); + + if ((status & STS_DATA_EXPECT) != 0) + return 0; + + /* go and do it */ + tpm_write8(STS_GO, STS(locality)); + + return (size_t)count; +} + +static size_t recv_data(unsigned char *buf, size_t len) +{ + size_t size = 0; + u8 *bufptr; + u32 burstcnt = 0; + + bufptr = (u8 *)buf; + + while (tis_data_available(locality) && size < len) { + burstcnt = burst_wait(); + for (; burstcnt > 0 && size < len; burstcnt--) { + *bufptr = tpm_read8(DATA_FIFO(locality)); + bufptr++; + size++; + } + } + + return size; +} + +size_t tis_recv(enum tpm_family f, struct tpmbuff *buf) +{ + u32 expected; + u8 *buf_ptr; + struct tpm_header *hdr; + + if (locality > TPM_MAX_LOCALITY) + return 0; + + /* ensure that there is data available */ + if (!tis_data_available(locality)) { + if (f == TPM12) + tpm1_timeout_d(); + else + tpm2_timeout_d(); + + if (!tis_data_available(locality)) + return 0; + } + + /* read header */ + hdr = (struct tpm_header *)buf->head; + expected = sizeof(struct tpm_header); + if (recv_data(buf->head, expected) < expected) + return 0; + + /* convert header */ + hdr->tag = be16_to_cpu(hdr->tag); + hdr->size = be32_to_cpu(hdr->size); + hdr->code = be32_to_cpu(hdr->code); + + /* protect against integer underflow */ + if (hdr->size <= expected) + return 0; + + /* hdr->size = header + data */ + expected = hdr->size - expected; + buf_ptr = tpmb_put(buf, expected); + if (!buf_ptr) + return 0; + + /* read all data, except last byte */ + if (recv_data(buf_ptr, expected - 1) < (expected - 1)) + return 0; + + /* check for receive underflow */ + if (!tis_data_available(locality)) + return 0; + + /* read last byte */ + if (recv_data(buf_ptr, 1) != 1) + return 0; + + /* make sure we read everything */ + if (tis_data_available(locality)) + return 0; + + tpm_write8(STS_COMMAND_READY, STS(locality)); + + return hdr->size; +} + +u8 tis_init(struct tpm *t) +{ + locality = TPM_NO_LOCALITY; + + if (tis_request_locality(0) != 0) + return 0; + + t->vendor = tpm_read32(DID_VID(0)); + if ((t->vendor & 0xFFFF) == 0xFFFF) + return 0; + + t->ops.request_locality = tis_request_locality; + t->ops.relinquish_locality = tis_relinquish_locality; + t->ops.send = tis_send; + t->ops.recv = tis_recv; + + return 1; +} diff --git a/arch/x86/boot/compressed/tpm/tis.h b/arch/x86/boot/compressed/tpm/tis.h new file mode 100644 index 0000000..31e6df1 --- /dev/null +++ b/arch/x86/boot/compressed/tpm/tis.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2020 Apertus Solutions, LLC + * + * Author(s): + * Daniel P. Smith + * + * The definitions in this header are extracted from the Trusted Computing + * Group's "TPM Main Specification", Parts 1-3. + * + */ + +#ifndef _TIS_H +#define _TIS_H + +#include "tpm.h" +#include "tpm_common.h" + +/* macros to access registers at locality ’’l’’ */ +#define ACCESS(l) (0x0000 | ((l) << 12)) +#define STS(l) (0x0018 | ((l) << 12)) +#define DATA_FIFO(l) (0x0024 | ((l) << 12)) +#define DID_VID(l) (0x0F00 | ((l) << 12)) +/* access bits */ +#define ACCESS_ACTIVE_LOCALITY 0x20 /* (R)*/ +#define ACCESS_RELINQUISH_LOCALITY 0x20 /* (W) */ +#define ACCESS_REQUEST_USE 0x02 /* (W) */ +/* status bits */ +#define STS_VALID 0x80 /* (R) */ +#define STS_COMMAND_READY 0x40 /* (R) */ +#define STS_DATA_AVAIL 0x10 /* (R) */ +#define STS_DATA_EXPECT 0x08 /* (R) */ +#define STS_GO 0x20 /* (W) */ + +static inline bool tis_data_available(int locality) +{ + int status; + + status = tpm_read8(STS(locality)); + return ((status & (STS_DATA_AVAIL | STS_VALID)) == + (STS_DATA_AVAIL | STS_VALID)); +} + +u8 tis_init(struct tpm *t); + +#endif diff --git a/arch/x86/boot/compressed/tpm/tpm.h b/arch/x86/boot/compressed/tpm/tpm.h new file mode 100644 index 0000000..1d3f12f --- /dev/null +++ b/arch/x86/boot/compressed/tpm/tpm.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2020 Apertus Solutions, LLC + * + * Author(s): + * Daniel P. Smith + * + */ + +#ifndef _TPM_H +#define _TPM_H + +#define TPM_NO_LOCALITY 0xFF + +enum tpm_hw_intf { + TPM_TIS, + TPM_CRB +}; + +enum tpm_family { + TPM12, + TPM20 +}; + +struct tpmbuff; + +struct tpm_hw_ops { + u8 (*request_locality)(u8 l); + void (*relinquish_locality)(void); + size_t (*send)(struct tpmbuff *buf); + size_t (*recv)(enum tpm_family family, struct tpmbuff *buf); +}; + +struct tpm { + u32 vendor; + enum tpm_family family; + enum tpm_hw_intf intf; + struct tpm_hw_ops ops; + struct tpmbuff *buff; +}; + +extern struct tpm *enable_tpm(void); +extern u8 tpm_request_locality(struct tpm *t, u8 l); +extern void tpm_relinquish_locality(struct tpm *t); +extern int tpm_extend_pcr(struct tpm *t, u32 pcr, u16 algo, + u8 *digest); +extern void free_tpm(struct tpm *t); +#endif diff --git a/arch/x86/boot/compressed/tpm/tpm_buff.c b/arch/x86/boot/compressed/tpm/tpm_buff.c new file mode 100644 index 0000000..628ac87 --- /dev/null +++ b/arch/x86/boot/compressed/tpm/tpm_buff.c @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 Apertus Solutions, LLC + * + * Author(s): + * Daniel P. Smith + * + */ + +#include +#include +#include "tpm.h" +#include "tpmbuff.h" +#include "tpm_common.h" + +#define STATIC_TIS_BUFFER_SIZE 1024 + +#define TPM_CRB_DATA_BUFFER_OFFSET 0x80 +#define TPM_CRB_DATA_BUFFER_SIZE 3966 + +u8 *tpmb_reserve(struct tpmbuff *b) +{ + if (b->locked) + return NULL; + + b->len = sizeof(struct tpm_header); + b->locked = 1; + b->data = b->head + b->len; + b->tail = b->data; + + return b->head; +} + +void tpmb_free(struct tpmbuff *b) +{ + memset(b->head, 0, b->len); + + b->len = 0; + b->locked = 0; + b->data = NULL; + b->tail = NULL; +} + +u8 *tpmb_put(struct tpmbuff *b, size_t size) +{ + u8 *tail = b->tail; + + if ((b->len + size) > b->truesize) + return NULL; /* TODO: add overflow buffer support */ + + b->tail += size; + b->len += size; + + return tail; +} + +size_t tpmb_trim(struct tpmbuff *b, size_t size) +{ + if (b->len < size) + size = b->len; + + /* TODO: add overflow buffer support */ + + b->tail -= size; + b->len -= size; + + return size; +} + +size_t tpmb_size(struct tpmbuff *b) +{ + return b->len; +} + +static u8 tis_buff[STATIC_TIS_BUFFER_SIZE]; +static struct tpmbuff tpm_buff; + +struct tpmbuff *alloc_tpmbuff(enum tpm_hw_intf intf, u8 locality) +{ + struct tpmbuff *b = &tpm_buff; + + switch (intf) { + case TPM_TIS: + if (b->head) + goto reset; + + b->head = (u8 *)&tis_buff; + b->truesize = STATIC_TIS_BUFFER_SIZE; + break; + case TPM_CRB: + b->head = (u8 *)(uintptr_t)(TPM_MMIO_BASE + (locality << 12) + + TPM_CRB_DATA_BUFFER_OFFSET); + b->truesize = TPM_CRB_DATA_BUFFER_SIZE; + break; + default: + return NULL; + } + +reset: + b->len = 0; + b->locked = 0; + b->data = NULL; + b->tail = NULL; + b->end = b->head + (b->truesize - 1); + + return b; +} + +void free_tpmbuff(struct tpmbuff *b, enum tpm_hw_intf intf) +{ + switch (intf) { + case TPM_TIS: + b->head = NULL; + break; + case TPM_CRB: + b->head = NULL; + break; + default: + break; + } +} diff --git a/arch/x86/boot/compressed/tpm/tpm_common.h b/arch/x86/boot/compressed/tpm/tpm_common.h new file mode 100644 index 0000000..84f765c --- /dev/null +++ b/arch/x86/boot/compressed/tpm/tpm_common.h @@ -0,0 +1,127 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2020 Apertus Solutions, LLC + * + * Author(s): + * Daniel P. Smith + * + */ + +#ifndef _TPM_COMMON_H +#define _TPM_COMMON_H + +#define TPM_MMIO_BASE 0xFED40000 +#define TPM_MAX_LOCALITY 4 + +#define SHA1_SIZE 20 +#define SHA256_SIZE 32 +#define SHA384_SIZE 48 +#define SHA512_SIZE 64 +#define SM3256_SIZE 32 + +struct tpm_header { + u16 tag; + u32 size; + u32 code; +} __packed; + +#define TPM_INTERFACE_ID_0 0x30 +#define TPM_TIS_INTF_ACTIVE 0x00 +#define TPM_CRB_INTF_ACTIVE 0x01 + +struct tpm_interface_id { + union { + u32 val; + struct { + u32 interface_type:4; + u32 interface_version:4; + u32 cap_locality:1; + u32 reserved1:4; + u32 cap_tis:1; + u32 cap_crb:1; + u32 cap_if_res:2; + u32 interface_selector:2; + u32 intf_sel_lock:1; + u32 reserved2:4; + u32 reserved3:8; + }; + }; +} __packed; + +#define TPM_INTF_CAPABILITY_0 0x14 +#define TPM12_TIS_INTF_12 0x00 +#define TPM12_TIS_INTF_13 0x02 +#define TPM20_TIS_INTF_13 0x03 + +struct tpm_intf_capability { + union { + u32 val; + struct { + u32 data_avail_int_support:1; + u32 sts_valid_int_support:1; + u32 locality_change_int_support:1; + u32 interrupt_level_high:1; + u32 interrupt_level_low:1; + u32 interrupt_edge_rising:1; + u32 interrupt_edge_falling:1; + u32 command_ready_int_support:1; + u32 burst_count_static:1; + u32 data_transfer_size_support:2; + u32 reserved1:17; + u32 interface_version:3; + u32 reserved2:1; + }; + }; +} __packed; + +void tpm_udelay(int loops); +void tpm_mdelay(int ms); + +/* + * Timeouts defined in Table 16 from the TPM2 PTP and + * Table 15 from the PC Client TIS + */ + +/* TPM Timeout A: 750ms */ +static inline void timeout_a(void) +{ + tpm_mdelay(750); +} + +/* TPM Timeout B: 2000ms */ +static inline void timeout_b(void) +{ + tpm_mdelay(2000); +} + +/* Timeouts C & D are different between 1.2 & 2.0 */ +/* TPM1.2 Timeout C: 750ms */ +static inline void tpm1_timeout_c(void) +{ + tpm_mdelay(750); +} + +/* TPM1.2 Timeout D: 750ms */ +static inline void tpm1_timeout_d(void) +{ + tpm_mdelay(750); +} + +/* TPM2 Timeout C: 200ms */ +static inline void tpm2_timeout_c(void) +{ + tpm_mdelay(200); +} + +/* TPM2 Timeout D: 30ms */ +static inline void tpm2_timeout_d(void) +{ + tpm_mdelay(30); +} + +u8 tpm_read8(u32 field); +void tpm_write8(unsigned char val, u32 field); +u32 tpm_read32(u32 field); +void tpm_write32(unsigned int val, u32 field); + +#endif diff --git a/arch/x86/boot/compressed/tpm/tpmbuff.h b/arch/x86/boot/compressed/tpm/tpmbuff.h new file mode 100644 index 0000000..562e586 --- /dev/null +++ b/arch/x86/boot/compressed/tpm/tpmbuff.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2020 Apertus Solutions, LLC + * + * Author(s): + * Daniel P. Smith + * + */ + +#ifndef _TPMBUFF_H +#define _TPMBUFF_H + +/* mirroring Linux SKB */ +struct tpmbuff { + size_t truesize; + size_t len; + + u8 locked; + + u8 *head; + u8 *data; + u8 *tail; + u8 *end; +}; + +u8 *tpmb_reserve(struct tpmbuff *b); +void tpmb_free(struct tpmbuff *b); +u8 *tpmb_put(struct tpmbuff *b, size_t size); +size_t tpmb_trim(struct tpmbuff *b, size_t size); +size_t tpmb_size(struct tpmbuff *b); +struct tpmbuff *alloc_tpmbuff(enum tpm_hw_intf i, u8 locality); +void free_tpmbuff(struct tpmbuff *b, enum tpm_hw_intf i); + +#endif diff --git a/arch/x86/boot/compressed/tpm/tpmio.c b/arch/x86/boot/compressed/tpm/tpmio.c new file mode 100644 index 0000000..1502ec1 --- /dev/null +++ b/arch/x86/boot/compressed/tpm/tpmio.c @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 Apertus Solutions, LLC + * + * Author(s): + * Daniel P. Smith + */ + +#include +#include +#include "tpm_common.h" + +static noinline void tpm_io_delay(void) +{ + /* This is the default delay type in native_io_delay */ + asm volatile ("outb %al, $0x80"); +} + +void tpm_udelay(int loops) +{ + while (loops--) + tpm_io_delay(); /* Approximately 1 us */ +} + +void tpm_mdelay(int ms) +{ + int i; + + for (i = 0; i < ms; i++) + tpm_udelay(1000); +} + +u8 tpm_read8(u32 field) +{ + return readb((void *)(u64)(TPM_MMIO_BASE | field)); +} + +void tpm_write8(unsigned char val, u32 field) +{ + writeb(val, (void *)(u64)(TPM_MMIO_BASE | field)); +} + +u32 tpm_read32(u32 field) +{ + return readl((void *)(u64)(TPM_MMIO_BASE | field)); +} + +void tpm_write32(u32 val, u32 field) +{ + writel(val, (void *)(u64)(TPM_MMIO_BASE | field)); +} From patchwork Thu Sep 24 14:58:33 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ross Philipson X-Patchwork-Id: 11797631 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id CD5B76CA for ; Thu, 24 Sep 2020 14:58:39 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 934BE2311B for ; Thu, 24 Sep 2020 14:58:39 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=oracle.com header.i=@oracle.com header.b="jruSWmNg" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728320AbgIXO6i (ORCPT ); Thu, 24 Sep 2020 10:58:38 -0400 Received: from userp2120.oracle.com ([156.151.31.85]:48110 "EHLO userp2120.oracle.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728294AbgIXO6i (ORCPT ); Thu, 24 Sep 2020 10:58:38 -0400 Received: from pps.filterd (userp2120.oracle.com [127.0.0.1]) by userp2120.oracle.com (8.16.0.42/8.16.0.42) with SMTP id 08OEso7R071860; Thu, 24 Sep 2020 14:58:14 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=from : to : cc : subject : date : message-id : in-reply-to : references; s=corp-2020-01-29; bh=Yqt+92qtIPnzV+UAbRlHcsR51LUOUu18fTQvRXDG2ek=; b=jruSWmNgqGvPdAVtwnpd/0M8fJOyw+Cno9jJ0ZxpoauDBW/soMYIjHrP+rDMFzlg1T/e 44ZroN3v6bbdrqm7zrdA57J33Lj7VwyY/mZN4BufW0HI2UTGcXoFZoVtDJzYhPNlhts9 Gm5x790up1N9RK9cZRzqXhPt7Zb7QyqBTqPhfXCtof4JxaU5YHGXZ5DujPXn8vYMqXTZ OjqWLkV+fPKuaHiPinVSk4vNW9PmND+N9yNwHwXooawb7M7YTujgJOKXlBZL8XPEaA5+ +YgQpAA5f4A5rVAgPXkpL1f5B6MARrOJVbJqMBk35uHAzgc6IUtXmmYhfoieOpvqz/lD KQ== Received: from userp3030.oracle.com (userp3030.oracle.com [156.151.31.80]) by userp2120.oracle.com with ESMTP id 33ndnurum0-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Thu, 24 Sep 2020 14:58:14 +0000 Received: from pps.filterd (userp3030.oracle.com [127.0.0.1]) by userp3030.oracle.com (8.16.0.42/8.16.0.42) with SMTP id 08OEtTlR159240; Thu, 24 Sep 2020 14:58:13 GMT Received: from aserv0122.oracle.com (aserv0122.oracle.com [141.146.126.236]) by userp3030.oracle.com with ESMTP id 33nux2vwjp-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 24 Sep 2020 14:58:13 +0000 Received: from abhmp0014.oracle.com (abhmp0014.oracle.com [141.146.116.20]) by aserv0122.oracle.com (8.14.4/8.14.4) with ESMTP id 08OEwCeA002782; Thu, 24 Sep 2020 14:58:12 GMT Received: from disposition.us.oracle.com (/10.152.32.81) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Thu, 24 Sep 2020 07:58:11 -0700 From: Ross Philipson To: linux-kernel@vger.kernel.org, x86@kernel.org, iommu@lists.linux-foundation.org, linux-integrity@vger.kernel.org, linux-doc@vger.kernel.org Cc: ross.philipson@oracle.com, dpsmith@apertussolutions.com, tglx@linutronix.de, mingo@redhat.com, bp@alien8.de, hpa@zytor.com, luto@amacapital.net, trenchboot-devel@googlegroups.com Subject: [PATCH 05/13] x86: Add early TPM1.2/TPM2.0 interface support for Secure Launch Date: Thu, 24 Sep 2020 10:58:33 -0400 Message-Id: <1600959521-24158-6-git-send-email-ross.philipson@oracle.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1600959521-24158-1-git-send-email-ross.philipson@oracle.com> References: <1600959521-24158-1-git-send-email-ross.philipson@oracle.com> X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9753 signatures=668680 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 malwarescore=0 mlxscore=0 adultscore=0 bulkscore=0 mlxlogscore=999 phishscore=0 suspectscore=2 spamscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2006250000 definitions=main-2009240114 X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9753 signatures=668680 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 priorityscore=1501 malwarescore=0 lowpriorityscore=0 phishscore=0 adultscore=0 suspectscore=2 bulkscore=0 clxscore=1015 impostorscore=0 mlxlogscore=999 mlxscore=0 spamscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2006250000 definitions=main-2009240114 Precedence: bulk List-ID: X-Mailing-List: linux-integrity@vger.kernel.org From: "Daniel P. Smith" This commit introduces an abstraction for TPM1.2 and TPM2.0 devices above the TPM hardware interface. Signed-off-by: Daniel P. Smith Signed-off-by: Ross Philipson --- arch/x86/boot/compressed/Makefile | 3 +- arch/x86/boot/compressed/tpm/tpm1.h | 112 ++++++++++++++++++++ arch/x86/boot/compressed/tpm/tpm1_cmds.c | 99 ++++++++++++++++++ arch/x86/boot/compressed/tpm/tpm2.h | 89 ++++++++++++++++ arch/x86/boot/compressed/tpm/tpm2_auth.c | 44 ++++++++ arch/x86/boot/compressed/tpm/tpm2_auth.h | 21 ++++ arch/x86/boot/compressed/tpm/tpm2_cmds.c | 145 ++++++++++++++++++++++++++ arch/x86/boot/compressed/tpm/tpm2_constants.h | 66 ++++++++++++ 8 files changed, 578 insertions(+), 1 deletion(-) create mode 100644 arch/x86/boot/compressed/tpm/tpm1.h create mode 100644 arch/x86/boot/compressed/tpm/tpm1_cmds.c create mode 100644 arch/x86/boot/compressed/tpm/tpm2.h create mode 100644 arch/x86/boot/compressed/tpm/tpm2_auth.c create mode 100644 arch/x86/boot/compressed/tpm/tpm2_auth.h create mode 100644 arch/x86/boot/compressed/tpm/tpm2_cmds.c create mode 100644 arch/x86/boot/compressed/tpm/tpm2_constants.h diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index 5515afa..a4308d5 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile @@ -100,7 +100,8 @@ vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o vmlinux-objs-$(CONFIG_SECURE_LAUNCH_SHA256) += $(obj)/early_sha256.o vmlinux-objs-$(CONFIG_SECURE_LAUNCH_SHA512) += $(obj)/early_sha512.o vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/tpm/tpmio.o $(obj)/tpm/tpm_buff.o \ - $(obj)/tpm/tis.o $(obj)/tpm/crb.o + $(obj)/tpm/tis.o $(obj)/tpm/crb.o $(obj)/tpm/tpm1_cmds.o \ + $(obj)/tpm/tpm2_cmds.o $(obj)/tpm/tpm2_auth.o # The compressed kernel is built with -fPIC/-fPIE so that a boot loader # can place it anywhere in memory and it will still run. However, since diff --git a/arch/x86/boot/compressed/tpm/tpm1.h b/arch/x86/boot/compressed/tpm/tpm1.h new file mode 100644 index 0000000..498fa45 --- /dev/null +++ b/arch/x86/boot/compressed/tpm/tpm1.h @@ -0,0 +1,112 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2020 Apertus Solutions, LLC + * + * Author(s): + * Daniel P. Smith + * + * The definitions in this header are extracted from the Trusted Computing + * Group's "TPM Main Specification", Parts 1-3. + * + */ + +#ifndef _TPM1_H +#define _TPM1_H + +#include "tpm.h" + +/* Section 2.2.3 */ +#define TPM_AUTH_DATA_USAGE u8 +#define TPM_PAYLOAD_TYPE u8 +#define TPM_VERSION_BYTE u8 +#define TPM_TAG u16 +#define TPM_PROTOCOL_ID u16 +#define TPM_STARTUP_TYPE u16 +#define TPM_ENC_SCHEME u16 +#define TPM_SIG_SCHEME u16 +#define TPM_MIGRATE_SCHEME u16 +#define TPM_PHYSICAL_PRESENCE u16 +#define TPM_ENTITY_TYPE u16 +#define TPM_KEY_USAGE u16 +#define TPM_EK_TYPE u16 +#define TPM_STRUCTURE_TAG u16 +#define TPM_PLATFORM_SPECIFIC u16 +#define TPM_COMMAND_CODE u32 +#define TPM_CAPABILITY_AREA u32 +#define TPM_KEY_FLAGS u32 +#define TPM_ALGORITHM_ID u32 +#define TPM_MODIFIER_INDICATOR u32 +#define TPM_ACTUAL_COUNT u32 +#define TPM_TRANSPORT_ATTRIBUTES u32 +#define TPM_AUTHHANDLE u32 +#define TPM_DIRINDEX u32 +#define TPM_KEY_HANDLE u32 +#define TPM_PCRINDEX u32 +#define TPM_RESULT u32 +#define TPM_RESOURCE_TYPE u32 +#define TPM_KEY_CONTROL u32 +#define TPM_NV_INDEX u32 The +#define TPM_FAMILY_ID u32 +#define TPM_FAMILY_VERIFICATION u32 +#define TPM_STARTUP_EFFECTS u32 +#define TPM_SYM_MODE u32 +#define TPM_FAMILY_FLAGS u32 +#define TPM_DELEGATE_INDEX u32 +#define TPM_CMK_DELEGATE u32 +#define TPM_COUNT_ID u32 +#define TPM_REDIT_COMMAND u32 +#define TPM_TRANSHANDLE u32 +#define TPM_HANDLE u32 +#define TPM_FAMILY_OPERATION u32 + +/* Section 6 */ +#define TPM_TAG_RQU_COMMAND 0x00C1 +#define TPM_TAG_RQU_AUTH1_COMMAND 0x00C2 +#define TPM_TAG_RQU_AUTH2_COMMAND 0x00C3 +#define TPM_TAG_RSP_COMMAND 0x00C4 +#define TPM_TAG_RSP_AUTH1_COMMAND 0x00C5 +#define TPM_TAG_RSP_AUTH2_COMMAND 0x00C6 + +/* Section 16 */ +#define TPM_SUCCESS 0x0 + +/* Section 17 */ +#define TPM_ORD_EXTEND 0x00000014 + +#define SHA1_DIGEST_SIZE 20 + +/* Section 5.4 */ +struct tpm_sha1_digest { + u8 digest[SHA1_DIGEST_SIZE]; +}; +struct tpm_digest { + TPM_PCRINDEX pcr; + union { + struct tpm_sha1_digest sha1; + } digest; +}; + +#define TPM_DIGEST struct tpm_sha1_digest +#define TPM_CHOSENID_HASH TPM_DIGEST +#define TPM_COMPOSITE_HASH TPM_DIGEST +#define TPM_DIRVALUE TPM_DIGEST +#define TPM_HMAC TPM_DIGEST +#define TPM_PCRVALUE TPM_DIGEST +#define TPM_AUDITDIGEST TPM_DIGEST +#define TPM_DAA_TPM_SEED TPM_DIGEST +#define TPM_DAA_CONTEXT_SEED TPM_DIGEST + +struct tpm_extend_cmd { + TPM_PCRINDEX pcr_num; + TPM_DIGEST digest; +}; + +struct tpm_extend_resp { + TPM_COMMAND_CODE ordinal; + TPM_PCRVALUE digest; +}; + +/* TPM Commands */ +int tpm1_pcr_extend(struct tpm *t, struct tpm_digest *d); + +#endif diff --git a/arch/x86/boot/compressed/tpm/tpm1_cmds.c b/arch/x86/boot/compressed/tpm/tpm1_cmds.c new file mode 100644 index 0000000..2d8c9e5 --- /dev/null +++ b/arch/x86/boot/compressed/tpm/tpm1_cmds.c @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 Apertus Solutions, LLC + * + * Author(s): + * Daniel P. Smith + * + * The code in this file is based on the article "Writing a TPM Device Driver" + * published on http://ptgmedia.pearsoncmg.com. + * + */ + +#include +#include +#include +#include +#include "tpm.h" +#include "tpmbuff.h" +#include "tis.h" +#include "tpm_common.h" +#include "tpm1.h" + +int tpm1_pcr_extend(struct tpm *t, struct tpm_digest *d) +{ + int ret = 0; + struct tpmbuff *b = t->buff; + struct tpm_header *hdr; + struct tpm_extend_cmd *cmd; + size_t size; + + if (b == NULL) { + ret = -EINVAL; + goto out; + } + + /* ensure buffer is free for use */ + tpmb_free(b); + + hdr = (struct tpm_header *)tpmb_reserve(b); + if (!hdr) { + ret = -ENOMEM; + goto out; + } + + + hdr->tag = cpu_to_be16(TPM_TAG_RQU_COMMAND); + hdr->code = cpu_to_be32(TPM_ORD_EXTEND); + + cmd = (struct tpm_extend_cmd *) + tpmb_put(b, sizeof(struct tpm_extend_cmd)); + if (cmd == NULL) { + ret = -ENOMEM; + goto free; + } + + cmd->pcr_num = cpu_to_be32(d->pcr); + memcpy(&(cmd->digest), &(d->digest), sizeof(TPM_DIGEST)); + + hdr->size = cpu_to_be32(tpmb_size(b)); + + if (be32_to_cpu(hdr->size) != t->ops.send(b)) { + ret = -EAGAIN; + goto free; + } + + /* Reset buffer for receive */ + tpmb_trim(b, tpmb_size(b)); + + hdr = (struct tpm_header *)b->head; + tpmb_put(b, sizeof(struct tpm_header)); + + /* + * The extend receive operation returns a struct tpm_extend_resp + * but the current implementation ignores the returned PCR value. + */ + + /* recv() will increase the buffer size */ + size = t->ops.recv(t->family, b); + if (tpmb_size(b) != size) { + ret = -EAGAIN; + goto free; + } + + /* + * On return, the code field is used for the return code out. Though + * the commands specifications section 16.1 implies there is an + * ordinal field, the return size and values point to this being + * incorrect. + * + * Also tis_recv() converts the header back to CPU endianness. + */ + if (hdr->code != TPM_SUCCESS) + ret = -EAGAIN; + +free: + tpmb_free(b); +out: + return ret; +} diff --git a/arch/x86/boot/compressed/tpm/tpm2.h b/arch/x86/boot/compressed/tpm/tpm2.h new file mode 100644 index 0000000..4bc64f5 --- /dev/null +++ b/arch/x86/boot/compressed/tpm/tpm2.h @@ -0,0 +1,89 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2020 Apertus Solutions, LLC + * + * Author(s): + * Daniel P. Smith + * + * The definitions in this header are extracted and/or dervied from the + * Trusted Computing Group's TPM 2.0 Library Specification Parts 1&2. + * + */ + +#ifndef _TPM2_H +#define _TPM2_H + +#include "tpm_common.h" +#include "tpm2_constants.h" + + +/* Table 192 Definition of TPM2B_TEMPLATE Structure: + * Using this as the base structure similar to the spec + */ +struct tpm2b { + u16 size; + u8 buffer[0]; +}; + +// Table 32 Definition of TPMA_SESSION Bits < IN/OUT> +struct tpma_session { + u8 continue_session : 1; + u8 audit_exclusive : 1; + u8 audit_reset : 1; + u8 reserved3_4 : 2; + u8 decrypt : 1; + u8 encrypt : 1; + u8 audit : 1; +}; + + +// Table 72 Definition of TPMT_HA Structure < IN/OUT> +struct tpmt_ha { + u16 alg; /* TPMI_ALG_HASH */ + u8 digest[0]; /* TPMU_HA */ +}; + +// Table 100 Definition of TPML_DIGEST_VALUES Structure +struct tpml_digest_values { + u32 count; + struct tpmt_ha digests[0]; +}; + + +// Table 124 Definition of TPMS_AUTH_COMMAND Structure < IN> +struct tpms_auth_cmd { + u32 *handle; + struct tpm2b *nonce; + struct tpma_session *attributes; + struct tpm2b *hmac; +}; + +// Table 125 Definition of TPMS_AUTH_RESPONSE Structure < OUT> +struct tpms_auth_resp { + struct tpm2b *nonce; + struct tpma_session *attributes; + struct tpm2b *hmac; +}; + +struct tpm2_cmd { + struct tpm_header *header; + u32 *handles; /* TPM Handles array */ + u32 *auth_size; /* Size of Auth Area */ + u8 *auth; /* Authorization Area */ + u8 *params; /* Parameters */ + u8 *raw; /* internal raw buffer */ +}; + +struct tpm2_resp { + struct tpm_header *header; + u32 *handles; /* TPM Handles array */ + u32 *param_size; /* Size of Parameters */ + struct tpm2b *params; /* Parameters */ + u8 *auth; /* Authorization Area */ + u8 *raw; /* internal raw buffer */ +}; + +int tpm2_extend_pcr(struct tpm *t, u32 pcr, + struct tpml_digest_values *digests); + +#endif diff --git a/arch/x86/boot/compressed/tpm/tpm2_auth.c b/arch/x86/boot/compressed/tpm/tpm2_auth.c new file mode 100644 index 0000000..016ecc1 --- /dev/null +++ b/arch/x86/boot/compressed/tpm/tpm2_auth.c @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 Apertus Solutions, LLC + * + * Author(s): + * Daniel P. Smith + * + */ + +#include +#include +#include +#include +#include "tpm.h" +#include "tpmbuff.h" +#include "tpm2.h" +#include "tpm2_constants.h" + +#define NULL_AUTH_SIZE 9 + +u32 tpm2_null_auth_size(void) +{ + return NULL_AUTH_SIZE; +} + +u8 *tpm2_null_auth(struct tpmbuff *b) +{ + u32 *handle; + u8 *auth = (u8 *)tpmb_put(b, NULL_AUTH_SIZE); + + if (!auth) + return NULL; + + memset(auth, 0, NULL_AUTH_SIZE); + + /* + * The handle, the first element, is the + * only non-zero value in a NULL auth + */ + handle = (u32 *)auth; + *handle = cpu_to_be32(TPM_RS_PW); + + return auth; +} diff --git a/arch/x86/boot/compressed/tpm/tpm2_auth.h b/arch/x86/boot/compressed/tpm/tpm2_auth.h new file mode 100644 index 0000000..1d4421c --- /dev/null +++ b/arch/x86/boot/compressed/tpm/tpm2_auth.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2020 Apertus Solutions, LLC + * + * Author(s): + * Daniel P. Smith + * + * The definitions in this header are extracted and/or dervied from the + * Trusted Computing Group's TPM 2.0 Library Specification Parts 1&2. + * + */ + +#ifndef _TPM2_AUTH_H +#define _TPM2_AUTH_H + +#include "tpm2.h" + +u32 tpm2_null_auth_size(void); +u8 *tpm2_null_auth(struct tpmbuff *b); + +#endif diff --git a/arch/x86/boot/compressed/tpm/tpm2_cmds.c b/arch/x86/boot/compressed/tpm/tpm2_cmds.c new file mode 100644 index 0000000..8e79f9e --- /dev/null +++ b/arch/x86/boot/compressed/tpm/tpm2_cmds.c @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 Apertus Solutions, LLC + * + * Author(s): + * Daniel P. Smith + * + */ + +#include +#include +#include +#include +#include +#include "tpm.h" +#include "tpmbuff.h" +#include "tpm_common.h" +#include "tpm2.h" +#include "tpm2_auth.h" +#include "tis.h" +#include "crb.h" + +static int tpm2_alloc_cmd(struct tpmbuff *b, struct tpm2_cmd *c, u16 tag, + u32 code) +{ + /* ensure buffer is free for use */ + tpmb_free(b); + + c->header = (struct tpm_header *)tpmb_reserve(b); + if (!c->header) + return -ENOMEM; + + c->header->tag = cpu_to_be16(tag); + c->header->code = cpu_to_be32(code); + + return 0; +} + +static u16 convert_digest_list(struct tpml_digest_values *digests) +{ + int i; + u16 size = sizeof(digests->count); + struct tpmt_ha *h = digests->digests; + + for (i = 0; i < digests->count; i++) { + switch (h->alg) { + case TPM_ALG_SHA1: + h->alg = cpu_to_be16(h->alg); + h = (struct tpmt_ha *)((u8 *)h + SHA1_SIZE); + size += sizeof(u16) + SHA1_SIZE; + break; + case TPM_ALG_SHA256: + h->alg = cpu_to_be16(h->alg); + h = (struct tpmt_ha *)((u8 *)h + SHA256_SIZE); + size += sizeof(u16) + SHA256_SIZE; + break; + case TPM_ALG_SHA384: + h->alg = cpu_to_be16(h->alg); + h = (struct tpmt_ha *)((u8 *)h + SHA384_SIZE); + size += sizeof(u16) + SHA384_SIZE; + break; + case TPM_ALG_SHA512: + h->alg = cpu_to_be16(h->alg); + h = (struct tpmt_ha *)((u8 *)h + SHA512_SIZE); + size += sizeof(u16) + SHA512_SIZE; + break; + case TPM_ALG_SM3_256: + h->alg = cpu_to_be16(h->alg); + h = (struct tpmt_ha *)((u8 *)h + SM3256_SIZE); + size += sizeof(u16) + SHA1_SIZE; + break; + default: + return 0; + } + } + + digests->count = cpu_to_be32(digests->count); + + return size; +} + +int tpm2_extend_pcr(struct tpm *t, u32 pcr, + struct tpml_digest_values *digests) +{ + struct tpmbuff *b = t->buff; + struct tpm2_cmd cmd; + u16 size; + int ret = 0; + + if (b == NULL) { + ret = -EINVAL; + goto out; + } + + ret = tpm2_alloc_cmd(b, &cmd, TPM_ST_SESSIONS, TPM_CC_PCR_EXTEND); + if (ret < 0) + goto out; + + cmd.handles = (u32 *)tpmb_put(b, sizeof(u32)); + if (cmd.handles == NULL) { + ret = -ENOMEM; + goto free; + } + + cmd.handles[0] = cpu_to_be32(pcr); + + cmd.auth_size = (u32 *)tpmb_put(b, sizeof(u32)); + if (cmd.auth_size == NULL) { + ret = -ENOMEM; + goto free; + } + + cmd.auth = tpm2_null_auth(b); + if (cmd.auth == NULL) { + ret = -ENOMEM; + goto free; + } + + *cmd.auth_size = cpu_to_be32(tpm2_null_auth_size()); + + size = convert_digest_list(digests); + if (size == 0) { + ret = -ENOMEM; + goto free; + } + + cmd.params = (u8 *)tpmb_put(b, size); + if (cmd.params == NULL) { + ret = -ENOMEM; + goto free; + } + + memcpy(cmd.params, digests, size); + + cmd.header->size = cpu_to_be32(tpmb_size(b)); + + size = t->ops.send(b); + if (tpmb_size(b) != size) + ret = -EAGAIN; + +free: + tpmb_free(b); +out: + return ret; +} diff --git a/arch/x86/boot/compressed/tpm/tpm2_constants.h b/arch/x86/boot/compressed/tpm/tpm2_constants.h new file mode 100644 index 0000000..bf31843 --- /dev/null +++ b/arch/x86/boot/compressed/tpm/tpm2_constants.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2020 Apertus Solutions, LLC + * + * Author(s): + * Daniel P. Smith + * + * The definitions in this header are extracted and/or dervied from the + * Trusted Computing Group's TPM 2.0 Library Specification Parts 1&2. + * + */ + +#ifndef _TPM2_CONSTANTS_H +#define _TPM2_CONSTANTS_H + +/* Table 9 Definition of (UINT16) TPM_ALG_ID Constants */ +#define TPM_ALG_ERROR _AT(u16, 0x0000) +#define TPM_ALG_RSA _AT(u16, 0x0001) +#define TPM_ALG_SHA _AT(u16, 0x0004) +#define TPM_ALG_SHA1 _AT(u16, 0x0004) +#define TPM_ALG_HMAC _AT(u16, 0x0005) +#define TPM_ALG_AES _AT(u16, 0x0006) +#define TPM_ALG_MGF1 _AT(u16, 0x0007) +#define TPM_ALG_KEYEDHASH _AT(u16, 0x0008) +#define TPM_ALG_XOR _AT(u16, 0x000A) +#define TPM_ALG_SHA256 _AT(u16, 0x000B) +#define TPM_ALG_SHA384 _AT(u16, 0x000C) +#define TPM_ALG_SHA512 _AT(u16, 0x000D) +#define TPM_ALG_NULL _AT(u16, 0x0010) +#define TPM_ALG_SM3_256 _AT(u16, 0x0012) +#define TPM_ALG_SM4 _AT(u16, 0x0013) +#define TPM_ALG_RSASSA _AT(u16, 0x0014) +#define TPM_ALG_RSAES _AT(u16, 0x0015) +#define TPM_ALG_RSAPSS _AT(u16, 0x0016) +#define TPM_ALG_OAEP _AT(u16, 0x0017) +#define TPM_ALG_ECDSA _AT(u16, 0x0018) +#define TPM_ALG_ECDH _AT(u16, 0x0019) +#define TPM_ALG_ECDAA _AT(u16, 0x001A) +#define TPM_ALG_SM2 _AT(u16, 0x001B) +#define TPM_ALG_ECSCHNORR _AT(u16, 0x001C) +#define TPM_ALG_ECMQV _AT(u16, 0x001D) +#define TPM_ALG_KDF1_SP800_56A _AT(u16, 0x0020) +#define TPM_ALG_KDF2 _AT(u16, 0x0021) +#define TPM_ALG_KDF1_SP800_108 _AT(u16, 0x0022) +#define TPM_ALG_ECC _AT(u16, 0x0023) +#define TPM_ALG_SYMCIPHER _AT(u16, 0x0025) +#define TPM_ALG_CAMELLIA _AT(u16, 0x0026) +#define TPM_ALG_CTR _AT(u16, 0x0040) +#define TPM_ALG_OFB _AT(u16, 0x0041) +#define TPM_ALG_CBC _AT(u16, 0x0042) +#define TPM_ALG_CFB _AT(u16, 0x0043) +#define TPM_ALG_ECB _AT(u16, 0x0044) +#define TPM_ALG_FIRST _AT(u16, 0x0001) +#define TPM_ALG_LAST _AT(u16, 0x0044) + +/* Table 12 Definition of (UINT32) TPM_CC Constants (Numeric Order) */ +#define TPM_CC_PCR_EXTEND _AT(u32, 0x00000182) + +/* Table 19 Definition of (UINT16) TPM_ST Constants */ +#define TPM_ST_NO_SESSIONS _AT(u16, 0x8001) +#define TPM_ST_SESSIONS _AT(u16, 0x8002) + +/* Table 28 Definition of (TPM_HANDLE) TPM_RH Constants */ +#define TPM_RS_PW _AT(u32, 0x40000009) + +#endif From patchwork Thu Sep 24 14:58:34 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ross Philipson X-Patchwork-Id: 11797643 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 4C1FF6CA for ; Thu, 24 Sep 2020 14:59:11 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 1F54A23787 for ; Thu, 24 Sep 2020 14:59:11 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=oracle.com header.i=@oracle.com header.b="i47qAal2" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728419AbgIXO6k (ORCPT ); Thu, 24 Sep 2020 10:58:40 -0400 Received: from aserp2130.oracle.com ([141.146.126.79]:57272 "EHLO aserp2130.oracle.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728406AbgIXO6j (ORCPT ); Thu, 24 Sep 2020 10:58:39 -0400 Received: from pps.filterd (aserp2130.oracle.com [127.0.0.1]) by aserp2130.oracle.com (8.16.0.42/8.16.0.42) with SMTP id 08OEriXw101671; Thu, 24 Sep 2020 14:58:18 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=from : to : cc : subject : date : message-id : in-reply-to : references; s=corp-2020-01-29; bh=3RB2GjK9ADEmAIr+xoSAWhTF8Rk2yEY/ISVfaoeNfBs=; b=i47qAal2g2PSZT09qgQ22BTMzKVLAaudUpojAuRafVDiFoWkCs9/nyqtZmW65zzD9DC5 2U/rwye04mKjbGyGKdvJGX5/JjyssqYgdsyVSgyrEFy7Vom8dMb47tV2lucyYKIBebmV qWiotEMA1JCEmqQIsyyHvJrtd4BMFDb39vbN8KUHTy1IFfK0YER3DgRGDIpt+5p85lR1 SVadiDJRRr82xNt4TkCqLxbUZZxV5wa2JnuChyxMcNA2EhsSAUbPOnb0NZwlSJMDh9lx eoFCN79O1LyDe81uG8/kVKa8d6e+3nWCxjjFgRdYFu+vpvhy6cXz8fwVZ3/CWeYzDF/8 og== Received: from aserp3030.oracle.com (aserp3030.oracle.com [141.146.126.71]) by aserp2130.oracle.com with ESMTP id 33qcpu5qcp-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Thu, 24 Sep 2020 14:58:18 +0000 Received: from pps.filterd (aserp3030.oracle.com [127.0.0.1]) by aserp3030.oracle.com (8.16.0.42/8.16.0.42) with SMTP id 08OEuT6E126286; Thu, 24 Sep 2020 14:58:18 GMT Received: from userv0122.oracle.com (userv0122.oracle.com [156.151.31.75]) by aserp3030.oracle.com with ESMTP id 33nujr18dk-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 24 Sep 2020 14:58:18 +0000 Received: from abhmp0014.oracle.com (abhmp0014.oracle.com [141.146.116.20]) by userv0122.oracle.com (8.14.4/8.14.4) with ESMTP id 08OEwD0q016152; Thu, 24 Sep 2020 14:58:13 GMT Received: from disposition.us.oracle.com (/10.152.32.81) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Thu, 24 Sep 2020 07:58:12 -0700 From: Ross Philipson To: linux-kernel@vger.kernel.org, x86@kernel.org, iommu@lists.linux-foundation.org, linux-integrity@vger.kernel.org, linux-doc@vger.kernel.org Cc: ross.philipson@oracle.com, dpsmith@apertussolutions.com, tglx@linutronix.de, mingo@redhat.com, bp@alien8.de, hpa@zytor.com, luto@amacapital.net, trenchboot-devel@googlegroups.com Subject: [PATCH 06/13] x86: Add early general TPM interface support for Secure Launch Date: Thu, 24 Sep 2020 10:58:34 -0400 Message-Id: <1600959521-24158-7-git-send-email-ross.philipson@oracle.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1600959521-24158-1-git-send-email-ross.philipson@oracle.com> References: <1600959521-24158-1-git-send-email-ross.philipson@oracle.com> X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9753 signatures=668680 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 bulkscore=0 malwarescore=0 mlxlogscore=999 phishscore=0 adultscore=0 spamscore=0 suspectscore=2 mlxscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2006250000 definitions=main-2009240114 X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9753 signatures=668680 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 suspectscore=2 mlxlogscore=999 adultscore=0 bulkscore=0 mlxscore=0 lowpriorityscore=0 priorityscore=1501 phishscore=0 spamscore=0 malwarescore=0 clxscore=1015 impostorscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2006250000 definitions=main-2009240114 Precedence: bulk List-ID: X-Mailing-List: linux-integrity@vger.kernel.org From: "Daniel P. Smith" This commit exposes a minimal general interface for the compressed kernel to request the required TPM operations to send measurements to a TPM. Signed-off-by: Daniel P. Smith Signed-off-by: Ross Philipson --- arch/x86/boot/compressed/Makefile | 2 +- arch/x86/boot/compressed/tpm/tpm.c | 145 +++++++++++++++++++++++++++++++++++++ 2 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 arch/x86/boot/compressed/tpm/tpm.c diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index a4308d5..35947b9 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile @@ -101,7 +101,7 @@ vmlinux-objs-$(CONFIG_SECURE_LAUNCH_SHA256) += $(obj)/early_sha256.o vmlinux-objs-$(CONFIG_SECURE_LAUNCH_SHA512) += $(obj)/early_sha512.o vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/tpm/tpmio.o $(obj)/tpm/tpm_buff.o \ $(obj)/tpm/tis.o $(obj)/tpm/crb.o $(obj)/tpm/tpm1_cmds.o \ - $(obj)/tpm/tpm2_cmds.o $(obj)/tpm/tpm2_auth.o + $(obj)/tpm/tpm2_cmds.o $(obj)/tpm/tpm2_auth.o $(obj)/tpm/tpm.o # The compressed kernel is built with -fPIC/-fPIE so that a boot loader # can place it anywhere in memory and it will still run. However, since diff --git a/arch/x86/boot/compressed/tpm/tpm.c b/arch/x86/boot/compressed/tpm/tpm.c new file mode 100644 index 0000000..0fe62d2 --- /dev/null +++ b/arch/x86/boot/compressed/tpm/tpm.c @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 Apertus Solutions, LLC + * + * Author(s): + * Daniel P. Smith + * + */ + +#include +#include +#include +#include +#include "tpm.h" +#include "tpmbuff.h" +#include "tis.h" +#include "crb.h" +#include "tpm_common.h" +#include "tpm1.h" +#include "tpm2.h" +#include "tpm2_constants.h" + +static struct tpm tpm; + +static void find_interface_and_family(struct tpm *t) +{ + struct tpm_interface_id intf_id; + struct tpm_intf_capability intf_cap; + + /* Sort out whether if it is 1.2 */ + intf_cap.val = tpm_read32(TPM_INTF_CAPABILITY_0); + if ((intf_cap.interface_version == TPM12_TIS_INTF_12) || + (intf_cap.interface_version == TPM12_TIS_INTF_13)) { + t->family = TPM12; + t->intf = TPM_TIS; + return; + } + + /* Assume that it is 2.0 and TIS */ + t->family = TPM20; + t->intf = TPM_TIS; + + /* Check if the interface is CRB */ + intf_id.val = tpm_read32(TPM_INTERFACE_ID_0); + if (intf_id.interface_type == TPM_CRB_INTF_ACTIVE) + t->intf = TPM_CRB; +} + +struct tpm *enable_tpm(void) +{ + struct tpm *t = &tpm; + + find_interface_and_family(t); + + switch (t->intf) { + case TPM_TIS: + if (!tis_init(t)) + return NULL; + break; + case TPM_CRB: + if (!crb_init(t)) + return NULL; + break; + } + + return t; +} + +u8 tpm_request_locality(struct tpm *t, u8 l) +{ + u8 ret = TPM_NO_LOCALITY; + + ret = t->ops.request_locality(l); + + if (ret < TPM_MAX_LOCALITY) + t->buff = alloc_tpmbuff(t->intf, ret); + + return ret; +} + +void tpm_relinquish_locality(struct tpm *t) +{ + t->ops.relinquish_locality(); + + free_tpmbuff(t->buff, t->intf); +} + +#define MAX_TPM_EXTEND_SIZE 70 /* TPM2 SHA512 is the largest */ +int tpm_extend_pcr(struct tpm *t, u32 pcr, u16 algo, + u8 *digest) +{ + int ret = 0; + + if (t->buff == NULL) + return -EINVAL; + + if (t->family == TPM12) { + struct tpm_digest d; + + if (algo != TPM_ALG_SHA1) + return -EINVAL; + + d.pcr = pcr; + memcpy((void *)d.digest.sha1.digest, + digest, SHA1_DIGEST_SIZE); + + ret = tpm1_pcr_extend(t, &d); + } else if (t->family == TPM20) { + struct tpml_digest_values *d; + u8 buf[MAX_TPM_EXTEND_SIZE]; + + d = (struct tpml_digest_values *) buf; + d->count = 1; + d->digests->alg = algo; + switch (algo) { + case TPM_ALG_SHA1: + memcpy(d->digests->digest, digest, SHA1_SIZE); + break; + case TPM_ALG_SHA256: + memcpy(d->digests->digest, digest, SHA256_SIZE); + break; + case TPM_ALG_SHA384: + memcpy(d->digests->digest, digest, SHA384_SIZE); + break; + case TPM_ALG_SHA512: + memcpy(d->digests->digest, digest, SHA512_SIZE); + break; + case TPM_ALG_SM3_256: + memcpy(d->digests->digest, digest, SM3256_SIZE); + break; + default: + return -EINVAL; + } + + ret = tpm2_extend_pcr(t, pcr, d); + } else + ret = -EINVAL; + + return ret; +} + +void free_tpm(struct tpm *t) +{ + tpm_relinquish_locality(t); +} From patchwork Thu Sep 24 14:58:35 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ross Philipson X-Patchwork-Id: 11797647 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 439D16CA for ; Thu, 24 Sep 2020 14:59:17 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id F33BD23787 for ; Thu, 24 Sep 2020 14:59:16 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=oracle.com header.i=@oracle.com header.b="W6+yNm5y" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728503AbgIXO7Q (ORCPT ); Thu, 24 Sep 2020 10:59:16 -0400 Received: from userp2120.oracle.com ([156.151.31.85]:48090 "EHLO userp2120.oracle.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728399AbgIXO6j (ORCPT ); Thu, 24 Sep 2020 10:58:39 -0400 Received: from pps.filterd (userp2120.oracle.com [127.0.0.1]) by userp2120.oracle.com (8.16.0.42/8.16.0.42) with SMTP id 08OEsmD7071825; Thu, 24 Sep 2020 14:58:18 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=from : to : cc : subject : date : message-id : in-reply-to : references; s=corp-2020-01-29; bh=C5MbyzBg6BPfwBGwswcqD+xcwRSEH1xE70etsgV+vlw=; b=W6+yNm5y2L9RtyvbgNfiJ+S/eZmgA25mpQJ9ESEB2AYRM0AcvQDEmOeOKASeEWBYWB3X YBTr12BzQFegWs6rUgp2mVGW/x9ODeJy8x5kdxOGPS/Z1a+M+On3Ik0L7avUoz7BGrSB /uCrZBGy92qEBvgSqlBhMLtoAHqFT/pnmR0XqGD6pjZSNBaADFcR8qqjx05W3vxOZOiD l+2wwal4sgK8umE0/2FhLIIqiKkmKcRkiG2mLkcPM5pCyADrgblYTW7WBJV3a070YXJE zkXWa10OktoIWFM/38p8DxpVKcXIuKFz+7do6jHcJuOqF4cefv3jccBxPzXCYIJSPko0 wg== Received: from userp3020.oracle.com (userp3020.oracle.com [156.151.31.79]) by userp2120.oracle.com with ESMTP id 33ndnurum9-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Thu, 24 Sep 2020 14:58:18 +0000 Received: from pps.filterd (userp3020.oracle.com [127.0.0.1]) by userp3020.oracle.com (8.16.0.42/8.16.0.42) with SMTP id 08OEuT1G096338; Thu, 24 Sep 2020 14:58:18 GMT Received: from userv0122.oracle.com (userv0122.oracle.com [156.151.31.75]) by userp3020.oracle.com with ESMTP id 33nurw9x5m-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 24 Sep 2020 14:58:17 +0000 Received: from abhmp0014.oracle.com (abhmp0014.oracle.com [141.146.116.20]) by userv0122.oracle.com (8.14.4/8.14.4) with ESMTP id 08OEwDpZ016156; Thu, 24 Sep 2020 14:58:14 GMT Received: from disposition.us.oracle.com (/10.152.32.81) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Thu, 24 Sep 2020 07:58:13 -0700 From: Ross Philipson To: linux-kernel@vger.kernel.org, x86@kernel.org, iommu@lists.linux-foundation.org, linux-integrity@vger.kernel.org, linux-doc@vger.kernel.org Cc: ross.philipson@oracle.com, dpsmith@apertussolutions.com, tglx@linutronix.de, mingo@redhat.com, bp@alien8.de, hpa@zytor.com, luto@amacapital.net, trenchboot-devel@googlegroups.com Subject: [PATCH 07/13] x86: Secure Launch kernel early boot stub Date: Thu, 24 Sep 2020 10:58:35 -0400 Message-Id: <1600959521-24158-8-git-send-email-ross.philipson@oracle.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1600959521-24158-1-git-send-email-ross.philipson@oracle.com> References: <1600959521-24158-1-git-send-email-ross.philipson@oracle.com> X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9753 signatures=668680 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 adultscore=0 malwarescore=0 phishscore=0 mlxlogscore=999 bulkscore=0 mlxscore=0 suspectscore=2 spamscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2006250000 definitions=main-2009240114 X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9753 signatures=668680 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 priorityscore=1501 malwarescore=0 lowpriorityscore=0 phishscore=0 adultscore=0 suspectscore=2 bulkscore=0 clxscore=1015 impostorscore=0 mlxlogscore=999 mlxscore=0 spamscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2006250000 definitions=main-2009240114 Precedence: bulk List-ID: X-Mailing-List: linux-integrity@vger.kernel.org The Secure Launch (SL) stub provides the entry point for Intel TXT (and later AMD SKINIT) to vector to during the late launch. The symbol sl_stub_entry is that entry point and its offset into the kernel is conveyed to the launching code using the MLE (Measured Launch Environment) header in the structure named mle_header. The offset of the MLE header is set in the kernel_info. The routine sl_stub contains the very early late launch setup code responsible for setting up the basic environment to allow the normal kernel startup_32 code to proceed. It is also responsible for properly waking and handling the APs on Intel platforms. The routine sl_main which runs after entering 64b mode is responsible for measuring configuration and module information before it is used like the boot params, the kernel command line, the TXT heap, an external initramfs, etc. Signed-off-by: Ross Philipson --- Documentation/x86/boot.rst | 9 + arch/x86/boot/compressed/Makefile | 1 + arch/x86/boot/compressed/head_64.S | 34 ++ arch/x86/boot/compressed/kernel_info.S | 7 + arch/x86/boot/compressed/sl_main.c | 390 +++++++++++++++++++++ arch/x86/boot/compressed/sl_stub.S | 606 +++++++++++++++++++++++++++++++++ arch/x86/kernel/asm-offsets.c | 16 + 7 files changed, 1063 insertions(+) create mode 100644 arch/x86/boot/compressed/sl_main.c create mode 100644 arch/x86/boot/compressed/sl_stub.S diff --git a/Documentation/x86/boot.rst b/Documentation/x86/boot.rst index 7fafc7a..7232801 100644 --- a/Documentation/x86/boot.rst +++ b/Documentation/x86/boot.rst @@ -1026,6 +1026,15 @@ Offset/size: 0x000c/4 This field contains maximal allowed type for setup_data and setup_indirect structs. +============ ================= +Field name: mle_header_offset +Offset/size: 0x0010/4 +============ ================= + + This field contains the offset to the Secure Launch Measured Launch Environment + (MLE) header. This offset is used to locate information needed during a secure + late launch using Intel TXT and AMD SKINIT. + The Image Checksum ================== diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index 35947b9..d881ff7 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile @@ -102,6 +102,7 @@ vmlinux-objs-$(CONFIG_SECURE_LAUNCH_SHA512) += $(obj)/early_sha512.o vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/tpm/tpmio.o $(obj)/tpm/tpm_buff.o \ $(obj)/tpm/tis.o $(obj)/tpm/crb.o $(obj)/tpm/tpm1_cmds.o \ $(obj)/tpm/tpm2_cmds.o $(obj)/tpm/tpm2_auth.o $(obj)/tpm/tpm.o +vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/sl_main.o $(obj)/sl_stub.o # The compressed kernel is built with -fPIC/-fPIE so that a boot loader # can place it anywhere in memory and it will still run. However, since diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S index 97d37f0..42043bf 100644 --- a/arch/x86/boot/compressed/head_64.S +++ b/arch/x86/boot/compressed/head_64.S @@ -279,6 +279,21 @@ SYM_INNER_LABEL(efi32_pe_stub_entry, SYM_L_LOCAL) SYM_FUNC_END(efi32_stub_entry) #endif +#ifdef CONFIG_SECURE_LAUNCH +SYM_FUNC_START(sl_stub_entry) + /* + * On entry, %ebx has the entry abs offset to sl_stub_entry. To + * find the beginning of where we are loaded, sub off from the + * beginning. + */ + leal (startup_32 - sl_stub_entry)(%ebx), %ebx + + /* More room to work in sl_stub in the text section */ + jmp sl_stub + +SYM_FUNC_END(sl_stub_entry) +#endif + .code64 .org 0x200 SYM_CODE_START(startup_64) @@ -537,6 +552,25 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated) shrq $3, %rcx rep stosq +#ifdef CONFIG_SECURE_LAUNCH + /* + * Have to do the final early sl stub work in 64b area. + * + * *********** NOTE *********** + * + * Several boot params get used before we get a chance to measure + * them in this call. This is a known issue and we currently don't + * have a solution. The scratch field doesn't matter and loadflags + * have KEEP_SEGMENTS set by the stub code. There is no obvious way + * to do anything about the use of kernel_alignment or init_size + * though these seem low risk. + */ + pushq %rsi + movq %rsi, %rdi + callq sl_main + popq %rsi +#endif + /* * Do the extraction, and jump to the new kernel.. */ diff --git a/arch/x86/boot/compressed/kernel_info.S b/arch/x86/boot/compressed/kernel_info.S index f818ee8..192d557 100644 --- a/arch/x86/boot/compressed/kernel_info.S +++ b/arch/x86/boot/compressed/kernel_info.S @@ -17,6 +17,13 @@ kernel_info: /* Maximal allowed type for setup_data and setup_indirect structs. */ .long SETUP_TYPE_MAX + /* Offset to the MLE header structure */ +#ifdef CONFIG_SECURE_LAUNCH + .long mle_header +#else + .long 0 +#endif + kernel_info_var_len_data: /* Empty for time being... */ kernel_info_end: diff --git a/arch/x86/boot/compressed/sl_main.c b/arch/x86/boot/compressed/sl_main.c new file mode 100644 index 0000000..09ec92d --- /dev/null +++ b/arch/x86/boot/compressed/sl_main.c @@ -0,0 +1,390 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Secure Launch early measurement and validation routines. + * + * Copyright (c) 2020, Oracle and/or its affiliates. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_SECURE_LAUNCH_SHA256 +#include +#endif +#ifdef CONFIG_SECURE_LAUNCH_SHA512 +#include +#endif + +#include "early_sha1.h" +#include "tpm/tpm_common.h" +#include "tpm/tpm2_constants.h" +#include "tpm/tpm.h" + +#define CAPS_VARIABLE_MTRR_COUNT_MASK 0xff + +#define SL_MAX_EVENT_DATA 64 +#define SL_TPM12_LOG_SIZE (sizeof(struct tpm12_pcr_event) + \ + SL_MAX_EVENT_DATA) +#define SL_TPM20_LOG_SIZE (sizeof(struct tpm20_ha) + \ + SHA512_SIZE + \ + sizeof(struct tpm20_digest_values) + \ + sizeof(struct tpm20_pcr_event_head) + \ + sizeof(struct tpm20_pcr_event_tail) + \ + SL_MAX_EVENT_DATA) + +static void *evtlog_base; +static struct txt_heap_event_log_pointer2_1_element *log20_elem; + +extern u32 sl_cpu_type; + +static u64 sl_txt_read(u32 reg) +{ + return readq((void *)(u64)(TXT_PRIV_CONFIG_REGS_BASE + reg)); +} + +static void sl_txt_write(u32 reg, u64 val) +{ + writeq(val, (void *)(u64)(TXT_PRIV_CONFIG_REGS_BASE + reg)); +} + +static void __noreturn sl_txt_reset(u64 error) +{ + /* Reading the E2STS register acts as a barrier for TXT registers */ + sl_txt_write(TXT_CR_ERRORCODE, error); + sl_txt_read(TXT_CR_E2STS); + sl_txt_write(TXT_CR_CMD_UNLOCK_MEM_CONFIG, 1); + sl_txt_read(TXT_CR_E2STS); + sl_txt_write(TXT_CR_CMD_RESET, 1); + + for ( ; ; ) + asm volatile ("hlt"); + + unreachable(); +} + +static u64 sl_rdmsr(u32 reg) +{ + u64 lo, hi; + + asm volatile ("rdmsr" : "=a" (lo), "=d" (hi) : "c" (reg)); + + return (hi << 32) | lo; +} + +/* + * Some MSRs are modified by the pre-launch code including the MTRRs. + * The early MLE code has to restore these values. This code validates + * the values after they are measured. + */ +static void sl_txt_validate_msrs(struct txt_os_mle_data *os_mle_data) +{ + u64 mtrr_caps, mtrr_def_type, mtrr_var, misc_en_msr; + u32 vcnt, i; + struct txt_mtrr_state *saved_bsp_mtrrs = + &(os_mle_data->saved_bsp_mtrrs); + + mtrr_caps = sl_rdmsr(MSR_MTRRcap); + vcnt = (u32)(mtrr_caps & CAPS_VARIABLE_MTRR_COUNT_MASK); + + if (saved_bsp_mtrrs->mtrr_vcnt > vcnt) + sl_txt_reset(SL_ERROR_MTRR_INV_VCNT); + if (saved_bsp_mtrrs->mtrr_vcnt > TXT_OS_MLE_MAX_VARIABLE_MTRRS) + sl_txt_reset(SL_ERROR_MTRR_INV_VCNT); + + mtrr_def_type = sl_rdmsr(MSR_MTRRdefType); + if (saved_bsp_mtrrs->default_mem_type != mtrr_def_type) + sl_txt_reset(SL_ERROR_MTRR_INV_DEF_TYPE); + + for (i = 0; i < saved_bsp_mtrrs->mtrr_vcnt; i++) { + mtrr_var = sl_rdmsr(MTRRphysBase_MSR(i)); + if (saved_bsp_mtrrs->mtrr_pair[i].mtrr_physbase != mtrr_var) + sl_txt_reset(SL_ERROR_MTRR_INV_BASE); + mtrr_var = sl_rdmsr(MTRRphysMask_MSR(i)); + if (saved_bsp_mtrrs->mtrr_pair[i].mtrr_physmask != mtrr_var) + sl_txt_reset(SL_ERROR_MTRR_INV_MASK); + } + + misc_en_msr = sl_rdmsr(MSR_IA32_MISC_ENABLE); + if (os_mle_data->saved_misc_enable_msr != misc_en_msr) + sl_txt_reset(SL_ERROR_MSR_INV_MISC_EN); +} + +static void sl_find_event_log(struct tpm *tpm) +{ + struct txt_os_mle_data *os_mle_data; + void *os_sinit_data; + void *txt_heap; + + txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE); + + os_mle_data = txt_os_mle_data_start(txt_heap); + evtlog_base = (void *)os_mle_data->evtlog_addr; + + if (tpm->family != TPM20) + return; + + /* + * For TPM 2.0, the event log 2.1 extended data structure has to also + * be located and fixed up. + */ + os_sinit_data = txt_os_sinit_data_start(txt_heap); + + /* Find the TPM2.0 logging extended heap element */ + log20_elem = tpm20_find_log2_1_element(os_sinit_data); + + if (!log20_elem) + sl_txt_reset(SL_ERROR_TPM_INVALID_LOG20); +} + +static void sl_tpm12_log_event(u32 pcr, u8 *digest, + const u8 *event_data, u32 event_size) +{ + struct tpm12_pcr_event *pcr_event; + u32 total_size; + u8 log_buf[SL_TPM12_LOG_SIZE] = {0}; + + pcr_event = (struct tpm12_pcr_event *)log_buf; + pcr_event->pcr_index = pcr; + pcr_event->type = TXT_EVTYPE_SLAUNCH; + memcpy(&pcr_event->digest[0], digest, SHA1_SIZE); + pcr_event->size = event_size; + memcpy((u8 *)pcr_event + sizeof(struct tpm12_pcr_event), + event_data, event_size); + + total_size = sizeof(struct tpm12_pcr_event) + event_size; + + if (tpm12_log_event(evtlog_base, total_size, pcr_event)) + sl_txt_reset(SL_ERROR_TPM_LOGGING_FAILED); +} + +static void sl_tpm20_log_event(u32 pcr, u8 *digest, u16 algo, + const u8 *event_data, u32 event_size) +{ + struct tpm20_pcr_event_head *head; + struct tpm20_digest_values *dvs; + struct tpm20_ha *ha; + struct tpm20_pcr_event_tail *tail; + u8 *dptr; + u32 total_size; + u8 log_buf[SL_TPM20_LOG_SIZE] = {0}; + + head = (struct tpm20_pcr_event_head *)log_buf; + head->pcr_index = pcr; + head->event_type = TXT_EVTYPE_SLAUNCH; + dvs = (struct tpm20_digest_values *) + ((u8 *)head + sizeof(struct tpm20_pcr_event_head)); + dvs->count = 1; + ha = (struct tpm20_ha *) + ((u8 *)dvs + sizeof(struct tpm20_digest_values)); + ha->algorithm_id = algo; + dptr = (u8 *)ha + sizeof(struct tpm20_ha); + + switch (algo) { + case TPM_ALG_SHA512: + memcpy(dptr, digest, SHA512_SIZE); + tail = (struct tpm20_pcr_event_tail *) + (dptr + SHA512_SIZE); + break; + case TPM_ALG_SHA256: + memcpy(dptr, digest, SHA256_SIZE); + tail = (struct tpm20_pcr_event_tail *) + (dptr + SHA256_SIZE); + break; + case TPM_ALG_SHA1: + default: + memcpy(dptr, digest, SHA1_SIZE); + tail = (struct tpm20_pcr_event_tail *) + (dptr + SHA1_SIZE); + }; + + tail->event_size = event_size; + memcpy((u8 *)tail + sizeof(struct tpm20_pcr_event_tail), + event_data, event_size); + + total_size = (u32)((u8 *)tail - (u8 *)head) + + sizeof(struct tpm20_pcr_event_tail) + event_size; + + if (tpm20_log_event(log20_elem, evtlog_base, total_size, &log_buf[0])) + sl_txt_reset(SL_ERROR_TPM_LOGGING_FAILED); +} + +void sl_tpm_extend_pcr(struct tpm *tpm, u32 pcr, const u8 *data, u32 length, + const char *desc) +{ + struct sha1_state sctx = {0}; + u8 sha1_hash[SHA1_SIZE] = {0}; + int ret; + + if (tpm->family == TPM20) { +#ifdef CONFIG_SECURE_LAUNCH_SHA256 + struct sha256_state sctx = {0}; + u8 sha256_hash[SHA256_SIZE] = {0}; + + sha256_init(&sctx); + sha256_update(&sctx, data, length); + sha256_final(&sctx, &sha256_hash[0]); + ret = tpm_extend_pcr(tpm, pcr, TPM_ALG_SHA256, &sha256_hash[0]); + if (!ret) { + sl_tpm20_log_event(pcr, &sha256_hash[0], + TPM_ALG_SHA256, + (const u8 *)desc, strlen(desc)); + return; + } else + sl_txt_reset(SL_ERROR_TPM_EXTEND); +#endif +#ifdef CONFIG_SECURE_LAUNCH_SHA512 + struct sha512_state sctx = {0}; + u8 sha512_hash[SHA512_SIZE] = {0}; + + sha512_init(&sctx); + sha512_update(&sctx, data, length); + sha512_final(&sctx, &sha512_hash[0]); + ret = tpm_extend_pcr(tpm, pcr, TPM_ALG_SHA512, &sha512_hash[0]); + if (!ret) { + sl_tpm20_log_event(pcr, &sha512_hash[0], + TPM_ALG_SHA512, + (const u8 *)desc, strlen(desc)); + return; + } else + sl_txt_reset(SL_ERROR_TPM_EXTEND); +#endif + } + + early_sha1_init(&sctx); + early_sha1_update(&sctx, data, length); + early_sha1_final(&sctx, &sha1_hash[0]); + ret = tpm_extend_pcr(tpm, pcr, TPM_ALG_SHA1, &sha1_hash[0]); + if (ret) + sl_txt_reset(SL_ERROR_TPM_EXTEND); + + if (tpm->family == TPM20) + sl_tpm20_log_event(pcr, &sha1_hash[0], TPM_ALG_SHA1, + (const u8 *)desc, strlen(desc)); + else + sl_tpm12_log_event(pcr, &sha1_hash[0], + (const u8 *)desc, strlen(desc)); +} + +void sl_main(u8 *bootparams) +{ + struct tpm *tpm; + struct boot_params *bp; + struct setup_data *data; + struct txt_os_mle_data *os_mle_data; + struct txt_os_mle_data os_mle_tmp = {0}; + const char *signature; + unsigned long mmap = 0; + void *txt_heap; + u32 data_count; + + /* + * Currently only Intel TXT is supported for Secure Launch. Testing + * this value also indicates that the kernel was booted successfully + * through the Secure Launch entry point and is in SMX mode. + */ + if (!(sl_cpu_type & SL_CPU_INTEL)) + return; + + /* + * If enable_tpm fails there is no point going on. The entire secure + * environment depends on this and the other TPM operations succeeding. + */ + tpm = enable_tpm(); + if (!tpm) + sl_txt_reset(SL_ERROR_TPM_INIT); + + /* Locate the TPM event log. */ + sl_find_event_log(tpm); + + /* + * Locality 2 is being opened so that the DRTM PCRs can be updated, + * specifically 17 and 18. + */ + if (tpm_request_locality(tpm, 2) == TPM_NO_LOCALITY) + sl_txt_reset(SL_ERROR_TPM_GET_LOC); + + /* Measure the zero page/boot params */ + sl_tpm_extend_pcr(tpm, SL_CONFIG_PCR18, bootparams, PAGE_SIZE, + "Measured boot parameters into PCR18"); + + /* Now safe to use boot params */ + bp = (struct boot_params *)bootparams; + + /* Measure the command line */ + sl_tpm_extend_pcr(tpm, SL_CONFIG_PCR18, + (u8 *)((unsigned long)bp->hdr.cmd_line_ptr), + bp->hdr.cmdline_size, + "Measured Kernel command line into PCR18"); + + /* + * Measuring the boot params measured the fixed e820 memory map. + * Measure any setup_data entries including e820 extended entries. + */ + data = (struct setup_data *)(unsigned long)bp->hdr.setup_data; + while (data) { + sl_tpm_extend_pcr(tpm, SL_CONFIG_PCR18, + ((u8 *)data) + sizeof(struct setup_data), + data->len, + "Measured Kernel setup_data into PCR18"); + + data = (struct setup_data *)(unsigned long)data->next; + } + + /* If bootloader was EFI, measure the memory map passed across */ + signature = + (const char *)&bp->efi_info.efi_loader_signature; + + if (!strncmp(signature, EFI32_LOADER_SIGNATURE, 4)) + mmap = bp->efi_info.efi_memmap; + else if (!strncmp(signature, EFI64_LOADER_SIGNATURE, 4)) + mmap = (bp->efi_info.efi_memmap | + ((u64)bp->efi_info.efi_memmap_hi << 32)); + + if (mmap) + sl_tpm_extend_pcr(tpm, SL_CONFIG_PCR18, (void *)mmap, + bp->efi_info.efi_memmap_size, + "Measured EFI memory map into PCR18"); + + /* Measure any external initrd */ + if (bp->hdr.ramdisk_image != 0 && bp->hdr.ramdisk_size != 0) + sl_tpm_extend_pcr(tpm, SL_IMAGE_PCR17, + (u8 *)((u64)bp->hdr.ramdisk_image), + bp->hdr.ramdisk_size, + "Measured initramfs into PCR17"); + + /* + * Some extra work to do on Intel, have to measure the OS-MLE + * heap area. + */ + txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE); + os_mle_data = txt_os_mle_data_start(txt_heap); + + /* Measure only portions of OS-MLE data, not addresses/sizes etc. */ + os_mle_tmp.version = os_mle_data->version; + os_mle_tmp.saved_misc_enable_msr = os_mle_data->saved_misc_enable_msr; + os_mle_tmp.saved_bsp_mtrrs = os_mle_data->saved_bsp_mtrrs; + + sl_tpm_extend_pcr(tpm, SL_CONFIG_PCR18, (u8 *)&os_mle_tmp, + sizeof(struct txt_os_mle_data), + "Measured TXT OS-MLE data into PCR18"); + + /* + * Now that the OS-MLE data is measured, ensure the MTRR and + * misc enable MSRs are what we expect. + */ + sl_txt_validate_msrs(os_mle_data); + + tpm_relinquish_locality(tpm); + free_tpm(tpm); +} diff --git a/arch/x86/boot/compressed/sl_stub.S b/arch/x86/boot/compressed/sl_stub.S new file mode 100644 index 0000000..a1e7c13 --- /dev/null +++ b/arch/x86/boot/compressed/sl_stub.S @@ -0,0 +1,606 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * Secure Launch protected mode entry point. + * + * Copyright (c) 2020, Oracle and/or its affiliates. + */ + .code32 + .text +#include +#include +#include +#include +#include +#include +#include +#include + +/* Can't include apiddef.h in asm */ +#define XAPIC_ENABLE (1 << 11) +#define X2APIC_ENABLE (1 << 10) + +/* Can't include traps.h in asm */ +#define X86_TRAP_NMI 2 + +/* Can't include mtrr.h in asm */ +#define MTRRphysBase0 0x200 + +#define IDT_VECTOR_LO_BITS 0 +#define IDT_VECTOR_HI_BITS 6 + +/* + * The GETSEC op code is open coded because older versions of + * GCC do not support the getsec mnemonic. + */ +.macro GETSEC leaf + pushl %ebx + xorl %ebx, %ebx /* Must be zero for SMCTRL */ + movl \leaf, %eax /* Leaf function */ + .byte 0x0f, 0x37 /* GETSEC opcode */ + popl %ebx +.endm + +.macro TXT_RESET error + /* + * Set a sticky error value and reset. Note the movs to %eax act as + * TXT register barriers. + */ + movl \error, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_ERRORCODE) + movl (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_E2STS), %eax + movl $1, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_CMD_NO_SECRETS) + movl (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_E2STS), %eax + movl $1, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_CMD_UNLOCK_MEM_CONFIG) + movl (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_E2STS), %eax + movl $1, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_CMD_RESET) +1: + hlt + jmp 1b +.endm + + /* + * The MLE Header per the TXT Specification, section 2.1 + * MLE capabilities, see table 4. Capabilities set: + * bit 0: Support for GETSEC[WAKEUP] for RLP wakeup + * bit 1: Support for RLP wakeup using MONITOR address + * bit 5: TPM 1.2 family: Details/authorities PCR usage support + * bit 9: Supported format of TPM 2.0 event log - TCG compliant + */ +SYM_DATA_START(mle_header) + .long 0x9082ac5a /* UUID0 */ + .long 0x74a7476f /* UUID1 */ + .long 0xa2555c0f /* UUID2 */ + .long 0x42b651cb /* UUID3 */ + .long 0x00000034 /* MLE header size */ + .long 0x00020002 /* MLE version 2.2 */ + .long sl_stub_entry /* Linear entry point of MLE (virt. address) */ + .long 0x00000000 /* First valid page of MLE */ + .long 0x00000000 /* Offset within binary of first byte of MLE */ + .long 0x00000000 /* Offset within binary of last byte + 1 of MLE */ + .long 0x00000223 /* Bit vector of MLE-supported capabilities */ + .long 0x00000000 /* Starting linear address of command line (unused) */ + .long 0x00000000 /* Ending linear address of command line (unused) */ +SYM_DATA_END(mle_header) + + .code32 +SYM_FUNC_START(sl_stub) + /* + * On entry, %ebx has the base address from head_64.S + * and only %cs and %ds segments are known good. + */ + cli + cld + + /* Load GDT, set segment regs and lret to __SL32_CS */ + addl %ebx, (sl_gdt_desc + 2)(%ebx) + lgdt sl_gdt_desc(%ebx) + + movl $(__SL32_DS), %eax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + movw %ax, %ss + + /* + * Now that %ss us known good, take the first stack for the BSP. The + * AP stacks are only used on Intel. + */ + leal sl_stacks_end(%ebx), %esp + + leal .Lsl_cs(%ebx), %eax + pushl $(__SL32_CS) + pushl %eax + lret + +.Lsl_cs: + /* Save our base pointer reg */ + pushl %ebx + + /* Now see if it is GenuineIntel. CPUID 0 returns the manufacturer */ + xorl %eax, %eax + cpuid + cmpl $(INTEL_CPUID_MFGID_EBX), %ebx + jnz .Ldo_unknown_cpu + cmpl $(INTEL_CPUID_MFGID_EDX), %edx + jnz .Ldo_unknown_cpu + cmpl $(INTEL_CPUID_MFGID_ECX), %ecx + jnz .Ldo_unknown_cpu + + popl %ebx + + /* Know it is Intel */ + movl $(SL_CPU_INTEL), sl_cpu_type(%ebx) + + /* Increment CPU count for BSP */ + incl sl_txt_cpu_count(%ebx) + + /* Enable SMI with GETSEC[SMCTRL] */ + GETSEC $(SMX_X86_GETSEC_SMCTRL) + + /* IRET-to-self can be used to enable NMIs which SENTER disabled */ + leal .Lnmi_enabled(%ebx), %eax + pushfl + pushl $(__SL32_CS) + pushl %eax + iret + +.Lnmi_enabled: + /* Clear the TXT error registers for a clean start of day */ + movl $0, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_ERRORCODE) + movl $0xffffffff, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_ESTS) + + /* On Intel, the zero page address is passed in the TXT heap */ + /* Read physical base of heap into EAX */ + movl (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_HEAP_BASE), %eax + /* Read the size of the BIOS data into ECX (first 8 bytes) */ + movl (%eax), %ecx + /* Skip over BIOS data and size of OS to MLE data section */ + leal 8(%eax, %ecx), %eax + + /* Check that the AP wake block is big enough */ + cmpl $(sl_txt_ap_wake_end - sl_txt_ap_wake_begin), \ + SL_ap_wake_block_size(%eax) + jae .Lwake_block_ok + TXT_RESET $(SL_ERROR_WAKE_BLOCK_TOO_SMALL) + +.Lwake_block_ok: + /* + * Get the boot params address from the heap. Note %esi and %ebx MUST + * be preserved across calls and operations. + */ + movl SL_boot_params_addr(%eax), %esi + + /* Save %ebx so the APs can find their way home */ + movl %ebx, (SL_mle_scratch + SL_SCRATCH_AP_EBX)(%eax) + + /* Fetch the AP wake code block address from the heap */ + movl SL_ap_wake_block(%eax), %edi + movl %edi, sl_txt_ap_wake_block(%ebx) + + /* Store the offset in the AP wake block to the jmp address */ + movl $(sl_ap_jmp_offset - sl_txt_ap_wake_begin), \ + (SL_mle_scratch + SL_SCRATCH_AP_JMP_OFFSET)(%eax) + + /* %eax still is the base of the OS-MLE block, save it */ + pushl %eax + + /* Relocate the AP wake code to the safe block */ + call sl_txt_reloc_ap_wake + + /* + * Wake up all APs that are blocked in the ACM and wait for them to + * halt. This should be done before restoring the MTRRs so the ACM is + * still properly in WB memory. + */ + call sl_txt_wake_aps + + /* + * Pop OS-MLE base address (was in %eax above) for call to load + * MTRRs/MISC MSR + */ + popl %edi + call sl_txt_load_regs + + jmp .Lcpu_setup_done + +.Ldo_unknown_cpu: + /* Non-Intel CPUs are not yet supported */ + ud2 + +.Lcpu_setup_done: + /* + * Don't enable MCE at this point. The kernel will enable + * it on the BSP later when it is ready. + */ + + /* Keep SL segments for the early portion of the kernel boot */ + orb $(KEEP_SEGMENTS), BP_loadflags(%esi) + + /* Done, jump to normal 32b pm entry */ + jmp startup_32 +SYM_FUNC_END(sl_stub) + +SYM_FUNC_START(sl_txt_ap_entry) + cli + cld + /* + * The %cs and %ds segments are known good after waking the AP. + * First order of business is to find where we are and + * save it in %ebx. + */ + + /* Read physical base of heap into EAX */ + movl (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_HEAP_BASE), %eax + /* Read the size of the BIOS data into ECX (first 8 bytes) */ + movl (%eax), %ecx + /* Skip over BIOS data and size of OS to MLE data section */ + leal 8(%eax, %ecx), %eax + + /* Saved %ebx from the BSP and stash OS-MLE pointer */ + movl (SL_mle_scratch + SL_SCRATCH_AP_EBX)(%eax), %ebx + /* Save OS-MLE base in %edi for call to sl_txt_load_regs */ + movl %eax, %edi + + /* Lock and get our stack index */ + movl $1, %ecx +.Lspin: + xorl %eax, %eax + lock cmpxchgl %ecx, sl_txt_spin_lock(%ebx) + pause + jnz .Lspin + + /* Increment the stack index and use the next value inside lock */ + incl sl_txt_stack_index(%ebx) + movl sl_txt_stack_index(%ebx), %eax + + /* Unlock */ + movl $0, sl_txt_spin_lock(%ebx) + + /* Location of the relocated AP wake block */ + movl sl_txt_ap_wake_block(%ebx), %ecx + + /* Load reloc GDT, set segment regs and lret to __SL32_CS */ + lgdt (sl_ap_gdt_desc - sl_txt_ap_wake_begin)(%ecx) + + movl $(__SL32_DS), %edx + movw %dx, %ds + movw %dx, %es + movw %dx, %fs + movw %dx, %gs + movw %dx, %ss + + /* Load our reloc AP stack */ + movl $(TXT_BOOT_STACK_SIZE), %edx + mull %edx + leal (sl_stacks_end - sl_txt_ap_wake_begin)(%ecx), %esp + subl %eax, %esp + + /* Switch to AP code segment */ + leal .Lsl_ap_cs(%ebx), %eax + pushl $(__SL32_CS) + pushl %eax + lret + +.Lsl_ap_cs: + /* Load the relocated AP IDT */ + lidt (sl_ap_idt_desc - sl_txt_ap_wake_begin)(%ecx) + + /* Fixup MTRRs and misc enable MSR on APs too */ + call sl_txt_load_regs + + /* Enable SMI with GETSEC[SMCTRL] */ + GETSEC $(SMX_X86_GETSEC_SMCTRL) + + /* IRET-to-self can be used to enable NMIs which SENTER disabled */ + leal .Lnmi_enabled_ap(%ebx), %eax + pushfl + pushl $(__SL32_CS) + pushl %eax + iret + +.Lnmi_enabled_ap: + /* Put APs in X2APIC mode like the BSP */ + movl $(MSR_IA32_APICBASE), %ecx + rdmsr + orl $(XAPIC_ENABLE | X2APIC_ENABLE), %eax + wrmsr + + /* + * Basically done, increment the CPU count and jump off to the AP + * wake block to wait. + */ + lock incl sl_txt_cpu_count(%ebx) + + movl sl_txt_ap_wake_block(%ebx), %eax + jmp *%eax +SYM_FUNC_END(sl_txt_ap_entry) + +SYM_FUNC_START(sl_txt_reloc_ap_wake) + /* Save boot params register */ + pushl %esi + + movl sl_txt_ap_wake_block(%ebx), %edi + + /* Fixup AP IDT and GDT descriptor before relocating */ + addl %edi, (sl_ap_idt_desc + 2)(%ebx) + addl %edi, (sl_ap_gdt_desc + 2)(%ebx) + + /* + * Copy the AP wake code and AP GDT/IDT to the protected wake block + * provided by the loader. Destination already in %edi. + */ + movl $(sl_txt_ap_wake_end - sl_txt_ap_wake_begin), %ecx + leal sl_txt_ap_wake_begin(%ebx), %esi + rep movsb + + /* Setup the IDT for the APs to use in the relocation block */ + movl sl_txt_ap_wake_block(%ebx), %ecx + addl $(sl_ap_idt - sl_txt_ap_wake_begin), %ecx + xorl %edx, %edx + + /* Form the default reset vector relocation address */ + movl sl_txt_ap_wake_block(%ebx), %esi + addl $(sl_txt_int_reset - sl_txt_ap_wake_begin), %esi + +1: + cmpw $(NR_VECTORS), %dx + jz .Lap_idt_done + + cmpw $(X86_TRAP_NMI), %dx + jz 2f + + /* Load all other fixed vectors with reset handler */ + movl %esi, %eax + movw %ax, (IDT_VECTOR_LO_BITS)(%ecx) + shrl $16, %eax + movw %ax, (IDT_VECTOR_HI_BITS)(%ecx) + jmp 3f + +2: + /* Load single wake NMI IPI vector at the relocation address */ + movl sl_txt_ap_wake_block(%ebx), %eax + addl $(sl_txt_int_ipi_wake - sl_txt_ap_wake_begin), %eax + movw %ax, (IDT_VECTOR_LO_BITS)(%ecx) + shrl $16, %eax + movw %ax, (IDT_VECTOR_HI_BITS)(%ecx) + +3: + incw %dx + addl $8, %ecx + jmp 1b + +.Lap_idt_done: + popl %esi + ret +SYM_FUNC_END(sl_txt_reloc_ap_wake) + +SYM_FUNC_START(sl_txt_load_regs) + /* Save base pointer register */ + pushl %ebx + + /* + * On Intel, the original variable MTRRs and Misc Enable MSR are + * restored on the BSP at early boot. Each AP will also restore + * its MTRRs and Misc Enable MSR. + */ + pushl %edi + addl $(SL_saved_bsp_mtrrs), %edi + movl (%edi), %ebx + pushl %ebx /* default_mem_type lo */ + addl $4, %edi + movl (%edi), %ebx + pushl %ebx /* default_mem_type hi */ + addl $4, %edi + movl (%edi), %ebx /* mtrr_vcnt lo, don't care about hi part */ + addl $8, %edi /* now at MTRR pair array */ + /* Write the variable MTRRs */ + movl $(MTRRphysBase0), %ecx +1: + cmpl $0, %ebx + jz 2f + + movl (%edi), %eax /* MTRRphysBaseX lo */ + addl $4, %edi + movl (%edi), %edx /* MTRRphysBaseX hi */ + wrmsr + addl $4, %edi + incl %ecx + movl (%edi), %eax /* MTRRphysMaskX lo */ + addl $4, %edi + movl (%edi), %edx /* MTRRphysMaskX hi */ + wrmsr + addl $4, %edi + incl %ecx + + decl %ebx + jmp 1b +2: + /* Write the default MTRR register */ + popl %edx + popl %eax + movl $(MSR_MTRRdefType), %ecx + wrmsr + + /* Return to beginning and write the misc enable msr */ + popl %edi + addl $(SL_saved_misc_enable_msr), %edi + movl (%edi), %eax /* saved_misc_enable_msr lo */ + addl $4, %edi + movl (%edi), %edx /* saved_misc_enable_msr hi */ + movl $(MSR_IA32_MISC_ENABLE), %ecx + wrmsr + + popl %ebx + ret +SYM_FUNC_END(sl_txt_load_regs) + +SYM_FUNC_START(sl_txt_wake_aps) + /* Save boot params register */ + pushl %esi + + /* First setup the MLE join structure and load it into TXT reg */ + leal sl_gdt(%ebx), %eax + leal sl_txt_ap_entry(%ebx), %ecx + leal sl_smx_rlp_mle_join(%ebx), %edx + movl %eax, SL_rlp_gdt_base(%edx) + movl %ecx, SL_rlp_entry_point(%edx) + movl %edx, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_MLE_JOIN) + + /* Another TXT heap walk to find various values needed to wake APs */ + movl (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_HEAP_BASE), %eax + /* At BIOS data size, find the number of logical processors */ + movl (SL_num_logical_procs + 8)(%eax), %edx + /* Skip over BIOS data */ + movl (%eax), %ecx + addl %ecx, %eax + /* Skip over OS to MLE */ + movl (%eax), %ecx + addl %ecx, %eax + /* At OS-SNIT size, get capabilities to know how to wake up the APs */ + movl (SL_capabilities + 8)(%eax), %esi + /* Skip over OS to SNIT */ + movl (%eax), %ecx + addl %ecx, %eax + /* At SINIT-MLE size, get the AP wake MONITOR address */ + movl (SL_rlp_wakeup_addr + 8)(%eax), %edi + + /* Determine how to wake up the APs */ + testl $(1 << TXT_SINIT_MLE_CAP_WAKE_MONITOR), %esi + jz .Lwake_getsec + + /* Wake using MWAIT MONITOR */ + movl $1, (%edi) + jmp .Laps_awake + +.Lwake_getsec: + /* Wake using GETSEC(WAKEUP) */ + GETSEC $(SMX_X86_GETSEC_WAKEUP) + +.Laps_awake: + /* + * All of the APs are woken up and rendesvous in the relocated wake + * block starting at sl_txt_ap_wake_begin. Wait for all of them to + * halt. + */ + pause + cmpl sl_txt_cpu_count(%ebx), %edx + jne .Laps_awake + + popl %esi + ret +SYM_FUNC_END(sl_txt_wake_aps) + +/* This is the beginning of the relocated AP wake code block */ + .global sl_txt_ap_wake_begin +sl_txt_ap_wake_begin: + + /* + * Wait for NMI IPI in the relocated AP wake block which was provided + * and protected in the memory map by the prelaunch code. Leave all + * other interrupts masked since we do not expect anything but an NMI. + */ + xorl %edx, %edx + +1: + hlt + testl %edx, %edx + jz 1b + + /* + * This is the long absolute jump to the 32b Secure Launch protected + * mode stub code in the rmpiggy. The jump address will be fixed in + * the SMP boot code when the first AP is brought up. This whole area + * is provided and protected in the memory map by the prelaunch code. + */ + .byte 0xea +sl_ap_jmp_offset: + .long 0x00000000 + .word __SL32_CS + +SYM_FUNC_START(sl_txt_int_ipi_wake) + movl $1, %edx + + /* NMI context, just IRET */ + iret +SYM_FUNC_END(sl_txt_int_ipi_wake) + +SYM_FUNC_START(sl_txt_int_reset) + TXT_RESET $(SL_ERROR_INV_AP_INTERRUPT) +SYM_FUNC_END(sl_txt_int_reset) + + .balign 16 +sl_ap_idt_desc: + .word sl_ap_idt_end - sl_ap_idt - 1 /* Limit */ + .long sl_ap_idt - sl_txt_ap_wake_begin /* Base */ +sl_ap_idt_desc_end: + + .balign 16 +sl_ap_idt: + .rept NR_VECTORS + .word 0x0000 /* Offset 15 to 0 */ + .word __SL32_CS /* Segment selector */ + .word 0x8e00 /* Present, DPL=0, 32b Vector, Interrupt */ + .word 0x0000 /* Offset 31 to 16 */ + .endr +sl_ap_idt_end: + + .balign 16 +sl_ap_gdt_desc: + .word sl_ap_gdt_end - sl_ap_gdt - 1 + .long sl_ap_gdt - sl_txt_ap_wake_begin +sl_ap_gdt_desc_end: + + .balign 16 +sl_ap_gdt: + .quad 0x0000000000000000 /* NULL */ + .quad 0x00cf9a000000ffff /* __SL32_CS */ + .quad 0x00cf92000000ffff /* __SL32_DS */ +sl_ap_gdt_end: + + /* Small stacks for BSP and APs to work with */ + .balign 4 +sl_stacks: + .fill (TXT_MAX_CPUS * TXT_BOOT_STACK_SIZE), 1, 0 +sl_stacks_end: + +/* This is the end of the relocated AP wake code block */ + .global sl_txt_ap_wake_end +sl_txt_ap_wake_end: + + .data + .balign 16 +sl_gdt_desc: + .word sl_gdt_end - sl_gdt - 1 + .long sl_gdt +sl_gdt_desc_end: + + .balign 16 +sl_gdt: + .quad 0x0000000000000000 /* NULL */ + .quad 0x00cf9a000000ffff /* __SL32_CS */ + .quad 0x00cf92000000ffff /* __SL32_DS */ +sl_gdt_end: + + .balign 16 +sl_smx_rlp_mle_join: + .long sl_gdt_end - sl_gdt - 1 /* GDT limit */ + .long 0x00000000 /* GDT base */ + .long __SL32_CS /* Seg Sel - CS (DS, ES, SS = seg_sel+8) */ + .long 0x00000000 /* Entry point physical address */ + +SYM_DATA_START(sl_cpu_type) + .long 0x00000000 +SYM_DATA_END(sl_cpu_type) + +sl_txt_spin_lock: + .long 0x00000000 + +sl_txt_stack_index: + .long 0x00000000 + +sl_txt_cpu_count: + .long 0x00000000 + +sl_txt_ap_wake_block: + .long 0x00000000 diff --git a/arch/x86/kernel/asm-offsets.c b/arch/x86/kernel/asm-offsets.c index 3ca07ad..c7e5ed1 100644 --- a/arch/x86/kernel/asm-offsets.c +++ b/arch/x86/kernel/asm-offsets.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -104,4 +105,19 @@ static void __used common(void) OFFSET(TSS_sp0, tss_struct, x86_tss.sp0); OFFSET(TSS_sp1, tss_struct, x86_tss.sp1); OFFSET(TSS_sp2, tss_struct, x86_tss.sp2); + +#ifdef CONFIG_SECURE_LAUNCH + BLANK(); + OFFSET(SL_boot_params_addr, txt_os_mle_data, boot_params_addr); + OFFSET(SL_saved_misc_enable_msr, txt_os_mle_data, saved_misc_enable_msr); + OFFSET(SL_saved_bsp_mtrrs, txt_os_mle_data, saved_bsp_mtrrs); + OFFSET(SL_ap_wake_block, txt_os_mle_data, ap_wake_block); + OFFSET(SL_ap_wake_block_size, txt_os_mle_data, ap_wake_block_size); + OFFSET(SL_mle_scratch, txt_os_mle_data, mle_scratch); + OFFSET(SL_num_logical_procs, txt_bios_data, num_logical_procs); + OFFSET(SL_capabilities, txt_os_sinit_data, capabilities); + OFFSET(SL_rlp_wakeup_addr, txt_sinit_mle_data, rlp_wakeup_addr); + OFFSET(SL_rlp_gdt_base, smx_rlp_mle_join, rlp_gdt_base); + OFFSET(SL_rlp_entry_point, smx_rlp_mle_join, rlp_entry_point); +#endif } From patchwork Thu Sep 24 14:58:36 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ross Philipson X-Patchwork-Id: 11797661 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 7758D6CA for ; Thu, 24 Sep 2020 15:00:47 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3FE502074B for ; Thu, 24 Sep 2020 15:00:47 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=oracle.com header.i=@oracle.com header.b="Oz3z6I1p" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728333AbgIXPAm (ORCPT ); Thu, 24 Sep 2020 11:00:42 -0400 Received: from aserp2130.oracle.com ([141.146.126.79]:59276 "EHLO aserp2130.oracle.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728532AbgIXPAj (ORCPT ); Thu, 24 Sep 2020 11:00:39 -0400 Received: from pps.filterd (aserp2130.oracle.com [127.0.0.1]) by aserp2130.oracle.com (8.16.0.42/8.16.0.42) with SMTP id 08OExX1Z122632; Thu, 24 Sep 2020 15:00:19 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=from : to : cc : subject : date : message-id : in-reply-to : references; s=corp-2020-01-29; bh=gzg5twMJKNjp6lvCo9UI8kbkdEJTXqmja6D+xkQICEA=; b=Oz3z6I1pf/MhqRK+Fwig/UC8eTjoRwvzB4sufBARwl1AmwdlaaJd/3L0uWVDdAJFSgWP redcpUHS8SKhZNSXOoW2oxHNJIlDTuCsnB1hlA7wHWazWmQHYcz4C4z1bclTdTk14OLM olUdA5z7dfu9fmmc6n2zdE1KnrlzjQKEn6W5+L6Y0mbObgb0MANq9rXAAuMCxT0uKRh7 FZ0VGn0PqYcKeV1SrsMXKoj+/RjhNoJB8byhZu7cCz4pCuOVtxfh16mKYC2+kEO33qls 2DSWsEK78t+K0toZ/k7nmv1eKtlzicULeHi4PRRR40HDC1tOZ3JNud3thiUaGeQzQuAp Eg== Received: from aserp3020.oracle.com (aserp3020.oracle.com [141.146.126.70]) by aserp2130.oracle.com with ESMTP id 33qcpu5qrf-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Thu, 24 Sep 2020 15:00:18 +0000 Received: from pps.filterd (aserp3020.oracle.com [127.0.0.1]) by aserp3020.oracle.com (8.16.0.42/8.16.0.42) with SMTP id 08OEuAEc177202; Thu, 24 Sep 2020 14:58:18 GMT Received: from userv0122.oracle.com (userv0122.oracle.com [156.151.31.75]) by aserp3020.oracle.com with ESMTP id 33r28x3vka-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 24 Sep 2020 14:58:18 +0000 Received: from abhmp0014.oracle.com (abhmp0014.oracle.com [141.146.116.20]) by userv0122.oracle.com (8.14.4/8.14.4) with ESMTP id 08OEwEX9016160; Thu, 24 Sep 2020 14:58:14 GMT Received: from disposition.us.oracle.com (/10.152.32.81) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Thu, 24 Sep 2020 07:58:14 -0700 From: Ross Philipson To: linux-kernel@vger.kernel.org, x86@kernel.org, iommu@lists.linux-foundation.org, linux-integrity@vger.kernel.org, linux-doc@vger.kernel.org Cc: ross.philipson@oracle.com, dpsmith@apertussolutions.com, tglx@linutronix.de, mingo@redhat.com, bp@alien8.de, hpa@zytor.com, luto@amacapital.net, trenchboot-devel@googlegroups.com Subject: [PATCH 08/13] x86: Secure Launch kernel late boot stub Date: Thu, 24 Sep 2020 10:58:36 -0400 Message-Id: <1600959521-24158-9-git-send-email-ross.philipson@oracle.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1600959521-24158-1-git-send-email-ross.philipson@oracle.com> References: <1600959521-24158-1-git-send-email-ross.philipson@oracle.com> X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9753 signatures=668680 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 mlxscore=0 mlxlogscore=999 suspectscore=0 adultscore=0 bulkscore=0 malwarescore=0 spamscore=0 phishscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2006250000 definitions=main-2009240114 X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9753 signatures=668680 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 suspectscore=0 mlxlogscore=999 adultscore=0 bulkscore=0 mlxscore=0 lowpriorityscore=0 priorityscore=1501 phishscore=0 spamscore=0 malwarescore=0 clxscore=1015 impostorscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2006250000 definitions=main-2009240115 Precedence: bulk List-ID: X-Mailing-List: linux-integrity@vger.kernel.org The routine slaunch_setup is called out of the x86 specific setup_arch routine during early kernel boot. After determining what platform is present, various operations specific to that platform occur. This includes finalizing setting for the platform late launch and verifying that memory protections are in place. For TXT, this code also reserves the original compressed kernel setup area where the APs were left looping so that this memory cannot be used. Signed-off-by: Ross Philipson --- arch/x86/kernel/Makefile | 1 + arch/x86/kernel/setup.c | 3 + arch/x86/kernel/slaunch.c | 495 +++++++++++++++++++++++++++++++++++++++++++++ drivers/iommu/intel/dmar.c | 4 + 4 files changed, 503 insertions(+) create mode 100644 arch/x86/kernel/slaunch.c diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index e77261d..318366f 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -76,6 +76,7 @@ obj-$(CONFIG_X86_32) += tls.o obj-$(CONFIG_IA32_EMULATION) += tls.o obj-y += step.o obj-$(CONFIG_INTEL_TXT) += tboot.o +obj-$(CONFIG_SECURE_LAUNCH) += slaunch.o obj-$(CONFIG_ISA_DMA_API) += i8237.o obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-y += cpu/ diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 3511736..cae9476 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -1009,6 +1010,8 @@ void __init setup_arch(char **cmdline_p) early_gart_iommu_check(); #endif + slaunch_setup(); + /* * partially used pages are not usable - thus * we are rounding upwards: diff --git a/arch/x86/kernel/slaunch.c b/arch/x86/kernel/slaunch.c new file mode 100644 index 0000000..e040e32 --- /dev/null +++ b/arch/x86/kernel/slaunch.c @@ -0,0 +1,495 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Secure Launch late validation/setup, securityfs exposure and + * finalization support. + * + * Copyright (c) 2020, Oracle and/or its affiliates. + * Copyright (c) 2020 Apertus Solutions, LLC + * + * Author(s): + * Daniel P. Smith + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static u32 sl_flags; +static struct sl_ap_wake_info ap_wake_info; +static u64 evtlog_addr; +static u32 evtlog_size; +static u64 vtd_pmr_lo_size; + +/* This should be plenty of room */ +static u8 txt_dmar[PAGE_SIZE] __aligned(16); + +u32 slaunch_get_flags(void) +{ + return sl_flags; +} +EXPORT_SYMBOL(slaunch_get_flags); + +struct sl_ap_wake_info *slaunch_get_ap_wake_info(void) +{ + return &ap_wake_info; +} + +struct acpi_table_header *slaunch_get_dmar_table(struct acpi_table_header *dmar) +{ + /* The DMAR is only stashed and provided via TXT on Intel systems */ + if (memcmp(txt_dmar, "DMAR", 4)) + return dmar; + + return (struct acpi_table_header *)(&txt_dmar[0]); +} + +static void __init __noreturn slaunch_txt_reset(void __iomem *txt, + const char *msg, u64 error) +{ + u64 one = 1, val; + + pr_err("%s", msg); + + /* + * This performs a TXT reset with a sticky error code. The reads of + * TXT_CR_E2STS act as barriers. + */ + memcpy_toio(txt + TXT_CR_ERRORCODE, &error, sizeof(u64)); + memcpy_fromio(&val, txt + TXT_CR_E2STS, sizeof(u64)); + memcpy_toio(txt + TXT_CR_CMD_NO_SECRETS, &one, sizeof(u64)); + memcpy_fromio(&val, txt + TXT_CR_E2STS, sizeof(u64)); + memcpy_toio(txt + TXT_CR_CMD_UNLOCK_MEM_CONFIG, &one, sizeof(u64)); + memcpy_fromio(&val, txt + TXT_CR_E2STS, sizeof(u64)); + memcpy_toio(txt + TXT_CR_CMD_RESET, &one, sizeof(u64)); + + for ( ; ; ) + asm volatile ("hlt"); + + unreachable(); +} + +/* + * The TXT heap is too big to map all at once with early_ioremap + * so it is done a table at a time. + */ +static void __init *txt_early_get_heap_table(void __iomem *txt, u32 type, + u32 bytes) +{ + void *heap; + u64 base, size, offset = 0; + int i; + + if (type > TXT_SINIT_MLE_DATA_TABLE) + slaunch_txt_reset(txt, + "Error invalid table type for early heap walk\n", + SL_ERROR_HEAP_WALK); + + memcpy_fromio(&base, txt + TXT_CR_HEAP_BASE, sizeof(u64)); + memcpy_fromio(&size, txt + TXT_CR_HEAP_SIZE, sizeof(u64)); + + /* Iterate over heap tables looking for table of "type" */ + for (i = 0; i < type; i++) { + base += offset; + heap = early_memremap(base, sizeof(u64)); + if (!heap) + slaunch_txt_reset(txt, + "Error early_memremap of heap for heap walk\n", + SL_ERROR_HEAP_WALK); + + offset = *((u64 *)heap); + + /* + * After the first iteration, any offset of zero is invalid and + * implies the TXT heap is corrupted. + */ + if (!offset) + slaunch_txt_reset(txt, + "Error invalid 0 offset in heap walk\n", + SL_ERROR_HEAP_ZERO_OFFSET); + + early_memunmap(heap, sizeof(u64)); + } + + /* Skip the size field at the head of each table */ + base += sizeof(u64); + heap = early_memremap(base, bytes); + if (!heap) + slaunch_txt_reset(txt, + "Error early_memremap of heap section\n", + SL_ERROR_HEAP_MAP); + + return heap; +} + +/* + * TXT uses a special set of VTd registers to protect all of memory from DMA + * until the IOMMU can be programmed to protect memory. There is the low + * memory PMR that can protect all memory up to 4G. The high memory PRM can + * be setup to protect all memory beyond 4Gb. Validate that these values cover + * what is expected. + */ +static void __init slaunch_verify_pmrs(void __iomem *txt) +{ + struct txt_os_sinit_data *os_sinit_data; + unsigned long last_pfn, initrd_extent; + u32 field_offset, err = 0; + const char *errmsg = ""; + + field_offset = offsetof(struct txt_os_sinit_data, lcp_po_base); + os_sinit_data = txt_early_get_heap_table(txt, TXT_OS_SINIT_DATA_TABLE, + field_offset); + + /* Save a copy */ + vtd_pmr_lo_size = os_sinit_data->vtd_pmr_lo_size; + + last_pfn = e820__end_of_ram_pfn(); + + /* + * First make sure the hi PMR covers all memory above 4G. In the + * unlikely case where there is < 4G on the system, the hi PMR will + * not be set. + */ + if (os_sinit_data->vtd_pmr_hi_base != 0x0ULL) { + if (os_sinit_data->vtd_pmr_hi_base != 0x100000000ULL) { + err = SL_ERROR_HI_PMR_BASE; + errmsg = "Error hi PMR base\n"; + goto out; + } + + if (last_pfn << PAGE_SHIFT > + os_sinit_data->vtd_pmr_hi_base + + os_sinit_data->vtd_pmr_hi_size) { + err = SL_ERROR_HI_PMR_SIZE; + errmsg = "Error hi PMR size\n"; + goto out; + } + } + + /* Lo PMR base should always be 0 */ + if (os_sinit_data->vtd_pmr_lo_base != 0x0ULL) { + err = SL_ERROR_LO_PMR_BASE; + errmsg = "Error lo PMR base\n"; + goto out; + } + + /* + * Check that if the kernel was loaded below 4G, that it is protected + * by the lo PMR. Note this is the decompressed kernel. The ACM would + * have ensured the compressed kernel (the MLE image) was protected. + */ + if ((__pa_symbol(_end) < 0x100000000ULL) && + (__pa_symbol(_end) > os_sinit_data->vtd_pmr_lo_size)) { + err = SL_ERROR_LO_PMR_MLE; + errmsg = "Error lo PMR does not cover MLE kernel\n"; + goto out; + } + + /* Check that the AP wake block is protected by the lo PMR. */ + if (ap_wake_info.ap_wake_block + PAGE_SIZE > + os_sinit_data->vtd_pmr_lo_size) { + err = SL_ERROR_LO_PMR_MLE; + errmsg = "Error lo PMR does not cover AP wake block\n"; + } + + /* + * If an external initrd is present and loaded below 4G, check + * that it is protected by the lo PMR. + */ + if (boot_params.hdr.ramdisk_image != 0 && + boot_params.hdr.ramdisk_size != 0) { + initrd_extent = boot_params.hdr.ramdisk_image + + boot_params.hdr.ramdisk_size; + if ((initrd_extent < 0x100000000ULL) && + (initrd_extent > os_sinit_data->vtd_pmr_lo_size)) { + err = SL_ERROR_LO_PMR_INITRD; + errmsg = "Error lo PMR does not cover external initrd\n"; + goto out; + } + } + +out: + early_memunmap(os_sinit_data, field_offset); + + if (err) + slaunch_txt_reset(txt, errmsg, err); +} + +static void __init slaunch_txt_reserve_range(u64 base, u64 size) +{ + int type; + + type = e820__get_entry_type(base, base + size - 1); + if (type == E820_TYPE_RAM) { + pr_info("memblock reserve base: %llx size: %llx\n", base, size); + memblock_reserve(base, size); + } +} + +/* + * For Intel, certain regions of memory must be marked as reserved by putting + * them on the memblock reserved list if they are not already e820 reserved. + * This includes: + * - The TXT HEAP + * - The ACM area + * - The TXT private register bank + * - The MDR list sent to the MLE by the ACM (see TXT specification) + * (Normally the above are properly reserved by firmware but if it was not + * done, reserve them now) + * - The AP wake block + * - TPM log external to the TXT heap + * + * Also if the low PMR doesn't cover all memory < 4G, any RAM regions above + * the low PMR must be reservered too. + */ +static void __init slaunch_txt_reserve(void __iomem *txt) +{ + struct txt_sinit_memory_descriptor_record *mdr; + struct txt_sinit_mle_data *sinit_mle_data; + void *mdrs; + u64 base, size, heap_base, heap_size; + u32 field_offset, mdrnum, mdroffset, mdrslen, i; + + base = TXT_PRIV_CONFIG_REGS_BASE; + size = TXT_PUB_CONFIG_REGS_BASE - TXT_PRIV_CONFIG_REGS_BASE; + slaunch_txt_reserve_range(base, size); + + memcpy_fromio(&heap_base, txt + TXT_CR_HEAP_BASE, sizeof(u64)); + memcpy_fromio(&heap_size, txt + TXT_CR_HEAP_SIZE, sizeof(u64)); + slaunch_txt_reserve_range(heap_base, heap_size); + + memcpy_fromio(&base, txt + TXT_CR_SINIT_BASE, sizeof(u64)); + memcpy_fromio(&size, txt + TXT_CR_SINIT_SIZE, sizeof(u64)); + slaunch_txt_reserve_range(base, size); + + field_offset = offsetof(struct txt_sinit_mle_data, + sinit_vtd_dmar_table_size); + sinit_mle_data = txt_early_get_heap_table(txt, TXT_SINIT_MLE_DATA_TABLE, + field_offset); + + mdrnum = sinit_mle_data->num_of_sinit_mdrs; + mdroffset = sinit_mle_data->sinit_mdrs_table_offset; + + early_memunmap(sinit_mle_data, field_offset); + + if (!mdrnum) + goto nomdr; + + mdrslen = (mdrnum * sizeof(struct txt_sinit_memory_descriptor_record)); + + mdrs = txt_early_get_heap_table(txt, TXT_SINIT_MLE_DATA_TABLE, + mdroffset + mdrslen - 8); + + mdr = (struct txt_sinit_memory_descriptor_record *) + (mdrs + mdroffset - 8); + + for (i = 0; i < mdrnum; i++, mdr++) { + /* Spec says some entries can have length 0, ignore them */ + if (mdr->type > 0 && mdr->length > 0) + slaunch_txt_reserve_range(mdr->address, mdr->length); + } + + early_memunmap(mdrs, mdroffset + mdrslen - 8); + +nomdr: + slaunch_txt_reserve_range(ap_wake_info.ap_wake_block, + ap_wake_info.ap_wake_block_size); + + if (evtlog_addr < heap_base || evtlog_addr > (heap_base + heap_size)) + slaunch_txt_reserve_range(evtlog_addr, evtlog_size); + + for (i = 0; i < e820_table->nr_entries; i++) { + base = e820_table->entries[i].addr; + size = e820_table->entries[i].size; + if ((base > vtd_pmr_lo_size) && (base < 0x100000000ULL)) + slaunch_txt_reserve_range(base, size); + } +} + +/* + * TXT stashes a safe copy of the DMAR ACPI table to prevent tampering. + * It is stored in the TXT heap. Fetch it from there and make it available + * to the IOMMU driver. + */ +static void __init slaunch_copy_dmar_table(void __iomem *txt) +{ + struct txt_sinit_mle_data *sinit_mle_data; + void *dmar; + u32 field_offset, dmar_size, dmar_offset; + + memset(&txt_dmar, 0, PAGE_SIZE); + + field_offset = offsetof(struct txt_sinit_mle_data, + processor_scrtm_status); + sinit_mle_data = txt_early_get_heap_table(txt, TXT_SINIT_MLE_DATA_TABLE, + field_offset); + + dmar_size = sinit_mle_data->sinit_vtd_dmar_table_size; + dmar_offset = sinit_mle_data->sinit_vtd_dmar_table_offset; + + early_memunmap(sinit_mle_data, field_offset); + + if (!dmar_size || !dmar_offset) + slaunch_txt_reset(txt, + "Error invalid DMAR table values\n", + SL_ERROR_HEAP_INVALID_DMAR); + + if (unlikely(dmar_size > PAGE_SIZE)) + slaunch_txt_reset(txt, + "Error DMAR too big to store\n", + SL_ERROR_HEAP_DMAR_SIZE); + + + dmar = txt_early_get_heap_table(txt, TXT_SINIT_MLE_DATA_TABLE, + dmar_offset + dmar_size - 8); + if (!dmar) + slaunch_txt_reset(txt, + "Error early_ioremap of DMAR\n", + SL_ERROR_HEAP_DMAR_MAP); + + memcpy(&txt_dmar[0], dmar + dmar_offset - 8, dmar_size); + + early_memunmap(dmar, dmar_offset + dmar_size - 8); +} + +/* + * The location of the safe AP wake code block is stored in the TXT heap. + * Fetch it here in the early init code for later use in SMP startup. + * + * Also get the TPM event log values that may have to be put on the + * memblock reserve list later. + */ +static void __init slaunch_fetch_os_mle_fields(void __iomem *txt) +{ + struct txt_os_mle_data *os_mle_data; + u8 *jmp_offset; + + os_mle_data = txt_early_get_heap_table(txt, TXT_OS_MLE_DATA_TABLE, + sizeof(struct txt_os_mle_data)); + + ap_wake_info.ap_wake_block = os_mle_data->ap_wake_block; + ap_wake_info.ap_wake_block_size = os_mle_data->ap_wake_block_size; + + jmp_offset = os_mle_data->mle_scratch + SL_SCRATCH_AP_JMP_OFFSET; + ap_wake_info.ap_jmp_offset = *((u32 *)jmp_offset); + + evtlog_addr = os_mle_data->evtlog_addr; + evtlog_size = os_mle_data->evtlog_size; + + early_memunmap(os_mle_data, sizeof(struct txt_os_mle_data)); +} + +/* + * Intel specific late stub setup and validation. + */ +static void __init slaunch_setup_intel(void) +{ + void __iomem *txt; + u64 val = 0x1ULL; + + /* + * First see if SENTER was done and not by TBOOT by reading the status + * register in the public space. + */ + txt = early_ioremap(TXT_PUB_CONFIG_REGS_BASE, + TXT_NR_CONFIG_PAGES * PAGE_SIZE); + if (!txt) { + /* This is really bad, no where to go from here */ + panic("Error early_ioremap of TXT pub registers\n"); + } + + memcpy_fromio(&val, txt + TXT_CR_STS, sizeof(u64)); + early_iounmap(txt, TXT_NR_CONFIG_PAGES * PAGE_SIZE); + + /* Was SENTER done? */ + if (!(val & TXT_SENTER_DONE_STS)) + return; + + /* Was it done by TBOOT? */ + if (boot_params.tboot_addr) + return; + + /* Now we want to use the private register space */ + txt = early_ioremap(TXT_PRIV_CONFIG_REGS_BASE, + TXT_NR_CONFIG_PAGES * PAGE_SIZE); + if (!txt) { + /* This is really bad, no where to go from here */ + panic("Error early_ioremap of TXT priv registers\n"); + } + + /* + * Try to read the Intel VID from the TXT private registers to see if + * TXT measured launch happened properly and the private space is + * available. + */ + memcpy_fromio(&val, txt + TXT_CR_DIDVID, sizeof(u64)); + if ((u16)(val & 0xffff) != 0x8086) { + /* + * Can't do a proper TXT reset since it appears something is + * wrong even though SENTER happened and it should be in SMX + * mode. + */ + panic("Invalid TXT vendor ID, not in SMX mode\n"); + } + + /* Set flags so subsequent code knows the status of the launch */ + sl_flags |= (SL_FLAG_ACTIVE|SL_FLAG_ARCH_TXT); + + /* + * Reading the proper DIDVID from the private register space means we + * are in SMX mode and private registers are open for read/write. + */ + + /* On Intel, have to handle TPM localities via TXT */ + val = 0x1ULL; + memcpy_toio(txt + TXT_CR_CMD_SECRETS, &val, sizeof(u64)); + memcpy_fromio(&val, txt + TXT_CR_E2STS, sizeof(u64)); + val = 0x1ULL; + memcpy_toio(txt + TXT_CR_CMD_OPEN_LOCALITY1, &val, sizeof(u64)); + memcpy_fromio(&val, txt + TXT_CR_E2STS, sizeof(u64)); + + slaunch_fetch_os_mle_fields(txt); + + slaunch_verify_pmrs(txt); + + slaunch_txt_reserve(txt); + + slaunch_copy_dmar_table(txt); + + early_iounmap(txt, TXT_NR_CONFIG_PAGES * PAGE_SIZE); + + pr_info("Intel TXT setup complete\n"); +} + +void __init slaunch_setup(void) +{ + u32 vendor[4]; + + /* Get manufacturer string with CPUID 0 */ + cpuid(0, &vendor[0], &vendor[1], &vendor[2], &vendor[3]); + + /* Only Intel TXT is supported at this point */ + if (vendor[1] == INTEL_CPUID_MFGID_EBX && + vendor[2] == INTEL_CPUID_MFGID_ECX && + vendor[3] == INTEL_CPUID_MFGID_EDX) + slaunch_setup_intel(); +} diff --git a/drivers/iommu/intel/dmar.c b/drivers/iommu/intel/dmar.c index 93e6345..d9856b5 100644 --- a/drivers/iommu/intel/dmar.c +++ b/drivers/iommu/intel/dmar.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -633,6 +634,9 @@ static inline int dmar_walk_dmar_table(struct acpi_table_dmar *dmar, */ dmar_tbl = tboot_get_dmar_table(dmar_tbl); + /* If Secure Launch is active, it has similar logic */ + dmar_tbl = slaunch_get_dmar_table(dmar_tbl); + dmar = (struct acpi_table_dmar *)dmar_tbl; if (!dmar) return -ENODEV; From patchwork Thu Sep 24 14:58:37 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ross Philipson X-Patchwork-Id: 11797633 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C85A76CA for ; Thu, 24 Sep 2020 14:58:50 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9881323A61 for ; Thu, 24 Sep 2020 14:58:50 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=oracle.com header.i=@oracle.com header.b="vD7Wb2hE" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728440AbgIXO6m (ORCPT ); Thu, 24 Sep 2020 10:58:42 -0400 Received: from aserp2120.oracle.com ([141.146.126.78]:55966 "EHLO aserp2120.oracle.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728424AbgIXO6l (ORCPT ); Thu, 24 Sep 2020 10:58:41 -0400 Received: from pps.filterd (aserp2120.oracle.com [127.0.0.1]) by aserp2120.oracle.com (8.16.0.42/8.16.0.42) with SMTP id 08OEtGqE037460; Thu, 24 Sep 2020 14:58:19 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=from : to : cc : subject : date : message-id : in-reply-to : references; s=corp-2020-01-29; bh=NiAX/lKhBwtj/b+yjV6cXPKWwcBGqpXA7p5pUSchAm0=; b=vD7Wb2hE0pZQ+BeUmSaNSTuKgTZLdB2OSQDork8YNrZIlKQnKWTrRriOQWEvr4fOpZ8F 7l2AKA351i5WLNejNJaLNVKCkYfcd99x+hqmbLyCufqV+UJibijufGVOyT7uauKMhFJ9 FA/n5Kd/wpes59nIiav7hqNUFcJkMYCHuafxChDxoiylu7iUVvTWngp2ab7bccHmtOUf C7miJPOuWQ5V7oSFyqqeJoOk+SG9d+4qhIkLYY/1u3tHv/Xm8DDnitIOMJ2kZOFyLsQO idAwfNvewodWonkZV8qcdVVZzb7rqdjwrmqTM6sw2ojECHzsSI6sQSfk/Xs8RtUih+ha xw== Received: from aserp3020.oracle.com (aserp3020.oracle.com [141.146.126.70]) by aserp2120.oracle.com with ESMTP id 33q5rgq585-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Thu, 24 Sep 2020 14:58:18 +0000 Received: from pps.filterd (aserp3020.oracle.com [127.0.0.1]) by aserp3020.oracle.com (8.16.0.42/8.16.0.42) with SMTP id 08OEuApX177221; Thu, 24 Sep 2020 14:58:18 GMT Received: from userv0121.oracle.com (userv0121.oracle.com [156.151.31.72]) by aserp3020.oracle.com with ESMTP id 33r28x3vkd-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 24 Sep 2020 14:58:18 +0000 Received: from abhmp0014.oracle.com (abhmp0014.oracle.com [141.146.116.20]) by userv0121.oracle.com (8.14.4/8.13.8) with ESMTP id 08OEwFG7000849; Thu, 24 Sep 2020 14:58:15 GMT Received: from disposition.us.oracle.com (/10.152.32.81) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Thu, 24 Sep 2020 07:58:15 -0700 From: Ross Philipson To: linux-kernel@vger.kernel.org, x86@kernel.org, iommu@lists.linux-foundation.org, linux-integrity@vger.kernel.org, linux-doc@vger.kernel.org Cc: ross.philipson@oracle.com, dpsmith@apertussolutions.com, tglx@linutronix.de, mingo@redhat.com, bp@alien8.de, hpa@zytor.com, luto@amacapital.net, trenchboot-devel@googlegroups.com Subject: [PATCH 09/13] x86: Secure Launch SMP bringup support Date: Thu, 24 Sep 2020 10:58:37 -0400 Message-Id: <1600959521-24158-10-git-send-email-ross.philipson@oracle.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1600959521-24158-1-git-send-email-ross.philipson@oracle.com> References: <1600959521-24158-1-git-send-email-ross.philipson@oracle.com> X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9753 signatures=668680 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 mlxscore=0 mlxlogscore=999 suspectscore=0 adultscore=0 bulkscore=0 malwarescore=0 spamscore=0 phishscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2006250000 definitions=main-2009240114 X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9753 signatures=668680 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 spamscore=0 impostorscore=0 clxscore=1015 suspectscore=0 phishscore=0 malwarescore=0 priorityscore=1501 mlxlogscore=999 adultscore=0 bulkscore=0 mlxscore=0 lowpriorityscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2006250000 definitions=main-2009240114 Precedence: bulk List-ID: X-Mailing-List: linux-integrity@vger.kernel.org On Intel, the APs are left in a well documented state after TXT performs the late launch. Specifically they cannot have #INIT asserted on them so a standard startup via INIT/SIPI/SIPI cannot be performed. Instead the early SL stub code parked the APs in a pause/jmp loop waiting for an NMI. The modified SMP boot code is called for the Secure Launch case. The jump address for the RM piggy entry point is fixed up in the jump where the APs are waiting and an NMI IPI is sent to the AP. The AP vectors to the Secure Launch entry point in the RM piggy which mimics what the real mode code would do then jumps the the standard RM piggy protected mode entry point. Signed-off-by: Ross Philipson --- arch/x86/include/asm/realmode.h | 3 ++ arch/x86/kernel/smpboot.c | 86 ++++++++++++++++++++++++++++++++++++ arch/x86/realmode/rm/header.S | 3 ++ arch/x86/realmode/rm/trampoline_64.S | 37 ++++++++++++++++ 4 files changed, 129 insertions(+) diff --git a/arch/x86/include/asm/realmode.h b/arch/x86/include/asm/realmode.h index b35030e..20bc283 100644 --- a/arch/x86/include/asm/realmode.h +++ b/arch/x86/include/asm/realmode.h @@ -34,6 +34,9 @@ struct real_mode_header { #ifdef CONFIG_X86_64 u32 machine_real_restart_seg; #endif +#ifdef CONFIG_SECURE_LAUNCH + u32 sl_trampoline_start32; +#endif }; /* This must match data at realmode/rm/trampoline_{32,64}.S */ diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index f5ef689..0ca0b07 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -56,6 +56,7 @@ #include #include #include +#include #include #include @@ -1017,6 +1018,83 @@ int common_cpu_up(unsigned int cpu, struct task_struct *idle) return 0; } +#ifdef CONFIG_SECURE_LAUNCH + +static atomic_t first_ap_only = {1}; + +/* + * Called to fix the long jump address for the waiting APs to vector to + * the correct startup location in the Secure Launch stub in the rmpiggy. + */ +static int +slaunch_fixup_jump_vector(void) +{ + struct sl_ap_wake_info *ap_wake_info; + unsigned int *ap_jmp_ptr = 0; + + if (!atomic_dec_and_test(&first_ap_only)) + return 0; + + ap_wake_info = slaunch_get_ap_wake_info(); + + ap_jmp_ptr = (unsigned int *)__va(ap_wake_info->ap_wake_block + + ap_wake_info->ap_jmp_offset); + + *ap_jmp_ptr = real_mode_header->sl_trampoline_start32; + + pr_info("TXT AP long jump address updated\n"); + + return 0; +} + +/* + * TXT AP startup is quite different than normal. The APs cannot have #INIT + * asserted on them or receive SIPIs. The early Secure Launch code has parked + * the APs in a pause loop waiting to receive an NMI. This will wake the APs + * and have them jump to the protected mode code in the rmpiggy where the rest + * of the SMP boot of the AP will proceed normally. + */ +static int +slaunch_wakeup_cpu_from_txt(int cpu, int apicid) +{ + unsigned long send_status = 0, accept_status = 0; + + /* Only done once */ + if (slaunch_fixup_jump_vector()) + return -1; + + /* Send NMI IPI to idling AP and wake it up */ + apic_icr_write(APIC_DM_NMI, apicid); + + if (init_udelay == 0) + udelay(10); + else + udelay(300); + + send_status = safe_apic_wait_icr_idle(); + + if (init_udelay == 0) + udelay(10); + else + udelay(300); + + accept_status = (apic_read(APIC_ESR) & 0xEF); + + if (send_status) + pr_err("Secure Launch IPI never delivered???\n"); + if (accept_status) + pr_err("Secure Launch IPI delivery error (%lx)\n", + accept_status); + + return (send_status | accept_status); +} + +#else + +#define slaunch_wakeup_cpu_from_txt(cpu, apicid) 0 + +#endif /* !CONFIG_SECURE_LAUNCH */ + /* * NOTE - on most systems this is a PHYSICAL apic ID, but on multiquad * (ie clustered apic addressing mode), this is a LOGICAL apic ID. @@ -1071,6 +1149,12 @@ static int do_boot_cpu(int apicid, int cpu, struct task_struct *idle, cpumask_clear_cpu(cpu, cpu_initialized_mask); smp_mb(); + /* With Intel TXT, the AP startup is totally different */ + if (slaunch_get_flags() & (SL_FLAG_ACTIVE|SL_FLAG_ARCH_TXT)) { + boot_error = slaunch_wakeup_cpu_from_txt(cpu, apicid); + goto txt_wake; + } + /* * Wake up a CPU in difference cases: * - Use the method in the APIC driver if it's defined @@ -1083,6 +1167,8 @@ static int do_boot_cpu(int apicid, int cpu, struct task_struct *idle, boot_error = wakeup_cpu_via_init_nmi(cpu, start_ip, apicid, cpu0_nmi_registered); +txt_wake: + if (!boot_error) { /* * Wait 10s total for first sign of life from AP diff --git a/arch/x86/realmode/rm/header.S b/arch/x86/realmode/rm/header.S index af04512..7215040 100644 --- a/arch/x86/realmode/rm/header.S +++ b/arch/x86/realmode/rm/header.S @@ -33,6 +33,9 @@ SYM_DATA_START(real_mode_header) #ifdef CONFIG_X86_64 .long __KERNEL32_CS #endif +#ifdef CONFIG_SECURE_LAUNCH + .long pa_sl_trampoline_start32 +#endif SYM_DATA_END(real_mode_header) /* End signature, used to verify integrity */ diff --git a/arch/x86/realmode/rm/trampoline_64.S b/arch/x86/realmode/rm/trampoline_64.S index 251758e..d5fb210 100644 --- a/arch/x86/realmode/rm/trampoline_64.S +++ b/arch/x86/realmode/rm/trampoline_64.S @@ -84,6 +84,43 @@ SYM_CODE_END(trampoline_start) .section ".text32","ax" .code32 +#ifdef CONFIG_SECURE_LAUNCH + .balign 4 +SYM_CODE_START(sl_trampoline_start32) + /* + * The early secure launch stub AP wakeup code has taken care of all + * the vagaries of launching out of TXT. This bit just mimics what the + * 16b entry code does and jumps off to the real startup_32. + */ + cli + wbinvd + + /* + * The %ebx provided is not terribly useful since it is the physical + * address of tb_trampoline_start and not the base of the image. + * Use pa_real_mode_base, which is fixed up, to get a run time + * base register to use for offsets to location that do not have + * pa_ symbols. + */ + movl $pa_real_mode_base, %ebx + + /* + * This may seem a little odd but this is what %esp would have had in + * it on the jmp from real mode because all real mode fixups were done + * via the code segment. The base is added at the 32b entry. + */ + movl rm_stack_end, %esp + + lgdt tr_gdt(%ebx) + lidt tr_idt(%ebx) + + movw $__KERNEL_DS, %dx # Data segment descriptor + + /* Jump to where the 16b code would have jumped */ + ljmpl $__KERNEL32_CS, $pa_startup_32 +SYM_CODE_END(sl_trampoline_start32) +#endif + .balign 4 SYM_CODE_START(startup_32) movl %edx, %ss From patchwork Thu Sep 24 14:58:38 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ross Philipson X-Patchwork-Id: 11797635 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 9E9336CA for ; Thu, 24 Sep 2020 14:58:51 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 798822388A for ; Thu, 24 Sep 2020 14:58:51 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=oracle.com header.i=@oracle.com header.b="IahnXl8H" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728436AbgIXO6m (ORCPT ); Thu, 24 Sep 2020 10:58:42 -0400 Received: from aserp2130.oracle.com ([141.146.126.79]:57270 "EHLO aserp2130.oracle.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728408AbgIXO6l (ORCPT ); Thu, 24 Sep 2020 10:58:41 -0400 Received: from pps.filterd (aserp2130.oracle.com [127.0.0.1]) by aserp2130.oracle.com (8.16.0.42/8.16.0.42) with SMTP id 08OErXvv101502; Thu, 24 Sep 2020 14:58:20 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=from : to : cc : subject : date : message-id : in-reply-to : references; s=corp-2020-01-29; bh=EG2cDtHDj3afXnJV2kE6YpRWdf+r6HX61ECzGa4txCg=; b=IahnXl8HN8sriDPY4qBMrEjj0cpksyu87777AgCnlvd433L2GxdhBXGtxsMEOGY9XJS4 ZEpHEMeTn9bto6biMUo0YVi6HXHhjxTatqGsxxDU6U9l51BJtRD5OZh/3C4l9VMoDecM s1keeIlhTS4GOZtB3M4ZBZ6h0Cj/Btyo5okriT/MoTsa7f9lH8yEXDghi0arnwaabujR HU79PSfaeOz//T2ikWpn3fLVGDTFq/n+98HenF/JDAozyeDFcguPdMjszMfvlorZzpkN cnajd4BEXtXUXQOvY2LKs6uVX7JJC4ZhdeLftfXLafbt4W6gNBIWEEjluMWCztoPb3Ha DQ== Received: from userp3030.oracle.com (userp3030.oracle.com [156.151.31.80]) by aserp2130.oracle.com with ESMTP id 33qcpu5qcr-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Thu, 24 Sep 2020 14:58:20 +0000 Received: from pps.filterd (userp3030.oracle.com [127.0.0.1]) by userp3030.oracle.com (8.16.0.42/8.16.0.42) with SMTP id 08OEtUQZ159389; Thu, 24 Sep 2020 14:58:19 GMT Received: from userv0122.oracle.com (userv0122.oracle.com [156.151.31.75]) by userp3030.oracle.com with ESMTP id 33nux2vwnf-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 24 Sep 2020 14:58:19 +0000 Received: from abhmp0014.oracle.com (abhmp0014.oracle.com [141.146.116.20]) by userv0122.oracle.com (8.14.4/8.14.4) with ESMTP id 08OEwGIx016161; Thu, 24 Sep 2020 14:58:16 GMT Received: from disposition.us.oracle.com (/10.152.32.81) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Thu, 24 Sep 2020 07:58:16 -0700 From: Ross Philipson To: linux-kernel@vger.kernel.org, x86@kernel.org, iommu@lists.linux-foundation.org, linux-integrity@vger.kernel.org, linux-doc@vger.kernel.org Cc: ross.philipson@oracle.com, dpsmith@apertussolutions.com, tglx@linutronix.de, mingo@redhat.com, bp@alien8.de, hpa@zytor.com, luto@amacapital.net, trenchboot-devel@googlegroups.com Subject: [PATCH 10/13] x86: Secure Launch adding event log securityfs Date: Thu, 24 Sep 2020 10:58:38 -0400 Message-Id: <1600959521-24158-11-git-send-email-ross.philipson@oracle.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1600959521-24158-1-git-send-email-ross.philipson@oracle.com> References: <1600959521-24158-1-git-send-email-ross.philipson@oracle.com> X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9753 signatures=668680 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 malwarescore=0 mlxscore=0 adultscore=0 bulkscore=0 mlxlogscore=999 phishscore=0 suspectscore=0 spamscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2006250000 definitions=main-2009240114 X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9753 signatures=668680 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 suspectscore=0 mlxlogscore=999 adultscore=0 bulkscore=0 mlxscore=0 lowpriorityscore=0 priorityscore=1501 phishscore=0 spamscore=0 malwarescore=0 clxscore=1015 impostorscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2006250000 definitions=main-2009240114 Precedence: bulk List-ID: X-Mailing-List: linux-integrity@vger.kernel.org From: "Daniel P. Smith" The late init functionality registers securityfs nodes to allow access to TXT register fields on Intel along with the fetching of and writing events to the late launch TPM log. Signed-off-by: Daniel P. Smith Signed-off-by: Ross Philipson Signed-off-by: garnetgrimm --- arch/x86/kernel/slaunch.c | 293 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 292 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/slaunch.c b/arch/x86/kernel/slaunch.c index e040e32..7bdb89e 100644 --- a/arch/x86/kernel/slaunch.c +++ b/arch/x86/kernel/slaunch.c @@ -8,7 +8,7 @@ * * Author(s): * Daniel P. Smith - * + * Garnet T. Grimm */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -493,3 +493,294 @@ void __init slaunch_setup(void) vendor[3] == INTEL_CPUID_MFGID_EDX) slaunch_setup_intel(); } + +#define SL_FS_ENTRIES 10 +/* root directory node must be last */ +#define SL_ROOT_DIR_ENTRY (SL_FS_ENTRIES - 1) +#define SL_TXT_DIR_ENTRY (SL_FS_ENTRIES - 2) +#define SL_TXT_FILE_FIRST (SL_TXT_DIR_ENTRY - 1) +#define SL_TXT_ENTRY_COUNT 7 + +#define DECLARE_TXT_PUB_READ_U(size, fmt, msg_size) \ +static ssize_t txt_pub_read_u##size(unsigned int offset, \ + loff_t *read_offset, \ + size_t read_len, \ + char __user *buf) \ +{ \ + void __iomem *txt; \ + char msg_buffer[msg_size]; \ + u##size reg_value = 0; \ + txt = ioremap(TXT_PUB_CONFIG_REGS_BASE, \ + TXT_NR_CONFIG_PAGES * PAGE_SIZE); \ + if (IS_ERR(txt)) \ + return PTR_ERR(txt); \ + memcpy_fromio(®_value, txt + offset, sizeof(u##size)); \ + iounmap(txt); \ + snprintf(msg_buffer, msg_size, fmt, reg_value); \ + return simple_read_from_buffer(buf, read_len, read_offset, \ + &msg_buffer, msg_size); \ +} + +DECLARE_TXT_PUB_READ_U(8, "%#04x\n", 6); +DECLARE_TXT_PUB_READ_U(32, "%#010x\n", 12); +DECLARE_TXT_PUB_READ_U(64, "%#018llx\n", 20); + +#define DECLARE_TXT_FOPS(reg_name, reg_offset, reg_size) \ +static ssize_t txt_##reg_name##_read(struct file *flip, \ + char __user *buf, size_t read_len, loff_t *read_offset) \ +{ \ + return txt_pub_read_u##reg_size(reg_offset, read_offset, \ + read_len, buf); \ +} \ +static const struct file_operations reg_name##_ops = { \ + .read = txt_##reg_name##_read, \ +} + +DECLARE_TXT_FOPS(sts, TXT_CR_STS, 64); +DECLARE_TXT_FOPS(ests, TXT_CR_ESTS, 8); +DECLARE_TXT_FOPS(errorcode, TXT_CR_ERRORCODE, 32); +DECLARE_TXT_FOPS(didvid, TXT_CR_DIDVID, 64); +DECLARE_TXT_FOPS(e2sts, TXT_CR_E2STS, 64); +DECLARE_TXT_FOPS(ver_emif, TXT_CR_VER_EMIF, 32); +DECLARE_TXT_FOPS(scratchpad, TXT_CR_SCRATCHPAD, 64); + +/* + * Securityfs exposure + */ +struct memfile { + char *name; + void *addr; + size_t size; +}; + +static struct memfile sl_evtlog = {"eventlog", 0, 0}; +static void *txt_heap; +static struct txt_heap_event_log_pointer2_1_element __iomem *evtlog20; +static DEFINE_MUTEX(sl_evt_log_mutex); + +static ssize_t sl_evtlog_read(struct file *file, char __user *buf, + size_t count, loff_t *pos) +{ + ssize_t size; + + if (!sl_evtlog.addr) + return 0; + + mutex_lock(&sl_evt_log_mutex); + size = simple_read_from_buffer(buf, count, pos, sl_evtlog.addr, + sl_evtlog.size); + mutex_unlock(&sl_evt_log_mutex); + + return size; +} + +static ssize_t sl_evtlog_write(struct file *file, const char __user *buf, + size_t datalen, loff_t *ppos) +{ + char *data; + ssize_t result; + + if (!sl_evtlog.addr) + return 0; + + /* No partial writes. */ + result = -EINVAL; + if (*ppos != 0) + goto out; + + data = memdup_user(buf, datalen); + if (IS_ERR(data)) { + result = PTR_ERR(data); + goto out; + } + + mutex_lock(&sl_evt_log_mutex); + if (evtlog20) + result = tpm20_log_event(evtlog20, sl_evtlog.addr, + datalen, data); + else + result = tpm12_log_event(sl_evtlog.addr, datalen, data); + mutex_unlock(&sl_evt_log_mutex); + + kfree(data); +out: + return result; +} + +static const struct file_operations sl_evtlog_ops = { + .read = sl_evtlog_read, + .write = sl_evtlog_write, + .llseek = default_llseek, +}; + +static struct dentry *fs_entries[SL_FS_ENTRIES]; + +struct sfs_file { + int parent; + const char *name; + const struct file_operations *fops; +}; + +static const struct sfs_file sl_files[] = { + { SL_TXT_DIR_ENTRY, "sts", &sts_ops }, + { SL_TXT_DIR_ENTRY, "ests", &ests_ops }, + { SL_TXT_DIR_ENTRY, "errorcode", &errorcode_ops }, + { SL_TXT_DIR_ENTRY, "didvid", &didvid_ops }, + { SL_TXT_DIR_ENTRY, "ver_emif", &ver_emif_ops }, + { SL_TXT_DIR_ENTRY, "scratchpad", &scratchpad_ops }, + { SL_TXT_DIR_ENTRY, "e2sts", &e2sts_ops } +}; + +static int sl_create_file(int entry, int parent, const char *name, + const struct file_operations *ops) +{ + if (entry < 0 || entry > SL_TXT_DIR_ENTRY) + return -EINVAL; + fs_entries[entry] = securityfs_create_file(name, 0440, + fs_entries[parent], NULL, ops); + if (IS_ERR(fs_entries[entry])) { + pr_err("Error creating securityfs %s file\n", name); + return PTR_ERR(fs_entries[entry]); + } + return 0; +} + +static long slaunch_expose_securityfs(void) +{ + long ret = 0; + int i = 0; + + fs_entries[SL_ROOT_DIR_ENTRY] = securityfs_create_dir("slaunch", NULL); + if (IS_ERR(fs_entries[SL_ROOT_DIR_ENTRY])) { + pr_err("Error creating securityfs slaunch root directory\n"); + ret = PTR_ERR(fs_entries[SL_ROOT_DIR_ENTRY]); + goto err; + } + + if (sl_flags & SL_FLAG_ARCH_TXT) { + fs_entries[SL_TXT_DIR_ENTRY] = securityfs_create_dir("txt", + fs_entries[SL_ROOT_DIR_ENTRY]); + if (IS_ERR(fs_entries[SL_TXT_DIR_ENTRY])) { + pr_err("Error creating securityfs txt directory\n"); + ret = PTR_ERR(fs_entries[SL_TXT_DIR_ENTRY]); + goto err_dir; + } + + for (i = 0; i < SL_TXT_ENTRY_COUNT; i++) { + ret = sl_create_file(SL_TXT_FILE_FIRST - i, + sl_files[i].parent, sl_files[i].name, + sl_files[i].fops); + if (ret) + goto err_dir; + } + } + + if (sl_evtlog.addr > 0) { + ret = sl_create_file(0, SL_ROOT_DIR_ENTRY, sl_evtlog.name, + &sl_evtlog_ops); + if (ret) + goto err_dir; + } + + return 0; + +err_dir: + for (i = 0; i <= SL_ROOT_DIR_ENTRY; i++) + securityfs_remove(fs_entries[i]); +err: + return ret; +} + +static void slaunch_teardown_securityfs(void) +{ + int i; + + for (i = 0; i < SL_FS_ENTRIES; i++) + securityfs_remove(fs_entries[i]); + + if (sl_flags & SL_FLAG_ARCH_TXT) { + if (sl_evtlog.addr) { + memunmap(sl_evtlog.addr); + sl_evtlog.addr = NULL; + } + sl_evtlog.size = 0; + if (txt_heap) { + memunmap(txt_heap); + txt_heap = NULL; + } + } +} + +static void slaunch_intel_evtlog(void) +{ + void __iomem *config; + struct txt_os_mle_data *params; + void *os_sinit_data; + u64 base, size; + + config = ioremap(TXT_PUB_CONFIG_REGS_BASE, TXT_NR_CONFIG_PAGES * + PAGE_SIZE); + if (!config) { + pr_err("Error failed to ioremap TXT reqs\n"); + return; + } + + memcpy_fromio(&base, config + TXT_CR_HEAP_BASE, sizeof(u64)); + memcpy_fromio(&size, config + TXT_CR_HEAP_SIZE, sizeof(u64)); + iounmap(config); + + /* now map TXT heap */ + txt_heap = memremap(base, size, MEMREMAP_WB); + if (!txt_heap) { + pr_err("Error failed to memremap TXT heap\n"); + return; + } + + params = (struct txt_os_mle_data *)txt_os_mle_data_start(txt_heap); + + sl_evtlog.size = params->evtlog_size; + sl_evtlog.addr = memremap(params->evtlog_addr, params->evtlog_size, + MEMREMAP_WB); + if (!sl_evtlog.addr) { + pr_err("Error failed to memremap TPM event log\n"); + return; + } + + /* Determine if this is TPM 1.2 or 2.0 event log */ + if (memcmp(sl_evtlog.addr + sizeof(struct tpm12_pcr_event), + TPM20_EVTLOG_SIGNATURE, sizeof(TPM20_EVTLOG_SIGNATURE))) + return; /* looks like it is not 2.0 */ + + /* For TPM 2.0 logs, the extended heap element must be located */ + os_sinit_data = txt_os_sinit_data_start(txt_heap); + + evtlog20 = tpm20_find_log2_1_element(os_sinit_data); + + /* + * If this fails, things are in really bad shape. Any attempt to write + * events to the log will fail. + */ + if (!evtlog20) + pr_err("Error failed to find TPM20 event log element\n"); +} + +static int __init slaunch_late_init(void) +{ + /* Check to see if Secure Launch happened */ + if (!(sl_flags & (SL_FLAG_ACTIVE|SL_FLAG_ARCH_TXT))) + return 0; + + /* Only Intel TXT is supported at this point */ + slaunch_intel_evtlog(); + + return slaunch_expose_securityfs(); +} + +static void __exit slaunch_exit(void) +{ + slaunch_teardown_securityfs(); +} + +late_initcall(slaunch_late_init); + +__exitcall(slaunch_exit); From patchwork Thu Sep 24 14:58:39 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ross Philipson X-Patchwork-Id: 11797645 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D44116CA for ; Thu, 24 Sep 2020 14:59:12 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B76E52311B for ; Thu, 24 Sep 2020 14:59:12 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=oracle.com header.i=@oracle.com header.b="QOMLsak1" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728408AbgIXO7L (ORCPT ); Thu, 24 Sep 2020 10:59:11 -0400 Received: from aserp2120.oracle.com ([141.146.126.78]:55920 "EHLO aserp2120.oracle.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728409AbgIXO6k (ORCPT ); Thu, 24 Sep 2020 10:58:40 -0400 Received: from pps.filterd (aserp2120.oracle.com [127.0.0.1]) by aserp2120.oracle.com (8.16.0.42/8.16.0.42) with SMTP id 08OEtNw4037511; Thu, 24 Sep 2020 14:58:20 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=from : to : cc : subject : date : message-id : in-reply-to : references; s=corp-2020-01-29; bh=qOx/WyIlX35flcYkRZF1E+iVsPY37zuDH5frIC2qMd0=; b=QOMLsak1AaK0UlwuJY54v7vqFZhJeJDEfG7OAoqaAdCwdOpo3GmutTgMAFVB7qwZLybv LP1GDNgDy72KIPR9c5u5zDWZNIPgY2WhFP2rz+V0blWtmy1YG0XKU+g8HJhvwNh5H3/o VeN40E9SUsjzYa2/loEK0YmoJ2cTLk0RKpOs9kj8RpI33Nx+9ZXsojGB5wjqYW7Z0RVH s8StFAWWGl3+4xAJI9P4CclJizomjyNFmrvSs0ogBG3O31dYYWs1awf3drMkPZxL4R4v +8M/2KuBH/LTtlGn/0bzvHXFZqssU/NjKe2Vj3LaMVbnkUUYxf7KV77I6geveHAYwhnB BQ== Received: from userp3020.oracle.com (userp3020.oracle.com [156.151.31.79]) by aserp2120.oracle.com with ESMTP id 33q5rgq588-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Thu, 24 Sep 2020 14:58:20 +0000 Received: from pps.filterd (userp3020.oracle.com [127.0.0.1]) by userp3020.oracle.com (8.16.0.42/8.16.0.42) with SMTP id 08OEuTdp096380; Thu, 24 Sep 2020 14:58:19 GMT Received: from userv0121.oracle.com (userv0121.oracle.com [156.151.31.72]) by userp3020.oracle.com with ESMTP id 33nurw9x6n-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 24 Sep 2020 14:58:19 +0000 Received: from abhmp0014.oracle.com (abhmp0014.oracle.com [141.146.116.20]) by userv0121.oracle.com (8.14.4/8.13.8) with ESMTP id 08OEwHYF000852; Thu, 24 Sep 2020 14:58:17 GMT Received: from disposition.us.oracle.com (/10.152.32.81) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Thu, 24 Sep 2020 07:58:17 -0700 From: Ross Philipson To: linux-kernel@vger.kernel.org, x86@kernel.org, iommu@lists.linux-foundation.org, linux-integrity@vger.kernel.org, linux-doc@vger.kernel.org Cc: ross.philipson@oracle.com, dpsmith@apertussolutions.com, tglx@linutronix.de, mingo@redhat.com, bp@alien8.de, hpa@zytor.com, luto@amacapital.net, trenchboot-devel@googlegroups.com Subject: [PATCH 11/13] kexec: Secure Launch kexec SEXIT support Date: Thu, 24 Sep 2020 10:58:39 -0400 Message-Id: <1600959521-24158-12-git-send-email-ross.philipson@oracle.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1600959521-24158-1-git-send-email-ross.philipson@oracle.com> References: <1600959521-24158-1-git-send-email-ross.philipson@oracle.com> X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9753 signatures=668680 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 adultscore=0 malwarescore=0 phishscore=0 mlxlogscore=999 bulkscore=0 mlxscore=0 suspectscore=0 spamscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2006250000 definitions=main-2009240114 X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9753 signatures=668680 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 spamscore=0 impostorscore=0 clxscore=1015 suspectscore=0 phishscore=0 malwarescore=0 priorityscore=1501 mlxlogscore=999 adultscore=0 bulkscore=0 mlxscore=0 lowpriorityscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2006250000 definitions=main-2009240114 Precedence: bulk List-ID: X-Mailing-List: linux-integrity@vger.kernel.org Prior to running the next kernel via kexec, the Secure Launch code closes down private SMX resources and does an SEXIT. This allows the next kernel to start normally without any issues starting the APs etc. Signed-off-by: Ross Philipson --- arch/x86/kernel/slaunch.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++ kernel/kexec_core.c | 4 +++ 2 files changed, 74 insertions(+) diff --git a/arch/x86/kernel/slaunch.c b/arch/x86/kernel/slaunch.c index 7bdb89e..b2221d8 100644 --- a/arch/x86/kernel/slaunch.c +++ b/arch/x86/kernel/slaunch.c @@ -784,3 +784,73 @@ static void __exit slaunch_exit(void) late_initcall(slaunch_late_init); __exitcall(slaunch_exit); + +static inline void smx_getsec_sexit(void) +{ + asm volatile (".byte 0x0f,0x37\n" + : : "a" (SMX_X86_GETSEC_SEXIT)); +} + +void slaunch_finalize(int do_sexit) +{ + void __iomem *config; + u64 one = 1, val; + + if (!(slaunch_get_flags() & (SL_FLAG_ACTIVE|SL_FLAG_ARCH_TXT))) + return; + + config = ioremap(TXT_PRIV_CONFIG_REGS_BASE, TXT_NR_CONFIG_PAGES * + PAGE_SIZE); + if (!config) { + pr_emerg("Error SEXIT failed to ioremap TXT private reqs\n"); + return; + } + + /* Clear secrets bit for SEXIT */ + memcpy_toio(config + TXT_CR_CMD_NO_SECRETS, &one, sizeof(u64)); + memcpy_fromio(&val, config + TXT_CR_E2STS, sizeof(u64)); + + /* Unlock memory configurations */ + memcpy_toio(config + TXT_CR_CMD_UNLOCK_MEM_CONFIG, &one, sizeof(u64)); + memcpy_fromio(&val, config + TXT_CR_E2STS, sizeof(u64)); + + /* Close the TXT private register space */ + memcpy_fromio(&val, config + TXT_CR_E2STS, sizeof(u64)); + memcpy_toio(config + TXT_CR_CMD_CLOSE_PRIVATE, &one, sizeof(u64)); + + /* + * Calls to iounmap are not being done because of the state of the + * system this late in the kexec process. Local IRQs are disabled and + * iounmap causes a TLB flush which in turn causes a warning. Leaving + * thse mappings is not an issue since the next kernel is going to + * completely re-setup memory management. + */ + + /* Map public registers and do a final read fence */ + config = ioremap(TXT_PUB_CONFIG_REGS_BASE, TXT_NR_CONFIG_PAGES * + PAGE_SIZE); + if (!config) { + pr_emerg("Error SEXIT failed to ioremap TXT public reqs\n"); + return; + } + + memcpy_fromio(&val, config + TXT_CR_E2STS, sizeof(u64)); + + pr_emerg("TXT clear secrets bit and unlock memory complete."); + + if (!do_sexit) + return; + + if (smp_processor_id() != 0) { + pr_emerg("Error TXT SEXIT must be called on CPU 0\n"); + return; + } + + /* Disable SMX mode */ + cr4_set_bits(X86_CR4_SMXE); + + /* Do the SEXIT SMX operation */ + smx_getsec_sexit(); + + pr_emerg("TXT SEXIT complete."); +} diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c index c19c0da..6b9ac11 100644 --- a/kernel/kexec_core.c +++ b/kernel/kexec_core.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -1179,6 +1180,9 @@ int kernel_kexec(void) cpu_hotplug_enable(); pr_notice("Starting new kernel\n"); machine_shutdown(); + + /* Finalize TXT registers and do SEXIT */ + slaunch_finalize(1); } machine_kexec(kexec_image); From patchwork Thu Sep 24 14:58:40 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ross Philipson X-Patchwork-Id: 11797637 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id BE6096CA for ; Thu, 24 Sep 2020 14:59:07 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9203C23A32 for ; Thu, 24 Sep 2020 14:59:07 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=oracle.com header.i=@oracle.com header.b="d+wrP197" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728429AbgIXO6x (ORCPT ); Thu, 24 Sep 2020 10:58:53 -0400 Received: from aserp2120.oracle.com ([141.146.126.78]:56014 "EHLO aserp2120.oracle.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728443AbgIXO6o (ORCPT ); Thu, 24 Sep 2020 10:58:44 -0400 Received: from pps.filterd (aserp2120.oracle.com [127.0.0.1]) by aserp2120.oracle.com (8.16.0.42/8.16.0.42) with SMTP id 08OEtG6L037473; Thu, 24 Sep 2020 14:58:21 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=from : to : cc : subject : date : message-id : in-reply-to : references; s=corp-2020-01-29; bh=uC5h3cusDAhwlGCCvDkY2qHUOCSMEHI64B7ZwPT8TG8=; b=d+wrP197JkSZeRU0ToJp4H5+e6NWuYpPGyv2FArOWMjRkndnYgJV7ORSXccE/WIUlGcH 8hVZluIa8OQi2BUw0ncvdXwOIGC1/KIAJtueXBrq1oax/V30xNIaiTAVaH3vb0eHbilu 7OeNlR1S76VsssfLFC3+CRjcWn8wT95rvQJ+W20OHVfNcYY21Dbknnjg4lu9rjLEpOw0 mrPYqPjKIuWhaSqbY/f6q596YEXV20krNV+Aub72LjzSDhWxgfwI/JQfPTPQARlxJBlg KnMFElffySZ/plRPzlfNh+AWXmhzUBevrEFDg5hbHUB7zwGLeh9mVx9wVuvxR7KrHLEk Bw== Received: from aserp3030.oracle.com (aserp3030.oracle.com [141.146.126.71]) by aserp2120.oracle.com with ESMTP id 33q5rgq58e-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Thu, 24 Sep 2020 14:58:21 +0000 Received: from pps.filterd (aserp3030.oracle.com [127.0.0.1]) by aserp3030.oracle.com (8.16.0.42/8.16.0.42) with SMTP id 08OEuSQg126153; Thu, 24 Sep 2020 14:58:21 GMT Received: from userv0121.oracle.com (userv0121.oracle.com [156.151.31.72]) by aserp3030.oracle.com with ESMTP id 33nujr18ff-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 24 Sep 2020 14:58:21 +0000 Received: from abhmp0014.oracle.com (abhmp0014.oracle.com [141.146.116.20]) by userv0121.oracle.com (8.14.4/8.13.8) with ESMTP id 08OEwIFX000856; Thu, 24 Sep 2020 14:58:18 GMT Received: from disposition.us.oracle.com (/10.152.32.81) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Thu, 24 Sep 2020 07:58:18 -0700 From: Ross Philipson To: linux-kernel@vger.kernel.org, x86@kernel.org, iommu@lists.linux-foundation.org, linux-integrity@vger.kernel.org, linux-doc@vger.kernel.org Cc: ross.philipson@oracle.com, dpsmith@apertussolutions.com, tglx@linutronix.de, mingo@redhat.com, bp@alien8.de, hpa@zytor.com, luto@amacapital.net, trenchboot-devel@googlegroups.com Subject: [PATCH 12/13] reboot: Secure Launch SEXIT support on reboot paths Date: Thu, 24 Sep 2020 10:58:40 -0400 Message-Id: <1600959521-24158-13-git-send-email-ross.philipson@oracle.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1600959521-24158-1-git-send-email-ross.philipson@oracle.com> References: <1600959521-24158-1-git-send-email-ross.philipson@oracle.com> X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9753 signatures=668680 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 bulkscore=0 malwarescore=0 mlxlogscore=999 phishscore=0 adultscore=0 spamscore=0 suspectscore=0 mlxscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2006250000 definitions=main-2009240114 X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9753 signatures=668680 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 spamscore=0 impostorscore=0 clxscore=1015 suspectscore=0 phishscore=0 malwarescore=0 priorityscore=1501 mlxlogscore=999 adultscore=0 bulkscore=0 mlxscore=0 lowpriorityscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2006250000 definitions=main-2009240114 Precedence: bulk List-ID: X-Mailing-List: linux-integrity@vger.kernel.org If the MLE kernel is being powered off, rebooted or halted, then SEXIT must be called. Note that the SEXIT GETSEC leaf can only be called after a machine_shutdown() has been done on these paths. The machine_shutdown() is not called on a few paths like when poweroff action does not have a poweroff callback (into ACPI code) or when an emergency reset is done. In these cases, just the TXT registers are finalized but SEXIT is skipped. Signed-off-by: Ross Philipson --- arch/x86/kernel/reboot.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index a515e2d..90d0647 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -732,6 +733,7 @@ static void native_machine_restart(char *__unused) if (!reboot_force) machine_shutdown(); + slaunch_finalize(!reboot_force); __machine_emergency_restart(0); } @@ -742,6 +744,9 @@ static void native_machine_halt(void) tboot_shutdown(TB_SHUTDOWN_HALT); + /* SEXIT done after machine_shutdown() to meet TXT requirements */ + slaunch_finalize(1); + stop_this_cpu(NULL); } @@ -750,8 +755,12 @@ static void native_machine_power_off(void) if (pm_power_off) { if (!reboot_force) machine_shutdown(); + slaunch_finalize(!reboot_force); pm_power_off(); + } else { + slaunch_finalize(0); } + /* A fallback in case there is no PM info available */ tboot_shutdown(TB_SHUTDOWN_HALT); } @@ -779,6 +788,7 @@ void machine_shutdown(void) void machine_emergency_restart(void) { + slaunch_finalize(0); __machine_emergency_restart(1); } From patchwork Thu Sep 24 14:58:41 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ross Philipson X-Patchwork-Id: 11797649 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 706936CB for ; Thu, 24 Sep 2020 14:59:21 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 4B0DA206C3 for ; Thu, 24 Sep 2020 14:59:21 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=oracle.com header.i=@oracle.com header.b="dRmZk9zT" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728405AbgIXO6i (ORCPT ); Thu, 24 Sep 2020 10:58:38 -0400 Received: from userp2120.oracle.com ([156.151.31.85]:48080 "EHLO userp2120.oracle.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728395AbgIXO6d (ORCPT ); Thu, 24 Sep 2020 10:58:33 -0400 Received: from pps.filterd (userp2120.oracle.com [127.0.0.1]) by userp2120.oracle.com (8.16.0.42/8.16.0.42) with SMTP id 08OEsvoK071951; Thu, 24 Sep 2020 14:58:20 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=from : to : cc : subject : date : message-id : in-reply-to : references; s=corp-2020-01-29; bh=vaYMWdLIOGxcNOMQTNn3bCU6SyHr+JucLkpHQ7mukEM=; b=dRmZk9zTDAL/dli17qKPLMAflBh4u8NCrCW3zKgSZMbzSC4YwYvZ/6kRDGvtE78zIGC3 Gwq3UKwuhxSqqnKh4tpvuXNclH3IvmeLhiXWv/NyfOfJqBVBHp55YTSObVKM3PRTs5mw T22i9NwH5rkwlZ7BZRjIylt4Icgc8AGawti7qV2sEDG7b07yE/fNFNj+PSYKLE2ExQAJ 4TbPcvWysd4N8OaOxyH4XqbkKKi38Fop0EgUidAWHEzAEmwaDyxVRdPUNe5/thOt/18W pcOts2kFW5UWGStl3/7l+qwSVz6xZirpDkCAKFdjFzrd1uVlB4zLmxJxXORvgVpaeZBJ GQ== Received: from userp3020.oracle.com (userp3020.oracle.com [156.151.31.79]) by userp2120.oracle.com with ESMTP id 33ndnurumg-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Thu, 24 Sep 2020 14:58:20 +0000 Received: from pps.filterd (userp3020.oracle.com [127.0.0.1]) by userp3020.oracle.com (8.16.0.42/8.16.0.42) with SMTP id 08OEuTRK096375; Thu, 24 Sep 2020 14:58:20 GMT Received: from aserv0122.oracle.com (aserv0122.oracle.com [141.146.126.236]) by userp3020.oracle.com with ESMTP id 33nurw9x6s-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 24 Sep 2020 14:58:20 +0000 Received: from abhmp0014.oracle.com (abhmp0014.oracle.com [141.146.116.20]) by aserv0122.oracle.com (8.14.4/8.14.4) with ESMTP id 08OEwJiT002831; Thu, 24 Sep 2020 14:58:19 GMT Received: from disposition.us.oracle.com (/10.152.32.81) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Thu, 24 Sep 2020 07:58:18 -0700 From: Ross Philipson To: linux-kernel@vger.kernel.org, x86@kernel.org, iommu@lists.linux-foundation.org, linux-integrity@vger.kernel.org, linux-doc@vger.kernel.org Cc: ross.philipson@oracle.com, dpsmith@apertussolutions.com, tglx@linutronix.de, mingo@redhat.com, bp@alien8.de, hpa@zytor.com, luto@amacapital.net, trenchboot-devel@googlegroups.com Subject: [PATCH 13/13] tpm: Allow locality 2 to be set when initializing the TPM for Secure Launch Date: Thu, 24 Sep 2020 10:58:41 -0400 Message-Id: <1600959521-24158-14-git-send-email-ross.philipson@oracle.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1600959521-24158-1-git-send-email-ross.philipson@oracle.com> References: <1600959521-24158-1-git-send-email-ross.philipson@oracle.com> X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9753 signatures=668680 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 adultscore=0 malwarescore=0 phishscore=0 mlxlogscore=999 bulkscore=0 mlxscore=0 suspectscore=0 spamscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2006250000 definitions=main-2009240114 X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9753 signatures=668680 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 priorityscore=1501 malwarescore=0 lowpriorityscore=0 phishscore=0 adultscore=0 suspectscore=0 bulkscore=0 clxscore=1015 impostorscore=0 mlxlogscore=999 mlxscore=0 spamscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2006250000 definitions=main-2009240114 Precedence: bulk List-ID: X-Mailing-List: linux-integrity@vger.kernel.org The Secure Launch MLE environment uses PCRs that are only accessible from the DRTM locality 2. By default the TPM drivers always initialize the locality to 0. When a Secure Launch is in progress, initialize the locality to 2. Signed-off-by: Ross Philipson --- drivers/char/tpm/tpm-chip.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index ddaeceb..f35faab 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "tpm.h" DEFINE_IDR(dev_nums_idr); @@ -34,12 +35,20 @@ static int tpm_request_locality(struct tpm_chip *chip) { - int rc; + int rc, locality; if (!chip->ops->request_locality) return 0; - rc = chip->ops->request_locality(chip, 0); + if (slaunch_get_flags() & (SL_FLAG_ACTIVE|SL_FLAG_ARCH_TXT)) { + dev_dbg(&chip->dev, "setting TPM locality to 2 for MLE\n"); + locality = 2; + } else { + dev_dbg(&chip->dev, "setting TPM locality to 0\n"); + locality = 0; + } + + rc = chip->ops->request_locality(chip, locality); if (rc < 0) return rc;