Linux userland API discussions
 help / color / mirror / Atom feed
From: Jiri Pirko <jiri@resnulli.us>
To: linux-coco@lists.linux.dev
Cc: linux-kernel@vger.kernel.org, linux-api@vger.kernel.org,
	x86@kernel.org, kvm@vger.kernel.org, linux-doc@vger.kernel.org,
	jgg@ziepe.ca, david.quigley@intel.com, lukas@wunner.de,
	ksinyuk@kernel.org, rodrigo.vivi@intel.com,
	cedric.xing@intel.com, sameo@meta.com, drdeeglaze@gmail.com,
	James.Bottomley@HansenPartnership.com, aik@amd.com,
	jpiotrowski@nvidia.com, qinkun@google.com, pgonda@google.com,
	jic23@kernel.org, alistair.francis@wdc.com, ankita@nvidia.com,
	suzuki.poulose@arm.com, kas@kernel.org,
	rick.p.edgecombe@intel.com, elena.reshetova@intel.com,
	dave.hansen@linux.intel.com,
	sathyanarayanan.kuppuswamy@linux.intel.com, peter.fang@intel.com
Subject: [PATCH RFC 20/20] attestation: Add the TDX family implementation
Date: Thu, 15 Oct 2026 16:50:53 +0200	[thread overview]
Message-ID: <20261015145053.3664509-21-jiri@resnulli.us> (raw)
In-Reply-To: <20261015145053.3664509-1-jiri@resnulli.us>

From: Jiri Pirko <jiri@nvidia.com>

Connect the attestation family to the native TDX service. Expose
TDREPORT, Quote, MRTD and RTMR operations while preserving the existing
native interfaces.

Assisted-by: Cursor: GPT-5.6 Sol
Assisted-by: Cursor: Claude Opus 5.5
Signed-off-by: Jiri Pirko <jiri@nvidia.com>
---
 Documentation/driver-api/attestation.rst |  16 ++
 drivers/attestation/Kconfig              |  14 ++
 drivers/attestation/Makefile             |   5 +
 drivers/attestation/providers/tdx.c      | 277 +++++++++++++++++++++++
 4 files changed, 312 insertions(+)
 create mode 100644 drivers/attestation/providers/tdx.c

diff --git a/Documentation/driver-api/attestation.rst b/Documentation/driver-api/attestation.rst
index 5ce121ded05f..f253c848e856 100644
--- a/Documentation/driver-api/attestation.rst
+++ b/Documentation/driver-api/attestation.rst
@@ -46,3 +46,19 @@ CTLV first drains userspace operations.  The base ``pre_fini`` callback then
 withdraws the instance from the kernel registry while provider state and CTLV
 event emission remain available.  CTLV stops events only after that callback
 returns; provider and base ``fini`` callbacks may then release native storage.
+
+TDX provider
+============
+
+``CONFIG_ATTESTATION_TDX`` registers a ``ctlv-attestation-tdx`` instance for
+the native TDX guest service.  MRTD has stable MR ID 0 and is read-only.
+RTMR0 through RTMR3 have IDs 1 through 4 and are readable and extendable with
+SHA-384.
+
+``EVIDENCE_GET`` supports complete raw TDREPORT and Quote objects.  Both
+formats cryptographically bind all architectural TDX measurement registers,
+so successful replies carry the matching MR-journal boundary.  The provider
+exposes no verdict or device-security operation.
+
+The provider consumes only ``<linux/tdx-guest.h>``.  It does not call the TDX
+misc ioctl, configfs TSM-report, or TSM-MR sysfs frontends.
diff --git a/drivers/attestation/Kconfig b/drivers/attestation/Kconfig
index e2fb4b4205fe..139bcc710019 100644
--- a/drivers/attestation/Kconfig
+++ b/drivers/attestation/Kconfig
@@ -10,3 +10,17 @@ menuconfig ATTESTATION
 	  translate the common operations to their native service.
 
 	  If you are unsure, say N.
+
+if ATTESTATION
+
+config ATTESTATION_TDX
+	tristate "TDX attestation provider"
+	depends on TDX_GUEST_DRIVER
+	help
+	  Exposes TDREPORT, Quote, MRTD and RTMR operations through the common
+	  attestation CTLV family. The native TDX misc, TSM-report and TSM-MR
+	  interfaces remain available independently.
+
+	  If you are unsure, say N.
+
+endif # ATTESTATION
diff --git a/drivers/attestation/Makefile b/drivers/attestation/Makefile
index e520fee2e90d..d56df9adaa75 100644
--- a/drivers/attestation/Makefile
+++ b/drivers/attestation/Makefile
@@ -3,3 +3,8 @@ obj-$(CONFIG_ATTESTATION) += attestation.o
 
 attestation-y := core/core.o core/ctlv.o core/events.o core/mr.o \
 		 generated/ctlv_attestation_gen.o
