linux-doc.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support
@ 2020-03-25 19:43 Ross Philipson
  2020-03-25 19:43 ` [RFC PATCH 01/12] x86: Secure Launch Kconfig Ross Philipson
                   ` (12 more replies)
  0 siblings, 13 replies; 43+ messages in thread
From: Ross Philipson @ 2020-03-25 19:43 UTC (permalink / raw)
  To: linux-kernel, x86, linux-doc
  Cc: ross.philipson, dpsmith, tglx, mingo, bp, hpa, trenchboot-devel

The Trenchboot project focus on boot security has led to the enabling of
the Linux kernel to be directly invocable by the x86 Dynamic Launch
instruction(s) for establishing a Dynamic Root of Trust for Measurement
(DRTM). The dynamic launch will be initiated by a boot loader with
associated support added to it, for example the first targeted boot
loader will be GRUB2. An integral part of establishing the DRTM involves
measuring everything that is intended to be run (kernel image, initrd,
etc) and everything that will configure that kernel to run (command
line, boot params, etc) into specific PCRs, the DRTM PCRs (17-22), in
the TPM. Another key aspect is the dynamic launch is rooted in hardware.
On Intel this is done using the GETSEC instruction set provided by
Intel's TXT and the SKINIT instruction provided by AMD's AMD-V.
Information on these technologies can be readily found online.

To enable the kernel to be launched by GETSEC or SKINIT, a stub must be
built into the setup section of the compressed kernel to handle the
specific state that the late launch process leaves the BSP. This is a
lot like the EFI stub that is found in the same area. Also this stub
must measure everything that is going to be used as early as possible.
This stub code and subsequent code must also deal with the specific
state that the late launch leaves the APs in.

A quick note on terminology. The larger open source project itself is
called Trenchboot, which is hosted on Github (links below). The kernel
feature enabling the use of the x86 technology is referred to as "Secure
Launch" within the kernel code. As such the prefixes sl_/SL_ or
slaunch/SLAUNCH will be seen in the code. The stub code discussed above
is referred to as the SL stub.

The basic flow is:

 - Entry from the late launch jumps to the SL stub
 - SL stub fixes up the world on the BSP
 - For TXT, SL stub wakes the APs, fixes up their worlds
 - For TXT, APs are left halted waiting for an NMI to wake them
 - SL stub jumps to startup_32
 - SL main runs to measure configuration and module information into the
   DRTM PCRs. It also locates the TPM event log.
 - Kernel boot proceeds normally from this point.
 - During early setup, slaunch_setup() runs to finish some validation
   and setup tasks.
 - The SMP bringup code is modified to wake the waiting APs. APs vector
   to rmpiggy and start up normally from that point.
 - Kernel boot finishes booting normally
 - SL securityfs module is present to allow reading and writing of the
   TPM event log.

Outstanding:

 - Currently Secure Launch only supports TXT, though there is an AMD
   version is in progress.
 - The compressed kernel TPM code includes a CRB interface
   implementation but is untested due to inability to locate a system
   with TXT and a TPM accessible with the CRB interface
 - There is a known crash that is difficult to reproduce and is unclear
   how the secure launch code is causing the crash. Thread on it here:
   https://groups.google.com/forum/#!topic/trenchboot-devel/EZN_4ymrCgs

Links:

The Trenchboot project including documentation:

https://github.com/trenchboot

Intel TXT is documented in its own specification and in the SDM Instruction Set volume:

https://www.intel.com/content/dam/www/public/us/en/documents/guides/intel-txt-software-development-guide.pdf
https://software.intel.com/en-us/articles/intel-sdm

AMD SKINIT is documented in the System Programming manual:

https://www.amd.com/system/files/TechDocs/24593.pdf

Thanks
Ross Philipson and Daniel P. Smith

Daniel P. Smith (5):
  x86: Add early SHA support for Secure Launch early measurements
  x86: Add early TPM TIS/CRB interface support for Secure Launch
  x86: Add early TPM1.2/TPM2.0 interface support for Secure Launch
  x86: Add early general TPM interface support for Secure Launch
  x86: Secure Launch adding event log securityfs

Ross Philipson (7):
  x86: Secure Launch Kconfig
  x86: Secure Launch main header file
  x86: Secure Launch kernel early boot stub
  x86: Secure Launch kernel late boot stub
  x86: Secure Launch SMP bringup support
  kexec: Secure Launch kexec SEXIT support
  tpm: Allow locality 2 to be set when initializing the TPM for Secure
    Launch

 Documentation/x86/boot.rst                    |   9 +
 arch/x86/Kconfig                              |  35 +
 arch/x86/boot/compressed/Makefile             |   8 +
 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 +
 arch/x86/boot/compressed/head_64.S            |  32 +
 arch/x86/boot/compressed/kernel_info.S        |   3 +
 arch/x86/boot/compressed/sl_main.c            | 378 ++++++++++
 arch/x86/boot/compressed/sl_stub.S            | 568 ++++++++++++++
 arch/x86/boot/compressed/tpm/crb.c            | 302 ++++++++
 arch/x86/boot/compressed/tpm/crb.h            |  25 +
 arch/x86/boot/compressed/tpm/tis.c            | 212 ++++++
 arch/x86/boot/compressed/tpm/tis.h            |  51 ++
 arch/x86/boot/compressed/tpm/tpm.c            | 190 +++++
 arch/x86/boot/compressed/tpm/tpm.h            |  42 ++
 arch/x86/boot/compressed/tpm/tpm1.h           | 112 +++
 arch/x86/boot/compressed/tpm/tpm1_cmds.c      | 133 ++++
 arch/x86/boot/compressed/tpm/tpm2.h           |  89 +++
 arch/x86/boot/compressed/tpm/tpm2_auth.c      |  31 +
 arch/x86/boot/compressed/tpm/tpm2_auth.h      |  21 +
 arch/x86/boot/compressed/tpm/tpm2_cmds.c      | 150 ++++
 arch/x86/boot/compressed/tpm/tpm2_constants.h |  66 ++
 arch/x86/boot/compressed/tpm/tpm_buff.c       | 135 ++++
 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 ++
 arch/x86/boot/compressed/vmlinux.lds.S        |   4 +
 arch/x86/include/asm/realmode.h               |   3 +
 arch/x86/kernel/Makefile                      |   1 +
 arch/x86/kernel/asm-offsets.c                 |  15 +
 arch/x86/kernel/setup.c                       |   3 +
 arch/x86/kernel/slaunch.c                     | 700 ++++++++++++++++++
 arch/x86/kernel/smpboot.c                     |  86 +++
 arch/x86/realmode/rm/header.S                 |   3 +
 arch/x86/realmode/rm/trampoline_64.S          |  37 +
 drivers/char/tpm/tpm-chip.c                   |  13 +-
 drivers/iommu/dmar.c                          |   4 +
 include/linux/sha512.h                        |  21 +
 include/linux/slaunch.h                       | 513 +++++++++++++
 kernel/kexec_core.c                           |   3 +
 lib/sha1.c                                    |   4 +
 lib/sha512.c                                  | 209 ++++++
 44 files changed, 4554 insertions(+), 2 deletions(-)
 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 arch/x86/boot/compressed/sl_main.c
 create mode 100644 arch/x86/boot/compressed/sl_stub.S
 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.c
 create mode 100644 arch/x86/boot/compressed/tpm/tpm.h
 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
 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
 create mode 100644 arch/x86/kernel/slaunch.c
 create mode 100644 include/linux/sha512.h
 create mode 100644 include/linux/slaunch.h
 create mode 100644 lib/sha512.c

-- 
2.25.1


^ permalink raw reply	[flat|nested] 43+ messages in thread

