public inbox for linux-coco@lists.linux.dev
 help / color / mirror / Atom feed
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>,
	 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 v2 4/4] x86/tdx: Expose TDX MRs through TSM sysfs interface
Date: Sun, 23 Feb 2025 21:20:15 -0600	[thread overview]
Message-ID: <20250223-tdx-rtmr-v2-4-f2d85b0a5f94@intel.com> (raw)
In-Reply-To: <20250223-tdx-rtmr-v2-0-f2d85b0a5f94@intel.com>

TDX MRs are made accessible to user mode as files (attributes) in sysfs.

Below shows the directory structure of TDX MRs inside a TDVM.

/sys/kernel/tsm
└── tdx
    ├── mrconfigid
    │   └── sha384
    │       └── digest
    ├── mrowner
    │   └── sha384
    │       └── digest
    ├── mrownerconfig
    │   └── sha384
    │       └── digest
    ├── mrtd
    │   └── sha384
    │       └── digest
    ├── report0
    ├── reportdata
    ├── rtmr0
    │   └── sha384
    │       └── digest
    ├── rtmr1
    │   └── sha384
    │       └── digest
    ├── rtmr2
    │   └── sha384
    │       └── digest
    ├── rtmr3
    │   └── sha384
    │       └── digest
    └── servtd_hash
        └── sha384
            └── digest

The digest attribute/file of each MR contains the MR's current value.

Writing to the digest attribute/file of an RTMR extends the written value
to that RTMR.

The report0 and reportdata attributes offer a simple interface for user
mode applications to request TDREPORTs. These 2 attributes can be
enabled/disabled by setting TDX_GUEST_DRIVER_TSM_REPORT to Y/n.

Signed-off-by: Cedric Xing <cedric.xing@intel.com>
---
 drivers/virt/coco/tdx-guest/Kconfig     |  24 +++++--
 drivers/virt/coco/tdx-guest/tdx-guest.c | 115 ++++++++++++++++++++++++++++++++
 2 files changed, 134 insertions(+), 5 deletions(-)

diff --git a/drivers/virt/coco/tdx-guest/Kconfig b/drivers/virt/coco/tdx-guest/Kconfig
index 22dd59e19431..a1c5e8fdd511 100644
--- a/drivers/virt/coco/tdx-guest/Kconfig
+++ b/drivers/virt/coco/tdx-guest/Kconfig
@@ -3,9 +3,23 @@ config TDX_GUEST_DRIVER
 	depends on INTEL_TDX_GUEST
 	select TSM_REPORTS
 	help
-	  The driver provides userspace interface to communicate with
-	  the TDX module to request the TDX guest details like attestation
-	  report.
+	  The driver provides userspace interface to communicate with the TDX
+	  module to request the TDX guest details like attestation report.
 
-	  To compile this driver as module, choose M here. The module will
-	  be called tdx-guest.
+	  To compile this driver as module, choose M here. The module will be
+	  called tdx-guest.
+
+if TDX_GUEST_DRIVER
+
+config TDX_GUEST_DRIVER_TSM_REPORT
+	bool "tdx-guest: Enable TSM raw TDREPORT interface"
+	default y
+	help
+	  This option adds 2 files, namely report0 and reportdata, to the TSM
+	  sysfs directory tree (/sys/kernel/tsm/tdx/).
+
+	  To request a TDREPORT, set REPORTDATA by writing to
+	  /sys/kernel/tsm/tdx/reportdata, then read
+	  /sys/kernel/tsm/tdx/report0.
+
+endif
diff --git a/drivers/virt/coco/tdx-guest/tdx-guest.c b/drivers/virt/coco/tdx-guest/tdx-guest.c
index 224e7dde9cde..a31fe2098901 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>
@@ -18,6 +20,8 @@
 #include <linux/tsm.h>
 #include <linux/sizes.h>
 
+#include <crypto/hash_info.h>
+
 #include <uapi/linux/tdx-guest.h>
 
 #include <asm/cpu_device_id.h>
@@ -304,6 +308,110 @@ static const struct tsm_ops tdx_tsm_ops = {
 	.report_bin_attr_visible = tdx_report_bin_attr_visible,
 };
 
