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 17/20] attestation: Add CTLV operation handling
Date: Thu, 15 Oct 2026 16:50:50 +0200	[thread overview]
Message-ID: <20261015145053.3664509-18-jiri@resnulli.us> (raw)
In-Reply-To: <20261015145053.3664509-1-jiri@resnulli.us>

From: Jiri Pirko <jiri@nvidia.com>

Translate CTLV evidence, MR and journal operations to the provider core and
wire the attestation family into the kernel build.

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 |   4 +
 drivers/Kconfig                          |   2 +
 drivers/Makefile                         |   1 +
 drivers/attestation/Makefile             |   3 +-
 drivers/attestation/core/core.c          |   2 +
 drivers/attestation/core/ctlv.c          | 520 +++++++++++++++++++++++
 6 files changed, 531 insertions(+), 1 deletion(-)
 create mode 100644 drivers/attestation/core/ctlv.c

diff --git a/Documentation/driver-api/attestation.rst b/Documentation/driver-api/attestation.rst
index 3cddd853aaa0..5ce121ded05f 100644
--- a/Documentation/driver-api/attestation.rst
+++ b/Documentation/driver-api/attestation.rst
@@ -35,6 +35,10 @@ and event before invoking ``mr_extend``.  A successful callback is followed
 only by infallible publication, so userspace observes the same ordered
 journal.
 
+``MR_READ`` uses ``mr_read_generation`` only to validate query continuation;
+the returned ``mr.generation`` is the journal boundary at which the values
+were read.
+
 Teardown
 ========
 
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 9acc7f74c5c8..971db1f0192c 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -27,6 +27,8 @@ source "drivers/connector/Kconfig"
 
 source "drivers/ctlv/Kconfig"
 
+source "drivers/attestation/Kconfig"
+
 source "drivers/firmware/Kconfig"
 
 source "drivers/fwctl/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index f2c0c3a367ea..2b4dfc8e256b 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -136,6 +136,7 @@ obj-$(CONFIG_INFINIBAND)	+= infiniband/
 obj-y				+= firmware/
 obj-$(CONFIG_FWCTL)		+= fwctl/
 obj-$(CONFIG_CTLV)		+= ctlv/
+obj-$(CONFIG_ATTESTATION)	+= attestation/
 obj-$(CONFIG_CRYPTO)		+= crypto/
 obj-$(CONFIG_SUPERH)		+= sh/
 obj-y				+= clocksource/
diff --git a/drivers/attestation/Makefile b/drivers/attestation/Makefile
index e7c9cb2dfec0..e520fee2e90d 100644
--- a/drivers/attestation/Makefile
+++ b/drivers/attestation/Makefile
@@ -1,4 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-$(CONFIG_ATTESTATION) += attestation.o
 
-attestation-y := core/core.o core/events.o core/mr.o
+attestation-y := core/core.o core/ctlv.o core/events.o core/mr.o \
+		 generated/ctlv_attestation_gen.o
diff --git a/drivers/attestation/core/core.c b/drivers/attestation/core/core.c
index 6db8ed093e93..3fb58f344663 100644
--- a/drivers/attestation/core/core.c
+++ b/drivers/attestation/core/core.c
@@ -326,6 +326,7 @@ int ctlv_attestation_op_pre(void *priv, struct ctlv_op_ctx *ctx)
 	}
 	return 0;
 }
+EXPORT_SYMBOL_NS_GPL(ctlv_attestation_op_pre, "ATTESTATION");
 
 void ctlv_attestation_op_post(void *priv, struct ctlv_op_ctx *ctx)
 {
@@ -333,6 +334,7 @@ void ctlv_attestation_op_post(void *priv, struct ctlv_op_ctx *ctx)
 
 	mutex_unlock(&att->lock);
 }