* [RFC PATCH 01/12] x86: Secure Launch Kconfig
  2020-03-25 19:43 [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support Ross Philipson
@ 2020-03-25 19:43 ` Ross Philipson
  2020-03-26 18:06   ` Daniel Kiper
  2020-03-25 19:43 ` [RFC PATCH 02/12] x86: Secure Launch main header file Ross Philipson
                   ` (11 subsequent siblings)
  12 siblings, 1 reply; 43+ messages in thread
From: Ross Philipson @ 2020-03-25 19:43 UTC (permalink / raw)
  To: linux-kernel, x86, linux-doc
  Cc: ross.philipson, dpsmith, tglx, mingo, bp, hpa, trenchboot-devel

Initial bits to bring in Secure Launch functionality. Add Kconfig
options for compiling in/out the Secure Launch code.

Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
---
 arch/x86/Kconfig | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 5e8949953660..7f3406a9948b 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -2014,6 +2014,17 @@ config EFI_MIXED
 
 	   If unsure, say N.
 
+config SECURE_LAUNCH
+	bool "Secure Launch support"
+	default n
+	depends on X86_64
+	help
+	  This Secure Launch kernel feature allows a bzImage to be loaded
+	  directly through Intel TXT or AMD SKINIT measured launch. This
+	  allows extablishing a Dynamic Root of Trust Measurement (DRTM)
+	  of all the modules and configuration information used for
+	  boooting the operating system.
+
 config SECCOMP
 	def_bool y
 	prompt "Enable seccomp to safely compute untrusted bytecode"
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [RFC PATCH 02/12] x86: Secure Launch main header file
  2020-03-25 19:43 [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support Ross Philipson
  2020-03-25 19:43 ` [RFC PATCH 01/12] x86: Secure Launch Kconfig Ross Philipson
@ 2020-03-25 19:43 ` Ross Philipson
  2020-03-26 19:00   ` Daniel Kiper
  2020-03-25 19:43 ` [RFC PATCH 03/12] x86: Add early SHA support for Secure Launch early measurements Ross Philipson
                   ` (10 subsequent siblings)
  12 siblings, 1 reply; 43+ messages in thread
From: Ross Philipson @ 2020-03-25 19:43 UTC (permalink / raw)
  To: linux-kernel, x86, linux-doc
  Cc: ross.philipson, dpsmith, tglx, mingo, bp, hpa, trenchboot-devel

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=y, Size: 13519 bytes --]

Introduce the main Secure Launch header file used in the early SL stub
and the early setup code.

Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
---
 include/linux/slaunch.h | 513 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 513 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 000000000000..8f090dc38984
--- /dev/null
+++ b/include/linux/slaunch.h
@@ -0,0 +1,513 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#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_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_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_MAX_EVENT_LOG_SIZE		(5*4*1024)   /* 4k*5 */
+#define TXT_MAX_VARIABLE_MTRRS		32
+#define TXT_OS_MLE_STRUCT_VERSION	1
+
+/*
+ * 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_HEAP_ZERO_OFFSET	0xc0008018
+
+/*
+ * 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_EBP		0
+#define SL_SCRATCH_AP_JMP_OFFSET	4
+
+#ifndef __ASSEMBLY__
+
+/*
+ * Secure Launch AP wakeup information fetched in SMP boot code.
+ */
+struct sl_ap_wake_info {
+	u64 ap_wake_block;
+	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_MAX_VARIABLE_MTRRS];
+} __packed;
+
+/*
+ * Secure Launch defined OS/MLE TXT Heap table
+ */
+struct txt_os_mle_data {
+	u32 version;
+	u32 zero_page_addr;
+	u8 msb_key_hash[20];
+	u64 saved_misc_enable_msr;
+	struct txt_mtrr_state saved_bsp_mtrrs;
+	u64 ap_wake_block;
+	/* These two fields should always be last */
+	u64 mle_scratch;
+	u8 event_log_buffer[TXT_MAX_EVENT_LOG_SIZE];
+} __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;
+
+#include <linux/io.h>
+
+/*
+ * Functions to extract data from the Intel TXT Heap Memory
+ */
+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_sexit(void);
+
+#endif /* !__ASSEMBLY */
+
+#else
+
+#define slaunch_setup()			do { } while (0)
+#define slaunch_get_flags()		0
+#define slaunch_get_dmar_table(d)	(d)
+#define slaunch_sexit()			do { } while (0)
+
+#endif /* !CONFIG_SECURE_LAUNCH */
+
+#endif /* _LINUX_SLAUNCH_H */
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [RFC PATCH 03/12] x86: Add early SHA support for Secure Launch early measurements
  2020-03-25 19:43 [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support Ross Philipson
  2020-03-25 19:43 ` [RFC PATCH 01/12] x86: Secure Launch Kconfig Ross Philipson
  2020-03-25 19:43 ` [RFC PATCH 02/12] x86: Secure Launch main header file Ross Philipson
@ 2020-03-25 19:43 ` Ross Philipson
  2020-03-26  3:44   ` Andy Lutomirski
  2020-03-25 19:43 ` [RFC PATCH 04/12] x86: Add early TPM TIS/CRB interface support for Secure Launch Ross Philipson
                   ` (9 subsequent siblings)
  12 siblings, 1 reply; 43+ messages in thread
From: Ross Philipson @ 2020-03-25 19:43 UTC (permalink / raw)
  To: linux-kernel, x86, linux-doc
  Cc: ross.philipson, dpsmith, tglx, mingo, bp, hpa, trenchboot-devel

From: "Daniel P. Smith" <dpsmith@apertussolutions.com>

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 SHA1 code here has its origins in the code in
include/crypto/sha1_base.h. That code could not be pulled directly into
the setup portion of the compressed kernel because of other dependencies
it pulls in. So this is a modified copy of that code that still leverages
the core SHA1 algorithm.

Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com>
---
 arch/x86/Kconfig                        |  24 +++
 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 ++++++++++++++++++++++++
 9 files changed, 395 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/Kconfig b/arch/x86/Kconfig
index 7f3406a9948b..f37057d3ce9f 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -2025,6 +2025,30 @@ config SECURE_LAUNCH
 	  of all the modules and configuration information used for
 	  boooting the operating system.
 
+choice
+	prompt "Select Secure Launch Algorithm for TPM2"
+	depends on SECURE_LAUNCH
+
+config SECURE_LAUNCH_SHA1
+	bool "Secure Launch TPM2 SHA1"
+	help
+	  When using Secure Launch and TPM2 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"
diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
index 1dac210f7d44..1f25bbdd72fb 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -93,6 +93,10 @@ vmlinux-objs-$(CONFIG_EFI_STUB) += $(obj)/eboot.o $(obj)/efi_stub_$(BITS).o \
 	$(objtree)/drivers/firmware/efi/libstub/lib.a
 vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_thunk_$(BITS).o
 
+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 000000000000..605c984ca5cf
--- /dev/null
+++ b/arch/x86/boot/compressed/early_sha1.c
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019 Apertus Solutions, LLC.
+ */
+
+#include <linux/init.h>
+#include <linux/linkage.h>
+#include <linux/string.h>
+#include <asm/boot.h>
+#include <asm/unaligned.h>
+
+#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[SHA_WORKSPACE_WORDS];
+
+	sha_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)
+{
+	sha_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 000000000000..58e2404fb301
--- /dev/null
+++ b/arch/x86/boot/compressed/early_sha1.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef BOOT_COMPRESSED_EARLY_SHA1_H
+#define BOOT_COMPRESSED_EARLY_SHA1_H
+
+/*
+ * Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include <crypto/sha.h>
+
+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 000000000000..81e863296ee8
--- /dev/null
+++ b/arch/x86/boot/compressed/early_sha256.c
@@ -0,0 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 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 000000000000..a5e34cc0382f
--- /dev/null
+++ b/arch/x86/boot/compressed/early_sha512.c
@@ -0,0 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Apertus Solutions, LLC
+ */
+
+#include "../../../../lib/sha512.c"
diff --git a/include/linux/sha512.h b/include/linux/sha512.h
new file mode 100644
index 000000000000..bbf6609a50bf
--- /dev/null
+++ b/include/linux/sha512.h
@@ -0,0 +1,21 @@
+/*
+ *  Copyright (C) 2019 Apertus Solutions, LLC
+ *
+ *  Author: Daniel P. Smith <dpsmith@apertussolutions.com>
+ *
+ * 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 <linux/types.h>
+#include <crypto/sha.h>
+
+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 1d96d2c02b82..a33fb8d42b9a 100644
--- a/lib/sha1.c
+++ b/lib/sha1.c
@@ -185,7 +185,9 @@ void sha_transform(__u32 *digest, const char *data, __u32 *array)
 	digest[3] += D;
 	digest[4] += E;
 }
+#ifndef SHA1_DISABLE_EXPORT
 EXPORT_SYMBOL(sha_transform);
+#endif
 
 /**
  * sha_init - initialize the vectors for a SHA1 digest
@@ -199,4 +201,6 @@ void sha_init(__u32 *buf)
 	buf[3] = 0x10325476;
 	buf[4] = 0xc3d2e1f0;
 }
+#ifndef SHA1_DISABLE_EXPORT
 EXPORT_SYMBOL(sha_init);
+#endif
diff --git a/lib/sha512.c b/lib/sha512.c
new file mode 100644
index 000000000000..ce98d127ea6e
--- /dev/null
+++ b/lib/sha512.c
@@ -0,0 +1,209 @@
+/* SHA-512 code by Jean-Luc Cooke <jlcooke@certainkey.com>
+ *
+ * Copyright (c) Jean-Luc Cooke <jlcooke@certainkey.com>
+ * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk>
+ * Copyright (c) 2003 Kyle McMartin <kyle@debian.org>
+ * Copyright (C) 2015 Linaro Ltd <ard.biesheuvel@linaro.org>
+ * Copyright (C) 2019 Apertus Solutions, LLC <dpsmith@apertussolutions.com>
+ *
+ * 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 <linux/bitops.h>
+#include <linux/sha512.h>
+#include <linux/string.h>
+#include <asm/byteorder.h>
+
+#include <asm/unaligned.h>
+
+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;
+}
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [RFC PATCH 04/12] x86: Add early TPM TIS/CRB interface support for Secure Launch
  2020-03-25 19:43 [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support Ross Philipson
                   ` (2 preceding siblings ...)
  2020-03-25 19:43 ` [RFC PATCH 03/12] x86: Add early SHA support for Secure Launch early measurements Ross Philipson
@ 2020-03-25 19:43 ` Ross Philipson
  2020-03-25 19:43 ` [RFC PATCH 05/12] x86: Add early TPM1.2/TPM2.0 " Ross Philipson
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 43+ messages in thread
From: Ross Philipson @ 2020-03-25 19:43 UTC (permalink / raw)
  To: linux-kernel, x86, linux-doc
  Cc: ross.philipson, dpsmith, tglx, mingo, bp, hpa, trenchboot-devel

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=y, Size: 23819 bytes --]

From: "Daniel P. Smith" <dpsmith@apertussolutions.com>

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 <dpsmith@apertussolutions.com>
---
 arch/x86/boot/compressed/Makefile         |   2 +
 arch/x86/boot/compressed/tpm/crb.c        | 302 ++++++++++++++++++++++
 arch/x86/boot/compressed/tpm/crb.h        |  25 ++
 arch/x86/boot/compressed/tpm/tis.c        | 212 +++++++++++++++
 arch/x86/boot/compressed/tpm/tis.h        |  51 ++++
 arch/x86/boot/compressed/tpm/tpm.h        |  42 +++
 arch/x86/boot/compressed/tpm/tpm_buff.c   | 135 ++++++++++
 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, 981 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 1f25bbdd72fb..b9682eaf8f59 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -96,6 +96,8 @@ vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_thunk_$(BITS).o
 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 000000000000..7df29cb3688d
--- /dev/null
+++ b/arch/x86/boot/compressed/tpm/crb.c
@@ -0,0 +1,302 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Apertus Solutions, LLC
+ *
+ * Author(s):
+ *      Daniel P. Smith <dpsmith@apertussolutions.com>
+ */
+
+#include <linux/types.h>
+#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 duration_b(void)
+{
+	tpm_mdelay(750);
+}
+
+/* TPM Duration C: 1000ms */
+static void 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 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 u8 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);
+}
+
+u8 crb_init(struct tpm *t)
+{
+	u8 i;
+	struct tpm_crb_intf_id_ext id;
+
+	for (i = 0; i <= TPM_MAX_LOCALITY; i++)
+		crb_relinquish_locality_internal(i);
+
+	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();
+
+	return 1;
+}
+
+/* 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;
+	u8 count = 0;
+
+	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(struct tpmbuff *buf)
+{
+	/* noop, currently send waits until execution is complete*/
+	return 0;
+}
diff --git a/arch/x86/boot/compressed/tpm/crb.h b/arch/x86/boot/compressed/tpm/crb.h
new file mode 100644
index 000000000000..7b39a9dcd7de
--- /dev/null
+++ b/arch/x86/boot/compressed/tpm/crb.h
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Apertus Solutions, LLC
+ *
+ * Author(s):
+ *      Daniel P. Smith <dpsmith@apertussolutions.com>
+ *
+ * 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"
+
+/* TPM Interface Specification functions */
+u8 crb_request_locality(u8 l);
+void crb_relinquish_locality(void);
+u8 crb_init(struct tpm *t);
+size_t crb_send(struct tpmbuff *buf);
+size_t crb_recv(struct tpmbuff *buf);
+
+#endif
diff --git a/arch/x86/boot/compressed/tpm/tis.c b/arch/x86/boot/compressed/tpm/tis.c
new file mode 100644
index 000000000000..587dc3b53155
--- /dev/null
+++ b/arch/x86/boot/compressed/tpm/tis.c
@@ -0,0 +1,212 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Apertus Solutions, LLC
+ *
+ * Author(s):
+ *      Daniel P. Smith <dpsmith@apertussolutions.com>
+ *
+ * The code in this file is based on the article "Writing a TPM Device Driver"
+ * published on http://ptgmedia.pearsoncmg.com.
+ *
+ */
+
+#include <linux/types.h>
+#include <asm/byteorder.h>
+#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;
+}
+
+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;
+
+	return 1;
+}
+
+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 status, *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 status, *buf_ptr;
+	struct tpm_header *hdr;
+
+	if (locality > TPM_MAX_LOCALITY)
+		goto err;
+
+	/* 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))
+			goto err;
+	}
+
+	/* read header */
+	hdr = (struct tpm_header *)buf->head;
+	expected = sizeof(struct tpm_header);
+	if (recv_data(buf->head, expected) < expected)
+		goto err;
+
+	/* 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)
+		goto err;
+
+	/* hdr->size = header + data */
+	expected = hdr->size - expected;
+	buf_ptr = tpmb_put(buf, expected);
+	if (!buf_ptr)
+		goto err;
+
+	/* read all data, except last byte */
+	if (recv_data(buf_ptr, expected - 1) < (expected - 1))
+		goto err;
+
+	/* check for receive underflow */
+	if (!tis_data_available(locality))
+		goto err;
+
+	/* read last byte */
+	if (recv_data(buf_ptr, 1) != 1)
+		goto err;
+
+	/* make sure we read everything */
+	if (tis_data_available(locality))
+		goto err;
+
+	tpm_write8(STS_COMMAND_READY, STS(locality));
+
+	return hdr->size;
+err:
+	return 0;
+}
diff --git a/arch/x86/boot/compressed/tpm/tis.h b/arch/x86/boot/compressed/tpm/tis.h
new file mode 100644
index 000000000000..cb0b252eeec4
--- /dev/null
+++ b/arch/x86/boot/compressed/tpm/tis.h
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Apertus Solutions, LLC
+ *
+ * Author(s):
+ *      Daniel P. Smith <dpsmith@apertussolutions.com>
+ *
+ * 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));
+}
+
+/* TPM Interface Specification functions */
+u8 tis_request_locality(u8 l);
+void tis_relinquish_locality(void);
+u8 tis_init(struct tpm *t);
+size_t tis_send(struct tpmbuff *buf);
+size_t tis_recv(enum tpm_family f, struct tpmbuff *buf);
+
+#endif
diff --git a/arch/x86/boot/compressed/tpm/tpm.h b/arch/x86/boot/compressed/tpm/tpm.h
new file mode 100644
index 000000000000..45d12e424809
--- /dev/null
+++ b/arch/x86/boot/compressed/tpm/tpm.h
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Apertus Solutions, LLC
+ *
+ * Author(s):
+ *      Daniel P. Smith <dpsmith@apertussolutions.com>
+ *
+ */
+
+#ifndef _TPM_H
+#define _TPM_H
+
+#define TPM_NO_LOCALITY		0xFF
+
+enum tpm_hw_intf {
+	TPM_DEVNODE,
+	TPM_TIS,
+	TPM_CRB,
+	TPM_UEFI
+};
+
+enum tpm_family {
+	TPM12,
+	TPM20
+};
+
+struct tpmbuff;
+
+struct tpm {
+	u32 vendor;
+	enum tpm_family family;
+	enum tpm_hw_intf intf;
+	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 000000000000..7bb684c127be
--- /dev/null
+++ b/arch/x86/boot/compressed/tpm/tpm_buff.c
@@ -0,0 +1,135 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Apertus Solutions, LLC
+ *
+ * Author(s):
+ *      Daniel P. Smith <dpsmith@apertussolutions.com>
+ *
+ */
+
+#include <linux/types.h>
+#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_DEVNODE:
+		/* TODO: need implementation */
+		goto err;
+	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 *)(u64)(TPM_MMIO_BASE + (locality << 12)
+			       + TPM_CRB_DATA_BUFFER_OFFSET);
+		b->truesize = TPM_CRB_DATA_BUFFER_SIZE;
+		break;
+	case TPM_UEFI:
+		/* Not implemented yet */
+		goto err;
+	default:
+		goto err;
+	}
+
+reset:
+	b->len = 0;
+	b->locked = 0;
+	b->data = NULL;
+	b->tail = NULL;
+	b->end = b->head + (b->truesize - 1);
+
+	return b;
+
+err:
+	return NULL;
+}
+
+void free_tpmbuff(struct tpmbuff *b, enum tpm_hw_intf intf)
+{
+	switch (intf) {
+	case TPM_DEVNODE:
+		/* Not implemented yet */
+		break;
+	case TPM_TIS:
+		b->head = NULL;
+		break;
+	case TPM_CRB:
+		b->head = NULL;
+		break;
+	case TPM_UEFI:
+		/* Not implemented yet */
+		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 000000000000..0ed86edda9b4
--- /dev/null
+++ b/arch/x86/boot/compressed/tpm/tpm_common.h
@@ -0,0 +1,127 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Apertus Solutions, LLC
+ *
+ * Author(s):
+ *      Daniel P. Smith <dpsmith@apertussolutions.com>
+ *
+ */
+
+#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 000000000000..8f51fd2ea16e
--- /dev/null
+++ b/arch/x86/boot/compressed/tpm/tpmbuff.h
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Apertus Solutions, LLC
+ *
+ * Author(s):
+ *      Daniel P. Smith <dpsmith@apertussolutions.com>
+ *
+ */
+
+#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 000000000000..9481faed3521
--- /dev/null
+++ b/arch/x86/boot/compressed/tpm/tpmio.c
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Apertus Solutions, LLC
+ *
+ * Author(s):
+ *      Daniel P. Smith <dpsmith@apertussolutions.com>
+ */
+
+#include <linux/types.h>
+#include <asm/io.h>
+#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));
+}
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [RFC PATCH 05/12] x86: Add early TPM1.2/TPM2.0 interface support for Secure Launch
  2020-03-25 19:43 [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support Ross Philipson
                   ` (3 preceding siblings ...)
  2020-03-25 19:43 ` [RFC PATCH 04/12] x86: Add early TPM TIS/CRB interface support for Secure Launch Ross Philipson
@ 2020-03-25 19:43 ` Ross Philipson
  2020-03-25 19:43 ` [RFC PATCH 06/12] x86: Add early general TPM " Ross Philipson
                   ` (7 subsequent siblings)
  12 siblings, 0 replies; 43+ messages in thread
From: Ross Philipson @ 2020-03-25 19:43 UTC (permalink / raw)
  To: linux-kernel, x86, linux-doc
  Cc: ross.philipson, dpsmith, tglx, mingo, bp, hpa, trenchboot-devel

From: "Daniel P. Smith" <dpsmith@apertussolutions.com>

This commit introduces an abstraction for TPM1.2 and TPM2.0 devices
above the TPM hardware interface.

Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com>
---
 arch/x86/boot/compressed/Makefile             |   3 +-
 arch/x86/boot/compressed/tpm/tpm1.h           | 112 +++++++++++++
 arch/x86/boot/compressed/tpm/tpm1_cmds.c      | 133 ++++++++++++++++
 arch/x86/boot/compressed/tpm/tpm2.h           |  89 +++++++++++
 arch/x86/boot/compressed/tpm/tpm2_auth.c      |  31 ++++
 arch/x86/boot/compressed/tpm/tpm2_auth.h      |  21 +++
 arch/x86/boot/compressed/tpm/tpm2_cmds.c      | 150 ++++++++++++++++++
 arch/x86/boot/compressed/tpm/tpm2_constants.h |  66 ++++++++
 8 files changed, 604 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 b9682eaf8f59..6c2beb306631 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -97,7 +97,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 000000000000..41798e9f58e3
--- /dev/null
+++ b/arch/x86/boot/compressed/tpm/tpm1.h
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Apertus Solutions, LLC
+ *
+ * Author(s):
+ *      Daniel P. Smith <dpsmith@apertussolutions.com>
+ *
+ * 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 000000000000..653228fc8c4a
--- /dev/null
+++ b/arch/x86/boot/compressed/tpm/tpm1_cmds.c
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Apertus Solutions, LLC
+ *
+ * Author(s):
+ *      Daniel P. Smith <dpsmith@apertussolutions.com>
+ *
+ * The code in this file is based on the article "Writing a TPM Device Driver"
+ * published on http://ptgmedia.pearsoncmg.com.
+ *
+ */
+
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <asm/byteorder.h>
+#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;
+	struct tpm_extend_resp *resp;
+	size_t bytes, size;
+
+	if (!tpmb_reserve(b)) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	hdr = (struct tpm_header *)b->head;
+
+	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));
+
+	switch (t->intf) {
+	case TPM_DEVNODE:
+		/* Not implemented yet */
+		ret = -EBADRQC;
+		break;
+	case TPM_TIS:
+		if (be32_to_cpu(hdr->size) != tis_send(b))
+			ret = -EAGAIN;
+		break;
+	case TPM_CRB:
+		/* Not valid for TPM 1.2 */
+		ret = -ENODEV;
+		break;
+	case TPM_UEFI:
+		/* Not implemented yet */
+		ret = -EBADRQC;
+		break;
+	}
+
+	if (ret)
+		goto free;
+
+	tpmb_free(b);
+
+	/* Reset buffer for receive */
+	if (!tpmb_reserve(b)) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	hdr = (struct tpm_header *)b->head;
+
+	/*
+	 * The extend receive operation returns a struct tpm_extend_resp
+	 * but the current implementation ignores the returned PCR value.
+	 */
+
+	switch (t->intf) {
+	case TPM_DEVNODE:
+		/* Not implemented yet */
+		ret = -EBADRQC;
+		break;
+	case TPM_TIS:
+		/* tis_recv() will increase the buffer size */
+		size = tis_recv(t->family, b);
+		if (tpmb_size(b) != size)
+			ret = -EAGAIN;
+		break;
+	case TPM_CRB:
+		/* Not valid for TPM 1.2 */
+		ret = -ENODEV;
+		break;
+	case TPM_UEFI:
+		/* Not implemented yet */
+		ret = -EBADRQC;
+		break;
+	}
+
+	tpmb_free(b);
+
+	if (ret)
+		goto out;
+
+	/*
+	 * 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;
+
+	return ret;
+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 000000000000..b3a8bf5acaf0
--- /dev/null
+++ b/arch/x86/boot/compressed/tpm/tpm2.h
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Apertus Solutions, LLC
+ *
+ * Author(s):
+ *      Daniel P. Smith <dpsmith@apertussolutions.com>
+ *
+ * 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	*/
+	struct tpms_auth_cmd *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 000000000000..cb80b644b719
--- /dev/null
+++ b/arch/x86/boot/compressed/tpm/tpm2_auth.c
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Apertus Solutions, LLC
+ *
+ * Author(s):
+ *      Daniel P. Smith <dpsmith@apertussolutions.com>
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <asm/byteorder.h>
+#include "tpm.h"
+#include "tpm2.h"
+#include "tpm2_constants.h"
+
+#define NULL_AUTH_SIZE 9
+
+u16 tpm2_null_auth_size(void)
+{
+	return NULL_AUTH_SIZE;
+}
+
+u16 tpm2_null_auth(struct tpms_auth_cmd *a)
+{
+	memset(a, 0, NULL_AUTH_SIZE);
+
+	*a->handle = cpu_to_be32(TPM_RS_PW);
+
+	return NULL_AUTH_SIZE;
+}
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 000000000000..bc9d0f7dfeee
--- /dev/null
+++ b/arch/x86/boot/compressed/tpm/tpm2_auth.h
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Apertus Solutions, LLC
+ *
+ * Author(s):
+ *      Daniel P. Smith <dpsmith@apertussolutions.com>
+ *
+ * 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"
+
+u16 tpm2_null_auth_size(void);
+u16 tpm2_null_auth(struct tpms_auth_cmd *a);
+
+#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 000000000000..66a40905365b
--- /dev/null
+++ b/arch/x86/boot/compressed/tpm/tpm2_cmds.c
@@ -0,0 +1,150 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Apertus Solutions, LLC
+ *
+ * Author(s):
+ *      Daniel P. Smith <dpsmith@apertussolutions.com>
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <asm/byteorder.h>
+#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)
+{
+	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;
+	u8 *ptr;
+	u16 size;
+	int ret = 0;
+
+	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 = (struct tpms_auth_cmd *)tpmb_put(b, tpm2_null_auth_size());
+	if (cmd.auth == NULL) {
+		ret = -ENOMEM;
+		goto free;
+	}
+
+	*cmd.auth_size = cpu_to_be32(tpm2_null_auth(cmd.auth));
+
+	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_be16(tpmb_size(b));
+
+	switch (t->intf) {
+	case TPM_DEVNODE:
+		/* Not implemented yet */
+		ret = -EBADRQC;
+		break;
+	case TPM_TIS:
+		ret = tis_send(b);
+		break;
+	case TPM_CRB:
+		ret = crb_send(b);
+		break;
+	case TPM_UEFI:
+		/* Not implemented yet */
+		ret = -EBADRQC;
+		break;
+	}
+
+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 000000000000..a1275e744ccd
--- /dev/null
+++ b/arch/x86/boot/compressed/tpm/tpm2_constants.h
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Apertus Solutions, LLC
+ *
+ * Author(s):
+ *      Daniel P. Smith <dpsmith@apertussolutions.com>
+ *
+ * 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 <IN/OUT, S> */
+#define TPM_ALG_ERROR                (u16)(0x0000)
+#define TPM_ALG_RSA                  (u16)(0x0001)
+#define TPM_ALG_SHA                  (u16)(0x0004)
+#define TPM_ALG_SHA1                 (u16)(0x0004)
+#define TPM_ALG_HMAC                 (u16)(0x0005)
+#define TPM_ALG_AES                  (u16)(0x0006)
+#define TPM_ALG_MGF1                 (u16)(0x0007)
+#define TPM_ALG_KEYEDHASH            (u16)(0x0008)
+#define TPM_ALG_XOR                  (u16)(0x000A)
+#define TPM_ALG_SHA256               (u16)(0x000B)
+#define TPM_ALG_SHA384               (u16)(0x000C)
+#define TPM_ALG_SHA512               (u16)(0x000D)
+#define TPM_ALG_NULL                 (u16)(0x0010)
+#define TPM_ALG_SM3_256              (u16)(0x0012)
+#define TPM_ALG_SM4                  (u16)(0x0013)
+#define TPM_ALG_RSASSA               (u16)(0x0014)
+#define TPM_ALG_RSAES                (u16)(0x0015)
+#define TPM_ALG_RSAPSS               (u16)(0x0016)
+#define TPM_ALG_OAEP                 (u16)(0x0017)
+#define TPM_ALG_ECDSA                (u16)(0x0018)
+#define TPM_ALG_ECDH                 (u16)(0x0019)
+#define TPM_ALG_ECDAA                (u16)(0x001A)
+#define TPM_ALG_SM2                  (u16)(0x001B)
+#define TPM_ALG_ECSCHNORR            (u16)(0x001C)
+#define TPM_ALG_ECMQV                (u16)(0x001D)
+#define TPM_ALG_KDF1_SP800_56A       (u16)(0x0020)
+#define TPM_ALG_KDF2                 (u16)(0x0021)
+#define TPM_ALG_KDF1_SP800_108       (u16)(0x0022)
+#define TPM_ALG_ECC                  (u16)(0x0023)
+#define TPM_ALG_SYMCIPHER            (u16)(0x0025)
+#define TPM_ALG_CAMELLIA             (u16)(0x0026)
+#define TPM_ALG_CTR                  (u16)(0x0040)
+#define TPM_ALG_OFB                  (u16)(0x0041)
+#define TPM_ALG_CBC                  (u16)(0x0042)
+#define TPM_ALG_CFB                  (u16)(0x0043)
+#define TPM_ALG_ECB                  (u16)(0x0044)
+#define TPM_ALG_FIRST                (u16)(0x0001)
+#define TPM_ALG_LAST                 (u16)(0x0044)
+
+/* Table 12  Definition of (UINT32) TPM_CC Constants (Numeric Order) <IN/OUT, S> */
+#define TPM_CC_PCR_EXTEND (u32)(0x00000182)
+
+/* Table 19  Definition of (UINT16) TPM_ST Constants <IN/OUT, S> */
+#define TPM_ST_NO_SESSIONS (u16)(0x8001)
+#define TPM_ST_SESSIONS (u16)(0x8002)
+
+/* Table 28  Definition of (TPM_HANDLE) TPM_RH Constants <S> */
+#define TPM_RS_PW (u32)(0x40000009)
+
+#endif
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [RFC PATCH 06/12] x86: Add early general TPM interface support for Secure Launch
  2020-03-25 19:43 [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support Ross Philipson
                   ` (4 preceding siblings ...)
  2020-03-25 19:43 ` [RFC PATCH 05/12] x86: Add early TPM1.2/TPM2.0 " Ross Philipson
@ 2020-03-25 19:43 ` Ross Philipson
  2020-03-25 19:43 ` [RFC PATCH 07/12] x86: Secure Launch kernel early boot stub Ross Philipson
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 43+ messages in thread
From: Ross Philipson @ 2020-03-25 19:43 UTC (permalink / raw)
  To: linux-kernel, x86, linux-doc
  Cc: ross.philipson, dpsmith, tglx, mingo, bp, hpa, trenchboot-devel

From: "Daniel P. Smith" <dpsmith@apertussolutions.com>

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 <dpsmith@apertussolutions.com>
---
 arch/x86/boot/compressed/Makefile  |   2 +-
 arch/x86/boot/compressed/tpm/tpm.c | 190 +++++++++++++++++++++++++++++
 2 files changed, 191 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 6c2beb306631..922223948499 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -98,7 +98,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 000000000000..85923d54dc04
--- /dev/null
+++ b/arch/x86/boot/compressed/tpm/tpm.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2019 Apertus Solutions, LLC
+ *
+ * Author(s):
+ *      Daniel P. Smith <dpsmith@apertussolutions.com>
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#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_DEVNODE:
+		/* Not implemented yet */
+		break;
+	case TPM_TIS:
+		if (!tis_init(t))
+			goto err;
+		break;
+	case TPM_CRB:
+		if (!crb_init(t))
+			goto err;
+		break;
+	case TPM_UEFI:
+		/* Not implemented yet */
+		break;
+	}
+
+	/* TODO: ACPI TPM discovery */
+
+	return t;
+
+err:
+	return NULL;
+}
+
+u8 tpm_request_locality(struct tpm *t, u8 l)
+{
+	u8 ret = TPM_NO_LOCALITY;
+
+	switch (t->intf) {
+	case TPM_DEVNODE:
+		/* Not implemented yet */
+		break;
+	case TPM_TIS:
+		ret = tis_request_locality(l);
+		break;
+	case TPM_CRB:
+		ret = crb_request_locality(l);
+		break;
+	case TPM_UEFI:
+		/* Not implemented yet */
+		break;
+	}
+
+	if (ret < TPM_MAX_LOCALITY)
+		t->buff = alloc_tpmbuff(t->intf, ret);
+
+	return ret;
+}
+
+void tpm_relinquish_locality(struct tpm *t)
+{
+	switch (t->intf) {
+	case TPM_DEVNODE:
+		/* Not implemented yet */
+		break;
+	case TPM_TIS:
+		tis_relinquish_locality();
+		break;
+	case TPM_CRB:
+		crb_relinquish_locality();
+		break;
+	case TPM_UEFI:
+		/* Not implemented yet */
+		break;
+	}
+
+	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) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (t->family == TPM12) {
+		struct tpm_digest d;
+
+		if (algo != TPM_ALG_SHA1) {
+			ret = -EINVAL;
+			goto out;
+		}
+
+		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;
+		switch (algo) {
+		case TPM_ALG_SHA1:
+			d->digests->alg = TPM_ALG_SHA1;
+			memcpy(d->digests->digest, digest, SHA1_SIZE);
+			break;
+		case TPM_ALG_SHA256:
+			d->digests->alg = TPM_ALG_SHA256;
+			memcpy(d->digests->digest, digest, SHA256_SIZE);
+			break;
+		case TPM_ALG_SHA384:
+			d->digests->alg = TPM_ALG_SHA384;
+			memcpy(d->digests->digest, digest, SHA384_SIZE);
+			break;
+		case TPM_ALG_SHA512:
+			d->digests->alg = TPM_ALG_SHA512;
+			memcpy(d->digests->digest, digest, SHA512_SIZE);
+			break;
+		case TPM_ALG_SM3_256:
+			d->digests->alg = TPM_ALG_SM3_256;
+			memcpy(d->digests->digest, digest, SM3256_SIZE);
+			break;
+		default:
+			ret = -EINVAL;
+			goto out;
+		}
+
+		ret = tpm2_extend_pcr(t, pcr, d);
+	} else {
+		ret = -EINVAL;
+	}
+out:
+	return ret;
+}
+
+void free_tpm(struct tpm *t)
+{
+	tpm_relinquish_locality(t);
+}
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [RFC PATCH 07/12] x86: Secure Launch kernel early boot stub
  2020-03-25 19:43 [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support Ross Philipson
                   ` (5 preceding siblings ...)
  2020-03-25 19:43 ` [RFC PATCH 06/12] x86: Add early general TPM " Ross Philipson
@ 2020-03-25 19:43 ` Ross Philipson
  2020-03-25 19:43 ` [RFC PATCH 08/12] x86: Secure Launch kernel late " Ross Philipson
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 43+ messages in thread
From: Ross Philipson @ 2020-03-25 19:43 UTC (permalink / raw)
  To: linux-kernel, x86, linux-doc
  Cc: ross.philipson, dpsmith, tglx, mingo, bp, hpa, trenchboot-devel

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 <ross.philipson@oracle.com>
---
 Documentation/x86/boot.rst             |   9 +
 arch/x86/boot/compressed/Makefile      |   1 +
 arch/x86/boot/compressed/head_64.S     |  32 ++
 arch/x86/boot/compressed/kernel_info.S |   3 +
 arch/x86/boot/compressed/sl_main.c     | 378 ++++++++++++++++
 arch/x86/boot/compressed/sl_stub.S     | 568 +++++++++++++++++++++++++
 arch/x86/boot/compressed/vmlinux.lds.S |   4 +
 arch/x86/kernel/asm-offsets.c          |  15 +
 8 files changed, 1010 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 90bb8f5ab384..7b8b521e0b34 100644
--- a/Documentation/x86/boot.rst
+++ b/Documentation/x86/boot.rst
@@ -1029,6 +1029,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 922223948499..6adb4ce39f5f 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -99,6 +99,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 ee60b81944a7..466e3869af2c 100644
--- a/arch/x86/boot/compressed/head_64.S
+++ b/arch/x86/boot/compressed/head_64.S
@@ -251,6 +251,21 @@ SYM_FUNC_START(efi32_stub_entry)
 
 	jmp	startup_32
 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), %ebp
