]> git.apps.os.sepia.ceph.com Git - ceph-client.git/commitdiff
Merge branch 'for-6.16/tsm-mr' into tsm-next
authorDan Williams <dan.j.williams@intel.com>
Tue, 13 May 2025 05:12:44 +0000 (22:12 -0700)
committerDan Williams <dan.j.williams@intel.com>
Tue, 13 May 2025 05:12:44 +0000 (22:12 -0700)
Merge measurement-register infrastructure for v6.16. Resolve conflicts
with the establishment of drivers/virt/coco/guest/ for cross-vendor
common TSM functionality.

Address a mis-merge with a fixup from Lukas:

Link: http://lore.kernel.org/20250509134031.70559-1-lukas.bulwahn@redhat.com
1  2 
Documentation/driver-api/coco/measurement-registers.rst
MAINTAINERS
drivers/virt/coco/Makefile
drivers/virt/coco/guest/Kconfig
drivers/virt/coco/guest/Makefile
drivers/virt/coco/guest/tsm-mr.c
drivers/virt/coco/tdx-guest/tdx-guest.c

index 0000000000000000000000000000000000000000,cef85945a9a74849dfec4fdc709bc72d4a595356..962a44efa2c0273ec353ab0dba2a871754ee0730
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,12 +1,12 @@@
 -.. kernel-doc:: drivers/virt/coco/tsm-mr.c
+ .. SPDX-License-Identifier: GPL-2.0
+ .. include:: <isonum.txt>
+ =====================
+ Measurement Registers
+ =====================
+ .. kernel-doc:: include/linux/tsm-mr.h
+    :internal:
++.. kernel-doc:: drivers/virt/coco/guest/tsm-mr.c
+    :export:
diff --cc MAINTAINERS
index 0a1ca9233ccf86be212af062a6d6e7ea90978559,912e16ace0b4affec1e84b5c78060db7e58d9243..10d6d99b8dc7e71b280e29b1d3ffa7485a27814e
@@@ -24555,13 -24643,15 +24643,15 @@@ M:        David Lechner <dlechner@baylibre.com
  S:    Maintained
  F:    Documentation/devicetree/bindings/trigger-source/pwm-trigger.yaml
  
--TRUSTED SECURITY MODULE (TSM) ATTESTATION REPORTS
++TRUSTED SECURITY MODULE (TSM) INFRASTRUCTURE
  M:    Dan Williams <dan.j.williams@intel.com>
  L:    linux-coco@lists.linux.dev
  S:    Maintained
 -F:    Documentation/ABI/testing/configfs-tsm
 +F:    Documentation/ABI/testing/configfs-tsm-report
+ F:    Documentation/driver-api/coco/
 -F:    drivers/virt/coco/tsm*.c
 +F:    drivers/virt/coco/guest/
- F:    include/linux/tsm.h
+ F:    include/linux/tsm*.h
 -F:    samples/tsm/
++F:    samples/tsm-mr/
  
  TRUSTED SERVICES TEE DRIVER
  M:    Balint Dobszay <balint.dobszay@arm.com>
index 885c9ef4e9fc97b15b336426db447d812e96dc7e,eb6ec5c1d2e17427ebf83891c57cc723b8c8d660..f918bbb61737598561366e128e3e6247e399d6d4
@@@ -7,4 -9,3 +7,4 @@@ obj-$(CONFIG_ARM_PKVM_GUEST)     += pkvm-gu
  obj-$(CONFIG_SEV_GUEST)               += sev-guest/
  obj-$(CONFIG_INTEL_TDX_GUEST) += tdx-guest/
  obj-$(CONFIG_ARM_CCA_GUEST)   += arm-cca-guest/
- obj-$(CONFIG_TSM_REPORTS)     += guest/
++obj-$(CONFIG_TSM_GUEST)               += guest/
index ed9bafbdd8548726f608d9711c1c24759a3d9f3c,0000000000000000000000000000000000000000..3d5e1d05bf34382153c599522f020b512c49a60a
mode 100644,000000..100644
--- /dev/null
@@@ -1,7 -1,0 +1,17 @@@
 +# SPDX-License-Identifier: GPL-2.0-only
 +#
 +# Confidential computing shared guest collateral
 +#
