[RFC PATCH v2] platform/x86: Add securityfs interface for TXT status

From: Jonathan McDowell
Date: Tue Apr 12 2022 - 10:23:19 EST


This module provides read-only access to the Intel TXT (Trusted
Execution Technology) status registers, allowing userspace to determine
the status of measured boot and whether the dynamic root of trust for
measurement (DRTM) has been fully enabled.

Tools such as txt-stat from tboot
<https://sourceforge.net/projects/tboot/> can make use of this driver to
display state and attempt to remediate issues rather than relying on
access to /dev/mem.

See Documentation/x86/intel_txt.rst for more information about Intel
TXT.

Signed-off-by: Jonathan McDowell <noodles@xxxxxx>
---
v2:
- Refer to securityfs instead of sysfs
- Clarify this is read-only access for remediation
- Add documentation for the securityfs files presented
---
.../ABI/testing/securityfs-intel-txt | 226 ++++++++++++++++++
arch/x86/include/asm/txt.h | 42 ++++
drivers/platform/x86/intel/Kconfig | 16 ++
drivers/platform/x86/intel/Makefile | 2 +
drivers/platform/x86/intel/txt_securityfs.c | 189 +++++++++++++++
5 files changed, 475 insertions(+)
create mode 100644 Documentation/ABI/testing/securityfs-intel-txt
create mode 100644 arch/x86/include/asm/txt.h
create mode 100644 drivers/platform/x86/intel/txt_securityfs.c