+
+	/* More room to work in sl_stub in the text section */
+	jmp	sl_stub
+
+SYM_FUNC_END(sl_stub_entry)
 #endif
 
 	.code64
@@ -529,6 +544,23 @@ 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. One solution might be to set them in the really
+	 * early sl stub asm code but that might not work well.
+	 */
+	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 f818ee8fba38..e31985541f00 100644
--- a/arch/x86/boot/compressed/kernel_info.S
+++ b/arch/x86/boot/compressed/kernel_info.S
@@ -17,6 +17,9 @@ kernel_info:
 	/* Maximal allowed type for setup_data and setup_indirect structs. */
 	.long	SETUP_TYPE_MAX
 
+	/* Offset to the MLE header structure */
+	.long	mle_header
+
 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 000000000000..6d803e12d352
--- /dev/null
+++ b/arch/x86/boot/compressed/sl_main.c
@@ -0,0 +1,378 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/linkage.h>
+#include <linux/efi.h>
+#include <asm/segment.h>
+#include <asm/boot.h>
+#include <asm/msr.h>
+#include <asm/io.h>
+#include <asm/mtrr.h>
+#include <asm/processor-flags.h>
+#include <asm/asm-offsets.h>
+#include <asm/bootparam.h>
+#include <asm/efi.h>
+#include <linux/slaunch.h>
+#ifdef CONFIG_SECURE_LAUNCH_SHA256
+#include <linux/sha256.h>
+#endif
+#ifdef CONFIG_SECURE_LAUNCH_SHA512
+#include <linux/sha512.h>
+#endif
+
+#include "early_sha1.h"
+#include "tpm/tpm_common.h"
+#include "tpm/tpm2_constants.h"
+#include "tpm/tpm.h"
+
+#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 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);
+	asm volatile ("hlt");
+}
+
+static u64 sl_rdmsr(u32 reg)
+{
+	u64 lo, hi;
+
+	asm volatile ("rdmsr"  : "=a" (lo), "=d" (hi) : "c" (reg));
+
+	return (hi << 32) | lo;
+}
+
+static void sl_txt_validate_msrs(struct txt_os_mle_data *os_mle_data)
+{
+#define CAPS_VARIABLE_MTRR_COUNT_MASK   0xff
+	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_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->event_log_buffer[0];
+
+	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];
+
+	memset(log_buf, 0, SL_TPM12_LOG_SIZE);
+	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];
+
+	memset(log_buf, 0, SL_TPM20_LOG_SIZE);
+	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;
+	const char *signature;
+	unsigned long mmap = 0;
+	void *txt_heap;
+	u32 data_count, os_mle_len;
+
+	/*
+	 * 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 OS-MLE data up to the MLE scratch field. The MLE scratch
+	 * field and the TPM logging should not be measured.
+	 */
+	os_mle_len = offsetof(struct txt_os_mle_data, mle_scratch);
+	sl_tpm_extend_pcr(tpm, SL_CONFIG_PCR18, (u8 *)os_mle_data, os_mle_len,
+			  "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 000000000000..ff2a8a7ae4b6
--- /dev/null
+++ b/arch/x86/boot/compressed/sl_stub.S
@@ -0,0 +1,568 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved.
+ */
+	.code32
+	.text
+#include <linux/linkage.h>
+#include <asm/segment.h>
+#include <asm/msr.h>
+#include <asm/processor-flags.h>
+#include <asm/asm-offsets.h>
+#include <asm/bootparam.h>
+#include <asm/irq_vectors.h>
+#include <linux/slaunch.h>
+
+/* 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
+
+.macro GETSEC leaf
+	xorl	%ebx, %ebx
+	movl	\leaf, %eax	/* Leaf function */
+	.byte 	0x0f, 0x37	/* GETSEC opcode */
+.endm
+
+	/*
+	 * The MLE Header per the TXT Specification, section 2.1
+	 * MLE capabilities, see table 2.
+	 */
+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 */
+	.long	0x00000000    /* Ending linear address of command line */
+SYM_DATA_END(mle_header)
+
+	.code32
+SYM_FUNC_START(sl_stub)
+	/*
+	 * On entry, %ebp has the base address from head_64.S
+	 * and only %cs is known good
+	 */
+	cli
+	cld
+
+	/*
+	 * Take the first stack for the BSP. The AP stacks are only used
+	 * on Intel.
+	 */
+	leal	sl_stacks_end(%ebp), %esp
+
+	/* Load GDT, set segment regs and lret to __SL32_CS */
+	addl	%ebp, (sl_gdt_desc + 2)(%ebp)
+	lgdt	sl_gdt_desc(%ebp)
+
+	movl	$(__SL32_DS), %eax
+	movw	%ax, %ds
+	movw	%ax, %es
+	movw	%ax, %fs
+	movw	%ax, %gs
+	movw	%ax, %ss
+
+	leal	.Lsl_cs(%ebp), %eax
+	pushl	$(__SL32_CS)
+	pushl	%eax
+	lret
+
+.Lsl_cs:
+	/* Assume unknown CPU start */
+	xorl	%edi, %edi
+
+	/* 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
+	movl	$(SL_CPU_INTEL), %edi
+
+	/* Know it is Intel */
+	movl	$(SL_CPU_INTEL), sl_cpu_type(%ebp)
+
+	/* Increment CPU count for BSP */
+	incl	sl_txt_cpu_count(%ebp)
+
+	/* 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(%ebp), %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
+
+	/* Get the zero page address from the heap.
+	 *
+	 * Note %esi and %ebp MUST be preserved across calls and
+	 * operations.
+	 */
+	movl	SL_zero_page_addr(%eax), %esi
+
+	/* Save ebp so the APs can find their way home */
+	movl	%ebp, (SL_mle_scratch + SL_SCRATCH_AP_EBP)(%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(%ebp)
+
+	/* 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 */
+	pushl	%esi
+	call	sl_txt_reloc_ap_wake
+	popl	%esi
+
+	/*
+	 * Wake up all APs 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 for call to load MTRRs/MISC MSR */
+	popl	%edi
+	call	sl_txt_load_regs
+
+	jmp	.Lcpu_setup_done
+
+.Ldo_unknown_cpu:
+	/* AMD is not yet supported */
+	ud2
+
+	/* On AMD %esi is set up by the Landing Zone, just go on */
+
+.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 code segment is known good. The data segments are
+	 * fine too so we can get to our stack before loading the
+	 * GDT.
+	 *
+	 * First order of business is to find where we are and
+	 * save it in ebp.
+	 */
+
+	/* 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 ebp from the BSP and stash OS-MLE pointer */
+	movl	(SL_mle_scratch + SL_SCRATCH_AP_EBP)(%eax), %ebp
+	movl	%eax, %edi
+
+	/* Lock and get our stack index */
+	movl	$1, %ecx
+.Lspin:
+	xorl	%eax, %eax
+	lock cmpxchgl	%ecx, sl_txt_spin_lock(%ebp)
+	jnz	.Lspin
+
+	/* Increment the stack index and use the next value inside lock */
+	incl	sl_txt_stack_index(%ebp)
+	movl	sl_txt_stack_index(%ebp), %eax
+
+	/* Unlock */
+	movl	$0, sl_txt_spin_lock(%ebp)
+
+	/* Load our AP stack */
+	movl	$(TXT_BOOT_STACK_SIZE), %edx
+	mull	%edx
+	leal	sl_stacks_end(%ebp), %esp
+	subl	%eax, %esp
+
+	/* Load reloc GDT, set segment regs and lret to __SL32_CS */
+	movl	sl_txt_ap_wake_block(%ebp), %eax
+	lgdt	(sl_ap_gdt_desc - sl_txt_ap_wake_begin)(%eax)
+
+	movl	$(__SL32_DS), %eax
+	movw	%ax, %ds
+	movw	%ax, %es
+	movw	%ax, %fs
+	movw	%ax, %gs
+	movw	%ax, %ss
+
+	leal	.Lsl_ap_cs(%ebp), %eax
+	pushl	$(__SL32_CS)
+	pushl	%eax
+	lret
+
+.Lsl_ap_cs:
+	/* Load the relocated AP IDT */
+	movl	sl_txt_ap_wake_block(%ebp), %eax
+	lidt	(sl_ap_idt_desc - sl_txt_ap_wake_begin)(%eax)
+
+	/* 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(%ebp), %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(%ebp)
+
+	movl	sl_txt_ap_wake_block(%ebp), %eax
+	jmp	*%eax
+SYM_FUNC_END(sl_txt_ap_entry)
+
+SYM_FUNC_START(sl_txt_reloc_ap_wake)
+	movl	sl_txt_ap_wake_block(%ebp), %edi
+
+	/* Fixup AP IDT and GDT descriptor before relocating */
+	addl	%edi, (sl_ap_idt_desc + 2)(%ebp)
+	addl	%edi, (sl_ap_gdt_desc + 2)(%ebp)
+
+	/*
+	 * 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(%ebp), %esi
+	rep movsb
+
+	/* Setup the IDT for the APs to use in the relocation block */
+	movl	sl_txt_ap_wake_block(%ebp), %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(%ebp), %ebx
+	addl	$(sl_txt_int_reset - sl_txt_ap_wake_begin), %ebx
+
+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	%ebx, %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(%ebp), %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:
+	ret
+
+SYM_FUNC_END(sl_txt_reloc_ap_wake)
+
+SYM_FUNC_START(sl_txt_load_regs)
+	/*
+	 * 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
+
+	ret
+SYM_FUNC_END(sl_txt_load_regs)
+
+SYM_FUNC_START(sl_txt_wake_aps)
+	/* First setup the MLE join structure and load it into TXT reg */
+	leal	sl_gdt(%ebp), %eax
+	leal	sl_txt_ap_entry(%ebp), %ecx
+	leal	sl_smx_rlp_mle_join(%ebp), %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), %ebx
+	/* Skip over OS to SNIT */
+	movl	(%eax), %ecx
+	addl	%ecx, %eax
+	/* At SNIT-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), %ebx
+	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.
+	 */
+1:
+	pause
+	cmpl	sl_txt_cpu_count(%ebp), %edx
+	jne	1b
+
+	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	%ebx, %ebx
+
+1:
+	hlt
+	testl	%ebx, %ebx
+	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, %ebx
+
+	/* NMI context, just IRET */
+	iret
+SYM_FUNC_END(sl_txt_int_ipi_wake)
+
+SYM_FUNC_START(sl_txt_int_reset)
+	/* Set a sticky error value and reset */
+	movl	$(SL_ERROR_INV_AP_INTERRUPT), (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_ERRORCODE)
+	/* The movs to %eax act as TXT register barriers */
+	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)
+	hlt
+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:
+
+/* 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
+
+	/* 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:
diff --git a/arch/x86/boot/compressed/vmlinux.lds.S b/arch/x86/boot/compressed/vmlinux.lds.S
index 508cfa6828c5..9f402059949d 100644
--- a/arch/x86/boot/compressed/vmlinux.lds.S
+++ b/arch/x86/boot/compressed/vmlinux.lds.S
@@ -74,3 +74,7 @@ SECTIONS
 	. = ALIGN(PAGE_SIZE);	/* keep ZO size page aligned */
 	_end = .;
 }
+
+#ifdef CONFIG_SECURE_LAUNCH
+ASSERT((sl_txt_ap_wake_end - sl_txt_ap_wake_begin) <= PAGE_SIZE, "SL AP wake code bigger than PAGE_SIZE");
+#endif
diff --git a/arch/x86/kernel/asm-offsets.c b/arch/x86/kernel/asm-offsets.c
index 5c7ee3df4d0b..fcddd6cc97d8 100644
--- a/arch/x86/kernel/asm-offsets.c
+++ b/arch/x86/kernel/asm-offsets.c
@@ -12,6 +12,7 @@
 #include <linux/hardirq.h>
 #include <linux/suspend.h>
 #include <linux/kbuild.h>
+#include <linux/slaunch.h>
 #include <asm/processor.h>
 #include <asm/thread_info.h>
 #include <asm/sigframe.h>
