[RFC PATCH v1 1/4] tsm: Runtime measurement register support

From: Samuel Ortiz
Date: Sun Jan 14 2024 - 17:37:21 EST


Some confidential computing architecture (Intel TDX, ARM-CCA, RISC-V
CoVE) provide the TVM (confidential computing guest) with a set of
runtime measurement registers (RTMR). TVMs can extend those registers
with their measurements at runtime, i.e. after the TVM initial
measurements are finalized and the TVM actually runs.

RTMRs are separated from the initial measurement registers set, and TSMs
typically includes RTMR values into a distinct section of their signed
attestion reports.

We add support for extending and reading a TSM runtime measurement
registers by extending the TSM ops structure with resp. an rtmr_extend()
and an rtmr_read() function pointers. TSM providers/backends will
implement those ops if they are capable of exposing RTMRs to their
TVMs. This capability is now described by a tsm_capabilites structure,
passed by the TSM provider to the TSM framework at registration time.

TVMs can configure, extend and read RTMRs from the configfs-tsm interface.

Signed-off-by: Samuel Ortiz <sameo@xxxxxxxxxxxx>
---
drivers/virt/coco/tsm.c | 80 +++++++++++++++++++++++++++++++++++++++++
include/linux/tsm.h | 28 ++++++++++++++-
2 files changed, 107 insertions(+), 1 deletion(-)

diff --git a/drivers/virt/coco/tsm.c b/drivers/virt/coco/tsm.c
index d1c2db83a8ca..6b71650271fe 100644
--- a/drivers/virt/coco/tsm.c
+++ b/drivers/virt/coco/tsm.c
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/cleanup.h>
#include <linux/configfs.h>
+#include <linux/tpm.h>