diff --git a/Documentation/ABI/testing/securityfs-intel-txt b/Documentation/ABI/testing/securityfs-intel-txt
new file mode 100644
index 000000000000..2e0df93a168c
--- /dev/null
+++ b/Documentation/ABI/testing/securityfs-intel-txt
@@ -0,0 +1,226 @@
+What: /sys/security/security/intel-txt/*
+Date: April 2022
+Contact: Jonathan McDowell <noodles@xxxxxx>
+Description:
+ Various files relating to Intel's TXT (Trusted Execution
+ Technology). These provide read-only access to the state of
+ measured boot and whether the dynamic root of trust (DRTM) has
+ been fully enabled.
+
+ These details are intended for use in allowing userspace to
+ remediate issues with the TXT feature. They should not be relied
+ upon for confirming the system is in a secure state.
+
+ Many of the files listed below provide the raw hex values from
+ the device registers. Where possible the bit fields are
+ documented, but bits defined as reserved have been observed to
+ be clear on some platforms and set on others. As the primary
+ purpose of this support is to allow full visibility of state for
+ the purpose of remediation it is more useful to have the raw
+ values than a partially decoded state.
+
+What: /sys/security/security/intel-txt/enabled
+Date: April 2022
+Contact: Jonathan McDowell <noodles@xxxxxx>
+Description:
+ Indicates if it looks like the BIOS has successfully enabled the
+ TXT functionality. Checks that a heap has correctly been
+ configured for the device. A non-initialised heap is not a
+ guarantee that an errant BIOS has not tried to enable
+ functionality and then clear status, nor does the presence of a
+ configured heap mean the device is fully initialised.
+
+What: /sys/security/security/intel-txt/didvid
+Date: April 2022
+Contact: Jonathan McDowell <noodles@xxxxxx>
+Description:
+ Contains the vendor, device and revision IDs for the memory
+ controller or chipset.
+
+ b[15:0]
+ Vendor ID: 8086 for Intel
+ b[31:16]
+ Device ID: Specific to the chipset/platform
+ b[47:32]
+ Revision ID: Specific to the chipset/platform
+ b[63:48]
+ Extended ID: Specific to the chipset/platform
+
+What: /sys/security/security/intel-txt/dpr
+Date: April 2022
+Contact: Jonathan McDowell <noodles@xxxxxx>
+Description:
+ Defines the details of the DMA Protected Range in which the TXT
+ heap and SINIT regions are located.
+
+ Platforms utilising SGX implement this as part of uncore and so
+ this register has no underlying hardware functionality on those
+ platforms.
+
+ b[0]
+ Bits 19:0 are locked down in this register when this bit
+ is set.
+ b[3:1]
+ Reserved.
+ b[11:4]
+ The size of memory, in MB, that will be protected from
+ DMA accesses. 0 indicates no memory is protected.
+ b[19:12]
+ Reserved.
+ b[31:20]
+ Top address + 1 of the DMA protected range.
+
+What: /sys/security/security/intel-txt/e2sts
+Date: April 2022
+Contact: Jonathan McDowell <noodles@xxxxxx>
+Description:
+ Extended error status details. Contents are preserved across
+ soft resets.
+
+ b[0]
+ Reserved.
+ b[1]
+ SECRET.STS.
+ 0 = Chipset acknowledged that no secrets are in memory.
+ 1 = Chipset believes that secrets are in memory and will
+ provide reset protection.
+ b[63:2]
+ Reserved.
+
+What: /sys/security/security/intel-txt/errorcode
+Date: April 2022
+Contact: Jonathan McDowell <noodles@xxxxxx>
+Description:
+ Shutdown error code details. Preserved over a soft reset,
+ cleared by a hard reset or power cycle.
+
+ b[3:0]
+ Module details.
+ 0 = BIOS ACM
+ 1 = SINIT
+ b[9:4]
+ Class code
+ b[14:10]
+ Major error code
+ b[15]
+ Software source
+ 0 = Authenticated Code Module (ACM)
+ 1 = Measure Launch Environment (MLE)
+ b[27:16]
+ Minor error code
+ b[29:28]
+ Reserved.
+ b[30]
+ 0 = Error reported by processor
+ 1 = Error reported by software
+ b[31]
+ Valid bit
+ 0 = Register contents invalid, should be ignored
+ 1 = Error details valid
+ b[63:32]
+ Reserved.
+
+What: /sys/security/security/intel-txt/ests
+Date: April 2022
+Contact: Jonathan McDowell <noodles@xxxxxx>
+Description:
+ Details associated with various error conditions. Contents are
+ preserved across soft resets.
+
+ b[0]
+ TXT_RESET.STS. Set to 1 to indicate an error occurred
+ which may prevent the proper use of TXT. While this bit
+ is set the Safer Mode Extension (SMX) instructions
+ GETSEC[ENTERACCS] and GETSEC[SENTER] will fail.
+
+ This bit is only cleared on a power cycle.
+ b[63:1]
+ Reserved.
+
+What: /sys/security/security/intel-txt/spad
+Date: April 2022
+Contact: Jonathan McDowell <noodles@xxxxxx>
+Description:
+ Details from the startup Authenticated Code Module (ACM)
+ conveying the results of its operation. Generally of interest to
+ the BIOS rather than the OS in normal operation it can provide
+ details of where TXT initialisation failed.
+
+ b[29:0]
+ Reserved.
+ b[30]
+ Indicates TXT startup success; successful preparation
+ for the BIOS, SINIT and MLE components.
+ b[46:31]
+ General startup ACM to BIOS boot status communication.
+ b[47]
+ Indicates memory contents were cleared via a power down.
+ b[52:48]
+ Startup ACM to BIOS communication in MP platforms.
+ b[53]
+ Startup ACM indication of run-time enabled status of
+ TXT. Generally driven by FIT type 0xA record.
+ b[58:54]
+ Startup ACM to BIOS communication in MP platforms.
+ b[59]
+ Indicates the BIOS is trusted.
+ b[60]
+ Indicates that TXT has been disabled by a runtime FIT
+ type 0xA record.
+ b[61]
+ Startup ACM to BIOS communication in MP platforms.
+ b[62]
+ Indicates an ACM authentication error from the CPU.
+ b[63]
+ Indicates S-ACM successfully enforced its logic for all
+ provisioned technologies.
+
+What: /sys/security/security/intel-txt/sts
+Date: April 2022
+Contact: Jonathan McDowell <noodles@xxxxxx>
+Description:
+ General status details for various TXT features.
+
+ b[0]
+ SENTER.DONE.STS. Set by the chipset when it sees all
+ threads have done a TXT.CYC.SENTER-ACK. When any of the
+ threads does a TXT.CYC.SYSEXIT-ACK then TXT.THREADS.JOIN
+ and TXT.THREAD.EXISTS registers will not be equal and
+ the chipset will clear this bit.
+ b[1]
+ SEXIT.DONE.STS. Set when all bits in the
+ TXT.THREADS.JOIN register are clear. This is thus set
+ after reset (since the bits are all 0) and once all
+ threads have done a TXT.CYC.SYSEXIT-ACK.
+ b[5:2]
+ Reserved.
+ b[6]
+ MEM-CONFIG-LOCK.STS. Set to 1 when the memory
+ configuration is locked. Cleared by
+ TXT.CMD.UNLOCK.MEMCONFIG or a system reset.
+ b[7]
+ PRIVATE-OPEN.STS. Set to 1 when TXT.CMD.OPEN-PRIVATE is
+ performed. Cleared by TXT.CMD.CLOSE-PRIVATE or by a
+ system reset.
+ b[14:8]
+ Reserved.
+ b[15]
+ TXT.LOCALITY1.OPEN.STS. Set when TXT.CMD.OPEN.LOCALITY1
+ is seen by the chipset. Cleared on reset or when
+ TXT.CMD.CLOSE.LOCALITY1 is seen.
+ b[16]
+ TXT.LOCALITY2.OPEN.STS. Set when TXT.CMD.OPEN.LOCALITY2
+ or TXT.CMD.OPEN.PRIVATE is seen by the chipset. Cleared
+ on reset, or when either TXT.CMD.CLOSE.LOCALITY2 or
+ TXT.CMD.CLOSE.PRIVATE is seen, and by the GETSEC[SEXIT]
+ instruction.
+ b[63:17]
+ Reserved.
+
+What: /sys/security/security/intel-txt/publickey
+Date: April 2022
+Contact: Jonathan McDowell <noodles@xxxxxx>
+Description:
+ 256 bit hash of the public key used for the verification of the
+ Authenticated Code Modules. Details are specific to the memory
+ controller or chipset.
diff --git a/arch/x86/include/asm/txt.h b/arch/x86/include/asm/txt.h
new file mode 100644
index 000000000000..a26df62f990c
--- /dev/null
+++ b/arch/x86/include/asm/txt.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * txt.h: Intel TXT (Trusted Execution Technology) related definitions
+ */
+
+#ifndef __TXT_H
+#define __TXT_H
+
+#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)
+
+/*
+ * TXT configuration registers (offsets from TXT_{PUB,PRIV}_CONFIG_REGS_BASE)
+ *
+ * Registers exist at the same offsets in both spaces, but access control
+ * may differ.
+ *
+ * See Intel's "Measured Launch Environment Developer's Guide" (315168)
+ * for full details.
+ */
+
+#define TXT_CR_STS 0x0000
+#define TXT_CR_ESTS 0x0008
+#define TXT_CR_ERRORCODE 0x0030
+#define TXT_CR_SPAD 0x00A0
+#define TXT_CR_VER_FSBIF 0x0100
+#define TXT_CR_DIDVID 0x0110
+#define TXT_CR_VER_EMIF 0x0200
+#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_DPR 0x0330
+#define TXT_CR_SCRATCHPAD 0x0378
+#define TXT_CR_PUBLIC_KEY 0x0400
+#define TXT_CR_E2STS 0x08f0
+
+#endif /* __TXT_H */
diff --git a/drivers/platform/x86/intel/Kconfig b/drivers/platform/x86/intel/Kconfig
index 8e65086bb6c8..40b55e7fbfce 100644
--- a/drivers/platform/x86/intel/Kconfig
+++ b/drivers/platform/x86/intel/Kconfig
@@ -159,6 +159,22 @@ config INTEL_TURBO_MAX_3
This driver is only required when the system is not using Hardware
P-States (HWP). In HWP mode, priority can be read from ACPI tables.

