This sample kernel module demonstrates how to make MRs accessible to user mode
through TSM.
Once loaded, this module registers a virtual measurement provider with the TSM
core and will result in the directory tree below.
/sys/kernel/tsm/
└── measurement-example
├── config_mr
├── full_report
├── report_digest
├── rtmr0
│ ├── append_event
│ ├── digest
│ ├── event_log
│ └── hash_algo
├── rtmr1
│ ├── append_event
│ ├── digest
│ ├── event_log
│ └── hash_algo
├── static_mr
└── user_data
Among the MRs in this example:
- `static_mr` and `config_mr` are static MRs.
- `full_report` illustrates that a complete architecture-dependent attestation
report structure (for instance, the `TDREPORT` structure in Intel TDX) can be
presented as an MR.
- `user_data` represents the data provided by the software to be incorporated
into the attestation report. Writing to this MR and then reading from
`full_report` effectively triggers a request for an attestation report from
the underlying CC hardware.
- `report_digest` serves as an example MR to demonstrate the use of the
`TSM_MR_F_L` flag.
- `rtmr0` is an RTMR with `TSM_MR_F_W` **cleared**, preventing direct
extensions; as a result, `rtmr0/digest` is read-only, and the sole method to
extend this RTMR is by writing to `rtmr0/append_event`.
- `rtmr1` is an RTMR with `TSM_MR_F_W` **set**, permitting direct extensions;
thus, `rtmr1/digest` is writable.
See comments in `samples/tsm/measurement-example.c` for more details.
Signed-off-by: Cedric Xing <cedric.xing@intel.com>
---
samples/Kconfig | 4 ++
samples/Makefile | 1 +
samples/tsm/Makefile | 2 +
samples/tsm/measurement-example.c | 116 ++++++++++++++++++++++++++++++++++++++
4 files changed, 123 insertions(+)
diff --git a/samples/Kconfig b/samples/Kconfig
index b288d9991d27..8159d3ca6487 100644
--- a/samples/Kconfig
+++ b/samples/Kconfig
@@ -184,6 +184,10 @@ config SAMPLE_TIMER
bool "Timer sample"
depends on CC_CAN_LINK && HEADERS_INSTALL
+config SAMPLE_TSM
+ tristate "TSM measurement sample"
+ depends on TSM_REPORTS
+
config SAMPLE_UHID
bool "UHID sample"
depends on CC_CAN_LINK && HEADERS_INSTALL
diff --git a/samples/Makefile b/samples/Makefile
index b85fa64390c5..891f5c12cd39 100644
--- a/samples/Makefile
+++ b/samples/Makefile
@@ -39,3 +39,4 @@ obj-$(CONFIG_SAMPLE_KMEMLEAK) += kmemleak/
obj-$(CONFIG_SAMPLE_CORESIGHT_SYSCFG) += coresight/
obj-$(CONFIG_SAMPLE_FPROBE) += fprobe/
obj-$(CONFIG_SAMPLES_RUST) += rust/
+obj-$(CONFIG_SAMPLE_TSM) += tsm/
diff --git a/samples/tsm/Makefile b/samples/tsm/Makefile
new file mode 100644
index 000000000000..3969a59221e9
--- /dev/null
+++ b/samples/tsm/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_SAMPLE_TSM) += measurement-example.o
diff --git a/samples/tsm/measurement-example.c b/samples/tsm/measurement-example.c
new file mode 100644
index 000000000000..b10bda4ba1ee
--- /dev/null
+++ b/samples/tsm/measurement-example.c
@@ -0,0 +1,116 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(c) 2024 Intel Corporation. All rights reserved. */
+
+#include <linux/module.h>
+#include <linux/tsm.h>
+#include <crypto/hash_info.h>
+#include <crypto/hash.h>
+
+struct __aligned(16)
+{
+ u8 static_mr[SHA384_DIGEST_SIZE];
+ u8 config_mr[SHA512_DIGEST_SIZE];
+ u8 rtmr0[SHA256_DIGEST_SIZE];
+ u8 rtmr1[SHA384_DIGEST_SIZE];
+ u8 user_data[SHA512_DIGEST_SIZE];
+ u8 report_digest[SHA512_DIGEST_SIZE];
+}
+example_report = {
+ .static_mr = "STATIC MR",
+ .config_mr = "CONFIG MR",
+};
+
+DEFINE_FREE(shash, struct crypto_shash *,
+ if (!IS_ERR(_T)) crypto_free_shash(_T));
+
+static int _refresh_report(struct tsm_measurement_provider *pvd,
+ const struct tsm_measurement_register *mr)
+{
+ pr_debug(KBUILD_MODNAME ": %s(%s,%s)\n", __func__, pvd->name,
+ mr->mr_name);
+ struct crypto_shash *tfm __free(shash) =
+ crypto_alloc_shash(hash_algo_name[HASH_ALGO_SHA512], 0, 0);
+ if (IS_ERR(tfm))
+ return PTR_ERR(tfm);
+ return crypto_shash_tfm_digest(tfm, (u8 *)&example_report,
+ offsetof(typeof(example_report),
+ report_digest),
+ example_report.report_digest);
+}
+
+static int _extend_mr(struct tsm_measurement_provider *pvd,
+ const struct tsm_measurement_register *mr, const u8 *data)
+{
+ SHASH_DESC_ON_STACK(desc, 0);
+ int rc;
+
+ pr_debug(KBUILD_MODNAME ": %s(%s,%s)\n", __func__, pvd->name,
+ mr->mr_name);
+
+ desc->tfm = crypto_alloc_shash(hash_algo_name[mr->mr_hash], 0, 0);
+ if (IS_ERR(desc->tfm))
+ return PTR_ERR(desc->tfm);
+
+ BUG_ON(crypto_shash_digestsize(desc->tfm) != mr->mr_size);
+
+ 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);
+ return rc;
+}
+
+#define MR_(mr) #mr, &example_report.mr, sizeof(example_report.mr), TSM_MR_F_R
+static const struct tsm_measurement_register example_mrs[] = {
+ /* the entire report can be considered as a LIVE MR */
+ { "full_report", &example_report, sizeof(example_report),
+ TSM_MR_F_LIVE },
+ /* static MR, read-only */
+ { MR_(static_mr) },
+ /* config MR, read-only */
+ { MR_(config_mr) },
+ /* RTMR, direct extension prohibited */
+ { MR_(rtmr0) | TSM_MR_F_RTMR, HASH_ALGO_SHA256 },
+ /* RTMR, direct extension allowed */
+ { MR_(rtmr1) | TSM_MR_F_RTMR | TSM_MR_F_W, HASH_ALGO_SHA384 },
+ /* most CC archs allow including user data in attestation */
+ { MR_(user_data) | TSM_MR_F_W },
+ /* LIVE MR example, usually doesn't exist in real CC arch */
+ { MR_(report_digest) | TSM_MR_F_L },
+ /* terminating NULL entry */
+ {}
+};
+#undef MR_
+
+static struct tsm_measurement_provider example_measurement_provider = {
+ .name = "measurement-example",
+ .mrs = example_mrs,
+ .refresh = _refresh_report,
+ .extend = _extend_mr,
+};
+
+static int __init measurement_example_init(void)
+{
+ int rc = tsm_register_measurement_provider(
+ &example_measurement_provider);
+ pr_debug(KBUILD_MODNAME ": tsm_register_measurement_provider(%p)=%d\n",
+ &example_measurement_provider, rc);
+ return rc;
+}
+
+static void __exit measurement_example_exit(void)
+{
+ int rc = tsm_unregister_measurement_provider(
+ &example_measurement_provider);
+ pr_debug(KBUILD_MODNAME
+ ": tsm_unregister_measurement_provider(%p)=%d\n",
+ &example_measurement_provider, rc);
+}
+
+module_init(measurement_example_init);
+module_exit(measurement_example_exit);
+
+MODULE_LICENSE("GPL");
--
2.43.0
On Sat, 2024-09-07 at 23:56 -0500, Cedric Xing wrote: > This sample kernel module demonstrates how to make MRs accessible to > user mode > through TSM. > > Once loaded, this module registers a virtual measurement provider > with the TSM > core and will result in the directory tree below. > > /sys/kernel/tsm/ > └── measurement-example > ├── config_mr > ├── full_report > ├── report_digest > ├── rtmr0 > │ ├── append_event > │ ├── digest > │ ├── event_log > │ └── hash_algo > ├── rtmr1 > │ ├── append_event > │ ├── digest > │ ├── event_log > │ └── hash_algo > ├── static_mr > └── user_data I'm not sure this is the best structure to apply to logs with multiple banks (hash algorithms). There needs to be a way to get the same registers measurement for each bank, but the log should sit above that (appending should extend all active banks) How about /sys/kernel/tsm/ └──<measurement type> ├──reg0 │ ├── <log format> │ │ ├── append_event │ │ └── event_log │ ├── <hash algo> │ ... └── digest ... That way it supports multiple log formats (would be the job of the log extender to ensure compatibility) and multiple banks. James
On 9/12/2024 7:28 AM, James Bottomley wrote: > On Sat, 2024-09-07 at 23:56 -0500, Cedric Xing wrote: >> This sample kernel module demonstrates how to make MRs accessible to >> user mode >> through TSM. >> >> Once loaded, this module registers a virtual measurement provider >> with the TSM >> core and will result in the directory tree below. >> >> /sys/kernel/tsm/ >> └── measurement-example >> ├── config_mr >> ├── full_report >> ├── report_digest >> ├── rtmr0 >> │ ├── append_event >> │ ├── digest >> │ ├── event_log >> │ └── hash_algo >> ├── rtmr1 >> │ ├── append_event >> │ ├── digest >> │ ├── event_log >> │ └── hash_algo >> ├── static_mr >> └── user_data > > I'm not sure this is the best structure to apply to logs with multiple > banks (hash algorithms). There needs to be a way to get the same > registers measurement for each bank, but the log should sit above that > (appending should extend all active banks) > > How about > > /sys/kernel/tsm/ > └──<measurement type> > ├──reg0 > │ ├── <log format> > │ │ ├── append_event > │ │ └── event_log > │ ├── <hash algo> > │ ... └── digest > ... > > That way it supports multiple log formats (would be the job of the log > extender to ensure compatibility) and multiple banks. > I have considered this before. But I'm not sure how to (define/describe criteria to) match an MR with its log format. Also, MRs are arch dependent and may also vary from gen to gen. I'm afraid this might bring in more chaos than order. -Cedric
On Sat, 2024-09-14 at 11:36 -0500, Xing, Cedric wrote: > On 9/12/2024 7:28 AM, James Bottomley wrote: > > On Sat, 2024-09-07 at 23:56 -0500, Cedric Xing wrote: > > > This sample kernel module demonstrates how to make MRs accessible > > > to > > > user mode > > > through TSM. > > > > > > Once loaded, this module registers a virtual measurement provider > > > with the TSM > > > core and will result in the directory tree below. > > > > > > /sys/kernel/tsm/ > > > └── measurement-example > > > ├── config_mr > > > ├── full_report > > > ├── report_digest > > > ├── rtmr0 > > > │ ├── append_event > > > │ ├── digest > > > │ ├── event_log > > > │ └── hash_algo > > > ├── rtmr1 > > > │ ├── append_event > > > │ ├── digest > > > │ ├── event_log > > > │ └── hash_algo > > > ├── static_mr > > > └── user_data > > > > I'm not sure this is the best structure to apply to logs with > > multiple banks (hash algorithms). There needs to be a way to get > > the same registers measurement for each bank, but the log should > > sit above that (appending should extend all active banks) > > > > How about > > > > /sys/kernel/tsm/ > > └──<measurement type> > > ├──reg0 > > │ ├── <log format> > > │ │ ├── append_event > > │ │ └── event_log > > │ ├── <hash algo> > > │ ... └── digest > > ... > > > > That way it supports multiple log formats (would be the job of the > > log extender to ensure compatibility) and multiple banks. > > > I have considered this before. But I'm not sure how to > (define/describe criteria to) match an MR with its log format. This is already defined for every existing log format ... why would you have to define it again? > Also, MRs are arch dependent and may also vary from gen to gen. I'm > afraid this might bring in more chaos than order. I think I understand this. All measurement registers are simply equivalent to PCRs in terms of the mathematical definition of how they extend. Exactly what measurements go into a PCR and how they are logged is defined in various standards. The TCG ones are fairly fixed now, but if Intel wants to keep redefining the way its measurements work, the logical thing to do is tie this to a version number and make measuring the version the first log entry so the tools know how to differentiate. James
On Sat, Sep 14, 2024 at 01:10:33PM -0400, James Bottomley wrote: > On Sat, 2024-09-14 at 11:36 -0500, Xing, Cedric wrote: > > > Also, MRs are arch dependent and may also vary from gen to gen. I'm > > afraid this might bring in more chaos than order. > > I think I understand this. All measurement registers are simply > equivalent to PCRs in terms of the mathematical definition of how they > extend. Exactly what measurements go into a PCR and how they are Given this, would it be reasonable to go back to the digest based input ABI idea where user space would use the TSM provider specifc hash algo to prepare the input? The kernel eventlog for each MR (or some notification mechanism to user space) would be provided just to keep the digest ordering. Apps would map their inputs to that digest list when doing attestation (in whatever format they choose). On that note, we have the CCC kernel SIG call again Friday this week. If we get enough people interested in this topic on the call, we could brainstorm this a bit further. -- Regards, Mikko
On 9/14/2024 12:10 PM, James Bottomley wrote: > On Sat, 2024-09-14 at 11:36 -0500, Xing, Cedric wrote: >> I have considered this before. But I'm not sure how to >> (define/describe criteria to) match an MR with its log format. > > This is already defined for every existing log format ... why would you > have to define it again? > >> Also, MRs are arch dependent and may also vary from gen to gen. I'm >> afraid this might bring in more chaos than order. > > I think I understand this. All measurement registers are simply > equivalent to PCRs in terms of the mathematical definition of how they > extend. Exactly what measurements go into a PCR and how they are > logged is defined in various standards. The TCG ones are fairly fixed > now, but if Intel wants to keep redefining the way its measurements > work, the logical thing to do is tie this to a version number and make > measuring the version the first log entry so the tools know how to > differentiate. > I’m not sure if I understand this correctly. Are you suggesting we continue using the event definitions from the existing TCG specs with just a simple RTMR-to-PCR map? That’s exactly the issue we’re trying to address. The current specs don’t cover new applications. For example, how to describe the event of launching a container measured to a specific SHA-256 digest in CoCo? Defining new event types would require revising the specs, which is a high barrier for most applications. While TPM has been widely adopted, its use has been mostly limited to pre-boot scenarios. The lack of OS applications leveraging TPM is partly due to this limitation IMHO.
On 9/7/24 21:56, Cedric Xing wrote:
...
> +module_init(measurement_example_init);
> +module_exit(measurement_example_exit);
> +
> +MODULE_LICENSE("GPL");
Missing MODULE_DESCRIPTION()
Since commit 1fffe7a34c89 ("script: modpost: emit a warning when the
description is missing"), a module without a MODULE_DESCRIPTION() will
result in a warning when built with make W=1. Recently, multiple
developers have been eradicating these warnings treewide, and very few
are left, so please don't introduce a new one :)
On 9/9/2024 10:14 AM, Jeff Johnson wrote:
> On 9/7/24 21:56, Cedric Xing wrote:
> ...
>> +module_init(measurement_example_init);
>> +module_exit(measurement_example_exit);
>> +
>> +MODULE_LICENSE("GPL");
>
> Missing MODULE_DESCRIPTION()
>
> Since commit 1fffe7a34c89 ("script: modpost: emit a warning when the
> description is missing"), a module without a MODULE_DESCRIPTION() will
> result in a warning when built with make W=1. Recently, multiple
> developers have been eradicating these warnings treewide, and very few
> are left, so please don't introduce a new one :)
>
Thanks! This will be fixed in the next version of the series.
© 2016 - 2025 Red Hat, Inc.