This sample kernel module demonstrates how to make MRs accessible to user
mode through the tsm-mr library.
Once loaded, this module registers a `miscdevice` that host a set of
emulated measurement registers as shown in the directory tree below.
/sys/class/misc/tsm_mr_sample
└── emulated_mr
├── config_mr
├── report_digest:sha512
├── rtmr0:sha256
├── rtmr1:sha384
├── rtmr_crypto_agile:sha256
├── rtmr_crypto_agile:sha384
└── static_mr:sha384
Among the MRs in this example:
- `config_mr` demonstrates a hashless MR, like MRCONFIGID in Intel TDX or
HOSTDATA in AMD SEV.
- `static_mr` demonstrates a static MR. The suffix `:sha384` indicates its
value is a sha384 digest.
- `rtmr0` is an RTMR with `TSM_MR_F_WRITABLE` **cleared**, preventing
direct extensions; as a result, the attribute `rtmr0:sha256` is
read-only.
- `rtmr1` is an RTMR with `TSM_MR_F_WRITABLE` **set**, permitting direct
extensions; thus, the attribute `rtmr1:sha384` is writable.
- `rtmr_crypto_agile` demonstrates a "single" MR that supports multiple
hash algorithms. Each supported algorithm has a corresponding digest,
usually referred to as a "bank" in TCG terminology. In this specific
sample, the 2 banks are aliased to `rtmr0` and `rtmr1`, respectively.
- `report_digest` contains the digest of the internal report structure
living in this sample module's memory. It is to demonstrate the use of
the `TSM_MR_F_LIVE` flag. Its value changes each time an RTMR is
extended.
Signed-off-by: Cedric Xing <cedric.xing@intel.com>
---
MAINTAINERS | 1 +
samples/Kconfig | 10 +++
samples/Makefile | 1 +
samples/tsm-mr/Makefile | 2 +
samples/tsm-mr/tsm_mr_sample.c | 138 +++++++++++++++++++++++++++++++++++++++++
5 files changed, 152 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index df3aada3ada6..b210ac3389a7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -24560,6 +24560,7 @@ S: Maintained
F: Documentation/ABI/testing/configfs-tsm
F: drivers/virt/coco/tsm*.c
F: include/linux/tsm*.h
+F: samples/tsm/*
TRUSTED SERVICES TEE DRIVER
M: Balint Dobszay <balint.dobszay@arm.com>
diff --git a/samples/Kconfig b/samples/Kconfig
index 09011be2391a..828bc4bebde8 100644
--- a/samples/Kconfig
+++ b/samples/Kconfig
@@ -184,6 +184,16 @@ config SAMPLE_TIMER
bool "Timer sample"
depends on CC_CAN_LINK && HEADERS_INSTALL
+config SAMPLE_TSM_MR
+ tristate "TSM measurement sample"
+ select TSM_MEASUREMENTS
+ help
+ Build a sample module that emulates MRs (Measurement Registers) and
+ exposes them to user mode applications through the TSM sysfs
+ interface (/sys/class/misc/tsm_mr_sample/emulated_mr/).
+
+ The module name will be tsm-mr-sample when built as a module.
+
config SAMPLE_UHID
bool "UHID sample"
depends on CC_CAN_LINK && HEADERS_INSTALL
diff --git a/samples/Makefile b/samples/Makefile
index bf6e6fca5410..c95bac31851c 100644
--- a/samples/Makefile
+++ b/samples/Makefile
@@ -43,3 +43,4 @@ obj-$(CONFIG_SAMPLES_RUST) += rust/
obj-$(CONFIG_SAMPLE_DAMON_WSSE) += damon/
obj-$(CONFIG_SAMPLE_DAMON_PRCL) += damon/
obj-$(CONFIG_SAMPLE_HUNG_TASK) += hung_task/
+obj-$(CONFIG_SAMPLE_TSM_MR) += tsm-mr/
diff --git a/samples/tsm-mr/Makefile b/samples/tsm-mr/Makefile
new file mode 100644
index 000000000000..587c3947b3a7
--- /dev/null
+++ b/samples/tsm-mr/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_SAMPLE_TSM_MR) += tsm_mr_sample.o
diff --git a/samples/tsm-mr/tsm_mr_sample.c b/samples/tsm-mr/tsm_mr_sample.c
new file mode 100644
index 000000000000..163f0f56e165
--- /dev/null
+++ b/samples/tsm-mr/tsm_mr_sample.c
@@ -0,0 +1,138 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(c) 2024 Intel Corporation. All rights reserved. */
+
+#define DEBUG
+#define pr_fmt(x) KBUILD_MODNAME ": " x
+
+#include <linux/module.h>
+#include <linux/tsm-mr.h>
+#include <linux/miscdevice.h>
+#include <crypto/hash.h>
+
+struct {
+ u8 static_mr[SHA384_DIGEST_SIZE];
+ u8 config_mr[SHA512_DIGEST_SIZE];
+ u8 rtmr0[SHA256_DIGEST_SIZE];
+ u8 rtmr1[SHA384_DIGEST_SIZE];
+ u8 report_digest[SHA512_DIGEST_SIZE];
+} sample_report = {
+ .static_mr = "static_mr",
+ .config_mr = "config_mr",
+ .rtmr0 = "rtmr0",
+ .rtmr1 = "rtmr1",
+};
+
+static int sample_report_refresh(const struct tsm_measurements *tm,
+ const struct tsm_measurement_register *mr)
+{
+ struct crypto_shash *tfm;
+ int rc;
+
+ pr_debug("%s(%s) is called\n", __func__, mr ? mr->mr_name : "<nil>");
+
+ tfm = crypto_alloc_shash(hash_algo_name[HASH_ALGO_SHA512], 0, 0);
+ if (IS_ERR(tfm)) {
+ pr_err("crypto_alloc_shash failed: %ld\n", PTR_ERR(tfm));
+ return PTR_ERR(tfm);
+ }
+
+ rc = crypto_shash_tfm_digest(tfm, (u8 *)&sample_report,
+ offsetof(typeof(sample_report),
+ report_digest),
+ sample_report.report_digest);
+ crypto_free_shash(tfm);
+ if (rc)
+ pr_err("crypto_shash_tfm_digest failed: %d\n", rc);
+ return rc;
+}
+
+static int sample_report_extend_mr(const struct tsm_measurements *tm,
+ const struct tsm_measurement_register *mr,
+ const u8 *data)
+{
+ SHASH_DESC_ON_STACK(desc, 0);
+ int rc;
+
+ pr_debug("%s(%s) is called\n", __func__, mr->mr_name);
+
+ desc->tfm = crypto_alloc_shash(hash_algo_name[mr->mr_hash], 0, 0);
+ if (IS_ERR(desc->tfm)) {
+ pr_err("crypto_alloc_shash failed: %ld\n", PTR_ERR(desc->tfm));
+ return PTR_ERR(desc->tfm);
+ }
+
+ rc = crypto_shash_init(desc);
+ if (!rc)
+ rc = crypto_shash_update(desc, mr->mr_value, mr->mr_size);
+ if (!rc)
+ rc = crypto_shash_finup(desc, data, mr->mr_size, mr->mr_value);
+ crypto_free_shash(desc->tfm);
+ if (rc)
+ pr_err("SHA calculation failed: %d\n", rc);
+ return rc;
+}
+
+#define MR_(mr, hash) .mr_value = &sample_report.mr, TSM_MR_(mr, hash)
+static const struct tsm_measurement_register emulated_mrs[] = {
+ /* static MR, read-only */
+ { MR_(static_mr, SHA384) },
+ /* config MR, read-only */
+ { MR_(config_mr, SHA512) | TSM_MR_F_NOHASH },
+ /* RTMR, direct extension prohibited */
+ { MR_(rtmr0, SHA256) | TSM_MR_F_LIVE },
+ /* RTMR, direct extension allowed */
+ { MR_(rtmr1, SHA384) | TSM_MR_F_RTMR },
+ /* RTMR, crypto agile, alaised to rtmr0 and rtmr1, respectively */
+ { .mr_value = &sample_report.rtmr0,
+ TSM_MR_(rtmr_crypto_agile, SHA256) | TSM_MR_F_RTMR },
+ { .mr_value = &sample_report.rtmr1,
+ TSM_MR_(rtmr_crypto_agile, SHA384) | TSM_MR_F_RTMR },
+ /* sha512 digest of the whole structure */
+ { MR_(report_digest, SHA512) | TSM_MR_F_LIVE },
+};
+#undef MR_
+
+static struct tsm_measurements emulated_mr = {
+ .name = "emulated_mr",
+ .mrs = emulated_mrs,
+ .nr_mrs = ARRAY_SIZE(emulated_mrs),
+ .refresh = sample_report_refresh,
+ .write = sample_report_extend_mr,
+};
+
+static const struct attribute_group *sample_groups[] = {
+ NULL,
+ NULL,
+};
+
+static struct miscdevice sample_misc_dev = {
+ .name = KBUILD_MODNAME,
+ .minor = MISC_DYNAMIC_MINOR,
+ .groups = sample_groups,
+};
+
+static int __init tsm_mr_sample_init(void)
+{
+ int rc;
+
+ sample_groups[0] = tsm_mr_create_attribute_group(&emulated_mr);
+ if (IS_ERR(sample_groups[0]))
+ return PTR_ERR(sample_groups[0]);
+
+ rc = misc_register(&sample_misc_dev);
+ if (rc)
+ tsm_mr_free_attribute_group(sample_groups[0]);
+ return rc;
+}
+
+static void __exit tsm_mr_sample_exit(void)
+{
+ misc_deregister(&sample_misc_dev);
+ tsm_mr_free_attribute_group(sample_groups[0]);
+}
+
+module_init(tsm_mr_sample_init);
+module_exit(tsm_mr_sample_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Sample module using tsm-mr to expose emulated MRs");
--
2.43.0
Cedric Xing wrote:
> This sample kernel module demonstrates how to make MRs accessible to user
> mode through the tsm-mr library.
>
> Once loaded, this module registers a `miscdevice` that host a set of
> emulated measurement registers as shown in the directory tree below.
>
> /sys/class/misc/tsm_mr_sample
> └── emulated_mr
> ├── config_mr
> ├── report_digest:sha512
> ├── rtmr0:sha256
> ├── rtmr1:sha384
> ├── rtmr_crypto_agile:sha256
> ├── rtmr_crypto_agile:sha384
> └── static_mr:sha384
>
> Among the MRs in this example:
>
> - `config_mr` demonstrates a hashless MR, like MRCONFIGID in Intel TDX or
> HOSTDATA in AMD SEV.
> - `static_mr` demonstrates a static MR. The suffix `:sha384` indicates its
> value is a sha384 digest.
> - `rtmr0` is an RTMR with `TSM_MR_F_WRITABLE` **cleared**, preventing
> direct extensions; as a result, the attribute `rtmr0:sha256` is
> read-only.
> - `rtmr1` is an RTMR with `TSM_MR_F_WRITABLE` **set**, permitting direct
> extensions; thus, the attribute `rtmr1:sha384` is writable.
> - `rtmr_crypto_agile` demonstrates a "single" MR that supports multiple
> hash algorithms. Each supported algorithm has a corresponding digest,
> usually referred to as a "bank" in TCG terminology. In this specific
> sample, the 2 banks are aliased to `rtmr0` and `rtmr1`, respectively.
> - `report_digest` contains the digest of the internal report structure
> living in this sample module's memory. It is to demonstrate the use of
> the `TSM_MR_F_LIVE` flag. Its value changes each time an RTMR is
> extended.
>
> Signed-off-by: Cedric Xing <cedric.xing@intel.com>
[..]
> +static struct tsm_measurements emulated_mr = {
> + .name = "emulated_mr",
I think the convention should be that all consumers use a common name
for this common ABI, similar to a sysfs-class. So, I would say set the
name to "measurement_registers" inside tsm_mr_create_attribute_group(),
and make the "custom name" or "no-name" case an isolated corner case.
Other than that, thanks for taking the time to build this sample it
makes the reviewing the implementation easier and allows for some ABI
testing.
Hi Cedric,
kernel test robot noticed the following build errors:
[auto build test ERROR on 0af2f6be1b4281385b618cb86ad946eded089ac8]
url: https://github.com/intel-lab-lkp/linux/commits/Cedric-Xing/tsm-mr-Add-TVM-Measurement-Register-support/20250408-032813
base: 0af2f6be1b4281385b618cb86ad946eded089ac8
patch link: https://lore.kernel.org/r/20250407-tdx-rtmr-v3-2-54f17bc65228%40intel.com
patch subject: [PATCH v3 2/5] tsm-mr: Add tsm-mr sample code
config: x86_64-allyesconfig (https://download.01.org/0day-ci/archive/20250409/202504090703.LtAt1UZI-lkp@intel.com/config)
compiler: clang version 20.1.2 (https://github.com/llvm/llvm-project 58df0ef89dd64126512e4ee27b4ac3fd8ddf6247)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250409/202504090703.LtAt1UZI-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202504090703.LtAt1UZI-lkp@intel.com/
All errors (new ones prefixed by >>):
In file included from samples/tsm-mr/tsm_mr_sample.c:8:
>> include/linux/tsm-mr.h:81:58: error: use of undeclared identifier 'nr_mrs'
81 | const struct tsm_measurement_register *mrs __counted_by(nr_mrs);
| ^
1 error generated.
vim +/nr_mrs +81 include/linux/tsm-mr.h
b6f2f446f66ff9 Cedric Xing 2025-04-07 47
b6f2f446f66ff9 Cedric Xing 2025-04-07 48 #define TSM_MR_(mr, hash) \
b6f2f446f66ff9 Cedric Xing 2025-04-07 49 .mr_name = #mr, .mr_size = hash##_DIGEST_SIZE, \
b6f2f446f66ff9 Cedric Xing 2025-04-07 50 .mr_hash = HASH_ALGO_##hash, .mr_flags = TSM_MR_F_READABLE
b6f2f446f66ff9 Cedric Xing 2025-04-07 51
b6f2f446f66ff9 Cedric Xing 2025-04-07 52 /**
b6f2f446f66ff9 Cedric Xing 2025-04-07 53 * struct tsm_measurements - Defines the CC-specific measurement facility and
b6f2f446f66ff9 Cedric Xing 2025-04-07 54 * methods for updating measurement registers (MRs).
b6f2f446f66ff9 Cedric Xing 2025-04-07 55 * @name: Optional parent directory name.
b6f2f446f66ff9 Cedric Xing 2025-04-07 56 * @mrs: Array of MR definitions.
b6f2f446f66ff9 Cedric Xing 2025-04-07 57 * @nr_mrs: Number of elements in @mrs.
b6f2f446f66ff9 Cedric Xing 2025-04-07 58 * @refresh: Callback function to load/sync all MRs from TVM hardware/firmware
b6f2f446f66ff9 Cedric Xing 2025-04-07 59 * into the kernel cache.
b6f2f446f66ff9 Cedric Xing 2025-04-07 60 * @write: Callback function to write to the MR specified by the parameter @mr.
b6f2f446f66ff9 Cedric Xing 2025-04-07 61 *
b6f2f446f66ff9 Cedric Xing 2025-04-07 62 * @refresh takes two parameters:
b6f2f446f66ff9 Cedric Xing 2025-04-07 63 *
b6f2f446f66ff9 Cedric Xing 2025-04-07 64 * * @tm - points back to this structure.
b6f2f446f66ff9 Cedric Xing 2025-04-07 65 * * @mr - points to the MR (an element of @mrs) being read (hence triggered
b6f2f446f66ff9 Cedric Xing 2025-04-07 66 * this callback).
b6f2f446f66ff9 Cedric Xing 2025-04-07 67 *
b6f2f446f66ff9 Cedric Xing 2025-04-07 68 * Note that @refresh is invoked only when an MR with %TSM_MR_F_LIVE set is
b6f2f446f66ff9 Cedric Xing 2025-04-07 69 * being read and the cache is stale. However, @refresh must reload not only
b6f2f446f66ff9 Cedric Xing 2025-04-07 70 * the MR being read (@mr) but also all MRs with %TSM_MR_F_LIVE set.
b6f2f446f66ff9 Cedric Xing 2025-04-07 71 *
b6f2f446f66ff9 Cedric Xing 2025-04-07 72 * @write takes an additional parameter besides @tm and @mr:
b6f2f446f66ff9 Cedric Xing 2025-04-07 73 *
b6f2f446f66ff9 Cedric Xing 2025-04-07 74 * * @data - contains the bytes to write and whose size is @mr->mr_size.
b6f2f446f66ff9 Cedric Xing 2025-04-07 75 *
b6f2f446f66ff9 Cedric Xing 2025-04-07 76 * Both @refresh and @write should return 0 on success and an appropriate error
b6f2f446f66ff9 Cedric Xing 2025-04-07 77 * code on failure.
b6f2f446f66ff9 Cedric Xing 2025-04-07 78 */
b6f2f446f66ff9 Cedric Xing 2025-04-07 79 struct tsm_measurements {
b6f2f446f66ff9 Cedric Xing 2025-04-07 80 const char *name;
b6f2f446f66ff9 Cedric Xing 2025-04-07 @81 const struct tsm_measurement_register *mrs __counted_by(nr_mrs);
b6f2f446f66ff9 Cedric Xing 2025-04-07 82 size_t nr_mrs;
b6f2f446f66ff9 Cedric Xing 2025-04-07 83 int (*refresh)(const struct tsm_measurements *tm,
b6f2f446f66ff9 Cedric Xing 2025-04-07 84 const struct tsm_measurement_register *mr);
b6f2f446f66ff9 Cedric Xing 2025-04-07 85 int (*write)(const struct tsm_measurements *tm,
b6f2f446f66ff9 Cedric Xing 2025-04-07 86 const struct tsm_measurement_register *mr, const u8 *data);
b6f2f446f66ff9 Cedric Xing 2025-04-07 87 };
b6f2f446f66ff9 Cedric Xing 2025-04-07 88
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
© 2016 - 2026 Red Hat, Inc.