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

Dionna Amalie Glaze
2024-01-29T16:58:03Z

The rtmr backend doesn't specify the digest size it expects to user
space, so rtmr_extend could be zero-fill, or provide a truncated
update, or be strict and return an error. Should the expected digest
size for writes not also be a RO attribute?

On Sun, Jan 28, 2024 at 1:27 PM Samuel Ortiz <sameo@rivosinc.com> wrote:
>
> 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@rivosinc.com>
> ---
> drivers/virt/coco/tsm.c | 80 +++++++++++++++++++++++++++++++++++++++++
> include/linux/tsm.h | 39 +++++++++++++++++++-
> 2 files changed, 118 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/virt/coco/tsm.c b/drivers/virt/coco/tsm.c
> index d1c2db83a8ca..1a8c3c096120 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;
> + const 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..a546983c24fc 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,44 @@ struct tsm_report {
> u8 *auxblob;
> };
>
> +#define TSM_MAX_RTMR 32
> +
> +/**
> + * struct tsm_rtmr_desc - Describes a TSM Runtime Measurement Register (RTMR).
> + * @hash_alg: The hash algorithm used to extend this runtime measurement
> + * register.
> + * @tcg_pcr_mask: A bit mask of all TCG PCRs mapped to this RTMR.
> + */
> +struct tsm_rtmr_desc {
> + enum hash_algo hash_alg;
> + unsigned long tcg_pcr_mask;
> +};
> +
> +/**
> + * 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;
> + const struct tsm_rtmr_desc *rtmrs;
> +};
> +
> /**
> * 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 +89,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
>

--
-Dionna Glaze, PhD (she/her)