+config INTEL_TXT_SECURITYFS
+ tristate "Intel TXT securityfs driver"
+ depends on HAVE_INTEL_TXT && SECURITYFS
+ help
+ This driver exports the TXT (Trusted Execution Technology) public
+ configuration space to user space via securityfs.
+
+ These registers provide details about the status of the platform's
+ measured launch and execution environment, allowing userspace to
+ perform diagnosis and potential remediation when attestation or
+ other trust related operations are failing.
+
+ For kernel implementations which actually provide a trusted
+ environment see tboot <https://sourceforge.net/projects/tboot/>
+ and TrenchBoot <https://trenchboot.org/>.
+
config INTEL_UNCORE_FREQ_CONTROL
tristate "Intel Uncore frequency control driver"
depends on X86_64
diff --git a/drivers/platform/x86/intel/Makefile b/drivers/platform/x86/intel/Makefile
index 35f2066578b2..5d4531d4ada5 100644
--- a/drivers/platform/x86/intel/Makefile
+++ b/drivers/platform/x86/intel/Makefile
@@ -26,6 +26,8 @@ intel_int0002_vgpio-y := int0002_vgpio.o
obj-$(CONFIG_INTEL_INT0002_VGPIO) += intel_int0002_vgpio.o
intel_oaktrail-y := oaktrail.o
obj-$(CONFIG_INTEL_OAKTRAIL) += intel_oaktrail.o
+intel_txt_securityfs-y := txt_securityfs.o
+obj-$(CONFIG_INTEL_TXT_SECURITYFS) += intel_txt_securityfs.o
intel_vsec-y := vsec.o
obj-$(CONFIG_INTEL_VSEC) += intel_vsec.o

