From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-dl1-f54.google.com (mail-dl1-f54.google.com [74.125.82.54]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2AA3C40C5D8 for ; Fri, 15 May 2026 21:15:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.54 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778879758; cv=none; b=dFWJyHZmMvfokeOPlKWarzP2ulhKFTwLMVs2JWde883iUm3lIBolsht/HWoYnVUjVB4VZHUPO+azW+RWg9xjlG7Ut2qeWU29j63blZ+Ac8p4azoZfZnouQX0ce9XXd6q/pZIOVjvFdlyp3qgVQr5You2apTMlsIZmgL7oHToB4M= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778879758; c=relaxed/simple; bh=7kz9F/A7fTabBES64n2mJiXuxrlDHAgKavRF6IJZP/4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ZZfRZfzxCUqRnIjO94n4LW4qV/K3R2sovCBXehpjVMY61YMG8CK8/xbr5LxjJCYIuS51zX9aq3yZFABcFv6w+/5RvPyTO+D6/0qGys6FOvbYf3CdYWpvLF3HUD6T7zZ1EcYuhZuLZMR44+fafZueNDVW80+IeKMSjaaFRG+ZxEE= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=cqHNMISC; arc=none smtp.client-ip=74.125.82.54 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="cqHNMISC" Received: by mail-dl1-f54.google.com with SMTP id a92af1059eb24-1353c2f35cfso952036c88.1 for ; Fri, 15 May 2026 14:15:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1778879755; x=1779484555; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=Gc9QK/7ZvXL3YWAwN0KCcbTGVvK6GenZl2ozt4yOZIg=; b=cqHNMISCPJsQTmlqCfNSv/ih/pdG3fy0Q3ykxPB7roAESvauGz36GurYGmOjECRKFv DSeE4Gmfh5qRU+4LaP7o4Ck6McG1bDINdimpxdvKk7rGpaNAF6s0RzDbLLWz6MFbbrUf 5W2qyKydoVi5N3IDsYARGhC9KyfdLfVsFt0e+VEaiTUhiVGIdyeaJZ+MGHl+KSNhg7In RYNF2fvXCa2gRPi6fgxfSLpfwioAn53yp3LqWKnr7vucUgo0PQ3zDJyAghG5rTUsBVIA rn5r1Gzt1gYfdbcCAazVvlV0mSrm4taWqtl3MpMFaEFZ4m9ml/Y535xseiIVg1kjW/eG fmkQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778879755; x=1779484555; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=Gc9QK/7ZvXL3YWAwN0KCcbTGVvK6GenZl2ozt4yOZIg=; b=M3tRsajN0ygu6/hASHemiAxuEuOqyTXzNRSUbSpuzBLTZjsUm/WVdq8Sf0tpJLwQ4i 6S1ZM3gP3rVUHsga+EU/ABFuGkqyZLJKkblx/MUE8LX8nHLh+N23h4qTIF8vlT3s4S6u 1xKJI8WQq/1L+vNA1+T/nYJCB3erEB6a6ZRLrbsu/r4z+B9E4vZXvilHxYQyWIFSPzoW m1oJ7BxP0B1TReJcXmRVVtRPlKFo++jylEUCuh67UFqs7CczZiOD1TqJO74jke/xdNpD RMDgTFgrozY31rMcTV8sJyCFdw+DsAilp0W8cYTJfLiad2mwO9OmMJ70GABiuScWAR3x KuLQ== X-Forwarded-Encrypted: i=1; AFNElJ8iaFq48uzCUychFaKQLRrN5SCf9X2jtBED1NcJHeFRyjr2MKBblcZhdrQx0AbMqF9e1j+inCJhuy4=@vger.kernel.org X-Gm-Message-State: AOJu0YzfBHpk1hHTwb670pQ7jGCeQbIBC9MxeutHnWuYTmh6zVRiaedK t+qmGcddXo7kNFKyHUmThTIWoxcbQChYGYNnwz2mprO23fG36pdg7TM5 X-Gm-Gg: Acq92OEFa2KWiKaL2IwyJ4i0U+z7eaD4zEEJCumgPRGRmLNtGdndRkqOvwufj3famES nsQSrpZQkcar48ByadELSL2RQ0ido0xCA6XnK1+MBBh3+l7GC56XXtgi6HOgEUYz2vQFJyLzwvT iGfQms7wYqkwef7bmOSf1VrZi7N9QBOor9N/tra3Gab3Px90hJzQKtbbuEjEGJruSZ7B/AImtJq AVQyytAneFJL7lMmcHbQ+ZNElUT05AGxTQpA6Gnk9qA9H5M+5SQLWkqKuqZrfNlkMBmUscba0qx BDN6JptvjlSobOHKatl68s+jTby7lKiraWSk4NdOwa0/5IghSIzJSgu+ZNdgDNDv7jY7azPFCND gVEG2Z9+7KP2I4TOYv3VHzbyrVz0MN+TsE/3zJbHNNOl1SuNyh1n2/0Q+GPlA4JWFu+EMd/5xxN VN9FD6L5zAZXHEu3cHp4hv8yrdMhesYRD9D+neKfQsfQ== X-Received: by 2002:a05:7022:661e:b0:12d:de3f:d844 with SMTP id a92af1059eb24-13504951829mr2578587c88.39.1778879755329; Fri, 15 May 2026 14:15:55 -0700 (PDT) Received: from mimas.lan ([2603:8000:df01:38f7:a6bb:6dff:fecf:e71a]) by smtp.gmail.com with ESMTPSA id a92af1059eb24-134cbdcf140sm11368464c88.5.2026.05.15.14.15.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 15 May 2026 14:15:54 -0700 (PDT) From: Ross Philipson To: linux-kernel@vger.kernel.org, x86@kernel.org, linux-integrity@vger.kernel.org, linux-doc@vger.kernel.org, linux-crypto@vger.kernel.org, kexec@lists.infradead.org, linux-efi@vger.kernel.org, iommu@lists.linux.dev Cc: ross.philipson@gmail.com, dpsmith@apertussolutions.com, tglx@linutronix.de, mingo@redhat.com, bp@alien8.de, hpa@zytor.com, dave.hansen@linux.intel.com, ardb@kernel.org, mjg59@srcf.ucam.org, James.Bottomley@hansenpartnership.com, peterhuewe@gmx.de, jarkko@kernel.org, jgg@ziepe.ca, luto@amacapital.net, nivedita@alum.mit.edu, herbert@gondor.apana.org.au, davem@davemloft.net, corbet@lwn.net, ebiederm@xmission.com, dwmw2@infradead.org, baolu.lu@linux.intel.com, kanth.ghatraju@oracle.com, daniel.kiper@oracle.com, andrew.cooper3@citrix.com, trenchboot-devel@googlegroups.com Subject: [PATCH v16 36/38] x86/slaunch: Secure Launch late initcall platform module Date: Fri, 15 May 2026 14:14:08 -0700 Message-ID: <20260515211410.31440-37-ross.philipson@gmail.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260515211410.31440-1-ross.philipson@gmail.com> References: <20260515211410.31440-1-ross.philipson@gmail.com> Precedence: bulk X-Mailing-List: linux-efi@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: "Daniel P. Smith" The Secure Launch platform module is a late init module. During the init call, the TPM event log is read and measurements taken in the early boot stub code are located. These measurements are extended into the TPM PCRs using the mainline TPM kernel driver. The platform module also registers the securityfs nodes to allow fetching and writing events from/to the DRTM TPM event log. In addition, on Intel, access to TXT register fields is made available for reading. Co-developed-by: garnetgrimm Signed-off-by: garnetgrimm Co-developed-by: Ross Philipson Signed-off-by: Daniel P. Smith Signed-off-by: Ross Philipson --- arch/x86/kernel/Makefile | 1 + arch/x86/kernel/slmodule.c | 353 +++++++++++++++++++++++++++++++++++++ 2 files changed, 354 insertions(+) create mode 100644 arch/x86/kernel/slmodule.c diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index bf2471701662..8b039ed0a902 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -98,6 +98,7 @@ obj-$(CONFIG_IA32_EMULATION) += tls.o obj-y += step.o obj-$(CONFIG_INTEL_TXT) += tboot.o obj-$(CONFIG_SECURE_LAUNCH) += slaunch.o +obj-$(CONFIG_SECURE_LAUNCH) += slmodule.o obj-$(CONFIG_ISA_DMA_API) += i8237.o obj-y += stacktrace.o obj-y += cpu/ diff --git a/arch/x86/kernel/slmodule.c b/arch/x86/kernel/slmodule.c new file mode 100644 index 000000000000..9688249e274c --- /dev/null +++ b/arch/x86/kernel/slmodule.c @@ -0,0 +1,353 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Secure Launch late validation/setup, securityfs exposure and finalization. + * + * Copyright (c) 2026 Apertus Solutions, LLC + * Copyright (c) 2026 Assured Information Security, Inc. + * Copyright (c) 2026, Oracle and/or its affiliates. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * The macro DECLARE_TXT_PUB_READ_U is used to read values from the TXT + * public registers as unsigned values. + */ +#define DECLARE_TXT_PUB_READ_U(size, fmt, msg_size) \ +static ssize_t txt_pub_read_u##size(unsigned int offset, \ + loff_t *read_offset, \ + size_t read_len, \ + char __user *buf) \ +{ \ + char msg_buffer[msg_size]; \ + u##size reg_value = 0; \ + void __iomem *txt; \ + \ + txt = ioremap(TXT_PUB_CONFIG_REGS_BASE, \ + TXT_NR_CONFIG_PAGES * PAGE_SIZE); \ + if (!txt) \ + return -EFAULT; \ + memcpy_fromio(®_value, txt + offset, sizeof(u##size)); \ + iounmap(txt); \ + snprintf(msg_buffer, msg_size, fmt, reg_value); \ + return simple_read_from_buffer(buf, read_len, read_offset, \ + &msg_buffer, msg_size); \ +} + +DECLARE_TXT_PUB_READ_U(8, "%#04x\n", 6); +DECLARE_TXT_PUB_READ_U(32, "%#010x\n", 12); +DECLARE_TXT_PUB_READ_U(64, "%#018llx\n", 20); + +#define DECLARE_TXT_FOPS(reg_name, reg_offset, reg_size) \ +static ssize_t txt_##reg_name##_read(struct file *flip, \ + char __user *buf, size_t read_len, loff_t *read_offset) \ +{ \ + return txt_pub_read_u##reg_size(reg_offset, read_offset, \ + read_len, buf); \ +} \ +static const struct file_operations reg_name##_ops = { \ + .read = txt_##reg_name##_read, \ +} + +DECLARE_TXT_FOPS(sts, TXT_CR_STS, 64); +DECLARE_TXT_FOPS(ests, TXT_CR_ESTS, 8); +DECLARE_TXT_FOPS(errorcode, TXT_CR_ERRORCODE, 32); +DECLARE_TXT_FOPS(didvid, TXT_CR_DIDVID, 64); +DECLARE_TXT_FOPS(e2sts, TXT_CR_E2STS, 64); +DECLARE_TXT_FOPS(ver_emif, TXT_CR_VER_EMIF, 32); +DECLARE_TXT_FOPS(scratchpad, TXT_CR_SCRATCHPAD, 64); + +/* + * Securityfs exposure + */ +struct memfile { + char *name; + void *addr; + size_t size; +}; + +static struct memfile sl_evtlog = { "eventlog", NULL, 0 }; +static void *txt_heap; +static struct txt_heap_event_log_pointer2_1_element *evtlog21; +static DEFINE_MUTEX(sl_evt_log_mutex); +static struct tcg_efi_specid_event_head *efi_head; + +static ssize_t sl_evtlog_read(struct file *file, char __user *buf, + size_t count, loff_t *pos) +{ + ssize_t size; + + if (!sl_evtlog.addr) + return 0; + + mutex_lock(&sl_evt_log_mutex); + size = simple_read_from_buffer(buf, count, pos, sl_evtlog.addr, + sl_evtlog.size); + mutex_unlock(&sl_evt_log_mutex); + + return size; +} + +static ssize_t sl_evtlog_write(struct file *file, const char __user *buf, + size_t datalen, loff_t *ppos) +{ + ssize_t result; + char *data; + + if (!sl_evtlog.addr) + return 0; + + /* No partial writes. */ + result = -EINVAL; + if (*ppos != 0) + goto out; + + data = memdup_user(buf, datalen); + if (IS_ERR(data)) { + result = PTR_ERR(data); + goto out; + } + + mutex_lock(&sl_evt_log_mutex); + if (evtlog21) + result = tpm2_log_event(evtlog21, sl_evtlog.addr, + sl_evtlog.size, datalen, data); + else + result = tpm_log_event(sl_evtlog.addr, sl_evtlog.size, + datalen, data); + mutex_unlock(&sl_evt_log_mutex); + + kfree(data); +out: + return result; +} + +static const struct file_operations sl_evtlog_ops = { + .read = sl_evtlog_read, + .write = sl_evtlog_write, + .llseek = default_llseek, +}; + +struct sfs_file { + const char *name; + const struct file_operations *fops; +}; + +#define SL_TXT_ENTRY_COUNT 7 +static const struct sfs_file sl_txt_files[] = { + { "sts", &sts_ops }, + { "ests", &ests_ops }, + { "errorcode", &errorcode_ops }, + { "didvid", &didvid_ops }, + { "ver_emif", &ver_emif_ops }, + { "scratchpad", &scratchpad_ops }, + { "e2sts", &e2sts_ops } +}; + +/* sysfs file handles */ +static struct dentry *slaunch_dir; +static struct dentry *event_file; +static struct dentry *txt_dir; +static struct dentry *txt_entries[SL_TXT_ENTRY_COUNT]; + +static long slaunch_expose_securityfs(void) +{ + long ret = 0; + int i; + + slaunch_dir = securityfs_create_dir("slaunch", NULL); + if (IS_ERR(slaunch_dir)) + return PTR_ERR(slaunch_dir); + + if (slaunch_get_flags() & SL_FLAG_ARCH_TXT) { + txt_dir = securityfs_create_dir("txt", slaunch_dir); + if (IS_ERR(txt_dir)) { + ret = PTR_ERR(txt_dir); + goto remove_slaunch; + } + + for (i = 0; i < ARRAY_SIZE(sl_txt_files); i++) { + txt_entries[i] = + securityfs_create_file(sl_txt_files[i].name, 0440, txt_dir, + NULL, sl_txt_files[i].fops); + if (IS_ERR(txt_entries[i])) { + ret = PTR_ERR(txt_entries[i]); + goto remove_files; + } + } + } + + if (sl_evtlog.addr) { + event_file = securityfs_create_file(sl_evtlog.name, 0440, + slaunch_dir, NULL, + &sl_evtlog_ops); + if (IS_ERR(event_file)) { + ret = PTR_ERR(event_file); + goto remove_files; + } + } + + return 0; + +remove_files: + if (slaunch_get_flags() & SL_FLAG_ARCH_TXT) { + while (--i >= 0) + securityfs_remove(txt_entries[i]); + securityfs_remove(txt_dir); + } + +remove_slaunch: + securityfs_remove(slaunch_dir); + + return ret; +} + +static void slaunch_teardown_securityfs(void) +{ + int i; + + securityfs_remove(event_file); + if (sl_evtlog.addr) { + memunmap(sl_evtlog.addr); + sl_evtlog.addr = NULL; + } + sl_evtlog.size = 0; + + if (slaunch_get_flags() & SL_FLAG_ARCH_TXT) { + for (i = 0; i < ARRAY_SIZE(sl_txt_files); i++) + securityfs_remove(txt_entries[i]); + + securityfs_remove(txt_dir); + + if (txt_heap) { + memunmap(txt_heap); + txt_heap = NULL; + } + } + + securityfs_remove(slaunch_dir); +} + +static void __init slaunch_intel_evtlog(void __iomem *txt) +{ + struct slr_entry_log_info *log_info; + struct txt_os_mle_data *params; + struct slr_table *slrt; + void *os_sinit_data; + u64 base, size; + + memcpy_fromio(&base, txt + TXT_CR_HEAP_BASE, sizeof(base)); + memcpy_fromio(&size, txt + TXT_CR_HEAP_SIZE, sizeof(size)); + + /* now map TXT heap */ + txt_heap = memremap(base, size, MEMREMAP_WB); + if (!txt_heap) + slaunch_reset(txt, "Error memremap TXT heap failed\n", SL_ERROR_HEAP_MAP); + + params = (struct txt_os_mle_data *)slaunch_txt_get_heap_table(txt_heap, + TXT_OS_MLE_DATA_TABLE); + + /* Get the SLRT and remap it */ + slrt = memremap(params->slrt, sizeof(*slrt), MEMREMAP_WB); + if (!slrt) + slaunch_reset(txt, "Error memremap SLR Table failed\n", SL_ERROR_SLRT_MAP); + size = slrt->size; + memunmap(slrt); + + slrt = memremap(params->slrt, size, MEMREMAP_WB); + if (!slrt) + slaunch_reset(txt, "Error memremap SLR Table failed\n", SL_ERROR_SLRT_MAP); + + log_info = slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_LOG_INFO); + if (!log_info) + slaunch_reset(txt, "Error SLR Table missing entry\n", SL_ERROR_SLRT_MISSING_ENTRY); + + sl_evtlog.size = log_info->size; + sl_evtlog.addr = memremap(log_info->addr, log_info->size, MEMREMAP_WB); + if (!sl_evtlog.addr) + slaunch_reset(txt, "Error memremap TPM event log failed\n", SL_ERROR_EVENTLOG_MAP); + + memunmap(slrt); + + /* Determine if this is TPM 1.2 or 2.0 event log */ + if (memcmp(sl_evtlog.addr + sizeof(struct tcg_pcr_event), + TCG_SPECID_SIG, sizeof(TCG_SPECID_SIG))) + return; /* looks like it is not 2.0 */ + + /* For TPM 2.0 logs, the extended heap element must be located */ + os_sinit_data = slaunch_txt_get_heap_table(txt_heap, TXT_OS_SINIT_DATA_TABLE); + + evtlog21 = txt_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 (!evtlog21) + slaunch_reset(txt, "Error locate TPM20 event log element failed\n", + SL_ERROR_TPM_INVALID_LOG20); + + /* Save pointer to the EFI SpecID log header */ + efi_head = (struct tcg_efi_specid_event_head *)(sl_evtlog.addr + + sizeof(struct tcg_pcr_event)); +} + +static void __init slaunch_tpm_open_locality2(void __iomem *txt) +{ + struct tpm_chip *tpm; + int rc; + + tpm = tpm_default_chip(); + if (!tpm) + slaunch_reset(txt, "Could not get default TPM chip\n", SL_ERROR_TPM_INIT); + + rc = tpm_chip_set_locality(tpm, 2); + if (rc) + slaunch_reset(txt, "Could not set TPM chip locality 2\n", SL_ERROR_TPM_INIT); +} + +static int __init slaunch_module_init(void) +{ + void __iomem *txt; + + /* Check to see if Secure Launch happened */ + if ((slaunch_get_flags() & (SL_FLAG_ACTIVE|SL_FLAG_ARCH_TXT)) != + (SL_FLAG_ACTIVE | SL_FLAG_ARCH_TXT)) + return 0; + + txt = ioremap(TXT_PRIV_CONFIG_REGS_BASE, TXT_NR_CONFIG_PAGES * + PAGE_SIZE); + if (!txt) + panic("Error ioremap of TXT priv registers\n"); + + /* Only Intel TXT is supported at this point */ + slaunch_intel_evtlog(txt); + slaunch_tpm_open_locality2(txt); + iounmap(txt); + + return slaunch_expose_securityfs(); +} + +static void __exit slaunch_module_exit(void) +{ + slaunch_teardown_securityfs(); +} + +late_initcall(slaunch_module_init); +__exitcall(slaunch_module_exit); -- 2.47.3