+
+obj-$(CONFIG_ATTESTATION_TDX) += attestation-tdx.o
+
+attestation-tdx-y := providers/tdx.o \
+		     generated/ctlv_attestation_tdx_gen.o
diff --git a/drivers/attestation/providers/tdx.c b/drivers/attestation/providers/tdx.c
new file mode 100644
index 000000000000..9b41b985c783
--- /dev/null
+++ b/drivers/attestation/providers/tdx.c
@@ -0,0 +1,277 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <crypto/sha2.h>
+#include <linux/attestation.h>
+#include <linux/ctlv.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/tdx-guest.h>
+
+#include "../generated/ctlv_attestation_tdx_gen.h"
+
+struct attestation_tdx_init_info {
+	struct device *parent_dev;
+	const struct tdx_guest_ops *ops;
+};
+
+struct attestation_tdx {
+	struct device *parent_dev;
+	const struct tdx_guest_ops *ops;
+};
+
+static const enum hash_algo attestation_tdx_algorithms[] = {
+	HASH_ALGO_SHA384,
+};
+
+static const struct attestation_mr_props attestation_tdx_mrs[] = {
+	{
+		.id = 0,
+		.name = "mrtd",
+		.algorithms = attestation_tdx_algorithms,
+		.algorithms_count = ARRAY_SIZE(attestation_tdx_algorithms),
+		.readable = true,
+	},
+	{
+		.id = 1,
+		.name = "rtmr0",
+		.algorithms = attestation_tdx_algorithms,
+		.algorithms_count = ARRAY_SIZE(attestation_tdx_algorithms),
+		.has_register_index = true,
+		.register_index = 0,
+		.readable = true,
+		.extendable = true,
+	},
+	{
+		.id = 2,
+		.name = "rtmr1",
+		.algorithms = attestation_tdx_algorithms,
+		.algorithms_count = ARRAY_SIZE(attestation_tdx_algorithms),
+		.has_register_index = true,
+		.register_index = 1,
+		.readable = true,
+		.extendable = true,
+	},
+	{
+		.id = 3,
+		.name = "rtmr2",
+		.algorithms = attestation_tdx_algorithms,
+		.algorithms_count = ARRAY_SIZE(attestation_tdx_algorithms),
+		.has_register_index = true,
+		.register_index = 2,
+		.readable = true,
+		.extendable = true,
+	},
+	{
+		.id = 4,
+		.name = "rtmr3",
+		.algorithms = attestation_tdx_algorithms,
+		.algorithms_count = ARRAY_SIZE(attestation_tdx_algorithms),
+		.has_register_index = true,
+		.register_index = 3,
+		.readable = true,
+		.extendable = true,
+	},
+};
+
+static const struct attestation_evidence_supported_object
+attestation_tdx_evidence_objects[] = {
+	{
+		.format = "tdx-tdreport-1.0",
+		.max_length = TDX_GUEST_REPORT_LEN,
+		.binds_mrs = true,
+	},
+	{
+		.format = "tdx-quote-1.0",
+		.max_length = TDX_GUEST_QUOTE_MAX_LEN,
+		.binds_mrs = true,
+	},
+};
+
+static const struct attestation_evidence_caps attestation_tdx_evidence_caps = {
+	.min_challenge_length = TDX_GUEST_REPORTDATA_LEN,
+	.max_challenge_length = TDX_GUEST_REPORTDATA_LEN,
+	.max_total_output_length = TDX_GUEST_QUOTE_MAX_LEN,
+	.objects = attestation_tdx_evidence_objects,
+	.objects_count = ARRAY_SIZE(attestation_tdx_evidence_objects),
+};
+
+static int
+attestation_tdx_evidence_get(struct attestation *att,
+			     const struct attestation_evidence_request *request,
+			     struct attestation_evidence_result *result)
+{
+	const struct attestation_evidence_object_request *object;
+	struct attestation_tdx *tdx = ctlv_priv_child(att);
+	size_t length;
+	void *buffer;
+	int ret;
+
+	if (request->objects_count != 1)
+		return -EOPNOTSUPP;
+	object = &request->objects[0];
+	buffer = kvmalloc(object->supported_object->max_length, GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+	if (object->supported_object == &attestation_tdx_evidence_objects[0])
+		ret = tdx->ops->report_get(tdx->parent_dev,
+			request->challenge,
+			request->challenge_length, buffer,
+			object->supported_object->max_length, &length);
+	else if (object->supported_object ==
+		 &attestation_tdx_evidence_objects[1])
+		ret = tdx->ops->quote_get(tdx->parent_dev,
+			request->challenge,
+			request->challenge_length, buffer,
+			object->supported_object->max_length, &length);
+	else
+		ret = -EOPNOTSUPP;
+	if (!ret)
+		ret = ctlv_blob_write(object->output, 0, buffer, length);
+	if (!ret)
+		result->object_lengths[0] = length;
+	kvfree(buffer);
+	return ret;
+}
+
+static int attestation_tdx_mr_read(struct attestation *att, unsigned int mr_id,
+				   struct attestation_digest_set *values)
+{
+	static const enum tdx_guest_mr native_mrs[] = {
+		TDX_GUEST_MR_MRTD,
+		TDX_GUEST_MR_RTMR0,
+		TDX_GUEST_MR_RTMR1,
+		TDX_GUEST_MR_RTMR2,
+		TDX_GUEST_MR_RTMR3,
+	};
+	struct attestation_tdx *tdx = ctlv_priv_child(att);
+
+	if (mr_id >= ARRAY_SIZE(native_mrs) ||
+	    values->values_count != 1 ||
+	    values->values[0].algorithm != HASH_ALGO_SHA384)
+		return -EINVAL;
+	return tdx->ops->mr_read(tdx->parent_dev, native_mrs[mr_id],
+		values->values[0].data);
+}
+
+static int
+attestation_tdx_mr_extend(struct attestation *att, unsigned int mr_id,
+			  const struct attestation_digest_set *values)
+{
+	struct attestation_tdx *tdx = ctlv_priv_child(att);
+
+	if (mr_id < 1 || mr_id > 4)
+		return -EOPNOTSUPP;
+	if (values->values_count != 1 ||
+	    values->values[0].algorithm != HASH_ALGO_SHA384)
+		return -EINVAL;
+	return tdx->ops->rtmr_extend(tdx->parent_dev, mr_id - 1,
+				     values->values[0].data);
+}
+
+static const struct attestation_provider attestation_tdx_provider = {
+	.evidence_get = attestation_tdx_evidence_get,
+	.mr_read = attestation_tdx_mr_read,
+	.mr_extend = attestation_tdx_mr_extend,
+	.evidence_caps = &attestation_tdx_evidence_caps,
+	.mrs = attestation_tdx_mrs,
+	.mrs_count = ARRAY_SIZE(attestation_tdx_mrs),
+};
+
+size_t ctlv_attestation_tdx_priv_size(void)
+{
+	return sizeof(struct attestation_tdx);
+}
+
+const void *ctlv_attestation_tdx_pre_init(const void *init_info)
+{
+	return &attestation_tdx_provider;
+}
+
+int ctlv_attestation_tdx_init(struct ctlv_device *ctlvdev,
+			      const void *init_info, void *priv)
+{
+	const struct attestation_tdx_init_info *info = init_info;
+	struct attestation_tdx *tdx = priv;
+
+	if (!info || !info->parent_dev || !info->ops)
+		return -EINVAL;
+	tdx->parent_dev = info->parent_dev;
+	tdx->ops = info->ops;
+	return 0;
+}
+
+void ctlv_attestation_tdx_fini(struct ctlv_device *ctlvdev, void *priv)
+{
+}
+
+int ctlv_attestation_tdx_op_pre(void *priv, struct ctlv_op_ctx *ctx)
+{
+	return ctlv_attestation_op_pre(ctlv_priv_parent(priv), ctx);
+}
+
+void ctlv_attestation_tdx_op_post(void *priv, struct ctlv_op_ctx *ctx)
+{
+	ctlv_attestation_op_post(ctlv_priv_parent(priv), ctx);
+}
+
+int ctlv_attestation_tdx_device_info_fill(void *priv,
+					  struct ctlv_op_ctx *ctx,
+					  const struct ctlv_cursor *request,
+					  struct ctlv_cursor *nest)
+{
+	struct attestation_tdx *tdx = priv;
+	const struct tdx_guest_info *info =
+		tdx->ops->info_get(tdx->parent_dev);
+	bool ok;
+
+	if (!info)
+		return -ENODEV;
+	ok = ctlv_attestation_tdx_info_mrconfigid_put(nest, info->mrconfigid,
+						      sizeof(info->mrconfigid));
+	ok &= ctlv_attestation_tdx_info_mrowner_put(nest, info->mrowner,
+						    sizeof(info->mrowner));
+	ok &= ctlv_attestation_tdx_info_mrownerconfig_put(nest,
+							   info->mrownerconfig,
+							   sizeof(info->mrownerconfig));
+	return ok ? 0 : -EMSGSIZE;
+}
+
+static void *attestation_tdx_add(struct device *parent_dev,
+				 const struct tdx_guest_ops *ops)
+{
+	struct attestation_tdx_init_info info = {
+		.parent_dev = parent_dev,
+		.ops = ops,
+	};
+
+	return ctlv_create(parent_dev, &ctlv_attestation_tdx_family,
+			   &info);
+}
+
+static void attestation_tdx_remove(void *client_priv)
+{
+	ctlv_destroy(client_priv);
+}
+
+static const struct tdx_guest_client attestation_tdx_client = {
+	.add = attestation_tdx_add,
+	.remove = attestation_tdx_remove,
+};
+
+static int __init attestation_tdx_init_module(void)
+{
+	return tdx_guest_client_register(&attestation_tdx_client);
+}
+
+static void __exit attestation_tdx_exit_module(void)
+{
+	tdx_guest_client_unregister(&attestation_tdx_client);
+}
+
+module_init(attestation_tdx_init_module);
+module_exit(attestation_tdx_exit_module);
+MODULE_DESCRIPTION("TDX attestation provider");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("ATTESTATION");
+MODULE_IMPORT_NS("CTLV");
+MODULE_IMPORT_NS("TDX_GUEST");
-- 
2.56.0


      parent reply	other threads:[~2026-10-15 14:52 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-15 14:50 [PATCH RFC 00/20] attestation: Add a common subsystem and TDX support Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 01/20] ctlv: Add the schema language and generator Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 02/20] ctlv: Add the UAPI wire format and family API Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 03/20] ctlv: Add the root family specification and generated files Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 04/20] Documentation: ctlv: Add userspace ABI Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 05/20] ctlv: Prepare message input handling Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 06/20] ctlv: Prepare blob descriptor validation Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 07/20] ctlv: Prepare schema validation Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 08/20] ctlv: Prepare message output handling Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 09/20] ctlv: Prepare VA blob handling Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 10/20] ctlv: Prepare event queue support Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 11/20] ctlv: Prepare runtime introspection Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 12/20] ctlv: Add device and operation dispatch Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 13/20] Documentation: ctlv: Describe how to write a family Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 14/20] attestation: Add the base family specification and generated files Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 15/20] attestation: Prepare provider and instance core Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 16/20] attestation: Prepare measurement register journal Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 17/20] attestation: Add CTLV operation handling Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 18/20] tdx-guest: Expose the native attestation service API Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 19/20] attestation: Add the TDX family specification and generated files Jiri Pirko
