From: Dan Williams <dan.j.williams@intel.com>
To: Alexey Kardashevskiy <aik@amd.com>,
Dan Williams <dan.j.williams@intel.com>,
<linux-coco@lists.linux.dev>
Cc: Kuppuswamy Sathyanarayanan
<sathyanarayanan.kuppuswamy@linux.intel.com>,
Dionna Amalie Glaze <dionnaglaze@google.com>,
James Bottomley <James.Bottomley@hansenpartnership.com>,
Peter Gonda <pgonda@google.com>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
Samuel Ortiz <sameo@rivosinc.com>,
Thomas Gleixner <tglx@linutronix.de>, <peterz@infradead.org>,
<dave.hansen@linux.intel.com>, <bp@alien8.de>
Subject: Re: [PATCH v6 3/7] configfs-tsm: Introduce a shared ABI for attestation reports
Date: Mon, 16 Oct 2023 19:19:33 -0700 [thread overview]
Message-ID: <652def355ef34_f8792949c@dwillia2-mobl3.amr.corp.intel.com.notmuch> (raw)
In-Reply-To: <9b919716-127d-407a-85c2-df81cbbd9ba9@amd.com>
Alexey Kardashevskiy wrote:
[..]
> > +What: /sys/kernel/config/tsm/report/$name/provider
> > +Date: September, 2023
> > +KernelVersion: v6.7
> > +Contact: linux-coco@lists.linux.dev
> > +Description:
> > + (RO) A name for the format-specification of @outblob like
> > + "sev-guest" [1] or "tdx-guest" [2] in the near term, or a
> > + common standard format in the future.
>
> Nit: /sys/kernel/config/tsm/report/report0/provider contains
> "sev_guest", i.e. "_", not "-".
Yes, will fix either with a follow-on or a respin if more feedback
arrives.
>
> > +
> > + [1]: SEV Secure Nested Paging Firmware ABI Specification
> > + Revision 1.55 Table 22
> > + https://www.amd.com/content/dam/amd/en/documents/epyc-technical-docs/specifications/56860.pdf
> > +
> > + [2]: Intel® Trust Domain Extensions Data Center Attestation
> > + Primitives : Quote Generation Library and Quote Verification
> > + Library Revision 0.8 Appendix 4,5
> > + https://download.01.org/intel-sgx/latest/dcap-latest/linux/docs/Intel_TDX_DCAP_Quoting_Library_API.pdf
> > +
> > +What: /sys/kernel/config/tsm/report/$name/generation
> > +Date: September, 2023
> > +KernelVersion: v6.7
> > +Contact: linux-coco@lists.linux.dev
> > +Description:
> > + (RO) The value in this attribute increments each time @inblob or
> > + any option is written. Userspace can detect conflicts by
> > + checking generation before writing to any attribute and making
> > + sure the number of writes matches expectations after reading
> > + @outblob, or it can prevent conflicts by creating a report
> > + instance per requesting context.
> > +
> > +What: /sys/kernel/config/tsm/report/$name/privlevel
> > +Date: September, 2023
> > +KernelVersion: v6.7
> > +Contact: linux-coco@lists.linux.dev
> > +Description:
> > + (WO) Attribute is visible if a TSM implementation provider
> > + supports the concept of attestation reports for TVMs running at
> > + different privilege levels, like SEV-SNP "VMPL", specify the
> > + privilege level via this attribute. The minimum acceptable
> > + value is conveyed via @privlevel_floor and the maximum
> > + acceptable value is TSM_PRIVLEVEL_MAX (3).
> > +
> > +What: /sys/kernel/config/tsm/report/$name/privlevel_floor
> > +Date: September, 2023
> > +KernelVersion: v6.7
> > +Contact: linux-coco@lists.linux.dev
> > +Description:
> > + (RO) Indicates the minimum permissible value that can be written
> > + to @privlevel.
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index b19995690904..8acbeb029ba1 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -21889,6 +21889,14 @@ W: https://github.com/srcres258/linux-doc
> > T: git git://github.com/srcres258/linux-doc.git doc-zh-tw
> > F: Documentation/translations/zh_TW/
> >
> > +TRUSTED SECURITY MODULE (TSM) ATTESTATION REPORTS
> > +M: Dan Williams <dan.j.williams@intel.com>
> > +L: linux-coco@lists.linux.dev
> > +S: Maintained
> > +F: Documentation/ABI/testing/configfs-tsm
> > +F: drivers/virt/coco/tsm.c
> > +F: include/linux/tsm.h
> > +
> > TTY LAYER AND SERIAL DRIVERS
> > M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > M: Jiri Slaby <jirislaby@kernel.org>
> > diff --git a/drivers/virt/coco/Kconfig b/drivers/virt/coco/Kconfig
> > index fc5c64f04c4a..87d142c1f932 100644
> > --- a/drivers/virt/coco/Kconfig
> > +++ b/drivers/virt/coco/Kconfig
> > @@ -2,6 +2,11 @@
> > #
> > # Confidential computing related collateral
> > #
> > +
> > +config TSM_REPORTS
> > + select CONFIGFS_FS
> > + tristate
> > +
> > source "drivers/virt/coco/efi_secret/Kconfig"
> >
> > source "drivers/virt/coco/sev-guest/Kconfig"
> > diff --git a/drivers/virt/coco/Makefile b/drivers/virt/coco/Makefile
> > index 55302ef719ad..18c1aba5edb7 100644
> > --- a/drivers/virt/coco/Makefile
> > +++ b/drivers/virt/coco/Makefile
> > @@ -2,6 +2,7 @@
> > #
> > # Confidential computing related collateral
> > #
> > +obj-$(CONFIG_TSM_REPORTS) += tsm.o
> > obj-$(CONFIG_EFI_SECRET) += efi_secret/
> > obj-$(CONFIG_SEV_GUEST) += sev-guest/
> > obj-$(CONFIG_INTEL_TDX_GUEST) += tdx-guest/
> > diff --git a/drivers/virt/coco/tsm.c b/drivers/virt/coco/tsm.c
> > new file mode 100644
> > index 000000000000..0200a86f1efe
> > --- /dev/null
> > +++ b/drivers/virt/coco/tsm.c
> > @@ -0,0 +1,423 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/* Copyright(c) 2023 Intel Corporation. All rights reserved. */
> > +
> > +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> > +
> > +#include <linux/tsm.h>
> > +#include <linux/err.h>
> > +#include <linux/slab.h>
> > +#include <linux/rwsem.h>
> > +#include <linux/string.h>
> > +#include <linux/module.h>
> > +#include <linux/cleanup.h>
> > +#include <linux/configfs.h>
> > +
> > +static struct tsm_provider {
> > + const struct tsm_ops *ops;
> > + const struct config_item_type *type;
> > + void *data;
> > +} provider;
> > +static DECLARE_RWSEM(tsm_rwsem);
> > +
> > +/**
> > + * DOC: Trusted Security Module (TSM) Attestation Report Interface
> > + *
> > + * The TSM report interface is a common provider of blobs that facilitate
> > + * attestation of a TVM (confidential computing guest) by an attestation
> > + * service. A TSM report combines a user-defined blob (likely a public-key with
> > + * a nonce for a key-exchange protocol) with a signed attestation report. That
> > + * combined blob is then used to obtain secrets provided by an agent that can
> > + * validate the attestation report. The expectation is that this interface is
> > + * invoked infrequently, however configfs allows for multiple agents to
> > + * own their own report generation instances to generate reports as
> > + * often as needed.
> > + *
> > + * The attestation report format is TSM provider specific, when / if a standard
> > + * materializes that can be published instead of the vendor layout. Until then
> > + * the 'provider' attribute indicates the format of 'outblob', and optionally
> > + * 'auxblob'.
> > + */
> > +
> > +struct tsm_report_state {
> > + struct tsm_report report;
> > + unsigned long write_generation;
> > + unsigned long read_generation;
> > + struct config_item cfg;
> > +};
> > +
> > +enum tsm_data_select {
> > + TSM_REPORT,
> > + TSM_CERTS,
> > +};
> > +
> > +static struct tsm_report *to_tsm_report(struct config_item *cfg)
> > +{
> > + struct tsm_report_state *state =
> > + container_of(cfg, struct tsm_report_state, cfg);
>
> This be one line of 88 chars (less than allowed 100).
>
> (I'll comment once on this, feel free to ignore :) )
Unless and until the kernel's .clang-format template is updated to 100
you will find my patches wrapped to its ColumnLimit setting (80). I did
manually fixup my sev_guest changes to 100 since there was precedent in
that file, everything else I just let .clang-format do its thing.
>
> > +
> > + return &state->report;
> > +}
> > +
> > +static struct tsm_report_state *to_state(struct tsm_report *report)
> > +{
> > + return container_of(report, struct tsm_report_state, report);
> > +}
> > +
> > +static int try_advance_write_generation(struct tsm_report *report)
> > +{
> > + struct tsm_report_state *state = to_state(report);
> > +
> > + lockdep_assert_held_write(&tsm_rwsem);
> > +
> > + /*
> > + * Malicious or broken userspace has written enough times for
> > + * read_generation == write_generation by modular arithmetic without an
> > + * interim read. Stop accepting updates until the current report
> > + * configuration is read.
> > + */
> > + if (state->write_generation == state->read_generation - 1)
> > + return -EBUSY;
> > + state->write_generation++;
> > + return 0;
> > +}
> > +
> > +static ssize_t tsm_report_privlevel_store(struct config_item *cfg,
> > + const char *buf, size_t len)
> > +{
> > + struct tsm_report *report = to_tsm_report(cfg);
> > + unsigned int val;
> > + int rc;
> > +
> > + rc = kstrtouint(buf, 0, &val);
> > + if (rc)
> > + return rc;
> > +
> > + /*
> > + * The valid privilege levels that a TSM might accept, if it accepts a
> > + * privilege level setting at all, are a max of TSM_PRIVLEVEL_MAX (see
> > + * SEV-SNP GHCB) and a minimum of a TSM selected floor value no less
> > + * than 0.
> > + */
>
> Sounds like privlevel_floor should be "unsigned int" rather than "int".
Sure.
> > + if (provider.ops->privlevel_floor > val || val > TSM_PRIVLEVEL_MAX)
> > + return -EINVAL;
> > +
> > + guard(rwsem_write)(&tsm_rwsem);
> > + rc = try_advance_write_generation(report);
> > + if (rc)
> > + return rc;
> > + report->desc.privlevel = val;
> > +
> > + return len;
> > +}
> > +CONFIGFS_ATTR_WO(tsm_report_, privlevel);
> > +
> > +static ssize_t tsm_report_privlevel_floor_show(struct config_item *cfg,
> > + char *buf)
> > +{
> > + guard(rwsem_read)(&tsm_rwsem);
> > + return sysfs_emit(buf, "%u\n", provider.ops->privlevel_floor);
>
> %d or change the type.
Ok.
>
> > +}
> > +CONFIGFS_ATTR_RO(tsm_report_, privlevel_floor);
> > +
> > +static ssize_t tsm_report_inblob_write(struct config_item *cfg,
> > + const void *buf, size_t count)
> > +{
> > + struct tsm_report *report = to_tsm_report(cfg);
> > + int rc;
> > +
> > + guard(rwsem_write)(&tsm_rwsem);
> > + rc = try_advance_write_generation(report);
> > + if (rc)
> > + return rc;
> > +
> > + report->desc.inblob_len = count;
> > + memcpy(report->desc.inblob, buf, count);
> > + return count;
> > +}
> > +CONFIGFS_BIN_ATTR_WO(tsm_report_, inblob, NULL, TSM_INBLOB_MAX);
> > +
> > +static ssize_t tsm_report_generation_show(struct config_item *cfg, char *buf)
> > +{
> > + struct tsm_report *report = to_tsm_report(cfg);
> > + struct tsm_report_state *state = to_state(report);
> > +
> > + guard(rwsem_read)(&tsm_rwsem);
> > + return sysfs_emit(buf, "%lu\n", state->write_generation);
> > +}
> > +CONFIGFS_ATTR_RO(tsm_report_, generation);
> > +
> > +static ssize_t tsm_report_provider_show(struct config_item *cfg, char *buf)
> > +{
> > + guard(rwsem_read)(&tsm_rwsem);
> > + return sysfs_emit(buf, "%s\n", provider.ops->name);
> > +}
> > +CONFIGFS_ATTR_RO(tsm_report_, provider);
> > +
> > +static ssize_t __read_report(struct tsm_report *report, void *buf, size_t count,
> > + enum tsm_data_select select)
> > +{
> > + loff_t offset = 0;
> > + ssize_t len;
> > + u8 *out;
> > +
> > + if (select == TSM_REPORT) {
> > + out = report->outblob;
> > + len = report->outblob_len;
> > + } else {
> > + out = report->auxblob;
> > + len = report->auxblob_len;
> > + }
> > +
> > + /*
> > + * Recall that a NULL @buf is configfs requesting the size of
> > + * the buffer.
> > + */
>
> The comment can be one line (or even dropped as it is configfs api).
I got a comment from a reviewer that did not understand why @buf is
allowed to be NULL. It's an oddity compared to sysfs binary attributes,
so I don't mind the comment.
[..]
> > +static ssize_t tsm_report_read(struct tsm_report *report, void *buf,
> > + size_t count, enum tsm_data_select select)
> > +{
> > + struct tsm_report_state *state = to_state(report);
> > + const struct tsm_ops *ops;
> > + ssize_t rc;
> > +
> > + /* try to read from the existing report if present and valid... */
> > + rc = read_cached_report(report, buf, count, select);
> > + if (rc >= 0 || rc != -EWOULDBLOCK)
> > + return rc;
> > +
> > + /* slow path, report may need to be regenerated... */
> > + guard(rwsem_write)(&tsm_rwsem);
> > + ops = provider.ops;
> > + if (!report->desc.inblob_len)
> > + return -EINVAL;
> > +
> > + /* did another thread already generate this report? */
> > + if (report->outblob &&
> > + state->read_generation == state->write_generation)
> > + goto out;
> > + kvfree(report->outblob);
> > + kvfree(report->auxblob);
> > + report->outblob = NULL;
> > + report->auxblob = NULL;
> > + rc = ops->report_new(report, provider.data);
>
>
> Drop @ops and use "provider.ops" here?
Shrug, ok.
>
> > + if (rc < 0)
> > + return rc;
> > + state->read_generation = state->write_generation;
> > +out:
> > + return __read_report(report, buf, count, select);
> > +}
> > +
> > +static ssize_t tsm_report_outblob_read(struct config_item *cfg, void *buf,
> > + size_t count)
> > +{
> > + struct tsm_report *report = to_tsm_report(cfg);
> > +
> > + return tsm_report_read(report, buf, count, TSM_REPORT);
> > +}
> > +CONFIGFS_BIN_ATTR_RO(tsm_report_, outblob, NULL, TSM_OUTBLOB_MAX);
> > +
> > +static ssize_t tsm_report_auxblob_read(struct config_item *cfg, void *buf,
> > + size_t count)
> > +{
> > + struct tsm_report *report = to_tsm_report(cfg);
> > +
> > + return tsm_report_read(report, buf, count, TSM_CERTS);
> > +}
> > +CONFIGFS_BIN_ATTR_RO(tsm_report_, auxblob, NULL, TSM_OUTBLOB_MAX);
> > +
> > +#define TSM_DEFAULT_ATTRS() \
>
> imho this one and TSM_DEFAULT_BIN_ATTRS are not really helping with
> readability or a size :)
It is meant to do neither, it is only here to make it clear that
tsm_report_bin_extra_attrs[] is a super-set of tsm_report_bin_attrs[].
What I really want is sysfs-style group syntax, but configfs does not
have that same declaration capability.
[..]
>
> A little confusing thing is that this guy is neither near the beginning
> of the file (with other statics, this could even be a member of
> tsm_provider) nor the code which sets/clears it - tsm_init/tsm_unregister.
@tsm_report_group is only used in tsm_{init,exit}(). I'll move its
declartion closer to tsm_init() in a follow-on.
[..]
> > diff --git a/include/linux/tsm.h b/include/linux/tsm.h
> > new file mode 100644
> > index 000000000000..5fadc382064d
> > --- /dev/null
> > +++ b/include/linux/tsm.h
> > @@ -0,0 +1,68 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +#ifndef __TSM_H
> > +#define __TSM_H
> > +
> > +#include <linux/sizes.h>
> > +#include <linux/types.h>
> > +#include <linux/device.h>
>
> device.h is not needed.
Yes, an earlier version of this interface referenced devices.
next prev parent reply other threads:[~2023-10-17 2:19 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-10-13 2:13 [PATCH v6 0/7] configfs-tsm: Attestation Report ABI Dan Williams
2023-10-13 2:14 ` [PATCH v6 1/7] virt: sevguest: Fix passing a stack buffer as a scatterlist target Dan Williams
2023-10-13 2:14 ` [PATCH v6 2/7] virt: coco: Add a coco/Makefile and coco/Kconfig Dan Williams
2023-10-13 2:14 ` [PATCH v6 3/7] configfs-tsm: Introduce a shared ABI for attestation reports Dan Williams
2023-10-13 4:43 ` Dionna Amalie Glaze
2023-10-13 5:15 ` Dan Williams
2023-10-16 6:36 ` Alexey Kardashevskiy
2023-10-17 2:19 ` Dan Williams [this message]
2023-10-17 6:20 ` Alexey Kardashevskiy
2023-10-19 1:29 ` Dan Williams
2023-10-19 20:24 ` Dan Williams
2023-10-13 2:14 ` [PATCH v6 4/7] virt: sevguest: Prep for kernel internal get_ext_report() Dan Williams
2023-10-13 2:14 ` [PATCH v6 5/7] mm/slab: Add __free() support for kvfree Dan Williams
2023-10-13 2:14 ` [PATCH v6 6/7] virt: sevguest: Add TSM_REPORTS support for SNP_GET_EXT_REPORT Dan Williams
2023-10-13 15:38 ` Tom Lendacky
2023-10-14 4:46 ` Dan Williams
2023-10-16 11:36 ` Alexey Kardashevskiy
2023-10-16 15:39 ` Dionna Amalie Glaze
2023-10-16 15:42 ` Peter Gonda
2023-10-17 0:42 ` Alexey Kardashevskiy
2023-10-19 4:30 ` Dan Williams
2023-10-17 4:07 ` Dan Williams
2023-10-17 5:35 ` Alexey Kardashevskiy
2023-10-17 6:28 ` Alexey Kardashevskiy
2023-10-19 4:43 ` Dan Williams
2023-10-19 5:12 ` Alexey Kardashevskiy
2023-10-19 3:34 ` Dan Williams
2023-10-13 2:14 ` [PATCH v6 7/7] virt: tdx-guest: Add Quote generation support using TSM_REPORTS Dan Williams
2023-10-19 18:12 ` Peter Gonda
2023-10-13 15:39 ` [PATCH v6 0/7] configfs-tsm: Attestation Report ABI Tom Lendacky
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=652def355ef34_f8792949c@dwillia2-mobl3.amr.corp.intel.com.notmuch \
--to=dan.j.williams@intel.com \
--cc=James.Bottomley@hansenpartnership.com \
--cc=aik@amd.com \
--cc=bp@alien8.de \
--cc=dave.hansen@linux.intel.com \
--cc=dionnaglaze@google.com \
--cc=gregkh@linuxfoundation.org \
--cc=linux-coco@lists.linux.dev \
--cc=peterz@infradead.org \
--cc=pgonda@google.com \
--cc=sameo@rivosinc.com \
--cc=sathyanarayanan.kuppuswamy@linux.intel.com \
--cc=tglx@linutronix.de \
/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