@@ -105,4 +106,18 @@ 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_zero_page_addr, txt_os_mle_data, zero_page_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_mle_scratch, txt_os_mle_data, mle_scratch);
+	OFFSET(SL_ap_wake_block, txt_os_mle_data, ap_wake_block);
+	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
 }
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [RFC PATCH 08/12] x86: Secure Launch kernel late boot stub
  2020-03-25 19:43 [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support Ross Philipson
                   ` (6 preceding siblings ...)
  2020-03-25 19:43 ` [RFC PATCH 07/12] x86: Secure Launch kernel early boot stub Ross Philipson
@ 2020-03-25 19:43 ` Ross Philipson
  2020-03-25 19:43 ` [RFC PATCH 09/12] x86: Secure Launch SMP bringup support Ross Philipson
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 43+ messages in thread
From: Ross Philipson @ 2020-03-25 19:43 UTC (permalink / raw)
  To: linux-kernel, x86, linux-doc
  Cc: ross.philipson, dpsmith, tglx, mingo, bp, hpa, trenchboot-devel

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 <ross.philipson@oracle.com>
---
 arch/x86/kernel/Makefile  |   1 +
 arch/x86/kernel/setup.c   |   3 +
 arch/x86/kernel/slaunch.c | 451 ++++++++++++++++++++++++++++++++++++++
 drivers/iommu/dmar.c      |   4 +
 4 files changed, 459 insertions(+)
 create mode 100644 arch/x86/kernel/slaunch.c

diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 6175e370ee4a..f0a12037c682 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -71,6 +71,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 cedfe2077a69..acf351592078 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -73,6 +73,7 @@
 #include <linux/jiffies.h>
 #include <linux/mem_encrypt.h>
 #include <linux/sizes.h>
+#include <linux/slaunch.h>
 
 #include <linux/usb/xhci-dbgp.h>
 #include <video/edid.h>
@@ -1073,6 +1074,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 000000000000..083fa72bd9f9
--- /dev/null
+++ b/arch/x86/kernel/slaunch.c
@@ -0,0 +1,451 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019 Apertus Solutions, LLC
+ *
+ * Author(s):
+ *     Daniel P. Smith <dpsmith@apertussolutions.com>
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/linkage.h>
+#include <linux/mm.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/security.h>
+#include <linux/memblock.h>
+#include <asm/segment.h>
+#include <asm/sections.h>
+#include <asm/boot.h>
+#include <asm/msr.h>
+#include <asm/tlbflush.h>
+#include <asm/processor-flags.h>
+#include <asm/asm-offsets.h>
+#include <asm/e820/api.h>
+#include <asm/bootparam.h>
+#include <asm/setup.h>
+#include <linux/slaunch.h>
+
+#define PREFIX	"SLAUNCH: "
+
+static u32 sl_flags;
+static struct sl_ap_wake_info ap_wake_info;
+
+/* 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 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_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));
+
+	asm volatile ("hlt");
+}
+
+/*
+ * 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;
+	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);
+
+	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.
+	 */
+	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";
+	}
+
+out:
+	early_memunmap(os_sinit_data, field_offset);
+
+	if (err)
+		slaunch_txt_reset(txt, errmsg, err);
+}
+
+static int __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) {
+		e820__range_update(base, size, E820_TYPE_RAM,
+				   E820_TYPE_RESERVED);
+		return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * For Intel, certain reqions of memory must be marked as reserved in the e820
+ * memory map if they are not already. This includes the TXT HEAP, the ACM area,
+ * the TXT private register bank. Normally these are properly reserved by
+ * firmware but if it was not done, do it now.
+ *
+ * Also the Memory Descriptor Ranges that are passed to the MLE (see TXT
+ * specification) may need to be reserved depeding on their type.
+ */
+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;
+	u32 field_offset, mdrnum, mdroffset, mdrslen, i;
+	int updated = 0;
+
+	base = TXT_PRIV_CONFIG_REGS_BASE;
+	size = TXT_PUB_CONFIG_REGS_BASE - TXT_PRIV_CONFIG_REGS_BASE;
+	updated += slaunch_txt_reserve_range(base, size);
+
+	memcpy_fromio(&base, txt + TXT_CR_HEAP_BASE, sizeof(u64));
+	memcpy_fromio(&size, txt + TXT_CR_HEAP_SIZE, sizeof(u64));
+	updated += slaunch_txt_reserve_range(base, size);
+
+	memcpy_fromio(&base, txt + TXT_CR_SINIT_BASE, sizeof(u64));
+	memcpy_fromio(&size, txt + TXT_CR_SINIT_SIZE, sizeof(u64));
+	updated += 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 out;
+
+	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)
+			updated += slaunch_txt_reserve_range(mdr->address,
+							     mdr->length);
+	}
+
+	early_memunmap(mdrs, mdroffset + mdrslen - 8);
+
+out:
+	if (updated) {
+		e820__update_table(e820_table);
+		pr_info("TXT altered physical RAM map:\n");
+		e820__print_table("TXT-reserve");
+	}
+}
+
+/*
+ * 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.
+ */
+static void __init slaunch_fetch_ap_wake_block(void __iomem *txt)
+{
+	struct txt_os_mle_data *os_mle_data;
+	u8 *jmp_offset;
+	u32 field_offset;
+
+	field_offset = offsetof(struct txt_os_mle_data, event_log_buffer);
+	os_mle_data = txt_early_get_heap_table(txt, TXT_OS_MLE_DATA_TABLE,
+					       field_offset);
+
+	ap_wake_info.ap_wake_block = os_mle_data->ap_wake_block;
+
+	jmp_offset = ((u8 *)&os_mle_data->mle_scratch)
+			+ SL_SCRATCH_AP_JMP_OFFSET;
+	ap_wake_info.ap_jmp_offset = *((u32 *)jmp_offset);
+
+	early_memunmap(os_mle_data, field_offset);
+}
+
+/*
+ * 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_ap_wake_block(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/dmar.c b/drivers/iommu/dmar.c
index 3acfa6a25fa2..667a5be83e58 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -28,6 +28,7 @@
 #include <linux/slab.h>
 #include <linux/iommu.h>
 #include <linux/numa.h>
+#include <linux/slaunch.h>
 #include <asm/irq_remapping.h>
 #include <asm/iommu_table.h>
 
@@ -623,6 +624,9 @@ parse_dmar_table(void)
 	 */
 	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;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [RFC PATCH 09/12] x86: Secure Launch SMP bringup support
  2020-03-25 19:43 [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support Ross Philipson
                   ` (7 preceding siblings ...)
  2020-03-25 19:43 ` [RFC PATCH 08/12] x86: Secure Launch kernel late " Ross Philipson
@ 2020-03-25 19:43 ` Ross Philipson
  2020-03-25 19:43 ` [RFC PATCH 10/12] x86: Secure Launch adding event log securityfs Ross Philipson
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 43+ messages in thread
From: Ross Philipson @ 2020-03-25 19:43 UTC (permalink / raw)
  To: linux-kernel, x86, linux-doc
  Cc: ross.philipson, dpsmith, tglx, mingo, bp, hpa, trenchboot-devel

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 <ross.philipson@oracle.com>
---
 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 09ecc32f6524..029c12fca4d9 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 trampoline_32/64.S */
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 69881b2d446c..321604a29dfa 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -55,6 +55,7 @@
 #include <linux/gfp.h>
 #include <linux/cpuidle.h>
 #include <linux/numa.h>
+#include <linux/slaunch.h>
 
 #include <asm/acpi.h>
 #include <asm/desc.h>
@@ -1014,6 +1015,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.
@@ -1068,6 +1146,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
@@ -1080,6 +1164,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 af04512c02d9..72150400c74d 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 251758ed7443..d5fb210a45a2 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
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [RFC PATCH 10/12] x86: Secure Launch adding event log securityfs
  2020-03-25 19:43 [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support Ross Philipson
                   ` (8 preceding siblings ...)
  2020-03-25 19:43 ` [RFC PATCH 09/12] x86: Secure Launch SMP bringup support Ross Philipson
@ 2020-03-25 19:43 ` Ross Philipson
  2020-03-25 20:21   ` Matthew Garrett
  2020-03-25 19:43 ` [RFC PATCH 11/12] kexec: Secure Launch kexec SEXIT support Ross Philipson
                   ` (2 subsequent siblings)
  12 siblings, 1 reply; 43+ messages in thread
From: Ross Philipson @ 2020-03-25 19:43 UTC (permalink / raw)
  To: linux-kernel, x86, linux-doc
  Cc: ross.philipson, dpsmith, tglx, mingo, bp, hpa, trenchboot-devel

From: "Daniel P. Smith" <dpsmith@apertussolutions.com>

The late init functionality registers securityfs nodes to allow fetching
of and writing events to the late launch TPM log.

Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com>
---
 arch/x86/kernel/slaunch.c | 184 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 184 insertions(+)

diff --git a/arch/x86/kernel/slaunch.c b/arch/x86/kernel/slaunch.c
index 083fa72bd9f9..fea15b0e36b7 100644
--- a/arch/x86/kernel/slaunch.c
+++ b/arch/x86/kernel/slaunch.c
@@ -449,3 +449,187 @@ void __init slaunch_setup(void)
 	    vendor[3] == INTEL_CPUID_MFGID_EDX)
 		slaunch_setup_intel();
 }
+
+/*
+ * Securityfs exposure
+ */
+struct memfile {
+	char *name;
+	void __iomem *addr;
+	size_t size;
+};
+
+static struct memfile sl_evtlog = {"eventlog", 0, 0};
+static void __iomem *txt_heap;
+static struct txt_heap_event_log_pointer2_1_element __iomem *evtlog20;
+
+static DEFINE_MUTEX(sl_evt_write_mutex);
+
+static ssize_t sl_evtlog_read(struct file *file, char __user *buf,
+			      size_t count, loff_t *pos)
+{
+	return simple_read_from_buffer(buf, count, pos,
+		sl_evtlog.addr, sl_evtlog.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;
+
+	/* 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_write_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_write_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,
+};
+
+#define SL_DIR_ENTRY	1 /* directoy node must be last */
+#define SL_FS_ENTRIES	2
+
+static struct dentry *fs_entries[SL_FS_ENTRIES];
+
+static long slaunch_expose_securityfs(void)
+{
+	long ret = 0;
+	int entry = SL_DIR_ENTRY;
+
+	fs_entries[entry] = securityfs_create_dir("slaunch", NULL);
+	if (IS_ERR(fs_entries[entry])) {
+		pr_err("Error creating securityfs sl_evt_log directory\n");
+		ret = PTR_ERR(fs_entries[entry]);
+		goto err;
+	}
+
+	if (sl_evtlog.addr > 0) {
+		entry--;
+		fs_entries[entry] = securityfs_create_file(sl_evtlog.name,
+					   S_IRUSR | S_IRGRP,
+					   fs_entries[SL_DIR_ENTRY], NULL,
+					   &sl_evtlog_ops);
+		if (IS_ERR(fs_entries[entry])) {
+			pr_err("Error creating securityfs %s file\n",
+				sl_evtlog.name);
+			ret = PTR_ERR(fs_entries[entry]);
+			goto err_dir;
+		}
+	}
+
+	return 0;
+
+err_dir:
+	securityfs_remove(fs_entries[SL_DIR_ENTRY]);
+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 (txt_heap) {
+			memunmap(txt_heap);
+			txt_heap = NULL;
+		}
+	}
+
+	sl_evtlog.addr = 0;
+	sl_evtlog.size = 0;
+}
+
+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 = TXT_MAX_EVENT_LOG_SIZE;
+	sl_evtlog.addr = (void __iomem *)&params->event_log_buffer[0];
+
+	/* 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);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [RFC PATCH 11/12] kexec: Secure Launch kexec SEXIT support
  2020-03-25 19:43 [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support Ross Philipson
                   ` (9 preceding siblings ...)
  2020-03-25 19:43 ` [RFC PATCH 10/12] x86: Secure Launch adding event log securityfs Ross Philipson
@ 2020-03-25 19:43 ` Ross Philipson
  2020-03-25 19:43 ` [RFC PATCH 12/12] tpm: Allow locality 2 to be set when initializing the TPM for Secure Launch Ross Philipson
  2020-03-25 20:29 ` [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support Matthew Garrett
  12 siblings, 0 replies; 43+ messages in thread
From: Ross Philipson @ 2020-03-25 19:43 UTC (permalink / raw)
  To: linux-kernel, x86, linux-doc
  Cc: ross.philipson, dpsmith, tglx, mingo, bp, hpa, trenchboot-devel

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 <ross.philipson@oracle.com>
---
 arch/x86/kernel/slaunch.c | 65 +++++++++++++++++++++++++++++++++++++++
 kernel/kexec_core.c       |  3 ++
 2 files changed, 68 insertions(+)

diff --git a/arch/x86/kernel/slaunch.c b/arch/x86/kernel/slaunch.c
index fea15b0e36b7..516964408fe5 100644
--- a/arch/x86/kernel/slaunch.c
+++ b/arch/x86/kernel/slaunch.c
@@ -633,3 +633,68 @@ static void __exit slaunch_exit(void)
 late_initcall(slaunch_late_init);
 
 __exitcall(slaunch_exit);
+
+static inline void txt_getsec_sexit(void)
+{
+	asm volatile (".byte 0x0f,0x37\n"
+		      : : "a" (SMX_X86_GETSEC_SEXIT));
+}
+
+void slaunch_sexit(void)
+{
+	void __iomem *config;
+	u64 one = 1, val;
+
+	if (!(slaunch_get_flags() & (SL_FLAG_ACTIVE|SL_FLAG_ARCH_TXT)))
+		return;
+
+	if (smp_processor_id() != 0) {
+		pr_err("Error TXT SEXIT must be called on CPU 0\n");
+		return;
+	}
+
+	config = ioremap(TXT_PRIV_CONFIG_REGS_BASE, TXT_NR_CONFIG_PAGES *
+			 PAGE_SIZE);
+	if (!config) {
+		pr_err("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_err("Error SEXIT failed to ioremap TXT public reqs\n");
+		return;
+	}
+
+	memcpy_fromio(&val, config + TXT_CR_E2STS, sizeof(u64));
+
+	/* Disable SMX mode */
+	cr4_set_bits(X86_CR4_SMXE);
+
+	/* Do the SEXIT SMX operation */
+	txt_getsec_sexit();
+
+	pr_emerg("TXT SEXIT complete.");
+}
diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c
index 15d70a90b50d..08105eeebf90 100644
--- a/kernel/kexec_core.c
+++ b/kernel/kexec_core.c
@@ -37,6 +37,7 @@
 #include <linux/compiler.h>
 #include <linux/hugetlb.h>
 #include <linux/frame.h>
+#include <linux/slaunch.h>
 
 #include <asm/page.h>
 #include <asm/sections.h>
@@ -1173,6 +1174,8 @@ int kernel_kexec(void)
 		cpu_hotplug_enable();
 		pr_emerg("Starting new kernel\n");
 		machine_shutdown();
