[PATCH RFC 3/3] tsm: Add TVM Measurement Sample Code

Cedric Xing posted 3 patches 1 year, 3 months ago
There is a newer version of this series
[PATCH RFC 3/3] tsm: Add TVM Measurement Sample Code
Posted by Cedric Xing 1 year, 3 months ago
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

Re: [PATCH RFC 3/3] tsm: Add TVM Measurement Sample Code
Posted by James Bottomley 1 year, 3 months ago
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

Re: [PATCH RFC 3/3] tsm: Add TVM Measurement Sample Code
Posted by Xing, Cedric 1 year, 3 months ago
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
Re: [PATCH RFC 3/3] tsm: Add TVM Measurement Sample Code
Posted by James Bottomley 1 year, 3 months ago
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

Re: [PATCH RFC 3/3] tsm: Add TVM Measurement Sample Code
Posted by Mikko Ylinen 1 year, 1 month ago
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
Re: [PATCH RFC 3/3] tsm: Add TVM Measurement Sample Code
Posted by Xing, Cedric 1 year, 3 months ago
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.

Re: [PATCH RFC 3/3] tsm: Add TVM Measurement Sample Code
Posted by Jeff Johnson 1 year, 3 months ago
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 :)
Re: [PATCH RFC 3/3] tsm: Add TVM Measurement Sample Code
Posted by Xing, Cedric 1 year, 3 months ago
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.