++config TSM_GUEST
++      bool
++
 +config TSM_REPORTS
++      select TSM_GUEST
 +      select CONFIGFS_FS
 +      tristate
++
++config TSM_MEASUREMENTS
++      select TSM_GUEST
++      select CRYPTO_HASH_INFO
++      select CRYPTO
++      bool
index b3b217af77cf5dc9a2c9f8a1230b752835737c82,0000000000000000000000000000000000000000..9ec4860bd213ae3cc7b88ecf95e1f7b8d94ef56c
mode 100644,000000..100644
--- /dev/null
@@@ -1,3 -1,0 +1,4 @@@
 +# SPDX-License-Identifier: GPL-2.0
 +obj-$(CONFIG_TSM_REPORTS)     += tsm_report.o
 +tsm_report-y := report.o
++obj-$(CONFIG_TSM_MEASUREMENTS)        += tsm-mr.o
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..1f0c43a516fb89af6f2bab41f2226f0e55d1276d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,251 @@@
++// SPDX-License-Identifier: GPL-2.0-only
++/* Copyright(c) 2024-2025 Intel Corporation. All rights reserved. */
++
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/sysfs.h>
++
++#define CREATE_TRACE_POINTS
++#include <trace/events/tsm_mr.h>
++
++/*
++ * struct tm_context - contains everything necessary to implement sysfs
++ * attributes for MRs.
++ * @rwsem: protects the MR cache from concurrent access.
++ * @agrp: contains all MR attributes created by tsm_mr_create_attribute_group().
++ * @tm: input to tsm_mr_create_attribute_group() containing MR definitions/ops.
++ * @in_sync: %true if MR cache is up-to-date.
++ * @mrs: array of &struct bin_attribute, one for each MR.
++ *
++ * This internal structure contains everything needed to implement
++ * tm_digest_read() and tm_digest_write().
++ *
++ * Given tm->refresh() is potentially expensive, tm_digest_read() caches MR
++ * values and calls tm->refresh() only when necessary. Only live MRs (i.e., with
++ * %TSM_MR_F_LIVE set) can trigger tm->refresh(), while others are assumed to
++ * retain their values from the last tm->write(). @in_sync tracks if there have
++ * been tm->write() calls since the last tm->refresh(). That is, tm->refresh()
++ * will be called only when a live MR is being read and the cache is stale
++ * (@in_sync is %false).
++ *
++ * tm_digest_write() sets @in_sync to %false and calls tm->write(), whose
++ * semantics is arch and MR specific. Most (if not all) writable MRs support the
++ * extension semantics (i.e., tm->write() extends the input buffer into the MR).
++ */
++struct tm_context {
++      struct rw_semaphore rwsem;
++      struct attribute_group agrp;
++      const struct tsm_measurements *tm;
++      bool in_sync;
++      struct bin_attribute mrs[];
++};
++
++static ssize_t tm_digest_read(struct file *filp, struct kobject *kobj,
++                            const struct bin_attribute *attr, char *buffer,
++                            loff_t off, size_t count)
++{
++      struct tm_context *ctx;
++      const struct tsm_measurement_register *mr;
++      int rc;
++
++      ctx = attr->private;
++      rc = down_read_interruptible(&ctx->rwsem);
++      if (rc)
++              return rc;
++
++      mr = &ctx->tm->mrs[attr - ctx->mrs];
++
++      /*
++       * @ctx->in_sync indicates if the MR cache is stale. It is a global
++       * instead of a per-MR flag for simplicity, as most (if not all) archs
++       * allow reading all MRs in oneshot.
++       *
++       * ctx->refresh() is necessary only for LIVE MRs, while others retain
++       * their values from their respective last ctx->write().
++       */
++      if ((mr->mr_flags & TSM_MR_F_LIVE) && !ctx->in_sync) {
++              up_read(&ctx->rwsem);
++
++              rc = down_write_killable(&ctx->rwsem);
++              if (rc)
++                      return rc;
++
++              if (!ctx->in_sync) {
++                      rc = ctx->tm->refresh(ctx->tm);
++                      ctx->in_sync = !rc;
++                      trace_tsm_mr_refresh(mr, rc);
++              }
++
++              downgrade_write(&ctx->rwsem);
++      }
++
++      memcpy(buffer, mr->mr_value + off, count);
++      trace_tsm_mr_read(mr);
++
++      up_read(&ctx->rwsem);
++      return rc ?: count;
++}
++
++static ssize_t tm_digest_write(struct file *filp, struct kobject *kobj,
++                             const struct bin_attribute *attr, char *buffer,
++                             loff_t off, size_t count)
++{
++      struct tm_context *ctx;
++      const struct tsm_measurement_register *mr;
++      ssize_t rc;
++
++      /* partial writes are not supported */
++      if (off != 0 || count != attr->size)
++              return -EINVAL;
++
++      ctx = attr->private;
++      mr = &ctx->tm->mrs[attr - ctx->mrs];
++
++      rc = down_write_killable(&ctx->rwsem);
++      if (rc)
++              return rc;
++
++      rc = ctx->tm->write(ctx->tm, mr, buffer);
++
++      /* mark MR cache stale */
++      if (!rc) {
++              ctx->in_sync = false;
++              trace_tsm_mr_write(mr, buffer);
++      }
++
++      up_write(&ctx->rwsem);
++      return rc ?: count;
++}
++
++/**
++ * tsm_mr_create_attribute_group() - creates an attribute group for measurement
++ * registers (MRs)
++ * @tm: pointer to &struct tsm_measurements containing the MR definitions.
++ *
++ * This function creates attributes corresponding to the MR definitions
++ * provided by @tm->mrs.
++ *
++ * The created attributes will reference @tm and its members. The caller must
++ * not free @tm until after tsm_mr_free_attribute_group() is called.
++ *
++ * Context: Process context. May sleep due to memory allocation.
++ *
++ * Return:
++ * * On success, the pointer to a an attribute group is returned; otherwise
++ * * %-EINVAL - Invalid MR definitions.
++ * * %-ENOMEM - Out of memory.
++ */
++const struct attribute_group *
++tsm_mr_create_attribute_group(const struct tsm_measurements *tm)
++{
++      size_t nlen;
++
++      if (!tm || !tm->mrs)
++              return ERR_PTR(-EINVAL);
++
++      /* aggregated length of all MR names */
++      nlen = 0;
++      for (size_t i = 0; i < tm->nr_mrs; ++i) {
++              if ((tm->mrs[i].mr_flags & TSM_MR_F_LIVE) && !tm->refresh)
++                      return ERR_PTR(-EINVAL);
++
++              if ((tm->mrs[i].mr_flags & TSM_MR_F_WRITABLE) && !tm->write)
++                      return ERR_PTR(-EINVAL);
++
++              if (!tm->mrs[i].mr_name)
++                      return ERR_PTR(-EINVAL);
++
++              if (tm->mrs[i].mr_flags & TSM_MR_F_NOHASH)
++                      continue;
++
++              if (tm->mrs[i].mr_hash >= HASH_ALGO__LAST)
++                      return ERR_PTR(-EINVAL);
++
++              /* MR sysfs attribute names have the form of MRNAME:HASH */
++              nlen += strlen(tm->mrs[i].mr_name) + 1 +
++                      strlen(hash_algo_name[tm->mrs[i].mr_hash]) + 1;
++      }
++
++      /*
++       * @attrs and the MR name strings are combined into a single allocation
++       * so that we don't have to free MR names one-by-one in
++       * tsm_mr_free_attribute_group()
++       */
++      const struct bin_attribute * const *attrs __free(kfree) =
++              kzalloc(sizeof(*attrs) * (tm->nr_mrs + 1) + nlen, GFP_KERNEL);
++      struct tm_context *ctx __free(kfree) =
++              kzalloc(struct_size(ctx, mrs, tm->nr_mrs), GFP_KERNEL);
++      char *name, *end;
++
++      if (!ctx || !attrs)
++              return ERR_PTR(-ENOMEM);
++
++      /* @attrs is followed immediately by MR name strings */
++      name = (char *)&attrs[tm->nr_mrs + 1];
++      end = name + nlen;
++
++      for (size_t i = 0; i < tm->nr_mrs; ++i) {
++              /* break const for init */
++              struct bin_attribute **bas = (struct bin_attribute **)attrs;
++
++              bas[i] = &ctx->mrs[i];
++              sysfs_bin_attr_init(bas[i]);
++
++              if (tm->mrs[i].mr_flags & TSM_MR_F_NOHASH)
++                      bas[i]->attr.name = tm->mrs[i].mr_name;
++              else if (name < end) {
++                      bas[i]->attr.name = name;
++                      name += snprintf(name, end - name, "%s:%s",
++                                       tm->mrs[i].mr_name,
++                                       hash_algo_name[tm->mrs[i].mr_hash]);
++                      ++name;
++              } else
++                      return ERR_PTR(-EINVAL);
++
++              /* check for duplicated MR definitions */
++              for (size_t j = 0; j < i; ++j)
++                      if (!strcmp(bas[i]->attr.name, bas[j]->attr.name))
++                              return ERR_PTR(-EINVAL);
++
++              if (tm->mrs[i].mr_flags & TSM_MR_F_READABLE) {
++                      bas[i]->attr.mode |= 0444;
++                      bas[i]->read_new = tm_digest_read;
++              }
++
++              if (tm->mrs[i].mr_flags & TSM_MR_F_WRITABLE) {
++                      bas[i]->attr.mode |= 0200;
++                      bas[i]->write_new = tm_digest_write;
++              }
++
++              bas[i]->size = tm->mrs[i].mr_size;
++              bas[i]->private = ctx;
++      }
++
++      if (name != end)
++              return ERR_PTR(-EINVAL);
++
++      init_rwsem(&ctx->rwsem);
++      ctx->agrp.name = "measurements";
++      ctx->agrp.bin_attrs_new = no_free_ptr(attrs);
++      ctx->tm = tm;
++      return &no_free_ptr(ctx)->agrp;
++}
++EXPORT_SYMBOL_GPL(tsm_mr_create_attribute_group);
++
++/**
++ * tsm_mr_free_attribute_group() - frees the attribute group returned by
++ * tsm_mr_create_attribute_group()
++ * @attr_grp: attribute group returned by tsm_mr_create_attribute_group()
++ *
++ * Context: Process context.
++ */
++void tsm_mr_free_attribute_group(const struct attribute_group *attr_grp)
++{
++      if (!IS_ERR_OR_NULL(attr_grp)) {
++              kfree(attr_grp->bin_attrs);
++              kfree(container_of(attr_grp, struct tm_context, agrp));
++      }
++}
++EXPORT_SYMBOL_GPL(tsm_mr_free_attribute_group);
index bd043838ab2e1b173d651b0d13dda51aab75b22f,60466c439a4bc63cb59bc80d68840727d12462fd..4e239ec960c9b5edef91bb324ad64d0473357ad6
@@@ -157,11 -262,11 +262,11 @@@ static int wait_for_quote_completion(st
        return (i == timeout) ? -ETIMEDOUT : 0;
  }
  
- static int tdx_report_new(struct tsm_report *report, void *data)
+ static int tdx_report_new_locked(struct tsm_report *report, void *data)
  {
-       u8 *buf, *reportdata = NULL, *tdreport = NULL;
+       u8 *buf;
        struct tdx_quote_buf *quote_buf = quote_data;
 -      struct tsm_desc *desc = &report->desc;
 +      struct tsm_report_desc *desc = &report->desc;
        int ret;
        u64 err;
  
@@@ -339,9 -429,10 +429,10 @@@ module_init(tdx_guest_init)
  
  static void __exit tdx_guest_exit(void)
  {
 -      tsm_unregister(&tdx_tsm_ops);
 +      tsm_report_unregister(&tdx_tsm_ops);
        free_quote_buf(quote_data);
        misc_deregister(&tdx_misc_dev);
+       tdx_mr_deinit(tdx_attr_groups[0]);
  }
  module_exit(tdx_guest_exit);