static struct tsm_provider {
const struct tsm_ops *ops;
@@ -50,6 +51,85 @@ enum tsm_data_select {
TSM_CERTS,
};

+/**
+ * DOC: Trusted Security Module (TSM) Runtime Measurement Register (RTMR) Interface
+ *
+ * The TSM RTMR interface is a common ABI for allowing TVMs to extend
+ * and read measurement registers at runtime, i.e. after the TVM initial
+ * measurement is finalized. TSMs that support such capability will typically
+ * include all runtime measurement registers values into their signed
+ * attestation report, providing the TVM post-boot measurements to e.g. remote
+ * attestation services.
+ *
+ * A TVM uses the TSM RTMR configfs ABI to create all runtime measurement
+ * registers (RTMR) that it needs. Each created RTMR must be configured first
+ * before being readable and extensible. TVM configures an RTMR by setting its
+ * index and optionally by mapping it to one or more TCG PCR indexes.
+ *
+ * A TSM backend statically declares the number of RTMRs it supports and which
+ * hash algorithm must be used when extending them. This declaration is done
+ * through the tsm_capabilities structure, at TSM registration time (see
+ * tsm_register()).
+ */
+
+/**
+ * struct tsm_rtmr_state - tracks the state of a TSM RTMR.
+ * @index: The RTMR hardware index.
+ * @alg: The hash algorithm used for this RTMR.
+ * @digest: The RTMR cached digest value.
+ * @cached_digest: Is the RTMR cached digest valid or not.
+ * @cfg: The configfs item for this RTMR.
+ */
+struct tsm_rtmr_state {
+ u32 index;
+ enum hash_algo alg;
+ u8 digest[TSM_DIGEST_MAX];
+ bool cached_digest;
+ struct config_item cfg;
+};
+
+static bool is_rtmr_configured(struct tsm_rtmr_state *rtmr_state)
+{
+ return rtmr_state->index != U32_MAX;
+}
+
+/**
+ * struct tsm_rtmrs_state - tracks the state of all RTMRs for a TSM.
+ * @rtmrs: The array of all created RTMRs.
+ * @tcg_map: A mapping between TCG PCR and RTMRs, indexed by PCR indexes.
+ * Entry `i` on this map points to an RTMR that covers TCG PCR[i] for the TSM
+ * hash algorithm.
+ * @group: The configfs group for a TSM RTMRs.
+ */
+static struct tsm_rtmrs_state {
+ struct tsm_rtmr_state **rtmrs;
+ struct tsm_rtmr_state *tcg_map[TPM2_PLATFORM_PCR];
+ struct config_group *group;
+} *tsm_rtmrs;
+
+static int tsm_rtmr_read(struct tsm_provider *tsm, u32 idx,
+ u8 *digest, size_t digest_size)
+{
+ if (tsm->ops && tsm->ops->rtmr_read)
+ return tsm->ops->rtmr_read(idx, digest, digest_size);
+
+ return -ENXIO;
+}
+
+static int tsm_rtmr_extend(struct tsm_provider *tsm, u32 idx,
+ const u8 *digest, size_t digest_size)
+{
+ if (tsm->ops && tsm->ops->rtmr_extend)
+ return tsm->ops->rtmr_extend(idx, digest, digest_size);
+
+ return -ENXIO;
+}
+
+static struct tsm_rtmr_state *to_tsm_rtmr_state(struct config_item *cfg)
+{
+ return container_of(cfg, struct tsm_rtmr_state, cfg);
+}
+
static struct tsm_report *to_tsm_report(struct config_item *cfg)
{
struct tsm_report_state *state =
diff --git a/include/linux/tsm.h b/include/linux/tsm.h
index de8324a2223c..e912cd665684 100644
--- a/include/linux/tsm.h
+++ b/include/linux/tsm.h
@@ -2,11 +2,13 @@
#ifndef __TSM_H
#define __TSM_H

+#include <crypto/hash_info.h>
#include <linux/sizes.h>
#include <linux/types.h>

#define TSM_INBLOB_MAX 64
#define TSM_OUTBLOB_MAX SZ_32K
+#define TSM_DIGEST_MAX SHA512_DIGEST_SIZE

/*
* Privilege level is a nested permission concept to allow confidential
@@ -42,12 +44,33 @@ struct tsm_report {
u8 *auxblob;
};

+#define TSM_MAX_RTMR 32
+
+/**
+ * struct tsm_capabilities - Describes a TSM capabilities.
+ * @num_rtmrs: The number of Runtime Measurement Registers (RTMR) available from
+ * a TSM.
+ * @rtmr_hash_alg: The hash algorithm used to extend a runtime measurement
+ * register.
+ */
+struct tsm_capabilities {
+ size_t num_rtmrs;
+ enum hash_algo rtmr_hash_alg;
+};
+
/**
* struct tsm_ops - attributes and operations for tsm instances
* @name: tsm id reflected in /sys/kernel/config/tsm/report/$report/provider
* @privlevel_floor: convey base privlevel for nested scenarios
+ * @capabilities: Describe the TSM capabilities, e.g. the number of available
+ * runtime measurement registers (see `struct tsm_capabilities`).
* @report_new: Populate @report with the report blob and auxblob
- * (optional), return 0 on successful population, or -errno otherwise
+ * (optional), return 0 on successful population, or -errno
+ * otherwise
+ * @rtmr_extend: Extend an RTMR with the provided digest.
+ * Return 0 on successful extension, or -errno otherwise.
+ * @rtmr_read: Reads the value of an RTMR.
+ * Return the number of bytes read or -errno for errors.
*
* Implementation specific ops, only one is expected to be registered at
* a time i.e. only one of "sev-guest", "tdx-guest", etc.
@@ -55,7 +78,10 @@ struct tsm_report {
struct tsm_ops {
const char *name;
const unsigned int privlevel_floor;
+ const struct tsm_capabilities capabilities;
int (*report_new)(struct tsm_report *report, void *data);
+ int (*rtmr_extend)(u32 idx, const u8 *digest, size_t digest_size);
+ ssize_t (*rtmr_read)(u32 idx, u8 *digest, size_t digest_size);
};

extern const struct config_item_type tsm_report_default_type;
--
2.42.0