+
+		slaunch_sexit();
 	}
 
 	machine_kexec(kexec_image);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [RFC PATCH 12/12] tpm: Allow locality 2 to be set when initializing the TPM for Secure Launch
  2020-03-25 19:43 [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support Ross Philipson
                   ` (10 preceding siblings ...)
  2020-03-25 19:43 ` [RFC PATCH 11/12] kexec: Secure Launch kexec SEXIT support Ross Philipson
@ 2020-03-25 19:43 ` Ross Philipson
  2020-03-25 20:29 ` [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support Matthew Garrett
  12 siblings, 0 replies; 43+ messages in thread
From: Ross Philipson @ 2020-03-25 19:43 UTC (permalink / raw)
  To: linux-kernel, x86, linux-doc
  Cc: ross.philipson, dpsmith, tglx, mingo, bp, hpa, trenchboot-devel

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 <ross.philipson@oracle.com>
---
 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 3d6d394a8661..e74860537252 100644
--- a/drivers/char/tpm/tpm-chip.c
+++ b/drivers/char/tpm/tpm-chip.c
@@ -23,6 +23,7 @@
 #include <linux/major.h>
 #include <linux/tpm_eventlog.h>
 #include <linux/hw_random.h>
+#include <linux/slaunch.h>
 #include "tpm.h"
 
 DEFINE_IDR(dev_nums_idr);
@@ -34,12 +35,20 @@ dev_t tpm_devt;
 
 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;
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* Re: [RFC PATCH 10/12] x86: Secure Launch adding event log securityfs
  2020-03-25 19:43 ` [RFC PATCH 10/12] x86: Secure Launch adding event log securityfs Ross Philipson
@ 2020-03-25 20:21   ` Matthew Garrett
  2020-03-25 21:43     ` Daniel P. Smith
  0 siblings, 1 reply; 43+ messages in thread
From: Matthew Garrett @ 2020-03-25 20:21 UTC (permalink / raw)
  To: Ross Philipson
  Cc: Linux Kernel Mailing List, the arch/x86 maintainers, linux-doc,
	dpsmith, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	H. Peter Anvin, trenchboot-devel

On Wed, Mar 25, 2020 at 12:43 PM Ross Philipson
<ross.philipson@oracle.com> wrote:
>
> From: "Daniel P. Smith" <dpsmith@apertussolutions.com>
>
> The late init functionality registers securityfs nodes to allow fetching
> of and writing events to the late launch TPM log.

Is there a reason we would want this exposed separately from the
regular event log, rather than just appending it there?

> +static ssize_t sl_evtlog_write(struct file *file, const char __user *buf,
> +                               size_t datalen, loff_t *ppos)
> +{

What's expected to be writing to this?

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support
  2020-03-25 19:43 [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support Ross Philipson
                   ` (11 preceding siblings ...)
  2020-03-25 19:43 ` [RFC PATCH 12/12] tpm: Allow locality 2 to be set when initializing the TPM for Secure Launch Ross Philipson
@ 2020-03-25 20:29 ` Matthew Garrett
  2020-03-25 22:51   ` Andy Lutomirski
                     ` (2 more replies)
  12 siblings, 3 replies; 43+ messages in thread
From: Matthew Garrett @ 2020-03-25 20:29 UTC (permalink / raw)
  To: Ross Philipson
  Cc: Linux Kernel Mailing List, the arch/x86 maintainers, linux-doc,
	dpsmith, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	H. Peter Anvin, trenchboot-devel

On Wed, Mar 25, 2020 at 12:43 PM Ross Philipson
<ross.philipson@oracle.com> wrote:
> To enable the kernel to be launched by GETSEC or SKINIT, a stub must be
> built into the setup section of the compressed kernel to handle the
> specific state that the late launch process leaves the BSP. This is a
> lot like the EFI stub that is found in the same area. Also this stub
> must measure everything that is going to be used as early as possible.
> This stub code and subsequent code must also deal with the specific
> state that the late launch leaves the APs in.

How does this integrate with the EFI entry point? That's the expected
entry point on most modern x86. What's calling ExitBootServices() in
this flow, and does the secure launch have to occur after it? It'd be
a lot easier if you could still use the firmware's TPM code rather
than carrying yet another copy.

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [RFC PATCH 10/12] x86: Secure Launch adding event log securityfs
  2020-03-25 20:21   ` Matthew Garrett
@ 2020-03-25 21:43     ` Daniel P. Smith
  0 siblings, 0 replies; 43+ messages in thread
From: Daniel P. Smith @ 2020-03-25 21:43 UTC (permalink / raw)
  To: Matthew Garrett, Ross Philipson
  Cc: Linux Kernel Mailing List, the arch/x86 maintainers, linux-doc,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, H. Peter Anvin,
	trenchboot-devel

On 3/25/20 4:21 PM, Matthew Garrett wrote:
> On Wed, Mar 25, 2020 at 12:43 PM Ross Philipson
> <ross.philipson@oracle.com> wrote:
>>
>> From: "Daniel P. Smith" <dpsmith@apertussolutions.com>
>>
>> The late init functionality registers securityfs nodes to allow fetching
>> of and writing events to the late launch TPM log.
> 
> Is there a reason we would want this exposed separately from the
> regular event log, rather than just appending it there?

We created a separate securityfs node as the intent is to eventually
expose additional information relating to state of the Dynamic Launch.
We only implemented the log node as it is the only node we required for
demonstrating the initial capability. By no means are we tied to this
path for the log. If maintainers would like to see the DRTM log be
colocated with the SRTM log, we can move the logic over to the tpm
driver's eventlog code.


>> +static ssize_t sl_evtlog_write(struct file *file, const char __user *buf,
>> +                               size_t datalen, loff_t *ppos)
>> +{
> 
> What's expected to be writing to this?
> 

We want to support a multitude of use cases but for an initial
demonstrator it was felt better to emulate the way people are using
Intel TXT, via tboot as an intermediate loader in the boot chain. When
using a Secure Launch for an intermediate loader implementation, the
implementer has the richness of the user-space runtime for collecting
measurements. As a result they may want(be forced) to do the hashing in
user-space and since this is a measurement that is part of the DRTM
chain it needs to get appended to that log. Thus it seemed natural to
enable the extending of the log by allowing one to write to the log's
securityfs node.

V/r,
Daniel P. Smith


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support
  2020-03-25 20:29 ` [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support Matthew Garrett
@ 2020-03-25 22:51   ` Andy Lutomirski
  2020-03-26 20:50     ` Daniel P. Smith
  2020-03-26 13:40   ` Daniel Kiper
  2020-03-26 20:50   ` Daniel P. Smith
  2 siblings, 1 reply; 43+ messages in thread
From: Andy Lutomirski @ 2020-03-25 22:51 UTC (permalink / raw)
  To: Matthew Garrett
  Cc: Ross Philipson, Linux Kernel Mailing List,
	the arch/x86 maintainers, open list:DOCUMENTATION, dpsmith,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, H. Peter Anvin,
	trenchboot-devel

On Wed, Mar 25, 2020 at 1:29 PM Matthew Garrett <mjg59@google.com> wrote:
>
> On Wed, Mar 25, 2020 at 12:43 PM Ross Philipson
> <ross.philipson@oracle.com> wrote:
> > To enable the kernel to be launched by GETSEC or SKINIT, a stub must be
> > built into the setup section of the compressed kernel to handle the
> > specific state that the late launch process leaves the BSP. This is a
> > lot like the EFI stub that is found in the same area. Also this stub
> > must measure everything that is going to be used as early as possible.
> > This stub code and subsequent code must also deal with the specific
> > state that the late launch leaves the APs in.
>
> How does this integrate with the EFI entry point? That's the expected
> entry point on most modern x86. What's calling ExitBootServices() in
> this flow, and does the secure launch have to occur after it? It'd be
> a lot easier if you could still use the firmware's TPM code rather
> than carrying yet another copy.

I was wondering why the bootloader was involved at all.  In other
words, could you instead hand off control to the kernel just like
normal and have the kernel itself (in normal code, the EFI stub, or
wherever it makes sense) do the DRTM launch all by itself?  This would
avoid needing to patch bootloaders, to implement this specially for
QEMU -kernel, to get the exact right buy-in from all the cloud
vendors, etc.  It would also give you more flexibility to evolve
exactly what configuration maps to exactly what PCRs in the future.

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [RFC PATCH 03/12] x86: Add early SHA support for Secure Launch early measurements
  2020-03-25 19:43 ` [RFC PATCH 03/12] x86: Add early SHA support for Secure Launch early measurements Ross Philipson
@ 2020-03-26  3:44   ` Andy Lutomirski
  2020-03-26 22:49     ` Daniel P. Smith
  0 siblings, 1 reply; 43+ messages in thread
From: Andy Lutomirski @ 2020-03-26  3:44 UTC (permalink / raw)
  To: Ross Philipson
  Cc: LKML, X86 ML, open list:DOCUMENTATION, dpsmith, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, H. Peter Anvin, trenchboot-devel

On Wed, Mar 25, 2020 at 12:43 PM Ross Philipson
<ross.philipson@oracle.com> wrote:
>
> From: "Daniel P. Smith" <dpsmith@apertussolutions.com>
>
> 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 SHA1 code here has its origins in the code in
> include/crypto/sha1_base.h. That code could not be pulled directly into
> the setup portion of the compressed kernel because of other dependencies
> it pulls in. So this is a modified copy of that code that still leverages
> the core SHA1 algorithm.
>
> Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com>
> ---
>  arch/x86/Kconfig                        |  24 +++
>  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 ++++++++++++++++++++++++
>  9 files changed, 395 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/Kconfig b/arch/x86/Kconfig
> index 7f3406a9948b..f37057d3ce9f 100644
> --- a/arch/x86/Kconfig
> +++ b/arch/x86/Kconfig
> @@ -2025,6 +2025,30 @@ config SECURE_LAUNCH
>           of all the modules and configuration information used for
>           boooting the operating system.
>
> +choice
> +       prompt "Select Secure Launch Algorithm for TPM2"
> +       depends on SECURE_LAUNCH
> +
> +config SECURE_LAUNCH_SHA1
> +       bool "Secure Launch TPM2 SHA1"
> +       help
> +         When using Secure Launch and TPM2 is present, use SHA1 hash
> +         algorithm for measurements.
> +

I'm surprised this is supported at all.  Why allow SHA1?

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support
  2020-03-25 20:29 ` [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support Matthew Garrett
  2020-03-25 22:51   ` Andy Lutomirski
@ 2020-03-26 13:40   ` Daniel Kiper
  2020-03-26 20:19     ` Matthew Garrett
  2020-03-26 20:50   ` Daniel P. Smith
  2 siblings, 1 reply; 43+ messages in thread
From: Daniel Kiper @ 2020-03-26 13:40 UTC (permalink / raw)
  To: Matthew Garrett
  Cc: Ross Philipson, Linux Kernel Mailing List,
	the arch/x86 maintainers, linux-doc, dpsmith, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, H. Peter Anvin, trenchboot-devel,
	ardb, leif, eric.snowberg, piotr.krol, krystian.hebel,
	michal.zygowski, james.bottomley, andrew.cooper3

Hey,

CC-in Ard, Leif, Eric, Piotr, Krystian, Michał, James and Andrew...

On Wed, Mar 25, 2020 at 01:29:03PM -0700, 'Matthew Garrett' via trenchboot-devel wrote:
> On Wed, Mar 25, 2020 at 12:43 PM Ross Philipson
> <ross.philipson@oracle.com> wrote:
> > To enable the kernel to be launched by GETSEC or SKINIT, a stub must be
> > built into the setup section of the compressed kernel to handle the
> > specific state that the late launch process leaves the BSP. This is a
> > lot like the EFI stub that is found in the same area. Also this stub
> > must measure everything that is going to be used as early as possible.
> > This stub code and subsequent code must also deal with the specific
> > state that the late launch leaves the APs in.
>
> How does this integrate with the EFI entry point? That's the expected

It does not. We do not want and need to tie secure launch with UEFI.

> entry point on most modern x86.

Yeah, most but not all...

> What's calling ExitBootServices() in

Currently it is a bootloader, the GRUB which I am working on... OK, this
is not perfect but if we want to call ExitBootServices() from the kernel
then we have to move all pre-launch code from the bootloader to the
kernel. Not nice because then everybody who wants to implement secure
launch in different kernel, hypervisor, etc. has to re-implement whole
pre-launch code again.

> this flow, and does the secure launch have to occur after it? It'd be

Yes, it does.

> a lot easier if you could still use the firmware's TPM code rather
> than carrying yet another copy.

I think any post-launch code in the kernel should not call anything from
the gap. And UEFI belongs to the gap. OK, we can potentially re-use UEFI
TPM code in the pre-launch phase but I am not convinced that we should
(I am looking at it right now). And this leads us to other question
which pops up here and there. How to call UEFI runtime services, e.g. to
modify UEFI variables, update firmware, etc., from MLE or even from the
OS started from MLE? In my opinion it is not safe to call anything from
the gap after secure launch. However, on the other hand we have to give
an option to change the boot order or update the firmware. So, how to
do that? I do not have an easy answer yet...

Daniel

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [RFC PATCH 01/12] x86: Secure Launch Kconfig
  2020-03-25 19:43 ` [RFC PATCH 01/12] x86: Secure Launch Kconfig Ross Philipson
@ 2020-03-26 18:06   ` Daniel Kiper
  2020-03-26 19:42     ` Ross Philipson
  0 siblings, 1 reply; 43+ messages in thread
From: Daniel Kiper @ 2020-03-26 18:06 UTC (permalink / raw)
  To: Ross Philipson
  Cc: linux-kernel, x86, linux-doc, dpsmith, tglx, mingo, bp, hpa,
	trenchboot-devel

On Wed, Mar 25, 2020 at 03:43:06PM -0400, Ross Philipson wrote:
> Initial bits to bring in Secure Launch functionality. Add Kconfig
> options for compiling in/out the Secure Launch code.
>
> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
> ---
>  arch/x86/Kconfig | 11 +++++++++++
>  1 file changed, 11 insertions(+)
>
> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> index 5e8949953660..7f3406a9948b 100644
> --- a/arch/x86/Kconfig
> +++ b/arch/x86/Kconfig
> @@ -2014,6 +2014,17 @@ config EFI_MIXED
>
>  	   If unsure, say N.
>
> +config SECURE_LAUNCH
> +	bool "Secure Launch support"
> +	default n
> +	depends on X86_64
> +	help
> +	  This Secure Launch kernel feature allows a bzImage to be loaded
> +	  directly through Intel TXT or AMD SKINIT measured launch. This

I think that you should drop AMD SKINIT from here. This should be added
when AMD secure launch implementation is added.

...and why we need this as separate patch? Could not we add this in
a patch which uses CONFIG_SECURE_LAUNCH for first time?

Daniel

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [RFC PATCH 02/12] x86: Secure Launch main header file
  2020-03-25 19:43 ` [RFC PATCH 02/12] x86: Secure Launch main header file Ross Philipson
@ 2020-03-26 19:00   ` Daniel Kiper
  0 siblings, 0 replies; 43+ messages in thread
From: Daniel Kiper @ 2020-03-26 19:00 UTC (permalink / raw)
  To: Ross Philipson
  Cc: linux-kernel, x86, linux-doc, dpsmith, tglx, mingo, bp, hpa,
	trenchboot-devel

On Wed, Mar 25, 2020 at 03:43:07PM -0400, Ross Philipson wrote:
> Introduce the main Secure Launch header file used in the early SL stub
> and the early setup code.
>
> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
> ---
>  include/linux/slaunch.h | 513 ++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 513 insertions(+)
>  create mode 100644 include/linux/slaunch.h
>
> diff --git a/include/linux/slaunch.h b/include/linux/slaunch.h

This patch is arch specific and should land in arch/x86/include.

Hmmm... arch/x86/include/slaunch/txt.h?

> new file mode 100644
> index 000000000000..8f090dc38984
> --- /dev/null
> +++ b/include/linux/slaunch.h
> @@ -0,0 +1,513 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#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.

Copyright (c) 2020, Oracle and/or its affiliates.

...and IMO this header should go immediately behind SPDX header...

> + */
> +
> +#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 */

Could not we add this to more generic header?

> +#define AMD_CPUID_MFGID_EBX	0x68747541 /* Auth */
> +#define AMD_CPUID_MFGID_EDX	0x69746e65 /* enti */
> +#define AMD_CPUID_MFGID_ECX	0x444d4163 /* cAMD */

Do we need AMD stuff if we do not add it in this patchset?

> +/*
> + * 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_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_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)

s/TXT_SENTER_DONE_STS/TXT_STS_SENTER_DONE/
s/TXT_SEXIT_DONE_STS/TXT_STS__SEXIT_DONE/

> +
> +/*
> + * 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_MAX_EVENT_LOG_SIZE		(5*4*1024)   /* 4k*5 */
> +#define TXT_MAX_VARIABLE_MTRRS		32
> +#define TXT_OS_MLE_STRUCT_VERSION	1
> +
> +/*
> + * 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

s/TXT_BIOS_DATA_TABLE/TXT_DATA_TABLE_BIOS/ etc.

> +/*
> + * 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_HEAP_ZERO_OFFSET	0xc0008018
> +
> +/*
> + * 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
> + */

I think that you can you use one line, e.g. /* MLE scratch area offsets */
here, below and above...

> +#define SL_SCRATCH_AP_EBP		0
> +#define SL_SCRATCH_AP_JMP_OFFSET	4
> +
> +#ifndef __ASSEMBLY__
> +
> +/*
> + * Secure Launch AP wakeup information fetched in SMP boot code.
> + */

Ditto...

> +struct sl_ap_wake_info {
> +	u64 ap_wake_block;
> +	u32 ap_jmp_offset;
> +};
> +
> +/*
> + * TXT heap extended data elements.
> + */

Ditto... Etc...

> +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_MAX_VARIABLE_MTRRS];
> +} __packed;
> +
> +/*
> + * Secure Launch defined OS/MLE TXT Heap table
> + */
> +struct txt_os_mle_data {
> +	u32 version;
> +	u32 zero_page_addr;

I think that you should change zero_page_addr to boot_params_addr.
boot_params sounds more generic and I can imagine that there can be an
different implementation of Intel TXT MLE kernel than Linux one. So, IMO
naming in this structure should be as much generic as possible.

> +	u8 msb_key_hash[20];
> +	u64 saved_misc_enable_msr;
> +	struct txt_mtrr_state saved_bsp_mtrrs;
> +	u64 ap_wake_block;
> +	/* These two fields should always be last */

Hmmm... What if you want to bump version number and extend this
structure with new members?

> +	u64 mle_scratch;
> +	u8 event_log_buffer[TXT_MAX_EVENT_LOG_SIZE];

This should be a pointer to a TPM event log. On TXT heap?
And of course another member with its size.

> +} __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] */

I suppose that you do somewhere weird arithmetic to get digest offset.
Why not digest[0] or digest[]? Then you can refer to this member
directly then...

> +} __packed;
> +
> +struct tpm20_digest_values {
> +	u32 count;
> +	/* TPMT_HA digests[count] */

Ditto and below...

> +} __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;
> +
> +#include <linux/io.h>

I would prefer to move this immediately behind "#ifndef __ASSEMBLY__"...

> +/*
> + * Functions to extract data from the Intel TXT Heap Memory
> + */
> +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)

Naming suggests that these TPM functions are generic ones. However,
they are not. They are TXT specific. Could you prefix them with "txt_"?

> +{
> +	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)

Ditto...

> +{
> +	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)

Ditto...

Daniel

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [RFC PATCH 01/12] x86: Secure Launch Kconfig
  2020-03-26 18:06   ` Daniel Kiper
@ 2020-03-26 19:42     ` Ross Philipson
  0 siblings, 0 replies; 43+ messages in thread
From: Ross Philipson @ 2020-03-26 19:42 UTC (permalink / raw)
  To: Daniel Kiper
  Cc: linux-kernel, x86, linux-doc, dpsmith, tglx, mingo, bp, hpa,
	trenchboot-devel

On 3/26/20 2:06 PM, Daniel Kiper wrote:
> On Wed, Mar 25, 2020 at 03:43:06PM -0400, Ross Philipson wrote:
>> Initial bits to bring in Secure Launch functionality. Add Kconfig
>> options for compiling in/out the Secure Launch code.
>>
>> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
>> ---
>>  arch/x86/Kconfig | 11 +++++++++++
>>  1 file changed, 11 insertions(+)
>>
>> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
>> index 5e8949953660..7f3406a9948b 100644
>> --- a/arch/x86/Kconfig
>> +++ b/arch/x86/Kconfig
>> @@ -2014,6 +2014,17 @@ config EFI_MIXED
>>
>>  	   If unsure, say N.
>>
>> +config SECURE_LAUNCH
>> +	bool "Secure Launch support"
>> +	default n
>> +	depends on X86_64
>> +	help
>> +	  This Secure Launch kernel feature allows a bzImage to be loaded
>> +	  directly through Intel TXT or AMD SKINIT measured launch. This
> 
> I think that you should drop AMD SKINIT from here. This should be added
> when AMD secure launch implementation is added.

Yea will do.

> 
> ...and why we need this as separate patch? Could not we add this in
> a patch which uses CONFIG_SECURE_LAUNCH for first time?

So it used to be part of a bigger patch but it ended up shrinking down
to this when kernel_info was introduced. The first patch to use it is
the SHA patch but that seems a weird place to introduce it. Will have to
think about it...

> 
> Daniel
> 


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support
  2020-03-26 13:40   ` Daniel Kiper
@ 2020-03-26 20:19     ` Matthew Garrett
  2020-03-26 20:33       ` Andy Lutomirski
  2020-05-11 19:00       ` Daniel P. Smith
  0 siblings, 2 replies; 43+ messages in thread
From: Matthew Garrett @ 2020-03-26 20:19 UTC (permalink / raw)
  To: Daniel Kiper
  Cc: Ross Philipson, Linux Kernel Mailing List,
	the arch/x86 maintainers, linux-doc, dpsmith, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, H. Peter Anvin, trenchboot-devel,
	Ard Biesheuvel, leif, eric.snowberg, piotr.krol, krystian.hebel,
	michal.zygowski, James Bottomley, andrew.cooper3

On Thu, Mar 26, 2020 at 6:40 AM Daniel Kiper <daniel.kiper@oracle.com> wrote:
> On Wed, Mar 25, 2020 at 01:29:03PM -0700, 'Matthew Garrett' via trenchboot-devel wrote:
> > On Wed, Mar 25, 2020 at 12:43 PM Ross Philipson
> > <ross.philipson@oracle.com> wrote:
> > > To enable the kernel to be launched by GETSEC or SKINIT, a stub must be
> > > built into the setup section of the compressed kernel to handle the
> > > specific state that the late launch process leaves the BSP. This is a
> > > lot like the EFI stub that is found in the same area. Also this stub
> > > must measure everything that is going to be used as early as possible.
> > > This stub code and subsequent code must also deal with the specific
> > > state that the late launch leaves the APs in.
> >
> > How does this integrate with the EFI entry point? That's the expected
>
> It does not. We do not want and need to tie secure launch with UEFI.

I agree that it shouldn't be required, but it should be possible. We
shouldn't add new entry points that don't integrate with the standard
way of booting the kernel.

> > What's calling ExitBootServices() in
>
> Currently it is a bootloader, the GRUB which I am working on... OK, this
> is not perfect but if we want to call ExitBootServices() from the kernel
> then we have to move all pre-launch code from the bootloader to the
> kernel. Not nice because then everybody who wants to implement secure
> launch in different kernel, hypervisor, etc. has to re-implement whole
> pre-launch code again.

We call ExitBootServices() in the EFI stub, so this is fine as long as
the EFI stub hands over control to the SL code. But yes, I think it's
a requirement that it be kernel-owned code calling ExitBootServices().

> > this flow, and does the secure launch have to occur after it? It'd be
>
> Yes, it does.

Ok. The firmware TPM interfaces are gone after ExitBootServices(), so
we're going to need an additional implementation.

> I think any post-launch code in the kernel should not call anything from
> the gap. And UEFI belongs to the gap. OK, we can potentially re-use UEFI
> TPM code in the pre-launch phase but I am not convinced that we should
> (I am looking at it right now). And this leads us to other question
> which pops up here and there. How to call UEFI runtime services, e.g. to
> modify UEFI variables, update firmware, etc., from MLE or even from the
> OS started from MLE? In my opinion it is not safe to call anything from
> the gap after secure launch. However, on the other hand we have to give
> an option to change the boot order or update the firmware. So, how to
> do that? I do not have an easy answer yet...

How does Windows manage this? Retaining access to EFI runtime services
is necessary, and the areas in the memory map marked as runtime
services code or data should be considered part of the TCB and
measured - they're very much not part of the gap.

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support
  2020-03-26 20:19     ` Matthew Garrett
@ 2020-03-26 20:33       ` Andy Lutomirski
  2020-03-26 20:40         ` Matthew Garrett
  2020-05-11 19:00       ` Daniel P. Smith
  1 sibling, 1 reply; 43+ messages in thread
From: Andy Lutomirski @ 2020-03-26 20:33 UTC (permalink / raw)
  To: Matthew Garrett
  Cc: Daniel Kiper, Ross Philipson, Linux Kernel Mailing List,
	the arch/x86 maintainers, linux-doc, dpsmith, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, H. Peter Anvin, trenchboot-devel,
	Ard Biesheuvel, leif, eric.snowberg, piotr.krol, krystian.hebel,
	michal.zygowski, James Bottomley, andrew.cooper3



> On Mar 26, 2020, at 1:19 PM, Matthew Garrett <mjg59@google.com> wrote:
> 
> On Thu, Mar 26, 2020 at 6:40 AM Daniel Kiper <daniel.kiper@oracle.com> wrote:
>>> On Wed, Mar 25, 2020 at 01:29:03PM -0700, 'Matthew Garrett' via trenchboot-devel wrote:
>>> On Wed, Mar 25, 2020 at 12:43 PM Ross Philipson
>>> <ross.philipson@oracle.com> wrote:
>>>> To enable the kernel to be launched by GETSEC or SKINIT, a stub must be
>>>> built into the setup section of the compressed kernel to handle the
>>>> specific state that the late launch process leaves the BSP. This is a
>>>> lot like the EFI stub that is found in the same area. Also this stub
>>>> must measure everything that is going to be used as early as possible.
>>>> This stub code and subsequent code must also deal with the specific
>>>> state that the late launch leaves the APs in.
>>> 
>>> How does this integrate with the EFI entry point? That's the expected
>> 
>> It does not. We do not want and need to tie secure launch with UEFI.
> 
> I agree that it shouldn't be required, but it should be possible. We
> shouldn't add new entry points that don't integrate with the standard
> way of booting the kernel.
> 
>>> What's calling ExitBootServices() in
>> 
>> Currently it is a bootloader, the GRUB which I am working on... OK, this
>> is not perfect but if we want to call ExitBootServices() from the kernel
>> then we have to move all pre-launch code from the bootloader to the
>> kernel. Not nice because then everybody who wants to implement secure
>> launch in different kernel, hypervisor, etc. has to re-implement whole
>> pre-launch code again.
> 
> We call ExitBootServices() in the EFI stub, so this is fine as long as
> the EFI stub hands over control to the SL code. But yes, I think it's
> a requirement that it be kernel-owned code calling ExitBootServices().
> 
>>> this flow, and does the secure launch have to occur after it? It'd be
>> 
>> Yes, it does.
> 
> Ok. The firmware TPM interfaces are gone after ExitBootServices(), so
> we're going to need an additional implementation.
> 
>> I think any post-launch code in the kernel should not call anything from
>> the gap. And UEFI belongs to the gap. OK, we can potentially re-use UEFI
>> TPM code in the pre-launch phase but I am not convinced that we should
>> (I am looking at it right now). And this leads us to other question
>> which pops up here and there. How to call UEFI runtime services, e.g. to
>> modify UEFI variables, update firmware, etc., from MLE or even from the
>> OS started from MLE? In my opinion it is not safe to call anything from
>> the gap after secure launch. However, on the other hand we have to give
>> an option to change the boot order or update the firmware. So, how to
>> do that? I do not have an easy answer yet...
> 
> How does Windows manage this? Retaining access to EFI runtime services
> is necessary, and the areas in the memory map marked as runtime
> services code or data should be considered part of the TCB and
> measured - they're very much not part of the gap.

As a straw-man approach: make the rule that we never call EFI after secure launch. Instead we write out any firmware variables that we want to change on disk somewhere.  When we want to commit those changes, we reboot, commit the changes, and re-launch. Or we deactivate the kernel kexec-style, seal the image against PCRs, blow away PCRs, call EFI, relaunch, unseal the PCRs, and continue on our merry way.

I’m not sure how SMM fits in to this whole mess.

If we insist on allowing EFI calls and SMM, then we may be able to *measure* our exposure to potentially malicious firmware, but we can’t eliminate it. I personally trust OEM firmware about as far as I can throw it.

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support
  2020-03-26 20:33       ` Andy Lutomirski
@ 2020-03-26 20:40         ` Matthew Garrett
  2020-03-26 20:59           ` Daniel P. Smith
  2020-03-26 21:07           ` Andy Lutomirski
  0 siblings, 2 replies; 43+ messages in thread