diff --git a/drivers/platform/x86/intel/txt_securityfs.c b/drivers/platform/x86/intel/txt_securityfs.c
new file mode 100644
index 000000000000..2db9aa95acb9
--- /dev/null
+++ b/drivers/platform/x86/intel/txt_securityfs.c
@@ -0,0 +1,189 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * This module can be used to access below resources
+ * - TXT config space
+ * - SMX parameter
+ *
+ * Intel TXT (Trusted Execution Technology) will provide higher
+ * assurance of system configuration and initial state as well as
+ * data reset protection. It also helps solve real end user concerns
+ * about having confidence that their hardware is running the VMM
+ * or kernel that it was configured with, especially since they may
+ * be responsible for providing such assurances to VMs and services
+ * running on it.
+ *
+ * See Documentation/x86/intel_txt.rst for more information about
+ * Intel TXT.
+ *
+ * Intel TXT configuration registers are a subset of chipset registers.
+ * These chipset registers that interact with SMX are accessed from two
+ * regions of memory, which represent the public and private configuration
+ * spaces, by system software using memory read/write protocols.
+ *
+ * Safer Mode Extensions (SMX) provide a processor's programming
+ * interface in an Intel TXT platform for system software to establish
+ * a measured environment within the platform to support trust decisions
+ * by end users.
+ *
+ * Data can be found below
+ * /sys/security/security/intel-txt/
+ *
+ * Details of the registers can be found in
+ * Documentation/ABI/testing/securityfs-intel-txt
+ */
+
+#include <linux/byteorder/little_endian.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/security.h>
+#include <linux/seq_file.h>
+
+#include <asm/cpu_device_id.h>
+#include <asm/txt.h>
+
+#define DEV_NAME "intel_txt"
+static struct platform_device *txt_pdev;
+
+static int txt_enabled_show(struct seq_file *m, void *v);
+static int txt_key_show(struct seq_file *m, void *v);
+static int txt_reg_show(struct seq_file *m, void *v);
+
+/* securityfs related data */
+static struct dentry *txt_dir;
+static void *txt_pub_regs;
+static struct txt_securityfs_file {
+ char *name;
+ u32 ofs;
+ int (*show)(struct seq_file *m, void *v);
+ struct dentry *dentry;
+} txt_securityfs_files[] = {
+ /* Raw registers */
+ { .name = "didvid", .ofs = TXT_CR_DIDVID, .show = txt_reg_show },
+ { .name = "dpr", .ofs = TXT_CR_DPR, .show = txt_reg_show },
+ { .name = "e2sts", .ofs = TXT_CR_E2STS, .show = txt_reg_show },
+ { .name = "errorcode", .ofs = TXT_CR_ERRORCODE, .show = txt_reg_show },
+ { .name = "ests", .ofs = TXT_CR_ESTS, .show = txt_reg_show },
+ { .name = "spad", .ofs = TXT_CR_SPAD, .show = txt_reg_show },
+ { .name = "sts", .ofs = TXT_CR_STS, .show = txt_reg_show },
+
+ { .name = "enabled", .show = txt_enabled_show },
+ { .name = "publickey", .show = txt_key_show },
+};
+
+/* Shows if TXT has been enabled */
+static int txt_enabled_show(struct seq_file *m, void *v)
+{
+ /* If the BIOS has enabled TXT then the heap base will be set */
+ seq_printf(m, "%d\n", *(u64 *)(txt_pub_regs + TXT_CR_HEAP_BASE) != 0);
+
+ return 0;
+}
+
+/* Shows the 256 bit hash of the public key */
+static int txt_key_show(struct seq_file *m, void *v)
+{
+ seq_printf(m, "%016llx%016llx%016llx%016llx\n",
+ cpu_to_be64(*(u64 *)(txt_pub_regs + TXT_CR_PUBLIC_KEY)),
+ cpu_to_be64(*(u64 *)(txt_pub_regs + TXT_CR_PUBLIC_KEY + 8)),
+ cpu_to_be64(*(u64 *)(txt_pub_regs + TXT_CR_PUBLIC_KEY + 16)),
+ cpu_to_be64(*(u64 *)(txt_pub_regs + TXT_CR_PUBLIC_KEY + 24)));
+
+ return 0;
+}
+
+/* Show a generic 64 bit register */
+static int txt_reg_show(struct seq_file *m, void *v)
+{
+ struct txt_securityfs_file *ctx = m->private;
+
+ seq_printf(m, "%016llx\n", *(u64 *)(txt_pub_regs + ctx->ofs));
+
+ return 0;
+}
+
+static int txt_pub_reg_open(struct inode *inode, struct file *filp)
+{
+ struct txt_securityfs_file *ctx = file_inode(filp)->i_private;
+
+ return single_open(filp, ctx->show, ctx);
+}
+
+static const struct file_operations txt_pub_reg_fops = {
+ .open = txt_pub_reg_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct x86_cpu_id smx_cpu_id[] = {
+ X86_MATCH_FEATURE(X86_FEATURE_SMX, NULL),
+ {}
+};
+MODULE_DEVICE_TABLE(x86cpu, smx_cpu_id);
+
+static int __init txt_securityfs_init(void)
+{
+ int i;
+ int err;
+
+ if (!x86_match_cpu(smx_cpu_id))
+ return -ENODEV;
+
+ txt_pdev = platform_device_register_simple(DEV_NAME, -1, NULL, 0);
+ if (IS_ERR(txt_pdev))
+ return PTR_ERR(txt_pdev);
+
+ txt_pub_regs = devm_ioremap(&txt_pdev->dev, TXT_PUB_CONFIG_REGS_BASE,
+ TXT_NR_CONFIG_PAGES * PAGE_SIZE);
+ if (!txt_pub_regs)
+ goto out;
+
+ txt_dir = securityfs_create_dir("intel-txt", NULL);
+ if (IS_ERR(txt_dir)) {
+ err = PTR_ERR(txt_dir);
+ txt_dir = NULL;
+ goto out;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(txt_securityfs_files); i++) {
+ txt_securityfs_files[i].dentry = securityfs_create_file(
+ txt_securityfs_files[i].name, 0444, txt_dir,
+ &txt_securityfs_files[i],
+ &txt_pub_reg_fops);
+ if (IS_ERR(txt_securityfs_files[i].dentry)) {
+ err = PTR_ERR(txt_securityfs_files[i].dentry);
+ txt_securityfs_files[i].dentry = NULL;
+ goto out;
+ }
+ }
+
+ return 0;
+out:
+ for (i = 0; i < ARRAY_SIZE(txt_securityfs_files); i++) {
+ if (txt_securityfs_files[i].dentry != NULL)
+ securityfs_remove(txt_securityfs_files[i].dentry);
+ }
+ if (txt_dir)
+ securityfs_remove(txt_dir);
+ platform_device_unregister(txt_pdev);
+ return err;
+}
+
+static void __exit txt_securityfs_exit(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(txt_securityfs_files); i++) {
+ if (txt_securityfs_files[i].dentry != NULL)
+ securityfs_remove(txt_securityfs_files[i].dentry);
+ }
+ securityfs_remove(txt_dir);
+ platform_device_unregister(txt_pdev);
+}
+
+module_init(txt_securityfs_init);
+module_exit(txt_securityfs_exit);
+
+MODULE_LICENSE("GPL");
--
2.34.1