2026-10-15 14:50 ` Jiri Pirko [this message]

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=20261015145053.3664509-21-jiri@resnulli.us \
    --to=jiri@resnulli.us \
    --cc=James.Bottomley@HansenPartnership.com \
    --cc=aik@amd.com \
    --cc=alistair.francis@wdc.com \
    --cc=ankita@nvidia.com \
    --cc=cedric.xing@intel.com \
    --cc=dave.hansen@linux.intel.com \
    --cc=david.quigley@intel.com \
    --cc=drdeeglaze@gmail.com \
    --cc=elena.reshetova@intel.com \
    --cc=jgg@ziepe.ca \
    --cc=jic23@kernel.org \
    --cc=jpiotrowski@nvidia.com \
    --cc=kas@kernel.org \
    --cc=ksinyuk@kernel.org \
    --cc=kvm@vger.kernel.org \
    --cc=linux-api@vger.kernel.org \
    --cc=linux-coco@lists.linux.dev \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lukas@wunner.de \
    --cc=peter.fang@intel.com \
    --cc=pgonda@google.com \
    --cc=qinkun@google.com \
    --cc=rick.p.edgecombe@intel.com \
    --cc=rodrigo.vivi@intel.com \
    --cc=sameo@meta.com \
    --cc=sathyanarayanan.kuppuswamy@linux.intel.com \
    --cc=suzuki.poulose@arm.com \
    --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