From: Matthew Garrett @ 2020-03-26 20:40 UTC (permalink / raw)
  To: Andy Lutomirski
  Cc: Daniel Kiper, Ross Philipson, Linux Kernel Mailing List,
	the arch/x86 maintainers, linux-doc, dpsmith, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, H. Peter Anvin, trenchboot-devel,
	Ard Biesheuvel, leif, eric.snowberg, piotr.krol, krystian.hebel,
	michal.zygowski, James Bottomley, andrew.cooper3

On Thu, Mar 26, 2020 at 1:33 PM Andy Lutomirski <luto@amacapital.net> wrote:
> As a straw-man approach: make the rule that we never call EFI after secure launch. Instead we write out any firmware variables that we want to change on disk somewhere.  When we want to commit those changes, we reboot, commit the changes, and re-launch. Or we deactivate the kernel kexec-style, seal the image against PCRs, blow away PCRs, call EFI, relaunch, unseal the PCRs, and continue on our merry way.

That breaks the memory overwrite protection code, where a variable is
set at boot and cleared on a controlled reboot. We'd also need to read
every variable and pass those values to the kernel in some way so the
read interfaces still work. Some platforms may also expect to be able
to use the EFI reboot call. As for the second approach - how would we
verify that the EFI code hadn't modified any user pages? Those
wouldn't be measured during the second secure launch. If we're calling
the code at runtime then I think we need to assert that it's trusted.

> I’m not sure how SMM fits in to this whole mess.

SMM's basically an unsolved problem, which makes the whole DRTM
approach somewhat questionable unless you include the whole firmware
in the TCB, which is kind of what we're trying to get away from.

> If we insist on allowing EFI calls and SMM, then we may be able to *measure* our exposure to potentially malicious firmware, but we can’t eliminate it. I personally trust OEM firmware about as far as I can throw it.

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support
  2020-03-25 20:29 ` [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support Matthew Garrett
  2020-03-25 22:51   ` Andy Lutomirski
  2020-03-26 13:40   ` Daniel Kiper
@ 2020-03-26 20:50   ` Daniel P. Smith
  2020-03-26 20:54     ` Matthew Garrett
  2 siblings, 1 reply; 43+ messages in thread
From: Daniel P. Smith @ 2020-03-26 20:50 UTC (permalink / raw)
  To: Matthew Garrett, Ross Philipson
  Cc: Linux Kernel Mailing List, the arch/x86 maintainers, linux-doc,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, H. Peter Anvin,
	trenchboot-devel

On 3/25/20 4:29 PM, Matthew Garrett wrote:
> On Wed, Mar 25, 2020 at 12:43 PM Ross Philipson
> <ross.philipson@oracle.com> wrote:
>> To enable the kernel to be launched by GETSEC or SKINIT, a stub must be
>> built into the setup section of the compressed kernel to handle the
>> specific state that the late launch process leaves the BSP. This is a
>> lot like the EFI stub that is found in the same area. Also this stub
>> must measure everything that is going to be used as early as possible.
>> This stub code and subsequent code must also deal with the specific
>> state that the late launch leaves the APs in.
> 
> How does this integrate with the EFI entry point? That's the expected
> entry point on most modern x86. What's calling ExitBootServices() in
> this flow, and does the secure launch have to occur after it? It'd be
> a lot easier if you could still use the firmware's TPM code rather
> than carrying yet another copy.


It is not part of the EFI entry point as we are not entering the kernel
from EFI but I will address that further in my response to Andy. The
expectation is that if you are on an UEFI platform then EBS should have
already been called. With respect to using the firmware's TPM code, one
of the purposes of a TCG Dynamic Launch is to remove the firmware from
the code being trusted in making the integrity measurement of the
kernel. I trust the firmware to initialize the hardware because I have
to and it does give a trust chain, aka the SRTM, that can attest to what
was used during that process. When the OS kernel is being started that
trust chain has become weak (or even broken). I want a new trust chain
that can provide better footing for asserting the integrity of the
kernel and this is what Dynamic Launch gives us. I would like to think I
did a fair job explaining this at LSS last fall[1][2] and would
recommend those that are curious to review the slides/watch the
presentation.

V/r,
Daniel P. Smith

[1]
https://lssna19.sched.com/event/RHb0/trenchboot-how-to-nicely-boot-system-with-intel-txt-and-amd-svm-daniel-kiper-oracle-daniel-smith-apertus-solutions
[2] https://youtu.be/DbpCU9iSi4g



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support
  2020-03-25 22:51   ` Andy Lutomirski
@ 2020-03-26 20:50     ` Daniel P. Smith
  2020-03-26 23:13       ` Andy Lutomirski
  0 siblings, 1 reply; 43+ messages in thread
From: Daniel P. Smith @ 2020-03-26 20:50 UTC (permalink / raw)
  To: Andy Lutomirski, Matthew Garrett
  Cc: Ross Philipson, Linux Kernel Mailing List,
	the arch/x86 maintainers, open list:DOCUMENTATION,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, H. Peter Anvin,
	trenchboot-devel

On 3/25/20 6:51 PM, Andy Lutomirski wrote:
> On Wed, Mar 25, 2020 at 1:29 PM Matthew Garrett <mjg59@google.com> wrote:
>>
>> On Wed, Mar 25, 2020 at 12:43 PM Ross Philipson
>> <ross.philipson@oracle.com> wrote:
>>> To enable the kernel to be launched by GETSEC or SKINIT, a stub must be
>>> built into the setup section of the compressed kernel to handle the
>>> specific state that the late launch process leaves the BSP. This is a
>>> lot like the EFI stub that is found in the same area. Also this stub
>>> must measure everything that is going to be used as early as possible.
>>> This stub code and subsequent code must also deal with the specific
>>> state that the late launch leaves the APs in.
>>
>> How does this integrate with the EFI entry point? That's the expected
>> entry point on most modern x86. What's calling ExitBootServices() in
>> this flow, and does the secure launch have to occur after it? It'd be
>> a lot easier if you could still use the firmware's TPM code rather
>> than carrying yet another copy.
> 
> I was wondering why the bootloader was involved at all.  In other
> words, could you instead hand off control to the kernel just like
> normal and have the kernel itself (in normal code, the EFI stub, or
> wherever it makes sense) do the DRTM launch all by itself?  This would
> avoid needing to patch bootloaders, to implement this specially for
> QEMU -kernel, to get the exact right buy-in from all the cloud
> vendors, etc.  It would also give you more flexibility to evolve
> exactly what configuration maps to exactly what PCRs in the future.
> 

Partly this is driven by the fact that one of the goals for the
TrenchBoot project is about more universal/unified, cross open source
project adoption of Dynamic Launch. Another aspect is that initiating a
Dynamic Launch requires additional file(s) to be loaded, the platform to
be put into a quiescent state, and the invocation of the SENTER/SKINIT
instruction can be thought of as a soft reset of the CPU that on Intel
even results in the CPU being in a different mode (SMX) which has a
subtle change to its behavior. In the TCG Dynamic Launch design, the
component responsible for this loading, preparing, and Dynamic Launch
Instruction invocation is referred to as the Preamble and IMHO the best
time for dealing with such a disruptive behavior caused by invoking the
instruction is at the boot boundary. It also makes for a good transition
point to enable switching between kernels in control of the system
whereby the integrity will be establish by the hardware instead of the
kernel (UEFI, GRUB, Linux, etc.) that loaded it. I think what helps
address your concern is that one of the next items on the roadmap is to
extend kexec to be able to perform the Preamble. As I just mentioned,
this provides a clean way to transition for one Linux kernel that may or
may not have been started via a Dynamic Launch could relaunch itself,
launch a new Linux kernel, or even launch a non-Linux kernel that is
Dynamic Launch aware.

As for controlling which PCRs are used, the ability to control that is
actually quite limited. The CPU will always put its first measurement
into PCR 17 and then next set of measurement will differ depending on
whether you are on Intel or AMD. With Intel, the Intel provided binary
blob called the ACM has a fixed measurement policy it uses to place
measurements into PCRs 17 and 18. On AMD they left their ACM equivalent
as an exercise for the implementer (for which we have one in
development) which give us control over the measurements that it takes.
Then you have to consider the properties of the DRTM PCRs, 17-22, where
PCRs 17, 18, and 19 are the only ones that cannot be reset after the
DRTM event. Where as PCRs 20, 21, 22 can be reset by Locality 2, the
highest locality for which the kernel will be able to request/access.

I hope this helps and if you have any other questions concerns I would
be glad to answer them.

V/r,
Daniel P. Smith


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support
  2020-03-26 20:50   ` Daniel P. Smith
@ 2020-03-26 20:54     ` Matthew Garrett
  2020-03-26 22:37       ` Daniel P. Smith
  0 siblings, 1 reply; 43+ messages in thread
From: Matthew Garrett @ 2020-03-26 20:54 UTC (permalink / raw)
  To: Daniel P. Smith
  Cc: Ross Philipson, Linux Kernel Mailing List,
	the arch/x86 maintainers, linux-doc, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, H. Peter Anvin, trenchboot-devel

On Thu, Mar 26, 2020 at 1:50 PM Daniel P. Smith
<dpsmith@apertussolutions.com> wrote:
> It is not part of the EFI entry point as we are not entering the kernel
> from EFI but I will address that further in my response to Andy. The
> expectation is that if you are on an UEFI platform then EBS should have
> already been called.

Ok. In that case should the EFI boot stub optionally be calling this
instead of startup_32?

> With respect to using the firmware's TPM code, one
> of the purposes of a TCG Dynamic Launch is to remove the firmware from
> the code being trusted in making the integrity measurement of the
> kernel. I trust the firmware to initialize the hardware because I have
> to and it does give a trust chain, aka the SRTM, that can attest to what
> was used during that process. When the OS kernel is being started that
> trust chain has become weak (or even broken). I want a new trust chain
> that can provide better footing for asserting the integrity of the
> kernel and this is what Dynamic Launch gives us. I would like to think I
> did a fair job explaining this at LSS last fall[1][2] and would
> recommend those that are curious to review the slides/watch the
> presentation.

PCs depend on the availability of EFI runtime services - it's not
possible to just assert that they're untrusted and so unsupported. The
TPM code is part of boot services which (based on your design) are
unavailable at this point, so I agree that you need your own
implementation.

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support
  2020-03-26 20:40         ` Matthew Garrett
@ 2020-03-26 20:59           ` Daniel P. Smith
  2020-03-26 21:07           ` Andy Lutomirski
  1 sibling, 0 replies; 43+ messages in thread
From: Daniel P. Smith @ 2020-03-26 20:59 UTC (permalink / raw)
  To: Matthew Garrett, Andy Lutomirski
  Cc: Daniel Kiper, Ross Philipson, Linux Kernel Mailing List,
	the arch/x86 maintainers, linux-doc, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, H. Peter Anvin, trenchboot-devel,
	Ard Biesheuvel, leif, eric.snowberg, piotr.krol, krystian.hebel,
	michal.zygowski, James Bottomley, andrew.cooper3

On 3/26/20 4:40 PM, Matthew Garrett wrote:
> On Thu, Mar 26, 2020 at 1:33 PM Andy Lutomirski <luto@amacapital.net> wrote:
>> As a straw-man approach: make the rule that we never call EFI after secure launch. Instead we write out any firmware variables that we want to change on disk somewhere.  When we want to commit those changes, we reboot, commit the changes, and re-launch. Or we deactivate the kernel kexec-style, seal the image against PCRs, blow away PCRs, call EFI, relaunch, unseal the PCRs, and continue on our merry way.
> 
> That breaks the memory overwrite protection code, where a variable is
> set at boot and cleared on a controlled reboot. We'd also need to read
> every variable and pass those values to the kernel in some way so the
> read interfaces still work. Some platforms may also expect to be able
> to use the EFI reboot call. As for the second approach - how would we
> verify that the EFI code hadn't modified any user pages? Those
> wouldn't be measured during the second secure launch. If we're calling
> the code at runtime then I think we need to assert that it's trusted.
> 
>> I’m not sure how SMM fits in to this whole mess.
> 
> SMM's basically an unsolved problem, which makes the whole DRTM
> approach somewhat questionable unless you include the whole firmware
> in the TCB, which is kind of what we're trying to get away from.

Yes and no. First, if you have a TXT-aware STM, then its solved (as
solved as it can be). But if you are not that luck(?) it is still not
possible for SMM to disrupt the initial measurements and thus the load
time integrity but it can tamper with the runtime integrity of the
kernel. But again everyone has acknowledge that if SMM is owned its game
over regardless. If EFI is corrupted then launching with Dynamic Launch
and not using Runtime Services, you will not be exposed, i.e. we have
contained the corruption.

An open question I have is whether it might be possible to re-establish
the integrity of runtime services by using a dynamically launched kernel.


>> If we insist on allowing EFI calls and SMM, then we may be able to *measure* our exposure to potentially malicious firmware, but we can’t eliminate it. I personally trust OEM firmware about as far as I can throw it.



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support
  2020-03-26 20:40         ` Matthew Garrett
  2020-03-26 20:59           ` Daniel P. Smith
@ 2020-03-26 21:07           ` Andy Lutomirski
  2020-03-26 21:28             ` Matthew Garrett
  1 sibling, 1 reply; 43+ messages in thread
From: Andy Lutomirski @ 2020-03-26 21:07 UTC (permalink / raw)
  To: Matthew Garrett
  Cc: Daniel Kiper, Ross Philipson, Linux Kernel Mailing List,
	the arch/x86 maintainers, linux-doc, dpsmith, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, H. Peter Anvin, trenchboot-devel,
	Ard Biesheuvel, leif, eric.snowberg, piotr.krol, krystian.hebel,
	michal.zygowski, James Bottomley, andrew.cooper3



> On Mar 26, 2020, at 1:40 PM, Matthew Garrett <mjg59@google.com> wrote:
> 
> On Thu, Mar 26, 2020 at 1:33 PM Andy Lutomirski <luto@amacapital.net> wrote:
>> As a straw-man approach: make the rule that we never call EFI after secure launch. Instead we write out any firmware variables that we want to change on disk somewhere.  When we want to commit those changes, we reboot, commit the changes, and re-launch. Or we deactivate the kernel kexec-style, seal the image against PCRs, blow away PCRs, call EFI, relaunch, unseal the PCRs, and continue on our merry way.
> 
> That breaks the memory overwrite protection code, where a variable is
> set at boot and cleared on a controlled reboot.

Can you elaborate?  I’m not familiar with this.

> We'd also need to read
> every variable and pass those values to the kernel in some way so the
> read interfaces still work.

Indeed.

> Some platforms may also expect to be able
> to use the EFI reboot call.

Reboot is easy-ish: idle all APs, zero all but one page of text and the page tables, and call reboot. There aren’t any secrets that need to stay in memory when rebooting.


> As for the second approach - how would we
> verify that the EFI code hadn't modified any user pages? Those
> wouldn't be measured during the second secure launch. If we're calling
> the code at runtime then I think we need to assert that it's trusted.

Maybe you’re misunderstanding my suggestion.  I’m suggesting that we hibernate the whole running system to memory (more like kexec jump than hibernate) and authenticated-encrypt the whole thing (including user memory) with a PCR-sealed key. We jump to a stub that zaps PCRs does EFI calls. Then we re-launch and decrypt memory.

Kind of like S3 implementation wise too except with an encryption step.  And if we support secure launch and S3 together we probably have to implement this.

> 
>> I’m not sure how SMM fits in to this whole mess.
> 
> SMM's basically an unsolved problem, which makes the whole DRTM
> approach somewhat questionable unless you include the whole firmware
> in the TCB, which is kind of what we're trying to get away from.
> 
>> If we insist on allowing EFI calls and SMM, then we may be able to *measure* our exposure to potentially malicious firmware, but we can’t eliminate it. I personally trust OEM firmware about as far as I can throw it.

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support
  2020-03-26 21:07           ` Andy Lutomirski
@ 2020-03-26 21:28             ` Matthew Garrett
  2020-03-26 22:52               ` Andy Lutomirski
  0 siblings, 1 reply; 43+ messages in thread
From: Matthew Garrett @ 2020-03-26 21:28 UTC (permalink / raw)
  To: Andy Lutomirski
  Cc: Daniel Kiper, Ross Philipson, Linux Kernel Mailing List,
	the arch/x86 maintainers, linux-doc, Daniel P. Smith,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, H. Peter Anvin,
	trenchboot-devel, Ard Biesheuvel, leif, eric.snowberg,
	piotr.krol, krystian.hebel, michal.zygowski, James Bottomley,
	andrew.cooper3

On Thu, Mar 26, 2020 at 2:07 PM Andy Lutomirski <luto@amacapital.net> wrote:
> > On Mar 26, 2020, at 1:40 PM, Matthew Garrett <mjg59@google.com> wrote:
> >
> > On Thu, Mar 26, 2020 at 1:33 PM Andy Lutomirski <luto@amacapital.net> wrote:
> >> As a straw-man approach: make the rule that we never call EFI after secure launch. Instead we write out any firmware variables that we want to change on disk somewhere.  When we want to commit those changes, we reboot, commit the changes, and re-launch. Or we deactivate the kernel kexec-style, seal the image against PCRs, blow away PCRs, call EFI, relaunch, unseal the PCRs, and continue on our merry way.
> >
> > That breaks the memory overwrite protection code, where a variable is
> > set at boot and cleared on a controlled reboot.
>
> Can you elaborate?  I’m not familiar with this.

https://trustedcomputinggroup.org/wp-content/uploads/TCG_PlatformResetAttackMitigationSpecification_1.10_published.pdf
- you want to protect in-memory secrets from a physically present
attacker hitting the reset button, booting something else and just
dumping RAM. This is avoided by setting a variable at boot time (in
the boot stub), and then clearing it on reboot once the secrets have
been cleared from RAM. If the variable isn't cleared, the firmware
overwrites all RAM contents before booting anything else.

> > As for the second approach - how would we
> > verify that the EFI code hadn't modified any user pages? Those
> > wouldn't be measured during the second secure launch. If we're calling
> > the code at runtime then I think we need to assert that it's trusted.
>
> Maybe you’re misunderstanding my suggestion.  I’m suggesting that we hibernate the whole running system to memory (more like kexec jump than hibernate) and authenticated-encrypt the whole thing (including user memory) with a PCR-sealed key. We jump to a stub that zaps PCRs does EFI calls. Then we re-launch and decrypt memory.

When you say "re-launch", you mean perform a second secure launch? I
think that would work, as long as we could reconstruct an identical
state to ensure that the PCR17 values matched - and that seems like a
hard problem.

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support
  2020-03-26 20:54     ` Matthew Garrett
@ 2020-03-26 22:37       ` Daniel P. Smith
  2020-03-26 22:41         ` Matthew Garrett
  0 siblings, 1 reply; 43+ messages in thread
From: Daniel P. Smith @ 2020-03-26 22:37 UTC (permalink / raw)
  To: Matthew Garrett
  Cc: Ross Philipson, Linux Kernel Mailing List,
	the arch/x86 maintainers, linux-doc, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, H. Peter Anvin, trenchboot-devel

On 3/26/20 4:54 PM, Matthew Garrett wrote:
> On Thu, Mar 26, 2020 at 1:50 PM Daniel P. Smith
> <dpsmith@apertussolutions.com> wrote:
>> It is not part of the EFI entry point as we are not entering the kernel
>> from EFI but I will address that further in my response to Andy. The
>> expectation is that if you are on an UEFI platform then EBS should have
>> already been called.
> 
> Ok. In that case should the EFI boot stub optionally be calling this
> instead of startup_32?
> 
>> With respect to using the firmware's TPM code, one
>> of the purposes of a TCG Dynamic Launch is to remove the firmware from
>> the code being trusted in making the integrity measurement of the
>> kernel. I trust the firmware to initialize the hardware because I have
>> to and it does give a trust chain, aka the SRTM, that can attest to what
>> was used during that process. When the OS kernel is being started that
>> trust chain has become weak (or even broken). I want a new trust chain
>> that can provide better footing for asserting the integrity of the
>> kernel and this is what Dynamic Launch gives us. I would like to think I
>> did a fair job explaining this at LSS last fall[1][2] and would
>> recommend those that are curious to review the slides/watch the
>> presentation.
> 
> PCs depend on the availability of EFI runtime services - it's not
> possible to just assert that they're untrusted and so unsupported. The
> TPM code is part of boot services which (based on your design) are
> unavailable at this point, so I agree that you need your own
> implementation.
> 

