From nobody Mon Feb 9 20:09:41 2026 Received: from mx0b-00069f02.pphosted.com (mx0b-00069f02.pphosted.com [205.220.177.32]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1301A32ED49; Mon, 15 Dec 2025 23:42:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.177.32 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1765842149; cv=none; b=FTl+EOH9EDgmfOKrr2MIoHsT9nNFtfz4P/75eIrRhQy3ik1Bsn2ltcba8aQzv3Bm4FkWbJKQUB8k1OO7OxZ1uISFCK729VTsL1UQyZV7pRxzTOhx3gfVPOdorwXTQimpj4HED4N5Vx7UrKJ8bp9dO/Myvcm4HOyKKoV6/IXqt4o= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1765842149; c=relaxed/simple; bh=KQsZ6d+uM6b6sflX3k+uU1wn+Q9VagVeLipFTW4VZ+o=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=FfjMFywxeh3u5ISgshGr4JxLxvvB/+Cg5L3FnM6CJZ4WasIhuM8q9HahDt8nJCoH8jXSyivXNaKX5rBvZCAJsIFwqRjHuinkkHYgqlhdPHdA5jUty7SE3VkFqqqdS4VE8na32csRmSwPrg5GJkGyJNL+RLUTVZigdRbHdq3DX3o= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oracle.com; spf=pass smtp.mailfrom=oracle.com; dkim=pass (2048-bit key) header.d=oracle.com header.i=@oracle.com header.b=UfQzZYPX; arc=none smtp.client-ip=205.220.177.32 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oracle.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oracle.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=oracle.com header.i=@oracle.com header.b="UfQzZYPX" Received: from pps.filterd (m0333520.ppops.net [127.0.0.1]) by mx0b-00069f02.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 5BFJC5ke3058793; Mon, 15 Dec 2025 23:41:44 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=cc :content-transfer-encoding:date:from:in-reply-to:message-id :mime-version:references:subject:to; s=corp-2025-04-25; bh=7OJVX EzVevsSpOMN+cbYD0/ttl0vZ+kO/ZWumX5Girc=; b=UfQzZYPXvKw32VOJqYMzm P1DK3gw7UEPx+umMq0zo/edf3AGuALY+D+Ve1GEh+PCMqBxLUQqvd5Bd6MqbOWn0 f+zzkShj4Jbm8Xvw5HNqAEGMhREevxRuIOobyJmsUmI1ngJmTx0mnxhYVGtEoOYP uP7zkyIsDQQvc3rBomGngs/VG+WxSFRh3f027l/yyTTSwYiyot4VD70dRr8GLW91 Juqas5R514cyTrHiJ0U9RoUPu9m/Vq6XgHC5Qa0AaF0cHt2vHVW0QLHuMn5m55iU 2pgovs0l7s8rpbQErm97v8SSSiJOePLxzMRFuVoA3iBlqMn5xO4w9iiwf4+Wd3MX w== Received: from iadpaimrmta03.imrmtpd1.prodappiadaev1.oraclevcn.com (iadpaimrmta03.appoci.oracle.com [130.35.103.27]) by mx0b-00069f02.pphosted.com (PPS) with ESMTPS id 4b106cb0t4-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Mon, 15 Dec 2025 23:41:44 +0000 (GMT) Received: from pps.filterd (iadpaimrmta03.imrmtpd1.prodappiadaev1.oraclevcn.com [127.0.0.1]) by iadpaimrmta03.imrmtpd1.prodappiadaev1.oraclevcn.com (8.18.1.2/8.18.1.2) with ESMTP id 5BFLGb7v016716; Mon, 15 Dec 2025 23:41:43 GMT Received: from pps.reinject (localhost [127.0.0.1]) by iadpaimrmta03.imrmtpd1.prodappiadaev1.oraclevcn.com (PPS) with ESMTPS id 4b0xkk3ajt-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Mon, 15 Dec 2025 23:41:43 +0000 Received: from iadpaimrmta03.imrmtpd1.prodappiadaev1.oraclevcn.com (iadpaimrmta03.imrmtpd1.prodappiadaev1.oraclevcn.com [127.0.0.1]) by pps.reinject (8.17.1.5/8.17.1.5) with ESMTP id 5BFNfgS0031766; Mon, 15 Dec 2025 23:41:42 GMT Received: from bur-virt-x6-2-100.us.oracle.com (bur-virt-x6-2-100.us.oracle.com [10.153.92.40]) by iadpaimrmta03.imrmtpd1.prodappiadaev1.oraclevcn.com (PPS) with ESMTPS id 4b0xkk3ajf-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Mon, 15 Dec 2025 23:41:42 +0000 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@oracle.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, andrew.cooper3@citrix.com, trenchboot-devel@googlegroups.com Subject: [PATCH v15 27/28] x86: Secure Launch late initcall platform module Date: Mon, 15 Dec 2025 15:33:15 -0800 Message-ID: <20251215233316.1076248-28-ross.philipson@oracle.com> X-Mailer: git-send-email 2.43.7 In-Reply-To: <20251215233316.1076248-1-ross.philipson@oracle.com> References: <20251215233316.1076248-1-ross.philipson@oracle.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.9,FMLib:17.12.100.49 definitions=2025-12-15_05,2025-12-15_03,2025-10-01_01 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 bulkscore=0 adultscore=0 mlxscore=0 suspectscore=0 phishscore=0 malwarescore=0 spamscore=0 mlxlogscore=999 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2510240000 definitions=main-2512150204 X-Proofpoint-ORIG-GUID: jakxJ0Qw0xTZQwYMXgboIoHX3OltLxxx X-Proofpoint-GUID: jakxJ0Qw0xTZQwYMXgboIoHX3OltLxxx X-Authority-Analysis: v=2.4 cv=et/SD4pX c=1 sm=1 tr=0 ts=69409cb8 b=1 cx=c_pps a=qoll8+KPOyaMroiJ2sR5sw==:117 a=qoll8+KPOyaMroiJ2sR5sw==:17 a=wP3pNCr1ah4A:10 a=VkNPw1HP01LnGYTKEx00:22 a=UN5060LkAAAA:8 a=C00ya6o1AAAA:8 a=yPCof4ZbAAAA:8 a=4Rqr_bL3mzIkAt31FOEA:9 a=E6eXv-vVeS7VqOnxGRGn:22 a=2yVXQu1BIle7vNODk0KG:22 cc=ntf awl=host:12110 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjUxMjE1MDIwNCBTYWx0ZWRfX3Pz/JIo8vNfS YdG1t2IQVTVKIUc5xMrKqeIe5FRXPocuW01OsZK9ULPqkTOMP1xukczf7IojeQqJOShNNHjmlZB teOT1K5LRol0+eHHaIHPxaDemxfuta1jyZYRYiqHSmrVpkmsgy6XdjdU8dKu/s/mY3j4iHrXNPr 1mXG218Won4tbJMpSYT5i/usDwpRDxkuj14Vlyt/0at3U/RT8xVFPHsBfZKge1KgbDpFdg5szyZ 7NM4R08fJ8MY5zsl96A7n3HfrpHx24Q2mzPD3mfjMJbZbFKBUdXtyZX+E+AfGJzjwNoJs1BUXu3 yDSRbCMOLabROPZTKECjRer7qzwGdYZWRJdgSB21U6bJExH7H9u3J1zRIgI2PFpxilNFWs2lJtZ Bp5if7E7asXf9M2PTN8s6LwnXmR6EXGZvk5NWVYz8FbUh8LKF40= Content-Type: text/plain; charset="utf-8" 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 events to the DRTM TPM event log. In addition, on Intel, access to TXT register fields is made available for reading. Signed-off-by: Daniel P. Smith Signed-off-by: garnetgrimm Signed-off-by: Ross Philipson --- arch/x86/kernel/Makefile | 1 + arch/x86/kernel/slmodule.c | 348 +++++++++++++++++++++++++++++++++++++ 2 files changed, 349 insertions(+) create mode 100644 arch/x86/kernel/slmodule.c diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 36ea2c12deed..c2025c8eac25 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -83,6 +83,7 @@ obj-$(CONFIG_IA32_EMULATION) +=3D tls.o obj-y +=3D step.o obj-$(CONFIG_INTEL_TXT) +=3D tboot.o obj-$(CONFIG_SECURE_LAUNCH) +=3D slaunch.o +obj-$(CONFIG_SECURE_LAUNCH) +=3D slmodule.o obj-$(CONFIG_ISA_DMA_API) +=3D i8237.o obj-y +=3D stacktrace.o obj-y +=3D cpu/ diff --git a/arch/x86/kernel/slmodule.c b/arch/x86/kernel/slmodule.c new file mode 100644 index 000000000000..407288c6c2d5 --- /dev/null +++ b/arch/x86/kernel/slmodule.c @@ -0,0 +1,348 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Secure Launch late validation/setup, securityfs exposure and finalizati= on. + * + * Copyright (c) 2025 Apertus Solutions, LLC + * Copyright (c) 2025 Assured Information Security, Inc. + * Copyright (c) 2025, 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 + +/* + * 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 =3D 0; \ + void __iomem *txt; \ + \ + txt =3D 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 =3D { \ + .read =3D 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 =3D { "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 =3D 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 =3D -EINVAL; + if (*ppos !=3D 0) + goto out; + + data =3D memdup_user(buf, datalen); + if (IS_ERR(data)) { + result =3D PTR_ERR(data); + goto out; + } + + mutex_lock(&sl_evt_log_mutex); + if (evtlog21) + result =3D tpm2_log_event(evtlog21, sl_evtlog.addr, + sl_evtlog.size, datalen, data); + else + result =3D 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 =3D { + .read =3D sl_evtlog_read, + .write =3D sl_evtlog_write, + .llseek =3D 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[] =3D { + { "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 =3D 0; + int i; + + slaunch_dir =3D 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 =3D securityfs_create_dir("txt", slaunch_dir); + if (IS_ERR(txt_dir)) { + ret =3D PTR_ERR(txt_dir); + goto remove_slaunch; + } + + for (i =3D 0; i < ARRAY_SIZE(sl_txt_files); i++) { + txt_entries[i] =3D + securityfs_create_file(sl_txt_files[i].name, 0440, txt_dir, + NULL, sl_txt_files[i].fops); + if (IS_ERR(txt_entries[i])) { + ret =3D PTR_ERR(txt_entries[i]); + goto remove_files; + } + } + } + + if (sl_evtlog.addr) { + event_file =3D securityfs_create_file(sl_evtlog.name, 0440, + slaunch_dir, NULL, + &sl_evtlog_ops); + if (IS_ERR(event_file)) { + ret =3D PTR_ERR(event_file); + goto remove_files; + } + } + + return 0; + +remove_files: + if (slaunch_get_flags() & SL_FLAG_ARCH_TXT) { + while (--i >=3D 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 =3D NULL; + } + sl_evtlog.size =3D 0; + + if (slaunch_get_flags() & SL_FLAG_ARCH_TXT) { + for (i =3D 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 =3D NULL; + } + } + + securityfs_remove(slaunch_dir); +} + +static void 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 =3D memremap(base, size, MEMREMAP_WB); + if (!txt_heap) + slaunch_reset(txt, "Error failed to memremap TXT heap\n", SL_ERROR_HEAP_= MAP); + + params =3D (struct txt_os_mle_data *)txt_os_mle_data_start(txt_heap); + + /* Get the SLRT and remap it */ + slrt =3D memremap(params->slrt, sizeof(*slrt), MEMREMAP_WB); + if (!slrt) + slaunch_reset(txt, "Error failed to memremap SLR Table\n", SL_ERROR_SLRT= _MAP); + size =3D slrt->size; + memunmap(slrt); + + slrt =3D memremap(params->slrt, size, MEMREMAP_WB); + if (!slrt) + slaunch_reset(txt, "Error failed to memremap SLR Table\n", SL_ERROR_SLRT= _MAP); + + log_info =3D slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_LOG_INFO); + if (!log_info) + slaunch_reset(txt, "Error failed to memremap SLR Table\n", SL_ERROR_SLRT= _MISSING_ENTRY); + + sl_evtlog.size =3D log_info->size; + sl_evtlog.addr =3D memremap(log_info->addr, log_info->size, MEMREMAP_WB); + if (!sl_evtlog.addr) + slaunch_reset(txt, "Error failed to memremap TPM event log\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 =3D txt_os_sinit_data_start(txt_heap); + + evtlog21 =3D 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 failed to find TPM20 event log element\n", SL_= ERROR_TPM_INVALID_LOG20); + + /* Save pointer to the EFI SpecID log header */ + efi_head =3D (struct tcg_efi_specid_event_head *)(sl_evtlog.addr + sizeof= (struct tcg_pcr_event)); +} + +static void slaunch_tpm_open_locality2(void __iomem *txt) +{ + struct tpm_chip *tpm; + int rc; + + tpm =3D tpm_default_chip(); + if (!tpm) + slaunch_reset(txt, "Could not get default TPM chip\n", SL_ERROR_TPM_INIT= ); + + rc =3D tpm_chip_set_locality(tpm, 2); + if (rc) + slaunch_reset(txt, "Could not set TPM chip locality 2\n", SL_ERROR_TPM_I= NIT); +} + +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)) !=3D + (SL_FLAG_ACTIVE | SL_FLAG_ARCH_TXT)) + return 0; + + txt =3D 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); --=20 2.43.7