+enum {
+	TDREPORT_MRSIZE = SHA384_DIGEST_SIZE,
+
+	TDREPORT_reportdata = 128,
+	TDREPORT_tdinfo = 512,
+	TDREPORT_mrtd = TDREPORT_tdinfo + 16,
+	TDREPORT_mrconfigid = TDREPORT_mrtd + TDREPORT_MRSIZE,
+	TDREPORT_mrowner = TDREPORT_mrconfigid + TDREPORT_MRSIZE,
+	TDREPORT_mrownerconfig = TDREPORT_mrowner + TDREPORT_MRSIZE,
+	TDREPORT_rtmr0 = TDREPORT_mrownerconfig + TDREPORT_MRSIZE,
+	TDREPORT_rtmr1 = TDREPORT_rtmr0 + TDREPORT_MRSIZE,
+	TDREPORT_rtmr2 = TDREPORT_rtmr1 + TDREPORT_MRSIZE,
+	TDREPORT_rtmr3 = TDREPORT_rtmr2 + TDREPORT_MRSIZE,
+	TDREPORT_servtd_hash = TDREPORT_rtmr3 + TDREPORT_MRSIZE,
+};
+
+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 | TSM_MR_F_W },
+	{ TDX_MR_(rtmr1) | TSM_MR_F_RTMR | TSM_MR_F_W },
+	{ TDX_MR_(rtmr2) | TSM_MR_F_RTMR | TSM_MR_F_W },
+	{ TDX_MR_(rtmr3) | TSM_MR_F_RTMR | TSM_MR_F_W },
+	{ TDX_MR_(mrtd) },
+	{ TDX_MR_(mrconfigid) },
+	{ TDX_MR_(mrowner) },
+	{ TDX_MR_(mrownerconfig) },
+	{ TDX_MR_(servtd_hash) },
+#if IS_ENABLED(CONFIG_TDX_GUEST_DRIVER_TSM_REPORT)
+	{ .mr_value = tdx_mr_report, .mr_size = sizeof(tdx_mr_report),
+	  .mr_name = "report0", .mr_flags = TSM_MR_F_LIVE | TSM_MR_F_F },
+	{ .mr_value = tdx_mr_report + TDREPORT_reportdata,
+	  TSM_MR_(reportdata, SHA512) | TSM_MR_F_W | TSM_MR_F_F },
+#endif
+	{}
+};
+#undef TDX_MR_
+
+static int tdx_mr_refresh(struct tsm_measurement *tmr,
+			  const struct tsm_measurement_register *mr)
+{
+	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 = kmalloc(sizeof(tdx_mr_report), GFP_KERNEL);
+	if (!tdreport)
+		return -ENOMEM;
+
+	reportdata = memcpy(tdreport + TDREPORT_reportdata, reportdata,
+			    TDX_REPORTDATA_LEN);
+#endif
+
+	ret = tdx_mcall_get_report0(reportdata, tdreport);
+	if (ret)
+		pr_err("GetReport call failed\n");
+
+#if !IS_BUILTIN(CONFIG_TDX_GUEST_DRIVER)
+	memcpy(tdx_mr_report, tdreport, sizeof(tdx_mr_report));
+	kfree(tdreport);
+#endif
+
+	return ret;
+}
+
+static int tdx_mr_extend(struct tsm_measurement *tmr,
+			 const struct tsm_measurement_register *mr, const u8 *data)
+{
+	u8 *buf;
+	int ret;
+
+	buf = kmalloc(64, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	memcpy(buf, data, TDREPORT_MRSIZE);
+
+	ret = tdx_mcall_extend_rtmr((u8)(mr - tmr->mrs), buf);
+	if (ret)
+		pr_err("Extending RTMR%ld failed\n", mr - tmr->mrs);
+
+	kfree(buf);
+	return ret;
+}
+
+static struct tsm_measurement tdx_measurement = {
+	.name = "tdx",
+	.mrs = tdx_mrs,
+	.refresh = tdx_mr_refresh,
+	.extend = tdx_mr_extend,
+};
+
 static int __init tdx_guest_init(void)
 {
 	int ret;
@@ -326,8 +434,14 @@ static int __init tdx_guest_init(void)
 	if (ret)
 		goto free_quote;
 
+	ret = tsm_register_measurement(&tdx_measurement);
+	if (ret)
+		goto unregister_tsm;
+
 	return 0;
 
+unregister_tsm:
+	tsm_unregister(&tdx_tsm_ops);
 free_quote:
 	free_quote_buf(quote_data);
 free_misc:
@@ -339,6 +453,7 @@ module_init(tdx_guest_init);
 
 static void __exit tdx_guest_exit(void)
 {
+	tsm_unregister_measurement(&tdx_measurement);
 	tsm_unregister(&tdx_tsm_ops);
 	free_quote_buf(quote_data);
 	misc_deregister(&tdx_misc_dev);

-- 
2.43.0


  parent reply	other threads:[~2025-02-24  3:22 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-02-24  3:20 [PATCH v2 0/4] tsm: Unified Measurement Register ABI for TVMs Cedric Xing
2025-02-24  3:20 ` [PATCH v2 1/4] tsm: Add TVM Measurement Register support Cedric Xing
2025-03-06  1:20   ` Huang, Kai
2025-03-12 18:26     ` Xing, Cedric
2025-03-12 23:11       ` Huang, Kai
2025-03-17 22:49         ` Xing, Cedric
2025-03-19 11:28           ` Huang, Kai
2025-03-19 14:41             ` Dionna Amalie Glaze
2025-02-24  3:20 ` [PATCH v2 2/4] tsm: Add TSM measurement sample code Cedric Xing
2025-02-24  3:20 ` [PATCH v2 3/4] x86/tdx: Add tdx_mcall_extend_rtmr() interface Cedric Xing
2025-02-24  3:20 ` Cedric Xing [this message]
2025-02-27 22:06 ` [PATCH v2 0/4] tsm: Unified Measurement Register ABI for TVMs Jianxiong Gao
2025-03-17 23:15 ` Sathyanarayanan Kuppuswamy
2025-03-18  3:48   ` Xing, Cedric
2025-03-18 12:44     ` James Bottomley

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=20250223-tdx-rtmr-v2-4-f2d85b0a5f94@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=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