I appreciate this has been a heated area of debate, but with all due
respect that might be a slight over statement w.r.t. dependency on
runtime services and not what I was saying about the trustworthiness of
UEFI. If I have a UEFI platform, I trust EFI to boot the system but that
does not mean I have to trust it to measure my OS kernel or manage the
running system. Secure Launch provides a means to start a measurement
trust chain starting with CPU taking the first measurement and then I
can do things like disabling runtime services in the kernel or do crazy
things like using the dynamic launch to switch to a minimal temporary
kernel that can do high trust operations such as interfacing with
entities outside your trust boundary, e.g. runtime services.

Please understand I really do not want my own implementation. I tried to
see if we could just #include in the minimal needed parts from the
in-tree TPM driver but could not find a clean way to do so. Perhaps
there might be a future opportunity to collaborate with the TPM driver
maintainers to refactor in a way that we can just reuse instead of
reimplement.


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support
  2020-03-26 22:37       ` Daniel P. Smith
@ 2020-03-26 22:41         ` Matthew Garrett
  2020-03-26 23:55           ` Daniel P. Smith
  0 siblings, 1 reply; 43+ messages in thread
From: Matthew Garrett @ 2020-03-26 22:41 UTC (permalink / raw)
  To: Daniel P. Smith
  Cc: Ross Philipson, Linux Kernel Mailing List,
	the arch/x86 maintainers, linux-doc, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, H. Peter Anvin, trenchboot-devel

On Thu, Mar 26, 2020 at 3:37 PM Daniel P. Smith
<dpsmith@apertussolutions.com> wrote:
> On 3/26/20 4:54 PM, Matthew Garrett wrote:
> > PCs depend on the availability of EFI runtime services - it's not
> > possible to just assert that they're untrusted and so unsupported. The
> > TPM code is part of boot services which (based on your design) are
> > unavailable at this point, so I agree that you need your own
> > implementation.
> >
>
> I appreciate this has been a heated area of debate, but with all due
> respect that might be a slight over statement w.r.t. dependency on
> runtime services and not what I was saying about the trustworthiness of
> UEFI. If I have a UEFI platform, I trust EFI to boot the system but that
> does not mean I have to trust it to measure my OS kernel or manage the
> running system. Secure Launch provides a means to start a measurement
> trust chain starting with CPU taking the first measurement and then I
> can do things like disabling runtime services in the kernel or do crazy
> things like using the dynamic launch to switch to a minimal temporary
> kernel that can do high trust operations such as interfacing with
> entities outside your trust boundary, e.g. runtime services.

I understand. However, it is *necessary* for EFI runtime services to
be available somehow, and this design needs to make that possible.
Either EFI runtime services need to be considered part of the TCB, or
we need a mechanism to re-verify the state of the system after making
an EFI call (such as Andy's suggestion).

> Please understand I really do not want my own implementation. I tried to
> see if we could just #include in the minimal needed parts from the
> in-tree TPM driver but could not find a clean way to do so. Perhaps
> there might be a future opportunity to collaborate with the TPM driver
> maintainers to refactor in a way that we can just reuse instead of
> reimplement.

I think it's reasonable to assert that boot services can't be part of
the TCB in this case, and as a result you're justified in not using
the firmware's TPM implementation. However, we still need a solution
for access to runtime services.

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [RFC PATCH 03/12] x86: Add early SHA support for Secure Launch early measurements
  2020-03-26  3:44   ` Andy Lutomirski
@ 2020-03-26 22:49     ` Daniel P. Smith
  0 siblings, 0 replies; 43+ messages in thread
From: Daniel P. Smith @ 2020-03-26 22:49 UTC (permalink / raw)
  To: Andy Lutomirski, Ross Philipson
  Cc: LKML, X86 ML, open list:DOCUMENTATION, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, H. Peter Anvin, trenchboot-devel

On 3/25/20 11:44 PM, Andy Lutomirski wrote:
> On Wed, Mar 25, 2020 at 12:43 PM Ross Philipson
> <ross.philipson@oracle.com> wrote:
>>
>> From: "Daniel P. Smith" <dpsmith@apertussolutions.com>
>>
>> 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 SHA1 code here has its origins in the code in
>> include/crypto/sha1_base.h. That code could not be pulled directly into
>> the setup portion of the compressed kernel because of other dependencies
>> it pulls in. So this is a modified copy of that code that still leverages
>> the core SHA1 algorithm.
>>
>> Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com>
>> ---
>>  arch/x86/Kconfig                        |  24 +++
>>  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 ++++++++++++++++++++++++
>>  9 files changed, 395 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/Kconfig b/arch/x86/Kconfig
>> index 7f3406a9948b..f37057d3ce9f 100644
>> --- a/arch/x86/Kconfig
>> +++ b/arch/x86/Kconfig
>> @@ -2025,6 +2025,30 @@ config SECURE_LAUNCH
>>           of all the modules and configuration information used for
>>           boooting the operating system.
>>
>> +choice
>> +       prompt "Select Secure Launch Algorithm for TPM2"
>> +       depends on SECURE_LAUNCH
>> +
>> +config SECURE_LAUNCH_SHA1
>> +       bool "Secure Launch TPM2 SHA1"
>> +       help
>> +         When using Secure Launch and TPM2 is present, use SHA1 hash
>> +         algorithm for measurements.
>> +
> 
> I'm surprised this is supported at all.  Why allow SHA1?
> 

The SHA1 code is already there for TPM1.2 and it is a valid supported
mode for TPM2 therefore we made it available. We could add a big glaring
warning that SHA1 is broken and should not be used unless you have a
very specific reason.


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support
  2020-03-26 21:28             ` Matthew Garrett
@ 2020-03-26 22:52               ` Andy Lutomirski
  2020-03-26 22:59                 ` Matthew Garrett
  2020-03-26 23:50                 ` Daniel P. Smith
  0 siblings, 2 replies; 43+ messages in thread
From: Andy Lutomirski @ 2020-03-26 22:52 UTC (permalink / raw)
  To: Matthew Garrett
  Cc: Daniel Kiper, Ross Philipson, Linux Kernel Mailing List,
	the arch/x86 maintainers, open list:DOCUMENTATION,
	Daniel P. Smith, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	H. Peter Anvin, trenchboot-devel, Ard Biesheuvel, leif,
	eric.snowberg, piotr.krol, krystian.hebel, michal.zygowski,
	James Bottomley, Andrew Cooper

On Thu, Mar 26, 2020 at 2:28 PM Matthew Garrett <mjg59@google.com> wrote:
>
> On Thu, Mar 26, 2020 at 2:07 PM Andy Lutomirski <luto@amacapital.net> wrote:
> > > On Mar 26, 2020, at 1:40 PM, Matthew Garrett <mjg59@google.com> wrote:
> > >
> > > On Thu, Mar 26, 2020 at 1:33 PM Andy Lutomirski <luto@amacapital.net> wrote:
> > >> As a straw-man approach: make the rule that we never call EFI after secure launch. Instead we write out any firmware variables that we want to change on disk somewhere.  When we want to commit those changes, we reboot, commit the changes, and re-launch. Or we deactivate the kernel kexec-style, seal the image against PCRs, blow away PCRs, call EFI, relaunch, unseal the PCRs, and continue on our merry way.
> > >
> > > That breaks the memory overwrite protection code, where a variable is
> > > set at boot and cleared on a controlled reboot.
> >
> > Can you elaborate?  I’m not familiar with this.
>
> https://trustedcomputinggroup.org/wp-content/uploads/TCG_PlatformResetAttackMitigationSpecification_1.10_published.pdf
> - you want to protect in-memory secrets from a physically present
> attacker hitting the reset button, booting something else and just
> dumping RAM. This is avoided by setting a variable at boot time (in
> the boot stub), and then clearing it on reboot once the secrets have
> been cleared from RAM. If the variable isn't cleared, the firmware
> overwrites all RAM contents before booting anything else.

I admit my information is rather dated, but I'm pretty sure that at
least some and possibly all TXT implementations solve this more
directly.  In particular, as I understand it, when you TXT-launch
anything, a nonvolatile flag in the chipset is set.  On reboot, the
chipset will not allow access to memory *at all* until an
authenticated code module wipes memory and clears that flag.

If your computer advertises TXT support but is missing that ACM, you
are SOL.  I learned about this when I bricked my old Lenovo laptop. As
far as I can tell, the flag was set, but the Lenovo BIOS didn't know
how to wipe memory.  Whoops!

>
> > > As for the second approach - how would we
> > > verify that the EFI code hadn't modified any user pages? Those
> > > wouldn't be measured during the second secure launch. If we're calling
> > > the code at runtime then I think we need to assert that it's trusted.
> >
> > Maybe you’re misunderstanding my suggestion.  I’m suggesting that we hibernate the whole running system to memory (more like kexec jump than hibernate) and authenticated-encrypt the whole thing (including user memory) with a PCR-sealed key. We jump to a stub that zaps PCRs does EFI calls. Then we re-launch and decrypt memory.
>
> When you say "re-launch", you mean perform a second secure launch? I
> think that would work, as long as we could reconstruct an identical
> state to ensure that the PCR17 values matched - and that seems like a
> hard problem.

Exactly.  I would hope that performing a second secure launch would
reproduce the same post-launch PCRs as the first launch.  If the
kernel were wise enough to record all PCR extensions, it could replay
them.

(I can imagine an alternate universe in which the PCR extension used a
more clever algorithm that allowed log-time fast forwarding.  As far
as I know, this is not currently the case.)

In any case, I'm kind of with Daniel here.  We survived for quite a
long time without EFI variables at all.  The ability to write them is
nice, and we certainly need some way, however awkward, to write them
on rare occasions, but I don't think we really need painless runtime
writes to EFI variables.

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support
  2020-03-26 22:52               ` Andy Lutomirski
@ 2020-03-26 22:59                 ` Matthew Garrett
  2020-03-26 23:04                   ` Andy Lutomirski
  2020-03-26 23:50                 ` Daniel P. Smith
  1 sibling, 1 reply; 43+ messages in thread
From: Matthew Garrett @ 2020-03-26 22:59 UTC (permalink / raw)
  To: Andy Lutomirski
  Cc: Daniel Kiper, Ross Philipson, Linux Kernel Mailing List,
	the arch/x86 maintainers, open list:DOCUMENTATION,
	Daniel P. Smith, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	H. Peter Anvin, trenchboot-devel, Ard Biesheuvel, leif,
	eric.snowberg, piotr.krol, krystian.hebel, michal.zygowski,
	James Bottomley, Andrew Cooper

On Thu, Mar 26, 2020 at 3:52 PM Andy Lutomirski <luto@kernel.org> wrote:
>
> On Thu, Mar 26, 2020 at 2:28 PM Matthew Garrett <mjg59@google.com> wrote:
> > https://trustedcomputinggroup.org/wp-content/uploads/TCG_PlatformResetAttackMitigationSpecification_1.10_published.pdf
> > - you want to protect in-memory secrets from a physically present
> > attacker hitting the reset button, booting something else and just
> > dumping RAM. This is avoided by setting a variable at boot time (in
> > the boot stub), and then clearing it on reboot once the secrets have
> > been cleared from RAM. If the variable isn't cleared, the firmware
> > overwrites all RAM contents before booting anything else.
>
> I admit my information is rather dated, but I'm pretty sure that at
> least some and possibly all TXT implementations solve this more
> directly.  In particular, as I understand it, when you TXT-launch
> anything, a nonvolatile flag in the chipset is set.  On reboot, the
> chipset will not allow access to memory *at all* until an
> authenticated code module wipes memory and clears that flag.

Mm, yes, this one might be something we can just ignore in the TXT case.

> > When you say "re-launch", you mean perform a second secure launch? I
> > think that would work, as long as we could reconstruct an identical
> > state to ensure that the PCR17 values matched - and that seems like a
> > hard problem.
>
> Exactly.  I would hope that performing a second secure launch would
> reproduce the same post-launch PCRs as the first launch.  If the
> kernel were wise enough to record all PCR extensions, it could replay
> them.

That presumably depends on how much state is in the measured region -
we can't just measure the code in order to assert that we're secure.

> In any case, I'm kind of with Daniel here.  We survived for quite a
> long time without EFI variables at all.  The ability to write them is
> nice, and we certainly need some way, however awkward, to write them
> on rare occasions, but I don't think we really need painless runtime
> writes to EFI variables.

I'm fine with a solution that involves jumping through some hoops, but
it feels like simply supporting measuring and passing through the
runtime services would be fine - if you want to keep them outside the
TCB, build a kernel that doesn't have EFI runtime service support and
skip that measurement?

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support
  2020-03-26 22:59                 ` Matthew Garrett
@ 2020-03-26 23:04                   ` Andy Lutomirski
  2020-03-27  0:01                     ` Daniel P. Smith
  0 siblings, 1 reply; 43+ messages in thread
From: Andy Lutomirski @ 2020-03-26 23:04 UTC (permalink / raw)
  To: Matthew Garrett
  Cc: Andy Lutomirski, Daniel Kiper, Ross Philipson,
	Linux Kernel Mailing List, the arch/x86 maintainers,
	open list:DOCUMENTATION, Daniel P. Smith, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, H. Peter Anvin, trenchboot-devel,
	Ard Biesheuvel, leif, eric.snowberg, piotr.krol, krystian.hebel,
	michal.zygowski, James Bottomley, Andrew Cooper

On Thu, Mar 26, 2020 at 4:00 PM Matthew Garrett <mjg59@google.com> wrote:
>
> On Thu, Mar 26, 2020 at 3:52 PM Andy Lutomirski <luto@kernel.org> wrote:
> >
> > On Thu, Mar 26, 2020 at 2:28 PM Matthew Garrett <mjg59@google.com> wrote:
> > > https://trustedcomputinggroup.org/wp-content/uploads/TCG_PlatformResetAttackMitigationSpecification_1.10_published.pdf
> > > - you want to protect in-memory secrets from a physically present
> > > attacker hitting the reset button, booting something else and just
> > > dumping RAM. This is avoided by setting a variable at boot time (in
> > > the boot stub), and then clearing it on reboot once the secrets have
> > > been cleared from RAM. If the variable isn't cleared, the firmware
> > > overwrites all RAM contents before booting anything else.
> >
> > I admit my information is rather dated, but I'm pretty sure that at
> > least some and possibly all TXT implementations solve this more
> > directly.  In particular, as I understand it, when you TXT-launch
> > anything, a nonvolatile flag in the chipset is set.  On reboot, the
> > chipset will not allow access to memory *at all* until an
> > authenticated code module wipes memory and clears that flag.
>
> Mm, yes, this one might be something we can just ignore in the TXT case.
>
> > > When you say "re-launch", you mean perform a second secure launch? I
> > > think that would work, as long as we could reconstruct an identical
> > > state to ensure that the PCR17 values matched - and that seems like a
> > > hard problem.
> >
> > Exactly.  I would hope that performing a second secure launch would
> > reproduce the same post-launch PCRs as the first launch.  If the
> > kernel were wise enough to record all PCR extensions, it could replay
> > them.
>
> That presumably depends on how much state is in the measured region -
> we can't just measure the code in order to assert that we're secure.
>
> > In any case, I'm kind of with Daniel here.  We survived for quite a
> > long time without EFI variables at all.  The ability to write them is
> > nice, and we certainly need some way, however awkward, to write them
> > on rare occasions, but I don't think we really need painless runtime
> > writes to EFI variables.
>
> I'm fine with a solution that involves jumping through some hoops, but
> it feels like simply supporting measuring and passing through the
> runtime services would be fine - if you want to keep them outside the
> TCB, build a kernel that doesn't have EFI runtime service support and
> skip that measurement?

I'm certainly fine with the kernel allowing a mode like this.  At the
end of the day, anyone building something based on secure launch
should know what they're doing.

On the other hand, unless I've missed something, we need to support a
transition from "secure" measured mode to unmeasured and back if we're
going to support secure launch and S3 at the same time. But maybe S3
is on its way out in favor of suspend-to-idle?

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support
  2020-03-26 20:50     ` Daniel P. Smith
@ 2020-03-26 23:13       ` Andy Lutomirski
  2020-05-11 19:00         ` Daniel P. Smith
  0 siblings, 1 reply; 43+ messages in thread
From: Andy Lutomirski @ 2020-03-26 23:13 UTC (permalink / raw)
  To: Daniel P. Smith
  Cc: Andy Lutomirski, Matthew Garrett, Ross Philipson,
	Linux Kernel Mailing List, the arch/x86 maintainers,
	open list:DOCUMENTATION, Thomas Gleixner, Ingo Molnar,
	Borislav Petkov, H. Peter Anvin, trenchboot-devel

On Thu, Mar 26, 2020 at 1:51 PM Daniel P. Smith
<dpsmith@apertussolutions.com> wrote:
>
> On 3/25/20 6:51 PM, Andy Lutomirski wrote:
> > On Wed, Mar 25, 2020 at 1:29 PM Matthew Garrett <mjg59@google.com> wrote:
> >>
> >> On Wed, Mar 25, 2020 at 12:43 PM Ross Philipson
> >> <ross.philipson@oracle.com> wrote:
> >>> To enable the kernel to be launched by GETSEC or SKINIT, a stub must be
> >>> built into the setup section of the compressed kernel to handle the
> >>> specific state that the late launch process leaves the BSP. This is a
> >>> lot like the EFI stub that is found in the same area. Also this stub
> >>> must measure everything that is going to be used as early as possible.
> >>> This stub code and subsequent code must also deal with the specific
> >>> state that the late launch leaves the APs in.
> >>
> >> How does this integrate with the EFI entry point? That's the expected
> >> entry point on most modern x86. What's calling ExitBootServices() in
> >> this flow, and does the secure launch have to occur after it? It'd be
> >> a lot easier if you could still use the firmware's TPM code rather
> >> than carrying yet another copy.
> >
> > I was wondering why the bootloader was involved at all.  In other
> > words, could you instead hand off control to the kernel just like
> > normal and have the kernel itself (in normal code, the EFI stub, or
> > wherever it makes sense) do the DRTM launch all by itself?  This would
> > avoid needing to patch bootloaders, to implement this specially for
> > QEMU -kernel, to get the exact right buy-in from all the cloud
> > vendors, etc.  It would also give you more flexibility to evolve
> > exactly what configuration maps to exactly what PCRs in the future.
> >
>
> Partly this is driven by the fact that one of the goals for the
> TrenchBoot project is about more universal/unified, cross open source
> project adoption of Dynamic Launch. Another aspect is that initiating a
> Dynamic Launch requires additional file(s) to be loaded, the platform to
> be put into a quiescent state, and the invocation of the SENTER/SKINIT
> instruction can be thought of as a soft reset of the CPU that on Intel
> even results in the CPU being in a different mode (SMX) which has a
> subtle change to its behavior. In the TCG Dynamic Launch design, the
> component responsible for this loading, preparing, and Dynamic Launch
> Instruction invocation is referred to as the Preamble and IMHO the best
> time for dealing with such a disruptive behavior caused by invoking the
> instruction is at the boot boundary. It also makes for a good transition
> point to enable switching between kernels in control of the system
> whereby the integrity will be establish by the hardware instead of the
> kernel (UEFI, GRUB, Linux, etc.) that loaded it. I think what helps
> address your concern is that one of the next items on the roadmap is to
> extend kexec to be able to perform the Preamble. As I just mentioned,
> this provides a clean way to transition for one Linux kernel that may or
> may not have been started via a Dynamic Launch could relaunch itself,
> launch a new Linux kernel, or even launch a non-Linux kernel that is
> Dynamic Launch aware.
>

Hmm.  I don't have any real objection to the kernel supporting this
type of secure launch, but I do have some more questions first.

One of the problems with the old tboot code and the general state of
dynamic-root-of-trust is that it's an incredible pain in the neck to
even test.  I think it would be helpful if I could build a kernel that
supported secure launch (Intel or AMD) and just run the thing.  I
realize that you're planning to integrate this into GRUB, etc, but it
might be nice if even existing GRUB and EFI shell can do this.  How
hard would it be to make the kernel support a mode where whatever
blobs are required are in the initrd or built in like firmware and
where I could set a command line argument like secure_launch=on and
have the kernel secure launch itself?

Are you planning on supporting a mode where kernel A kexecs to kernel
B, kernel B is secure launched, and then kernel B resumes kernel A and
re-launches it?  If so, would it work better if the measured state of
the kernel were the *uncompressed* text or even the uncompressed and
alternative-ified text?  Or is the idea that the secure launch entry
will figure out that it's actually a resume and not a fresh boot and
behave accordingly?

What's the situation like in a VM?  Can I run the secure launch entry
in a VM somehow?  Can I actually initiate the dynamic launch from the
VM?

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support
  2020-03-26 22:52               ` Andy Lutomirski
  2020-03-26 22:59                 ` Matthew Garrett
@ 2020-03-26 23:50                 ` Daniel P. Smith
  1 sibling, 0 replies; 43+ messages in thread
