From: Cedric Xing <cedric.xing@intel.com>
To: Dan Williams <dan.j.williams@intel.com>,
"Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>,
Dave Hansen <dave.hansen@linux.intel.com>,
Thomas Gleixner <tglx@linutronix.de>,
Ingo Molnar <mingo@redhat.com>, Borislav Petkov <bp@alien8.de>,
x86@kernel.org, "H. Peter Anvin" <hpa@zytor.com>
Cc: linux-kernel@vger.kernel.org, linux-coco@lists.linux.dev,
Dionna Amalie Glaze <dionnaglaze@google.com>,
Guorui Yu <guorui.yu@linux.alibaba.com>,
James Bottomley <James.Bottomley@HansenPartnership.com>,
Dan Middleton <dan.middleton@linux.intel.com>,
Mikko Ylinen <mikko.ylinen@linux.intel.com>,
Sathyanarayanan Kuppuswamy
<sathyanarayanan.kuppuswamy@linux.intel.com>
Subject: [PATCH v3 5/5] virt: tdx-guest: Expose TDX MRs as sysfs attributes
Date: Mon, 07 Apr 2025 13:59:32 -0500 [thread overview]
Message-ID: <20250407-tdx-rtmr-v3-5-54f17bc65228@intel.com> (raw)
In-Reply-To: <20250407-tdx-rtmr-v3-0-54f17bc65228@intel.com>
Expose the most commonly used TDX MRs (Measurement Registers) as sysfs
attributes. Use the ioctl() interface of /dev/tdx_guest to request a full
TDREPORT for access to other TD measurements.
Directory structure of TDX MRs inside a TDVM is as follows:
/sys/class/misc/tdx_guest
└── mr
├── mrconfigid
├── mrowner
├── mrownerconfig
├── mrtd:sha384
├── rtmr0:sha384
├── rtmr1:sha384
├── rtmr2:sha384
└── rtmr3:sha384
Read the file/attribute to retrieve the current value of an MR. Write to
the file/attribute (if writable) to extend the corresponding RTMR. Refer to
Documentation/ABI/testing/sysfs-devices-virtual-misc-tdx_guest-mr for more
information.
Signed-off-by: Cedric Xing <cedric.xing@intel.com>
---
.../sysfs-devices-virtual-misc-tdx_guest-mr | 48 ++++++
MAINTAINERS | 1 +
drivers/virt/coco/tdx-guest/Kconfig | 1 +
drivers/virt/coco/tdx-guest/tdx-guest.c | 169 ++++++++++++++++++++-
4 files changed, 217 insertions(+), 2 deletions(-)
diff --git a/Documentation/ABI/testing/sysfs-devices-virtual-misc-tdx_guest-mr b/Documentation/ABI/testing/sysfs-devices-virtual-misc-tdx_guest-mr
new file mode 100644
index 000000000000..682b2973737a
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-devices-virtual-misc-tdx_guest-mr
@@ -0,0 +1,48 @@
+What: /sys/devices/virtual/misc/tdx_guest/mr/MRNAME[:HASH]
+Date: April, 2025
+KernelVersion: v6.16
+Contact: linux-coco@lists.linux.dev
+Description:
+ Value of a TDX measurement register (MR). MRNAME and HASH above
+ are placeholders. The optional suffix :HASH is used for MRs
+ that have associated hash algorithms. See below for a complete
+ list of TDX MRs exposed via sysfs. Comprehensive information is
+ available at https://intel.com/tdx
+
+What: /sys/devices/virtual/misc/tdx_guest/mr/mrconfigid
+Date: April, 2025
+KernelVersion: v6.16
+Contact: cedric.xing@intel.com
+Description:
+ (RO) Value of MRCONFIGID - immutable storage for SW use.
+
+What: /sys/devices/virtual/misc/tdx_guest/mr/mrowner
+Date: April, 2025
+KernelVersion: v6.16
+Contact: cedric.xing@intel.com
+Description:
+ (RO) Value of MROWNER - immutable storage for SW use.
+
+What: /sys/devices/virtual/misc/tdx_guest/mr/mrownerconfig
+Date: April, 2025
+KernelVersion: v6.16
+Contact: cedric.xing@intel.com
+Description:
+ (RO) Value of MROWNERCONFIG - immutable storage for SW use.
+
+What: /sys/devices/virtual/misc/tdx_guest/mr/mrtd:sha384
+Date: April, 2025
+KernelVersion: v6.16
+Contact: cedric.xing@intel.com
+Description:
+ (RO) Value of MRTD - the measurement of the initial memory
+ image of the current TD.
+
+What: /sys/devices/virtual/misc/tdx_guest/mr/rtmr[0123]:sha384
+Date: April, 2025
+KernelVersion: v6.16
+Contact: cedric.xing@intel.com
+Description:
+ (RW) Read returns the current value of the RTMR. Write extends
+ the written buffer to the RTMR. All writes must start at offset
+ 0 and be 48 bytes in size. Partial writes are not supported.
diff --git a/MAINTAINERS b/MAINTAINERS
index b210ac3389a7..c702f456643a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -26226,6 +26226,7 @@ L: x86@kernel.org
L: linux-coco@lists.linux.dev
S: Supported
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/tdx
+F: Documentation/ABI/testing/sysfs-devices-virtual-misc-tdx_guest-mr
F: arch/x86/boot/compressed/tdx*
F: arch/x86/coco/tdx/
F: arch/x86/include/asm/shared/tdx.h
diff --git a/drivers/virt/coco/tdx-guest/Kconfig b/drivers/virt/coco/tdx-guest/Kconfig
index 22dd59e19431..dbbdc14383b1 100644
--- a/drivers/virt/coco/tdx-guest/Kconfig
+++ b/drivers/virt/coco/tdx-guest/Kconfig
@@ -2,6 +2,7 @@ config TDX_GUEST_DRIVER
tristate "TDX Guest driver"
depends on INTEL_TDX_GUEST
select TSM_REPORTS
+ select TSM_MEASUREMENTS
help
The driver provides userspace interface to communicate with
the TDX module to request the TDX guest details like attestation
diff --git a/drivers/virt/coco/tdx-guest/tdx-guest.c b/drivers/virt/coco/tdx-guest/tdx-guest.c
index 224e7dde9cde..1160f861c027 100644
--- a/drivers/virt/coco/tdx-guest/tdx-guest.c
+++ b/drivers/virt/coco/tdx-guest/tdx-guest.c
@@ -5,6 +5,8 @@
* Copyright (C) 2022 Intel Corporation
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/miscdevice.h>
#include <linux/mm.h>
@@ -16,7 +18,7 @@
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/tsm.h>
-#include <linux/sizes.h>
+#include <linux/tsm-mr.h>
#include <uapi/linux/tdx-guest.h>
@@ -86,8 +88,14 @@ static long tdx_get_report0(struct tdx_report_req __user *req)
goto out;
}
+ if (mutex_lock_interruptible("e_lock)) {
+ ret = -EINTR;
+ goto out;
+ }
+
/* Generate TDREPORT0 using "TDG.MR.REPORT" TDCALL */
ret = tdx_mcall_get_report0(reportdata, tdreport);
+ mutex_unlock("e_lock);
if (ret)
goto out;
@@ -285,10 +293,16 @@ static const struct file_operations tdx_guest_fops = {
.unlocked_ioctl = tdx_guest_ioctl,
};
+static const struct attribute_group *tdx_attr_groups[] = {
+ NULL,
+ NULL,
+};
+
static struct miscdevice tdx_misc_dev = {
.name = KBUILD_MODNAME,
.minor = MISC_DYNAMIC_MINOR,
.fops = &tdx_guest_fops,
+ .groups = tdx_attr_groups,
};
static const struct x86_cpu_id tdx_guest_ids[] = {
@@ -304,6 +318,144 @@ static const struct tsm_ops tdx_tsm_ops = {
.report_bin_attr_visible = tdx_report_bin_attr_visible,
};
+enum {
+ TDREPORT_reportdata = 128,
+ TDREPORT_tee_tcb_info = 256,
+ TDREPORT_tdinfo = TDREPORT_tee_tcb_info + 256,
+ TDREPORT_attributes = TDREPORT_tdinfo,
+ TDREPORT_xfam = TDREPORT_attributes + sizeof(u64),
+ TDREPORT_mrtd = TDREPORT_xfam + sizeof(u64),
+ TDREPORT_mrconfigid = TDREPORT_mrtd + SHA384_DIGEST_SIZE,
+ TDREPORT_mrowner = TDREPORT_mrconfigid + SHA384_DIGEST_SIZE,
+ TDREPORT_mrownerconfig = TDREPORT_mrowner + SHA384_DIGEST_SIZE,
+ TDREPORT_rtmr0 = TDREPORT_mrownerconfig + SHA384_DIGEST_SIZE,
+ TDREPORT_rtmr1 = TDREPORT_rtmr0 + SHA384_DIGEST_SIZE,
+ TDREPORT_rtmr2 = TDREPORT_rtmr1 + SHA384_DIGEST_SIZE,
+ TDREPORT_rtmr3 = TDREPORT_rtmr2 + SHA384_DIGEST_SIZE,
+ TDREPORT_servtd_hash = TDREPORT_rtmr3 + SHA384_DIGEST_SIZE,
+};
+
+static u8 tdx_mr_report[TDX_REPORT_LEN] __aligned(TDX_REPORT_LEN);
+
+#define TDX_MR_(r) .mr_value = tdx_mr_report + TDREPORT_##r, TSM_MR_(r, SHA384)
+static const struct tsm_measurement_register tdx_mrs[] = {
+ { TDX_MR_(rtmr0) | TSM_MR_F_RTMR },
+ { TDX_MR_(rtmr1) | TSM_MR_F_RTMR },
+ { TDX_MR_(rtmr2) | TSM_MR_F_RTMR },
+ { TDX_MR_(rtmr3) | TSM_MR_F_RTMR },
+ { TDX_MR_(mrtd) },
+ { TDX_MR_(mrconfigid) | TSM_MR_F_NOHASH },
+ { TDX_MR_(mrowner) | TSM_MR_F_NOHASH },
+ { TDX_MR_(mrownerconfig) | TSM_MR_F_NOHASH },
+};
+#undef TDX_MR_
+
+static int tdx_mr_try_refresh(void)
+{
+ u8 *reportdata, *tdreport;
+ int ret;
+
+ reportdata = tdx_mr_report + TDREPORT_reportdata;
+
+ /*
+ * TDCALL requires a GPA as input. Depending on whether this module is
+ * built as a built-in (Y) or a module (M), tdx_mr_report may or may
+ * not be converted to a GPA using virt_to_phys. If not, a directly
+ * mapped buffer must be allocated using kmalloc and used as an
+ * intermediary.
+ */
+ if (IS_BUILTIN(CONFIG_TDX_GUEST_DRIVER))
+ tdreport = tdx_mr_report;
+ else {
+ /* TDREPORT buffer must be naturally aligned */
+ tdreport = kmalloc(__alignof(tdx_mr_report), GFP_KERNEL);
+ if (!tdreport)
+ return -ENOMEM;
+
+ reportdata = memcpy(tdreport + TDREPORT_reportdata, reportdata,
+ TDX_REPORTDATA_LEN);
+ }
+
+ ret = tdx_mcall_get_report0(reportdata, tdreport);
+ if (ret)
+ pr_err("GetReport call failed\n");
+
+ if (!IS_BUILTIN(CONFIG_TDX_GUEST_DRIVER)) {
+ if (!ret)
+ memcpy(tdx_mr_report, tdreport, sizeof(tdx_mr_report));
+ kfree(tdreport);
+ }
+
+ return ret;
+}
+
+static int tdx_mr_refresh(const struct tsm_measurements *tm,
+ const struct tsm_measurement_register *mr)
+{
+ int ret = -EINTR;
+
+ if (!mutex_lock_interruptible("e_lock)) {
+ ret = tdx_mr_try_refresh();
+ mutex_unlock("e_lock);
+
+ WARN_ON(ret);
+ }
+ return ret;
+}
+
+static int tdx_mr_try_extend(ptrdiff_t mr_ind, const u8 *data)
+{
+#if IS_BUILTIN(CONFIG_TDX_GUEST_DRIVER)
+ /*
+ * TDG.MR.RTMR.EXTEND takes the GPA of a 64-byte aligned buffer on
+ * input. virt_to_phys() works on static buffers only if the current
+ * module is built-in.
+ */
+ static u8 buf[SHA384_DIGEST_SIZE] __aligned(64);
+#else
+ /*
+ * Otherwise, kmalloc() must be used to allocate the 64-byte aligned
+ * input buffer.
+ */
+ u8 *buf __free(kfree) = kmalloc(64, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+#endif
+
+ int ret;
+
+ memcpy(buf, data, SHA384_DIGEST_SIZE);
+
+ ret = tdx_mcall_extend_rtmr((u8)mr_ind, buf);
+ if (ret)
+ pr_err("Extending RTMR%ld failed\n", mr_ind);
+
+ return ret;
+}
+
+static int tdx_mr_extend(const struct tsm_measurements *tm,
+ const struct tsm_measurement_register *mr,
+ const u8 *data)
+{
+ int ret = -EINTR;
+
+ if (!mutex_lock_interruptible("e_lock)) {
+ ret = tdx_mr_try_extend(mr - tm->mrs, data);
+ mutex_unlock("e_lock);
+
+ WARN_ON(ret);
+ }
+ return ret;
+}
+
+static struct tsm_measurements tdx_measurements = {
+ .name = "mr",
+ .mrs = tdx_mrs,
+ .nr_mrs = ARRAY_SIZE(tdx_mrs),
+ .refresh = tdx_mr_refresh,
+ .write = tdx_mr_extend,
+};
+
static int __init tdx_guest_init(void)
{
int ret;
@@ -311,9 +463,19 @@ static int __init tdx_guest_init(void)
if (!x86_match_cpu(tdx_guest_ids))
return -ENODEV;
+ ret = tdx_mr_try_refresh();
+ if (ret) {
+ pr_err("Failed to read MRs: %d\n", ret);
+ return ret;
+ }
+
+ tdx_attr_groups[0] = tsm_mr_create_attribute_group(&tdx_measurements);
+ if (IS_ERR(tdx_attr_groups[0]))
+ return PTR_ERR(tdx_attr_groups[0]);
+
ret = misc_register(&tdx_misc_dev);
if (ret)
- return ret;
+ goto free_tsm_mr;
quote_data = alloc_quote_buf();
if (!quote_data) {
@@ -332,6 +494,8 @@ static int __init tdx_guest_init(void)
free_quote_buf(quote_data);
free_misc:
misc_deregister(&tdx_misc_dev);
+free_tsm_mr:
+ tsm_mr_free_attribute_group(tdx_attr_groups[0]);
return ret;
}
@@ -342,6 +506,7 @@ static void __exit tdx_guest_exit(void)
tsm_unregister(&tdx_tsm_ops);
free_quote_buf(quote_data);
misc_deregister(&tdx_misc_dev);
+ tsm_mr_free_attribute_group(tdx_attr_groups[0]);
}
module_exit(tdx_guest_exit);
--
2.43.0
next prev parent reply other threads:[~2025-04-07 18:59 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-04-07 18:59 [PATCH v3 0/5] tsm-mr: Unified Measurement Register ABI for TVMs Cedric Xing
2025-04-07 18:59 ` [PATCH v3 1/5] tsm-mr: Add TVM Measurement Register support Cedric Xing
2025-04-09 0:27 ` Dan Williams
2025-04-11 4:01 ` Xing, Cedric
2025-04-07 18:59 ` [PATCH v3 2/5] tsm-mr: Add tsm-mr sample code Cedric Xing
2025-04-09 2:11 ` kernel test robot
2025-04-09 4:26 ` Dan Williams
2025-04-07 18:59 ` [PATCH v3 3/5] x86/tdx: Add tdx_mcall_extend_rtmr() interface Cedric Xing
2025-04-09 5:10 ` Dan Williams
2025-04-11 17:49 ` Xing, Cedric
2025-04-07 18:59 ` [PATCH v3 4/5] x86/tdx: tdx_mcall_get_report0: Return -EBUSY on TDCALL_OPERAND_BUSY error Cedric Xing
2025-04-09 5:13 ` Dan Williams
2025-04-11 17:37 ` Xing, Cedric
2025-04-07 18:59 ` Cedric Xing [this message]
2025-04-08 20:21 ` [PATCH v3 0/5] tsm-mr: Unified Measurement Register ABI for TVMs Dan Williams
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250407-tdx-rtmr-v3-5-54f17bc65228@intel.com \
--to=cedric.xing@intel.com \
--cc=James.Bottomley@HansenPartnership.com \
--cc=bp@alien8.de \
--cc=dan.j.williams@intel.com \
--cc=dan.middleton@linux.intel.com \
--cc=dave.hansen@linux.intel.com \
--cc=dionnaglaze@google.com \
--cc=guorui.yu@linux.alibaba.com \
--cc=hpa@zytor.com \
--cc=kirill.shutemov@linux.intel.com \
--cc=linux-coco@lists.linux.dev \
--cc=linux-kernel@vger.kernel.org \
--cc=mikko.ylinen@linux.intel.com \
--cc=mingo@redhat.com \
--cc=sathyanarayanan.kuppuswamy@linux.intel.com \
--cc=tglx@linutronix.de \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®