+EXPORT_SYMBOL_NS_GPL(ctlv_attestation_op_post, "ATTESTATION");
 
 static int __init attestation_module_init(void)
 {
diff --git a/drivers/attestation/core/ctlv.c b/drivers/attestation/core/ctlv.c
new file mode 100644
index 000000000000..ff19400843c2
--- /dev/null
+++ b/drivers/attestation/core/ctlv.c
@@ -0,0 +1,520 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <crypto/hash_info.h>
+#include <linux/cleanup.h>
+#include <linux/err.h>
+#include <linux/limits.h>
+#include <linux/slab.h>
+#include <linux/sort.h>
+#include <linux/string.h>
+
+#include "internal.h"
+
+static const struct attestation_evidence_supported_object *
+attestation_evidence_object_find(const struct attestation_evidence_caps *caps, const char *format)
+{
+	size_t index;
+
+	for (index = 0; index < caps->objects_count; index++) {
+		const struct attestation_evidence_supported_object *object = &caps->objects[index];
+
+		if (!strcmp(object->format, format))
+			return object;
+	}
+	return NULL;
+}
+
+static int attestation_device_caps_put(struct attestation *att, struct ctlv_cursor *reply)
+{
+	const struct attestation_provider *provider = att->provider;
+	struct ctlv_cursor caps_nest, group, object;
+	bool ok = true;
+	size_t index;
+	u64 flags;
+
+	if (!ctlv_attestation_device_caps_start(reply, &caps_nest))
+		return -EMSGSIZE;
+	if (provider->evidence_caps) {
+		const struct attestation_evidence_caps *caps = provider->evidence_caps;
+		u64 blob_class = CTLV_ATTESTATION_EVIDENCE_BLOB_CLASS_PRIMARY;
+		u64 representation = CTLV_ATTESTATION_EVIDENCE_REPRESENTATION_RAW;
+		u64 max_output_length = caps->max_total_output_length;
+
+		if (!ctlv_attestation_cap_evidence_start(&caps_nest, &group))
+			return -EMSGSIZE;
+		ok &= ctlv_attestation_cap_min_challenge_length_put(&group,
+								    caps->min_challenge_length);
+		ok &= ctlv_attestation_cap_max_challenge_length_put(&group,
+								    caps->max_challenge_length);
+		ok &= ctlv_attestation_cap_max_total_output_length_put(&group, max_output_length);
+		for (index = 0; index < caps->objects_count; index++) {
+			const struct attestation_evidence_supported_object *cap =
+				&caps->objects[index];
+
+			if (!ctlv_attestation_cap_object_start(&group, &object)) {
+				ok = false;
+				break;
+			}
+			ok &= ctlv_attestation_cap_blob_class_put(&object, blob_class);
+			ok &= ctlv_attestation_cap_format_put(&object, cap->format);
+			ok &= ctlv_attestation_cap_representation_put(&object, representation);
+			ok &= ctlv_attestation_cap_max_length_put(&object, cap->max_length);
+			ctlv_nest_end(&object);
+		}
+		ctlv_nest_end(&group);
+	}
+	if (provider->mrs_count) {
+		if (!ctlv_attestation_cap_mr_start(&caps_nest, &group))
+			return -EMSGSIZE;
+		flags = 0;
+		if (provider->mr_read)
+			flags |= CTLV_ATTESTATION_MR_DEVICE_CAPS_READ;
+		if (provider->mr_extend)
+			flags |= CTLV_ATTESTATION_MR_DEVICE_CAPS_EXTEND;
+		ok &= ctlv_attestation_cap_mr_flags_put(&group, flags);
+		ctlv_nest_end(&group);
+	}
+	ctlv_nest_end(&caps_nest);
+	return ok ? 0 : -EMSGSIZE;
+}
+
+int ctlv_attestation_device_get_action(void *priv, struct ctlv_op_ctx *ctx,
+				       const struct ctlv_cursor *request, struct ctlv_cursor *reply)
+{
+	struct attestation *att = priv;
+	struct ctlv_cursor info;
+	int ret;
+
+	ret = attestation_device_caps_put(att, reply);
+	if (ret)
+		return ret;
+	if (!ctlv_attestation_device_info_start(reply, &info))
+		return -EMSGSIZE;
+	ret = ctlv_stub_fill(ctx, request, &info);
+	ctlv_nest_end(&info);
+	return ret;
+}
+
+static int
+attestation_evidence_decode_objects(struct attestation *att, struct ctlv_op_ctx *ctx,
+				    const struct ctlv_cursor *request,
+				    struct attestation_evidence_request *decoded,
+				    struct attestation_evidence_object_request **objects_out)
+{
+	const struct attestation_evidence_caps *caps = att->provider->evidence_caps;
+	struct attestation_evidence_object_request *objects;
+	struct ctlv_cursor object;
+	size_t count = 0, index = 0, previous;
+
+	ctlv_attestation_evidence_get_evidence_object_for_each(&object, request) count++;
+	objects = kcalloc(count, sizeof(*objects), GFP_KERNEL);
+	if (!objects)
+		return -ENOMEM;
+	ctlv_attestation_evidence_get_evidence_object_for_each(&object, request)
+	{
+		const struct attestation_evidence_supported_object *supported;
+		const char *format;
+		size_t total = 0;
+
+		format = ctlv_attestation_evidence_get_object_evidence_format_get(&object);
+		supported = attestation_evidence_object_find(caps, format);
+		if (!supported) {
+			kfree(objects);
+			return -EOPNOTSUPP;
+		}
+		for (previous = 0; previous < index; previous++)
+			if (objects[previous].supported_object == supported) {
+				kfree(objects);
+				return -EINVAL;
+			}
+		objects[index].supported_object = supported;
+		objects[index].output =
+			ctlv_attestation_evidence_get_object_evidence_data_resolve(ctx, &object);
+		if (IS_ERR(objects[index].output)) {
+			int ret = PTR_ERR(objects[index].output);
+
+			objects[index].output = NULL;
+			while (index)
+				ctlv_blob_put(objects[--index].output);
+			kfree(objects);
+			return ret;
+		}
+		if (ctlv_blob_len(objects[index].output) < supported->max_length) {
+			for (previous = 0; previous <= index; previous++)
+				ctlv_blob_put(objects[previous].output);
+			kfree(objects);
+			return -EMSGSIZE;
+		}
+		for (previous = 0; previous <= index; previous++) {
+			if (check_add_overflow(total, ctlv_blob_len(objects[previous].output),
+					       &total) ||
+			    total > caps->max_total_output_length) {
+				for (previous = 0; previous <= index; previous++)
+					ctlv_blob_put(objects[previous].output);
+				kfree(objects);
+				return -E2BIG;
+			}
+		}
+		index++;
+	}
+	decoded->objects = objects;
+	decoded->objects_count = count;
+	*objects_out = objects;
+	return 0;
+}
+
+static int attestation_evidence_request_decode(struct attestation *att, struct ctlv_op_ctx *ctx,
+					       const struct ctlv_cursor *request,
+					       struct attestation_evidence_request *decoded,
+					       struct attestation_evidence_object_request **objects)
+{
+	const struct attestation_evidence_caps *caps = att->provider->evidence_caps;
+	u32 challenge_length;
+
+	decoded->challenge =
+		ctlv_attestation_evidence_get_evidence_challenge_get(request, &challenge_length);
+	decoded->challenge_length = challenge_length;
+	if (challenge_length < caps->min_challenge_length ||
+	    challenge_length > caps->max_challenge_length)
+		return -EINVAL;
+	return attestation_evidence_decode_objects(att, ctx, request, decoded, objects);
+}
+
+static void attestation_evidence_request_free(struct attestation_evidence_object_request *objects,
+					      size_t count)
+{
+	while (count) {
+		count--;
+		if (objects[count].output)
+			ctlv_blob_put(objects[count].output);
+	}
+	kfree(objects);
+}
+
+int ctlv_attestation_evidence_get_action(void *priv, struct ctlv_op_ctx *ctx,
+					 const struct ctlv_cursor *request,
+					 struct ctlv_cursor *reply)
+{
+	struct attestation_evidence_object_request *objects = NULL;
+	struct attestation_evidence_request decoded = {};
+	struct attestation_evidence_result result = {};
+	struct attestation *att = priv;
+	bool mr_dependent = false;
+	size_t index;
+	int put_ret;
+	int ret;
+
+	ret = attestation_evidence_request_decode(att, ctx, request, &decoded, &objects);
+	if (ret)
+		goto out;
+	result.object_lengths =
+		kcalloc(decoded.objects_count, sizeof(*result.object_lengths), GFP_KERNEL);
+	if (!result.object_lengths) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	for (index = 0; index < decoded.objects_count; index++)
+		mr_dependent |= decoded.objects[index].supported_object->binds_mrs;
+	ret = att->provider->evidence_get(att, &decoded, &result);
+	if (ret)
+		goto out;
+	for (index = 0; index < decoded.objects_count; index++) {
+		if (result.object_lengths[index] >
+			    decoded.objects[index].supported_object->max_length ||
+		    result.object_lengths[index] > ctlv_blob_len(decoded.objects[index].output)) {
+			ret = -E2BIG;
+			goto out;
+		}
+	}
+	for (index = 0; index < decoded.objects_count; index++) {
+		put_ret = ctlv_blob_put(decoded.objects[index].output);
+		objects[index].output = NULL;
+		if (!ret)
+			ret = put_ret;
+	}
+	if (ret)
+		goto out;
+	if (mr_dependent && !ctlv_attestation_mr_generation_put(reply, att->log->generation)) {
+		ret = -EMSGSIZE;
+		goto out;
+	}
+	for (index = 0; index < decoded.objects_count; index++)
+		if (!ctlv_attestation_evidence_object_length_put(reply,
+								 result.object_lengths[index])) {
+			ret = -EMSGSIZE;
+			goto out;
+		}
+out:
+	kfree(result.object_lengths);
+	attestation_evidence_request_free(objects, decoded.objects_count);
+	return ret;
+}
+
+int ctlv_attestation_mr_get_action(void *priv, struct ctlv_op_ctx *ctx,
+				   const struct ctlv_cursor *request, struct ctlv_cursor *reply)
+{
+	struct attestation *att = priv;
+	struct attestation_mr *mr;
+	u64 id = ctlv_attestation_mr_get_mr_id_get(request);
+
+	if (id > UINT_MAX)
+		return -ERANGE;
+	mr = attestation_mr_lookup_live(att, id);
+	return IS_ERR(mr) ? PTR_ERR(mr) : attestation_mr_props_encode(reply, mr, false);
+}
+
+int ctlv_attestation_mr_dump_query(void *priv, struct ctlv_op_ctx *ctx,
+				   const struct ctlv_cursor *request, struct ctlv_cursor *reply)
+{
+	struct attestation *att = priv;
+	struct attestation_mr *mr;
+	struct ctlv_cursor nested;
+	unsigned long id;
+	u64 cursor = ctlv_op_query_cursor(ctx);
+	unsigned int generation = att->log->generation;
+	int ret;
+
+	if (cursor && ctlv_op_query_generation(ctx) != generation)
+		return -ESTALE;
+	id = cursor ? cursor - 1 : 0;
+	mr = xa_find(&att->mrs, &id, UINT_MAX, XA_PRESENT);
+	while (mr) {
+		if (!ctlv_attestation_mr_item_start(reply, &nested))
+			return ctlv_op_query_more(ctx, generation, id + 1);
+		ret = attestation_mr_props_encode(&nested, mr, true);
+		ctlv_nest_end(&nested);
+		if (ret)
+			return ret;
+		mr = xa_find_after(&att->mrs, &id, UINT_MAX, XA_PRESENT);
+	}
+	return ctlv_op_query_done(ctx, generation);
+}
+
+static int attestation_mr_values_put(struct ctlv_cursor *reply,
+				     const struct attestation_digest_set *values)
+{
+	struct ctlv_cursor nested;
+	size_t index;
+	bool ok;
+
+	for (index = 0; index < values->values_count; index++) {
+		const struct attestation_digest *value = &values->values[index];
+		enum hash_algo algorithm = value->algorithm;
+		size_t length = hash_digest_size[algorithm];
+
+		if (!ctlv_attestation_mr_value_start(reply, &nested))
+			return -EMSGSIZE;
+		ok = ctlv_attestation_mr_hash_algo_put(&nested, algorithm);
+		ok &= ctlv_attestation_mr_data_put(&nested, value->data, length);
+		ctlv_nest_end(&nested);
+		if (!ok)
+			return -EMSGSIZE;
+	}
+	return 0;
+}
+
+int ctlv_attestation_mr_read_query(void *priv, struct ctlv_op_ctx *ctx,
+				   const struct ctlv_cursor *request, struct ctlv_cursor *reply)
+{
+	struct attestation_digest_set values = {};
+	struct attestation *att = priv;
+	struct attestation_mr *mr;
+	u64 id;
+	int ret;
+
+	if (ctlv_op_query_cursor(ctx) &&
+	    ctlv_op_query_generation(ctx) != att->mr_read_generation)
+		return -ESTALE;
+	id = ctlv_attestation_mr_read_mr_id_get(request);
+	if (id > UINT_MAX)
+		return -ERANGE;
+	mr = attestation_mr_lookup_live(att, id);
+	if (IS_ERR(mr))
+		return PTR_ERR(mr);
+	if (!mr->props->readable)
+		return -EOPNOTSUPP;
+	values.values_count = mr->props->algorithms_count;
+	values.values = kcalloc(values.values_count, sizeof(*values.values), GFP_KERNEL);
+	if (!values.values)
+		return -ENOMEM;
+	for (id = 0; id < values.values_count; id++)
+		values.values[id].algorithm = mr->props->algorithms[id];
+	ret = att->provider->mr_read(att, mr->props->id, &values);
+	if (!ret)
+		ret = attestation_mr_values_validate(mr, &values);
+	if (!ret && !ctlv_attestation_mr_generation_put(reply, att->log->generation))
+		ret = -EMSGSIZE;
+	if (!ret)
+		ret = attestation_mr_values_put(reply, &values);
+	kfree(values.values);
+	if (ret)
+		return ret;
+	return ctlv_op_query_done(ctx, att->mr_read_generation);
+}
+
+static int attestation_digest_compare(const void *left, const void *right)
+{
+	const struct attestation_digest *a = left;
+	const struct attestation_digest *b = right;
+
+	return (int)a->algorithm - (int)b->algorithm;
+}
+
+static int attestation_mr_extend_decode(const struct ctlv_cursor *request,
+					struct attestation_digest_set *values)
+{
+	struct ctlv_cursor item;
+	size_t count = 0, index = 0;
+
+	ctlv_attestation_mr_extend_mr_value_for_each(&item, request) count++;
+	values->values = kcalloc(count, sizeof(*values->values), GFP_KERNEL);
+	if (!values->values)
+		return -ENOMEM;
+	values->values_count = count;
+	ctlv_attestation_mr_extend_mr_value_for_each(&item, request)
+	{
+		struct attestation_digest *value = &values->values[index++];
+		u32 length;
+		const void *data;
+		u64 algorithm;
+
+		algorithm =
+			ctlv_attestation_mr_extend_value_mr_hash_algo_get(&item);
+		if (algorithm >= HASH_ALGO__LAST || !hash_digest_size[algorithm])
+			return -EINVAL;
+		data = ctlv_attestation_mr_extend_value_mr_data_get(&item, &length);
+		if (length != hash_digest_size[algorithm])
+			return -EINVAL;
+		value->algorithm = algorithm;
+		memcpy(value->data, data, length);
+	}
+	sort(values->values, values->values_count, sizeof(*values->values),
+	     attestation_digest_compare, NULL);
+	return 0;
+}
+
+int ctlv_attestation_mr_extend_action(void *priv, struct ctlv_op_ctx *ctx,
+				      const struct ctlv_cursor *request, struct ctlv_cursor *reply)
+{
+	struct attestation_digest_set values = {};
+	struct attestation_mr_change *change;
+	const struct attestation_mr_log_entry *entry;
+	struct attestation *att = priv;
+	struct attestation_mr *mr;
+	u64 id;
+	int ret;
+
+	id = ctlv_attestation_mr_extend_mr_id_get(request);
+	if (id > UINT_MAX)
+		return -ERANGE;
+	mr = attestation_mr_lookup_live(att, id);
+	if (IS_ERR(mr))
+		return PTR_ERR(mr);
+	if (!mr->props->extendable)
+		return -EOPNOTSUPP;
+	ret = attestation_mr_extend_decode(request, &values);
+	if (ret)
+		goto out_values;
+	ret = attestation_mr_values_validate(mr, &values);
+	if (ret)
+		goto out_values;
+	change = attestation_mr_change_prepare(att, mr, &values);
+	if (IS_ERR(change)) {
+		ret = PTR_ERR(change);
+		goto out_values;
+	}
+	entry = attestation_mr_extend_locked(att, change);
+	if (IS_ERR(entry))
+		ret = PTR_ERR(entry);
+	else if (!ctlv_attestation_mr_generation_put(reply, entry->mr_generation))
+		ret = -EMSGSIZE;
+	attestation_mr_change_free(change);
+out_values:
+	kfree(values.values);
+	return ret;
+}
+
+static bool attestation_log_selected(const unsigned int *ids, size_t count, unsigned int id)
+{
+	size_t index;
+
+	if (!count)
+		return true;
+	for (index = 0; index < count; index++)
+		if (ids[index] == id)
+			return true;
+	return false;
+}
+
+int ctlv_attestation_mr_log_get_query(void *priv, struct ctlv_op_ctx *ctx,
+				      const struct ctlv_cursor *request, struct ctlv_cursor *reply)
+{
+	struct attestation *att = priv;
+	struct attestation_mr_log_entry *entry;
+	struct ctlv_cursor item, nested;
+	unsigned int ids[256];
+	size_t ids_count = 0, index;
+	unsigned int start, end;
+	unsigned long xa_index;
+	u64 boundary;
+	u64 cursor = ctlv_op_query_cursor(ctx);
+	int ret;
+
+	ctlv_attestation_mr_log_get_mr_selection_for_each(&item, request)
+	{
+		u64 id = ctlv_attestation_mr_log_get_selection_mr_id_get(&item);
+
+		if (id > UINT_MAX)
+			return -ERANGE;
+		for (index = 0; index < ids_count; index++)
+			if (ids[index] == id)
+				return -EINVAL;
+		ids[ids_count++] = id;
+	}
+	if (cursor)
+		boundary = ctlv_op_query_generation(ctx);
+	else
+		boundary = att->log->generation;
+	if (boundary > UINT_MAX || boundary > att->log->generation)
+		return -ESTALE;
+	end = boundary;
+	if (ctlv_attestation_mr_log_get_mr_end_generation_present(request)) {
+		u64 requested_end = ctlv_attestation_mr_log_get_mr_end_generation_get(request);
+
+		end = min_t(u64, end, requested_end);
+	}
+	start = 1;
+	if (ctlv_attestation_mr_log_get_mr_start_generation_present(request)) {
+		u64 value = ctlv_attestation_mr_log_get_mr_start_generation_get(request);
+
+		if (value > UINT_MAX)
+			return -EINVAL;
+		start = value;
+	}
+	if (att->log->generation && start > end)
+		return -EINVAL;
+	if (!cursor && att->log->generation) {
+		if (!ctlv_attestation_mr_start_generation_put(reply, start) ||
+		    !ctlv_attestation_mr_end_generation_put(reply, end))
+			return -EMSGSIZE;
+	}
+	xa_index = cursor ? cursor : start;
+	entry = xa_find(&att->log->entries, &xa_index, end, XA_PRESENT);
+	while (entry && !attestation_log_selected(ids, ids_count, entry->mr_id))
+		entry = xa_find_after(&att->log->entries, &xa_index, end, XA_PRESENT);
+	if (!entry)
+		return ctlv_op_query_done(ctx, boundary);
+	if (!cursor)
+		return ctlv_op_query_more(ctx, boundary, entry->mr_generation);
+	if (!ctlv_attestation_log_entry_start(reply, &nested))
+		return -EMSGSIZE;
+	ret = attestation_mr_log_entry_encode(&nested, entry);
+	ctlv_nest_end(&nested);
+	if (ret)
+		return ret;
+	entry = xa_find_after(&att->log->entries, &xa_index, end, XA_PRESENT);
+	while (entry && !attestation_log_selected(ids, ids_count, entry->mr_id))
+		entry = xa_find_after(&att->log->entries, &xa_index, end, XA_PRESENT);
+	if (entry)
+		return ctlv_op_query_more(ctx, boundary, entry->mr_generation);
+	return ctlv_op_query_done(ctx, boundary);
+}
-- 
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 ` Jiri Pirko [this message]
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 ` [PATCH RFC 20/20] attestation: Add the TDX family implementation Jiri Pirko

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-18-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