From: Daniel P. Smith @ 2020-03-26 23:50 UTC (permalink / raw)
  To: Andy Lutomirski, Matthew Garrett
  Cc: Daniel Kiper, Ross Philipson, Linux Kernel Mailing List,
	the arch/x86 maintainers, open list:DOCUMENTATION,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, H. Peter Anvin,
	trenchboot-devel, Ard Biesheuvel, leif, eric.snowberg,
	piotr.krol, krystian.hebel, michal.zygowski, James Bottomley,
	Andrew Cooper

On 3/26/20 6:52 PM, Andy Lutomirski wrote:
> On Thu, Mar 26, 2020 at 2:28 PM Matthew Garrett <mjg59@google.com> wrote:
>>
>> On Thu, Mar 26, 2020 at 2:07 PM Andy Lutomirski <luto@amacapital.net> wrote:
>>>> On Mar 26, 2020, at 1:40 PM, Matthew Garrett <mjg59@google.com> wrote:
>>>>
>>>> On Thu, Mar 26, 2020 at 1:33 PM Andy Lutomirski <luto@amacapital.net> wrote:
>>>>> As a straw-man approach: make the rule that we never call EFI after secure launch. Instead we write out any firmware variables that we want to change on disk somewhere.  When we want to commit those changes, we reboot, commit the changes, and re-launch. Or we deactivate the kernel kexec-style, seal the image against PCRs, blow away PCRs, call EFI, relaunch, unseal the PCRs, and continue on our merry way.
>>>>
>>>> That breaks the memory overwrite protection code, where a variable is
>>>> set at boot and cleared on a controlled reboot.
>>>
>>> Can you elaborate?  I’m not familiar with this.
>>
>> https://trustedcomputinggroup.org/wp-content/uploads/TCG_PlatformResetAttackMitigationSpecification_1.10_published.pdf
>> - you want to protect in-memory secrets from a physically present
>> attacker hitting the reset button, booting something else and just
>> dumping RAM. This is avoided by setting a variable at boot time (in
>> the boot stub), and then clearing it on reboot once the secrets have
>> been cleared from RAM. If the variable isn't cleared, the firmware
>> overwrites all RAM contents before booting anything else.
> 
> I admit my information is rather dated, but I'm pretty sure that at
> least some and possibly all TXT implementations solve this more
> directly.  In particular, as I understand it, when you TXT-launch
> anything, a nonvolatile flag in the chipset is set.  On reboot, the
> chipset will not allow access to memory *at all* until an
> authenticated code module wipes memory and clears that flag.
> 
> If your computer advertises TXT support but is missing that ACM, you
> are SOL.  I learned about this when I bricked my old Lenovo laptop. As
> far as I can tell, the flag was set, but the Lenovo BIOS didn't know
> how to wipe memory.  Whoops!
> 

You are correct, there is the SECRETS flag. If it set during DL then
when the system comes back around to the BIOS ACM and it finds the flag
set it, it will take action. The exact details are locked up under NDA
but you could take a look at the recent work in coreboot to add TXT
support to see how they handled it.

>>
>>>> As for the second approach - how would we
>>>> verify that the EFI code hadn't modified any user pages? Those
>>>> wouldn't be measured during the second secure launch. If we're calling
>>>> the code at runtime then I think we need to assert that it's trusted.
>>>
>>> Maybe you’re misunderstanding my suggestion.  I’m suggesting that we hibernate the whole running system to memory (more like kexec jump than hibernate) and authenticated-encrypt the whole thing (including user memory) with a PCR-sealed key. We jump to a stub that zaps PCRs does EFI calls. Then we re-launch and decrypt memory.
>>
>> When you say "re-launch", you mean perform a second secure launch? I
>> think that would work, as long as we could reconstruct an identical
>> state to ensure that the PCR17 values matched - and that seems like a
>> hard problem.
> 
> Exactly.  I would hope that performing a second secure launch would
> reproduce the same post-launch PCRs as the first launch.  If the
> kernel were wise enough to record all PCR extensions, it could replay
> them.
> 
> (I can imagine an alternate universe in which the PCR extension used a
> more clever algorithm that allowed log-time fast forwarding.  As far
> as I know, this is not currently the case.)
> 
> In any case, I'm kind of with Daniel here.  We survived for quite a
> long time without EFI variables at all.  The ability to write them is
> nice, and we certainly need some way, however awkward, to write them
> on rare occasions, but I don't think we really need painless runtime
> writes to EFI variables.
> 



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support
  2020-03-26 22:41         ` Matthew Garrett
@ 2020-03-26 23:55           ` Daniel P. Smith
  0 siblings, 0 replies; 43+ messages in thread
From: Daniel P. Smith @ 2020-03-26 23:55 UTC (permalink / raw)
  To: Matthew Garrett
  Cc: Ross Philipson, Linux Kernel Mailing List,
	the arch/x86 maintainers, linux-doc, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, H. Peter Anvin, trenchboot-devel

On 3/26/20 6:41 PM, Matthew Garrett wrote:
> On Thu, Mar 26, 2020 at 3:37 PM Daniel P. Smith
> <dpsmith@apertussolutions.com> wrote:
>> On 3/26/20 4:54 PM, Matthew Garrett wrote:
>>> PCs depend on the availability of EFI runtime services - it's not
>>> possible to just assert that they're untrusted and so unsupported. The
>>> TPM code is part of boot services which (based on your design) are
>>> unavailable at this point, so I agree that you need your own
>>> implementation.
>>>
>>
>> I appreciate this has been a heated area of debate, but with all due
>> respect that might be a slight over statement w.r.t. dependency on
>> runtime services and not what I was saying about the trustworthiness of
>> UEFI. If I have a UEFI platform, I trust EFI to boot the system but that
>> does not mean I have to trust it to measure my OS kernel or manage the
>> running system. Secure Launch provides a means to start a measurement
>> trust chain starting with CPU taking the first measurement and then I
>> can do things like disabling runtime services in the kernel or do crazy
>> things like using the dynamic launch to switch to a minimal temporary
>> kernel that can do high trust operations such as interfacing with
>> entities outside your trust boundary, e.g. runtime services.
> 
> I understand. However, it is *necessary* for EFI runtime services to
> be available somehow, and this design needs to make that possible.
> Either EFI runtime services need to be considered part of the TCB, or
> we need a mechanism to re-verify the state of the system after making
> an EFI call (such as Andy's suggestion).
> 

Yes if you are on UEFI you will eventually need to deal with RS during
the system's lifetime, unless you don't want to patch your firmware
which I won't comment on what kind of idea that is. And yes I have been
chatting with a few people in the LinuxBoot community about re-verifying
the RS. The answer seemed to be that it might be possible but it doesn't
look like it will be trivial.

>> Please understand I really do not want my own implementation. I tried to
>> see if we could just #include in the minimal needed parts from the
>> in-tree TPM driver but could not find a clean way to do so. Perhaps
>> there might be a future opportunity to collaborate with the TPM driver
>> maintainers to refactor in a way that we can just reuse instead of
>> reimplement.
> 
> I think it's reasonable to assert that boot services can't be part of
> the TCB in this case, and as a result you're justified in not using
> the firmware's TPM implementation. However, we still need a solution
> for access to runtime services.
> 


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support
  2020-03-26 23:04                   ` Andy Lutomirski
@ 2020-03-27  0:01                     ` Daniel P. Smith
  0 siblings, 0 replies; 43+ messages in thread
From: Daniel P. Smith @ 2020-03-27  0:01 UTC (permalink / raw)
  To: Andy Lutomirski, Matthew Garrett
  Cc: Daniel Kiper, Ross Philipson, Linux Kernel Mailing List,
	the arch/x86 maintainers, open list:DOCUMENTATION,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, H. Peter Anvin,
	trenchboot-devel, Ard Biesheuvel, leif, eric.snowberg,
	piotr.krol, krystian.hebel, michal.zygowski, James Bottomley,
	Andrew Cooper

On 3/26/20 7:04 PM, Andy Lutomirski wrote:
> On Thu, Mar 26, 2020 at 4:00 PM Matthew Garrett <mjg59@google.com> wrote:
>>
>> On Thu, Mar 26, 2020 at 3:52 PM Andy Lutomirski <luto@kernel.org> wrote:
>>>
>>> On Thu, Mar 26, 2020 at 2:28 PM Matthew Garrett <mjg59@google.com> wrote:
>>>> https://trustedcomputinggroup.org/wp-content/uploads/TCG_PlatformResetAttackMitigationSpecification_1.10_published.pdf
>>>> - you want to protect in-memory secrets from a physically present
>>>> attacker hitting the reset button, booting something else and just
>>>> dumping RAM. This is avoided by setting a variable at boot time (in
>>>> the boot stub), and then clearing it on reboot once the secrets have
>>>> been cleared from RAM. If the variable isn't cleared, the firmware
>>>> overwrites all RAM contents before booting anything else.
>>>
>>> I admit my information is rather dated, but I'm pretty sure that at
>>> least some and possibly all TXT implementations solve this more
>>> directly.  In particular, as I understand it, when you TXT-launch
>>> anything, a nonvolatile flag in the chipset is set.  On reboot, the
>>> chipset will not allow access to memory *at all* until an
>>> authenticated code module wipes memory and clears that flag.
>>
>> Mm, yes, this one might be something we can just ignore in the TXT case.
>>
>>>> When you say "re-launch", you mean perform a second secure launch? I
>>>> think that would work, as long as we could reconstruct an identical
>>>> state to ensure that the PCR17 values matched - and that seems like a
>>>> hard problem.
>>>
>>> Exactly.  I would hope that performing a second secure launch would
>>> reproduce the same post-launch PCRs as the first launch.  If the
>>> kernel were wise enough to record all PCR extensions, it could replay
>>> them.
>>
>> That presumably depends on how much state is in the measured region -
>> we can't just measure the code in order to assert that we're secure.
>>
>>> In any case, I'm kind of with Daniel here.  We survived for quite a
>>> long time without EFI variables at all.  The ability to write them is
>>> nice, and we certainly need some way, however awkward, to write them
>>> on rare occasions, but I don't think we really need painless runtime
>>> writes to EFI variables.
>>
>> I'm fine with a solution that involves jumping through some hoops, but
>> it feels like simply supporting measuring and passing through the
>> runtime services would be fine - if you want to keep them outside the
>> TCB, build a kernel that doesn't have EFI runtime service support and
>> skip that measurement?
> 
> I'm certainly fine with the kernel allowing a mode like this.  At the
> end of the day, anyone building something based on secure launch
> should know what they're doing.
> 
> On the other hand, unless I've missed something, we need to support a
> transition from "secure" measured mode to unmeasured and back if we're
> going to support secure launch and S3 at the same time. But maybe S3
> is on its way out in favor of suspend-to-idle?
> 

I didn't comment earlier on S3 and my view is that it is horrible when
trying to deal with it from a security perspective. As a result I have
been driven to the belief that you cannot assume your security posture
is the same after S3 as it was before or that you even know what your
posture is. On Intel we have the SEXIT instruction to signal that we are
no longer in SMX which, in theory, blocks modification of DRTM PCRs.
Thus SEXIT should be called before S3 and then when you come back one
needs to then re-launch to get back to a known state of integrity.


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support
  2020-03-26 23:13       ` Andy Lutomirski
@ 2020-05-11 19:00         ` Daniel P. Smith
  0 siblings, 0 replies; 43+ messages in thread
From: Daniel P. Smith @ 2020-05-11 19:00 UTC (permalink / raw)
  To: Andy Lutomirski
  Cc: Matthew Garrett, Ross Philipson, Linux Kernel Mailing List,
	the arch/x86 maintainers, open list:DOCUMENTATION,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, H. Peter Anvin,
	trenchboot-devel

On 3/26/20 7:13 PM, Andy Lutomirski wrote:
> 
> Hmm.  I don't have any real objection to the kernel supporting this
> type of secure launch, but I do have some more questions first.

Coming back through the thread to ensure all questions have been
responded before a submission patch set is sent.

> One of the problems with the old tboot code and the general state of
> dynamic-root-of-trust is that it's an incredible pain in the neck to
> even test.  I think it would be helpful if I could build a kernel that
> supported secure launch (Intel or AMD) and just run the thing.  I
> realize that you're planning to integrate this into GRUB, etc, but it
> might be nice if even existing GRUB and EFI shell can do this.  How
> hard would it be to make the kernel support a mode where whatever
> blobs are required are in the initrd or built in like firmware and
> where I could set a command line argument like secure_launch=on and
> have the kernel secure launch itself?
> 
> Are you planning on supporting a mode where kernel A kexecs to kernel
> B, kernel B is secure launched, and then kernel B resumes kernel A and
> re-launches it?  If so, would it work better if the measured state of
> the kernel were the *uncompressed* text or even the uncompressed and
> alternative-ified text?  Or is the idea that the secure launch entry
> will figure out that it's actually a resume and not a fresh boot and
> behave accordingly?

A primary purpose of the TrenchBoot project is to make using DRTM
seamless for people, e.g. a few config settings and it just works(tm).
To achieve what you are proposing, the kernel would have to know how to
do both the DL preamble (pre-launch in tboot) and DL entry (post-launch
in tboot). The short answer is we are working towards that capability.
First is the ability to handle the DL entry, which is SecureLaunch. For
now we are clearing the SECRETS bit and doing the SEXIT leaf on kexec
and S5 to minimize the risk of bricking your system with TXT. Later the
DL preamble can be added to kexec such that the user space can
coordinate a DRTM launch. Not sure if this is exactly what you are
envisioning but albeit at least a close approximation.


> What's the situation like in a VM?  Can I run the secure launch entry
> in a VM somehow?  Can I actually initiate the dynamic launch from the
> VM?

A DL entails calling a CPU instruction which take over full control of
the system. If a hypervisor blindly allowed a VM to directly call the
op, it would end up with full control of the system outside of the
hypervisor. With that said, An approach on the roadmap for TrenchBoot is
how a hypervisor and a VM might coordinate the use of a DL to establish
a new measurement chain consisting of runtime inspection of the
hypervisor which in-turn has a means to establish the integrity of the VM.

V/r,
DPS


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support
  2020-03-26 20:19     ` Matthew Garrett
  2020-03-26 20:33       ` Andy Lutomirski
@ 2020-05-11 19:00       ` Daniel P. Smith
  1 sibling, 0 replies; 43+ messages in thread
From: Daniel P. Smith @ 2020-05-11 19:00 UTC (permalink / raw)
  To: Matthew Garrett, Daniel Kiper
  Cc: Ross Philipson, Linux Kernel Mailing List,
	the arch/x86 maintainers, linux-doc, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, H. Peter Anvin, trenchboot-devel,
	Ard Biesheuvel, leif, eric.snowberg, piotr.krol, krystian.hebel,
	michal.zygowski, James Bottomley, andrew.cooper3

On 3/26/20 4:19 PM, Matthew Garrett wrote:
> How does Windows manage this? Retaining access to EFI runtime services
> is necessary, and the areas in the memory map marked as runtime
> services code or data should be considered part of the TCB and
> measured - they're very much not part of the gap.
> 

Dave Weston was kind enough to speak at PSEC specifically on how they
are leveraging DRTM.

https://www.platformsecuritysummit.com/2019/speaker/weston/

V/r,
DPS


^ permalink raw reply	[flat|nested] 43+ messages in thread

end of thread, other threads:[~2020-05-11 19:01 UTC | newest]

Thread overview: 43+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-03-25 19:43 [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support Ross Philipson
2020-03-25 19:43 ` [RFC PATCH 01/12] x86: Secure Launch Kconfig Ross Philipson
2020-03-26 18:06   ` Daniel Kiper
2020-03-26 19:42     ` Ross Philipson
2020-03-25 19:43 ` [RFC PATCH 02/12] x86: Secure Launch main header file Ross Philipson
2020-03-26 19:00   ` Daniel Kiper
2020-03-25 19:43 ` [RFC PATCH 03/12] x86: Add early SHA support for Secure Launch early measurements Ross Philipson
2020-03-26  3:44   ` Andy Lutomirski
2020-03-26 22:49     ` Daniel P. Smith
2020-03-25 19:43 ` [RFC PATCH 04/12] x86: Add early TPM TIS/CRB interface support for Secure Launch Ross Philipson
2020-03-25 19:43 ` [RFC PATCH 05/12] x86: Add early TPM1.2/TPM2.0 " Ross Philipson
2020-03-25 19:43 ` [RFC PATCH 06/12] x86: Add early general TPM " Ross Philipson
2020-03-25 19:43 ` [RFC PATCH 07/12] x86: Secure Launch kernel early boot stub Ross Philipson
2020-03-25 19:43 ` [RFC PATCH 08/12] x86: Secure Launch kernel late " Ross Philipson
2020-03-25 19:43 ` [RFC PATCH 09/12] x86: Secure Launch SMP bringup support Ross Philipson
2020-03-25 19:43 ` [RFC PATCH 10/12] x86: Secure Launch adding event log securityfs Ross Philipson
2020-03-25 20:21   ` Matthew Garrett
2020-03-25 21:43     ` Daniel P. Smith
2020-03-25 19:43 ` [RFC PATCH 11/12] kexec: Secure Launch kexec SEXIT support Ross Philipson
2020-03-25 19:43 ` [RFC PATCH 12/12] tpm: Allow locality 2 to be set when initializing the TPM for Secure Launch Ross Philipson
2020-03-25 20:29 ` [RFC PATCH 00/12] x86: Trenchboot secure late launch Linux kernel support Matthew Garrett
2020-03-25 22:51   ` Andy Lutomirski
2020-03-26 20:50     ` Daniel P. Smith
2020-03-26 23:13       ` Andy Lutomirski
2020-05-11 19:00         ` Daniel P. Smith
2020-03-26 13:40   ` Daniel Kiper
2020-03-26 20:19     ` Matthew Garrett
2020-03-26 20:33       ` Andy Lutomirski
2020-03-26 20:40         ` Matthew Garrett
2020-03-26 20:59           ` Daniel P. Smith
2020-03-26 21:07           ` Andy Lutomirski
2020-03-26 21:28             ` Matthew Garrett
2020-03-26 22:52               ` Andy Lutomirski
2020-03-26 22:59                 ` Matthew Garrett
2020-03-26 23:04                   ` Andy Lutomirski
2020-03-27  0:01                     ` Daniel P. Smith
2020-03-26 23:50                 ` Daniel P. Smith
2020-05-11 19:00       ` Daniel P. Smith
2020-03-26 20:50   ` Daniel P. Smith
2020-03-26 20:54     ` Matthew Garrett
2020-03-26 22:37       ` Daniel P. Smith
2020-03-26 22:41         ` Matthew Garrett
2020-03-26 23:55           ` Daniel P. Smith

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).