mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH RFC 0/3] security: ima: support TSM measurement registers
@ 2026-09-30 13:43 Yeoreum Yun
  2026-09-30 13:43 ` [PATCH RFC 1/3] virt: coco: introduce tsm_default_tm() and tsm_mr_read()/write() Yeoreum Yun
                   ` (3 more replies)
  0 siblings, 4 replies; 9+ messages in thread
From: Yeoreum Yun @ 2026-09-30 13:43 UTC (permalink / raw)
  To: linux-coco, linux-kernel, linux-arm-kernel, Eric Snowberg,
	linux-integrity, linux-security-module
  Cc: Dan Williams, Mimi Zohar, Roberto Sassu, Dmitry Kasatkin,
	Paul Moore, James Morris, Serge E. Hallyn, Catalin Marinas,
	Jason Gunthorpe, Suzuki Poulose, Steven Price, Sami Mujawar,
	Aneesh Kumar K.V, Jiri Pirko, Yeoreum Yun

Confidential computing guests without a TPM can use TSM measurement
registers to record IMA measurement digests instead of TPM PCRs.

This series introduces in-kernel interfaces for accessing TSM
measurement registers, abstracts IMA's measurement-register operations,
and adds a TSM backend for Intel TDX and Arm CCA.

The following mappings between TPM PCR indices and TSM measurement
registers are defined for Intel TDX [0] and proposed for Arm CCA [1]:

  TPM PCR index | Intel TDX register | Arm CCA register
  --------------+--------------------+-----------------
  0             | MRTD               | RIM
  1, 7          | RTMR[0]            | REM[0]
  2-6           | RTMR[1]            | REM[1]
  8-15          | RTMR[2]            | REM[2]

These mappings allow IMA to translate PCR indices into the corresponding
TSM measurement registers.

The TPM backend remains preferred when it is available at IMA
initialization. Otherwise, IMA falls back to a supported TSM backend.
Only one backend is selected; IMA measurements are not extended to both
TPM PCRs and TSM measurement registers.

The attestation proccess for guest with TSM measurement register will
be done with Confidential Compute Event Log (CCEL) which is exported by
/sys/firmware/acpi/tables/data/CCEL. Here is brief process in arm64:

  Verifier                 Realm guest              RMM / Platform
     |                         |                           |
     |--- Challenge (nonce) -->|                           |
     |                         |--- Request token -------->|
     |                         |    with challenge         |
     |                         |                           |
     |                         |<-- CCA token T -----------|
     |<-- CCA token T ---------|                           |
     |<-- CCEL event log ------|                           |
     |<-- IMA measurement log -|                           |
     |                         |                           |
 Verify token T:               |                           |
  - signatures                 |                           |
  - Platform/Realm             |                           |
    token binding              |                           |
  - challenge freshness        |                           |
  - platform/RIM policy        |                           |
  - verify measurement logs    |                           |
     |                         |                           |
     | ----ACCEPT / REJECT---->|                           |

This patch based on arm-cca-mr series [3].

Link: [0] https://uefi.org/specs/UEFI/2.11/38_Confidential_Computing.html#intel-trust-domain-extension
Link: [1] https://github.com/tianocore/edk2/issues/11383
Link: [2] https://github.com/tianocore/edk2/issues/11384
Link: [3] https://lore.kernel.org/all/20260929-arm_cca_mr-v2-0-1d98bba187fd@arm.com/

---
Yeoreum Yun (3):
      virt: coco: introduce tsm_default_tm() and tsm_mr_read()/write()
      security: IMA: introduce ima_mr structure
      security: IMA: use TSM measurement registers

 drivers/virt/coco/guest/tsm-mr.c          | 159 +++++++++++++---
 include/linux/tsm-mr.h                    |  26 +++
 security/integrity/ima/Makefile           |   3 +-
 security/integrity/ima/ima.h              |   7 +-
 security/integrity/ima/ima_api.c          |   4 +-
 security/integrity/ima/ima_crypto.c       | 137 +++++---------
 security/integrity/ima/ima_fs.c           |  16 +-
 security/integrity/ima/ima_init.c         |   7 +-
 security/integrity/ima/ima_mr.c           |  48 +++++
 security/integrity/ima/ima_mr.h           |  76 ++++++++
 security/integrity/ima/ima_mr_tpm.c       | 155 ++++++++++++++++
 security/integrity/ima/ima_mr_tsm.c       | 290 ++++++++++++++++++++++++++++++
 security/integrity/ima/ima_queue.c        |  39 ++--
 security/integrity/ima/ima_template.c     |   4 +-
 security/integrity/ima/ima_template_lib.c |   2 +-
 15 files changed, 819 insertions(+), 154 deletions(-)
---
base-commit: b561246f45174b7472c24b75358ea95bae72b7b8
change-id: 20260929-ima_tgx_integration_v2-1c54aeeaeaee

Best regards,
-- 
Sincerely,
Yeoreum Yun


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH RFC 1/3] virt: coco: introduce tsm_default_tm() and tsm_mr_read()/write()
  2026-09-30 13:43 [PATCH RFC 0/3] security: ima: support TSM measurement registers Yeoreum Yun
@ 2026-09-30 13:43 ` Yeoreum Yun
  2026-09-30 13:44 ` [PATCH RFC 2/3] security: IMA: introduce ima_mr structure Yeoreum Yun
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 9+ messages in thread
From: Yeoreum Yun @ 2026-09-30 13:43 UTC (permalink / raw)
  To: linux-coco, linux-kernel, linux-arm-kernel, Eric Snowberg,
	linux-integrity, linux-security-module
  Cc: Dan Williams, Mimi Zohar, Roberto Sassu, Dmitry Kasatkin,
	Paul Moore, James Morris, Serge E. Hallyn, Catalin Marinas,
	Jason Gunthorpe, Suzuki Poulose, Steven Price, Sami Mujawar,
	Aneesh Kumar K.V, Jiri Pirko, Yeoreum Yun

This is preparatory patch to use tsm measurement registers in IMA.
Introduce tsm_default_tm() and tsm_mr_read()/write() APIs
to read and extend the tsm measurement registers in IMA.

Since IMA is supported only when it's built as built-in,
export those symbols only tsm-mr is built as built-in.

Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
 drivers/virt/coco/guest/tsm-mr.c | 159 +++++++++++++++++++++++++++++++++------
 include/linux/tsm-mr.h           |  26 +++++++
 2 files changed, 161 insertions(+), 24 deletions(-)

diff --git a/drivers/virt/coco/guest/tsm-mr.c b/drivers/virt/coco/guest/tsm-mr.c
index 657b9c5739d0..9e721348be8d 100644
--- a/drivers/virt/coco/guest/tsm-mr.c
+++ b/drivers/virt/coco/guest/tsm-mr.c
@@ -7,9 +7,15 @@
 #include <linux/slab.h>
 #include <linux/sysfs.h>
 
+
 #define CREATE_TRACE_POINTS
 #include <trace/events/tsm_mr.h>
 
+#define TM_NUM_CTX	(64 * HASH_ALGO__LAST)
+
+DEFINE_IDR(tm_ctx_idr);
+static DEFINE_MUTEX(idr_lock);
+
 /*
  * struct tm_context - contains everything necessary to implement sysfs
  * attributes for MRs.
@@ -42,21 +48,16 @@ struct tm_context {
 	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)
+static ssize_t __tsm_mr_read(struct tm_context *ctx,
+			 const struct tsm_measurement_register *mr,
+			 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
@@ -88,20 +89,11 @@ static ssize_t tm_digest_read(struct file *filp, struct kobject *kobj,
 	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)
+static ssize_t __tsm_mr_write(struct tm_context *ctx,
+			 const struct tsm_measurement_register *mr,
+			 char *buffer, 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];
+	int rc;
 
 	rc = down_write_killable(&ctx->rwsem);
 	if (rc)
@@ -119,6 +111,36 @@ static ssize_t tm_digest_write(struct file *filp, struct kobject *kobj,
 	return rc ?: count;
 }
 
+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;
+
+	ctx = attr->private;
+	mr = &ctx->tm->mrs[attr - ctx->mrs];
+
+	return __tsm_mr_read(ctx, mr, buffer, off, 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;
+
+	/* partial writes are not supported */
+	if (off != 0 || count != attr->size)
+		return -EINVAL;
+
+	ctx = attr->private;
+	mr = &ctx->tm->mrs[attr - ctx->mrs];
+
+	return __tsm_mr_write(ctx, mr, buffer, count);
+}
+
 /**
  * tsm_mr_create_attribute_group() - creates an attribute group for measurement
  * registers (MRs)
@@ -138,8 +160,7 @@ static ssize_t tm_digest_write(struct file *filp, struct kobject *kobj,
  * * %-ENOMEM - Out of memory.
  */
 const struct attribute_group *
-tsm_mr_create_attribute_group(const struct tsm_measurements *tm)
-{
+tsm_mr_create_attribute_group(const struct tsm_measurements *tm) {
 	size_t nlen;
 
 	if (!tm || !tm->mrs)
@@ -230,6 +251,15 @@ tsm_mr_create_attribute_group(const struct tsm_measurements *tm)
 	ctx->agrp.name = "measurements";
 	ctx->agrp.bin_attrs = no_free_ptr(attrs);
 	ctx->tm = tm;
+
+	guard(mutex)(&idr_lock);
+	((struct tsm_measurements *)tm)->ctx_id = idr_alloc(&tm_ctx_idr, ctx, 0,
+							    TM_NUM_CTX, GFP_KERNEL);
+	if (tm->ctx_id < 0) {
+		kfree(ctx->agrp.bin_attrs);
+		return ERR_PTR(tm->ctx_id);
+	}
+
 	return &no_free_ptr(ctx)->agrp;
 }
 EXPORT_SYMBOL_GPL(tsm_mr_create_attribute_group);
@@ -243,9 +273,90 @@ EXPORT_SYMBOL_GPL(tsm_mr_create_attribute_group);
  */
 void tsm_mr_free_attribute_group(const struct attribute_group *attr_grp)
 {
+	struct tm_context *ctx;
+
 	if (!IS_ERR_OR_NULL(attr_grp)) {
+		ctx = container_of(attr_grp, struct tm_context, agrp);
+		scoped_guard(mutex, &idr_lock)
+			idr_remove(&tm_ctx_idr, ctx->tm->ctx_id);
 		kfree(attr_grp->bin_attrs);
-		kfree(container_of(attr_grp, struct tm_context, agrp));
+		kfree(ctx);
 	}
 }
 EXPORT_SYMBOL_GPL(tsm_mr_free_attribute_group);
+
+#if defined(CONFIG_TSM_MEASUREMENTS)
+const struct tsm_measurements *tsm_default_tm(void)
+{
+	struct tm_context *ctx;
+	int next_id = 0;
+
+	guard(mutex)(&idr_lock);
+
+	ctx = idr_get_next(&tm_ctx_idr, &next_id);
+	if (!ctx)
+		return NULL;
+
+	return ctx->tm;
+}
+EXPORT_SYMBOL_GPL(tsm_default_tm);
+
+int tsm_mr_read(const struct tsm_measurements *tm, int idx,
+		u8 *digest, u32 digest_size)
+{
+	struct tm_context *ctx;
+	const struct tsm_measurement_register *mr;
+	int rc;
+
+	scoped_guard(mutex, &idr_lock)
+		ctx = idr_find(&tm_ctx_idr, tm->ctx_id);
+
+	if (IS_ERR_OR_NULL(ctx))
+		return -ENODEV;
+
+	if (!digest || (idx >= ctx->tm->nr_mrs) ||
+	    (ctx->tm->mrs[idx].mr_size > digest_size) ||
+	    !(ctx->tm->mrs[idx].mr_flags & TSM_MR_F_READABLE))
+		return -EINVAL;
+
+	mr = &ctx->tm->mrs[idx];
+
+	rc = __tsm_mr_read(ctx, mr, (char *)digest, 0, mr->mr_size);
+	if (rc < 0)
+		return rc;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tsm_mr_read);
+
+int tsm_mr_write(const struct tsm_measurements *tm, int idx,
+		 u8 *digest, u32 digest_size)
+{
+	struct tm_context *ctx;
+	const struct tsm_measurement_register *mr;
+	int rc;
+
+	scoped_guard(mutex, &idr_lock)
+		ctx = idr_find(&tm_ctx_idr, tm->ctx_id);
+
+	if (IS_ERR_OR_NULL(ctx))
+		return -ENODEV;
+
+	if (!digest || (idx >= ctx->tm->nr_mrs) ||
+	    !(ctx->tm->mrs[idx].mr_flags & TSM_MR_F_WRITABLE))
+		return -EINVAL;
+
+	/* partial writes are not supported */
+	if (ctx->tm->mrs[idx].mr_size != digest_size)
+		return -EINVAL;
+
+	mr = &ctx->tm->mrs[idx];
+
+	rc = __tsm_mr_write(ctx, mr, (char *)digest, mr->mr_size);
+	if (rc < 0)
+		return rc;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tsm_mr_write);
+#endif
diff --git a/include/linux/tsm-mr.h b/include/linux/tsm-mr.h
index 50a521f4ac97..43a0f761cd96 100644
--- a/include/linux/tsm-mr.h
+++ b/include/linux/tsm-mr.h
@@ -80,10 +80,36 @@ struct tsm_measurements {
 	int (*refresh)(const struct tsm_measurements *tm);
 	int (*write)(const struct tsm_measurements *tm,
 		     const struct tsm_measurement_register *mr, const u8 *data);
+	int ctx_id;
 };
 
 const struct attribute_group *
 tsm_mr_create_attribute_group(const struct tsm_measurements *tm);
 void tsm_mr_free_attribute_group(const struct attribute_group *attr_grp);
 
+#if defined(CONFIG_TSM_MEASUREMENTS)
+const struct tsm_measurements *tsm_default_tm(void);
+int tsm_mr_read(const struct tsm_measurements *tm, int idx,
+		u8 *digest, u32 digest_size);
+int tsm_mr_write(const struct tsm_measurements *tm, int idx,
+		 u8 *digest, u32 digest_size);
+#else
+static inline const struct tsm_measurements *tsm_default_tm(void)
+{
+	return NULL;
+}
+
+static inline int tsm_mr_read(const struct tsm_measurements *tm, int idx,
+			      u8 *digest, u32 digest_size)
+{
+	return 0;
+}
+
+static inline int tsm_mr_write(const struct tsm_measurements *tm, int idx,
+			       u8 *digest, u32 digest_size)
+{
+	return 0;
+}
+#endif
+
 #endif

-- 
2.43.0


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH RFC 2/3] security: IMA: introduce ima_mr structure
  2026-09-30 13:43 [PATCH RFC 0/3] security: ima: support TSM measurement registers Yeoreum Yun
  2026-09-30 13:43 ` [PATCH RFC 1/3] virt: coco: introduce tsm_default_tm() and tsm_mr_read()/write() Yeoreum Yun
@ 2026-09-30 13:44 ` Yeoreum Yun
  2026-09-30 13:44 ` [PATCH RFC 3/3] security: IMA: use TSM measurement registers Yeoreum Yun
  2026-10-01 11:27 ` [PATCH RFC 0/3] security: ima: support " Roberto Sassu
  3 siblings, 0 replies; 9+ messages in thread
From: Yeoreum Yun @ 2026-09-30 13:44 UTC (permalink / raw)
  To: linux-coco, linux-kernel, linux-arm-kernel, Eric Snowberg,
	linux-integrity, linux-security-module
  Cc: Dan Williams, Mimi Zohar, Roberto Sassu, Dmitry Kasatkin,
	Paul Moore, James Morris, Serge E. Hallyn, Catalin Marinas,
	Jason Gunthorpe, Suzuki Poulose, Steven Price, Sami Mujawar,
	Aneesh Kumar K.V, Jiri Pirko, Yeoreum Yun

This is preparatory patch to integrate tsm measurement registers with IMA.

To integrate tsm measurement registers, introcude ima_mr structure
which abstract measurements register and ima_mr_operation structure
which defines below operations to communicate with them:

  - mr_init(): find and initialise to communicate measurement registers
  - mr_get_bank_info: get information of bank of measurement registers.
  - mr_calc_boot_aggregate: generate boot aggregate hash with
                            measurement registers.
  - mr_extend: extend measurement registers.

Also, this patch adds ima_mr using TPM device using PCR as
measurement registers.

Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
 security/integrity/ima/Makefile           |   2 +-
 security/integrity/ima/ima.h              |   7 +-
 security/integrity/ima/ima_api.c          |   4 +-
 security/integrity/ima/ima_crypto.c       | 137 +++++++++-----------------
 security/integrity/ima/ima_fs.c           |  16 ++-
 security/integrity/ima/ima_init.c         |   7 +-
 security/integrity/ima/ima_mr.c           |  47 +++++++++
 security/integrity/ima/ima_mr.h           |  75 +++++++++++++++
 security/integrity/ima/ima_mr_tpm.c       | 155 ++++++++++++++++++++++++++++++
 security/integrity/ima/ima_queue.c        |  39 ++++----
 security/integrity/ima/ima_template.c     |   4 +-
 security/integrity/ima/ima_template_lib.c |   2 +-
 12 files changed, 365 insertions(+), 130 deletions(-)

diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile
index b376d38b4ee6..f2c46b405a00 100644
--- a/security/integrity/ima/Makefile
+++ b/security/integrity/ima/Makefile
@@ -7,7 +7,7 @@
 obj-$(CONFIG_IMA) += ima.o ima_iint.o
 
 ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \
-	 ima_policy.o ima_template.o ima_template_lib.o
+	 ima_policy.o ima_template.o ima_template_lib.o ima_mr.o ima_mr_tpm.o
 ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o
 ima-$(CONFIG_IMA_APPRAISE_MODSIG) += ima_modsig.o
 ima-$(CONFIG_HAVE_IMA_KEXEC) += ima_kexec.o
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 10214f73ca1e..5e43d3140357 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -22,11 +22,11 @@
 #include <linux/audit.h>
 #include <crypto/hash_info.h>
 
+#include "ima_mr.h"
 #include "../integrity.h"
 
 enum ima_show_type { IMA_SHOW_BINARY, IMA_SHOW_BINARY_NO_FIELD_LEN,
 		     IMA_SHOW_BINARY_OLD_STRING_FMT, IMA_SHOW_ASCII };
-enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8, TPM_PCR10 = 10 };
 
 /*
  * BINARY: current binary measurements list
@@ -50,8 +50,6 @@ enum binary_lists {
 #define IMA_TEMPLATE_IMA_NAME "ima"
 #define IMA_TEMPLATE_IMA_FMT "d|n"
 
-#define NR_BANKS(chip) ((chip != NULL) ? chip->nr_allocated_banks : 0)
-
 /* current content of the policy */
 extern int ima_policy_flag;
 
@@ -75,7 +73,6 @@ extern int ima_extra_slots __ro_after_init;
 extern struct ima_algo_desc *ima_algo_array __ro_after_init;
 
 extern int ima_appraise;
-extern struct tpm_chip *ima_tpm_chip;
 extern const char boot_aggregate_name[];
 extern const char boot_aggregate_late_name[];
 
@@ -118,7 +115,7 @@ struct ima_template_desc {
 
 struct ima_template_entry {
 	int pcr;
-	struct tpm_digest *digests;
+	mr_digest_t *digests;
 	struct ima_template_desc *template_desc; /* template descriptor */
 	u32 template_data_len;
 	struct ima_field_data template_data[];	/* template related data */
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index 122d127e108d..8a7194a26b81 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -40,7 +40,7 @@ int ima_alloc_init_template(struct ima_event_data *event_data,
 			    struct ima_template_desc *desc)
 {
 	struct ima_template_desc *template_desc;
-	struct tpm_digest *digests;
+	mr_digest_t *digests;
 	int i, result = 0;
 
 	if (desc)
@@ -54,7 +54,7 @@ int ima_alloc_init_template(struct ima_event_data *event_data,
 		return -ENOMEM;
 
 	digests = kzalloc_objs(*digests,
-			       NR_BANKS(ima_tpm_chip) + ima_extra_slots,
+			       NR_BANKS(ima_mr) + ima_extra_slots,
 			       GFP_NOFS);
 	if (!digests) {
 		kfree(*entry);
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c
index 0d72b48249ee..efa27ce5f128 100644
--- a/security/integrity/ima/ima_crypto.c
+++ b/security/integrity/ima/ima_crypto.c
@@ -58,7 +58,7 @@ static struct crypto_shash *ima_alloc_tfm(enum hash_algo algo)
 	if (algo == ima_hash_algo)
 		return tfm;
 
-	for (i = 0; i < NR_BANKS(ima_tpm_chip) + ima_extra_slots; i++)
+	for (i = 0; i < NR_BANKS(ima_mr) + ima_extra_slots; i++)
 		if (ima_algo_array[i].tfm && ima_algo_array[i].algo == algo)
 			return ima_algo_array[i].tfm;
 
@@ -77,6 +77,7 @@ int __init ima_init_crypto(void)
 	enum hash_algo algo;
 	long rc;
 	int i;
+	mr_bank_info_t bank_info;
 
 	rc = ima_init_ima_crypto();
 	if (rc)
@@ -85,8 +86,12 @@ int __init ima_init_crypto(void)
 	ima_sha1_idx = -1;
 	ima_hash_algo_idx = -1;
 
-	for (i = 0; i < NR_BANKS(ima_tpm_chip); i++) {
-		algo = ima_tpm_chip->allocated_banks[i].crypto_id;
+	for (i = 0; i < NR_BANKS(ima_mr); i++) {
+		rc = ima_mr->ops->mr_get_bank_info(ima_mr, i, &bank_info);
+		if (rc)
+			return rc;
+
+		algo = bank_info.crypto_id;
 		if (algo == HASH_ALGO_SHA1)
 			ima_sha1_idx = i;
 
@@ -95,24 +100,28 @@ int __init ima_init_crypto(void)
 	}
 
 	if (ima_sha1_idx < 0) {
-		ima_sha1_idx = NR_BANKS(ima_tpm_chip) + ima_extra_slots++;
+		ima_sha1_idx = NR_BANKS(ima_mr) + ima_extra_slots++;
 		if (ima_hash_algo == HASH_ALGO_SHA1)
 			ima_hash_algo_idx = ima_sha1_idx;
 	}
 
 	if (ima_hash_algo_idx < 0)
-		ima_hash_algo_idx = NR_BANKS(ima_tpm_chip) + ima_extra_slots++;
+		ima_hash_algo_idx = NR_BANKS(ima_mr) + ima_extra_slots++;
 
 	ima_algo_array = kzalloc_objs(*ima_algo_array,
-				      NR_BANKS(ima_tpm_chip) + ima_extra_slots);
+				      NR_BANKS(ima_mr) + ima_extra_slots);
 	if (!ima_algo_array) {
 		rc = -ENOMEM;
 		goto out;
 	}
 
-	for (i = 0; i < NR_BANKS(ima_tpm_chip); i++) {
-		algo = ima_tpm_chip->allocated_banks[i].crypto_id;
-		digest_size = ima_tpm_chip->allocated_banks[i].digest_size;
+	for (i = 0; i < NR_BANKS(ima_mr); i++) {
+		rc = ima_mr->ops->mr_get_bank_info(ima_mr, i, &bank_info);
+		if (rc)
+			return rc;
+
+		algo = bank_info.crypto_id;
+		digest_size = bank_info.digest_size;
 		ima_algo_array[i].algo = algo;
 		ima_algo_array[i].digest_size = digest_size;
 
@@ -137,7 +146,7 @@ int __init ima_init_crypto(void)
 		}
 	}
 
-	if (ima_sha1_idx >= NR_BANKS(ima_tpm_chip)) {
+	if (ima_sha1_idx >= NR_BANKS(ima_mr)) {
 		if (ima_hash_algo == HASH_ALGO_SHA1) {
 			ima_algo_array[ima_sha1_idx].tfm = ima_shash_tfm;
 		} else {
@@ -153,7 +162,7 @@ int __init ima_init_crypto(void)
 		ima_algo_array[ima_sha1_idx].digest_size = SHA1_DIGEST_SIZE;
 	}
 
-	if (ima_hash_algo_idx >= NR_BANKS(ima_tpm_chip) &&
+	if (ima_hash_algo_idx >= NR_BANKS(ima_mr) &&
 	    ima_hash_algo_idx != ima_sha1_idx) {
 		digest_size = hash_digest_size[ima_hash_algo];
 		ima_algo_array[ima_hash_algo_idx].tfm = ima_shash_tfm;
@@ -163,7 +172,7 @@ int __init ima_init_crypto(void)
 
 	return 0;
 out_array:
-	for (i = 0; i < NR_BANKS(ima_tpm_chip) + ima_extra_slots; i++) {
+	for (i = 0; i < NR_BANKS(ima_mr) + ima_extra_slots; i++) {
 		if (!ima_algo_array[i].tfm ||
 		    ima_algo_array[i].tfm == ima_shash_tfm)
 			continue;
@@ -183,7 +192,7 @@ static void ima_free_tfm(struct crypto_shash *tfm)
 	if (tfm == ima_shash_tfm)
 		return;
 
-	for (i = 0; i < NR_BANKS(ima_tpm_chip) + ima_extra_slots; i++)
+	for (i = 0; i < NR_BANKS(ima_mr) + ima_extra_slots; i++)
 		if (ima_algo_array[i].tfm == tfm)
 			return;
 
@@ -335,7 +344,7 @@ static int ima_calc_field_array_hash_tfm(struct ima_field_data *field_data,
 int ima_calc_field_array_hash(struct ima_field_data *field_data,
 			      struct ima_template_entry *entry)
 {
-	u16 alg_id;
+	mr_bank_info_t bank_info;
 	int rc, i;
 
 	rc = ima_calc_field_array_hash_tfm(field_data, entry, ima_sha1_idx);
@@ -344,13 +353,16 @@ int ima_calc_field_array_hash(struct ima_field_data *field_data,
 
 	entry->digests[ima_sha1_idx].alg_id = TPM_ALG_SHA1;
 
-	for (i = 0; i < NR_BANKS(ima_tpm_chip) + ima_extra_slots; i++) {
+	for (i = 0; i < NR_BANKS(ima_mr) + ima_extra_slots; i++) {
 		if (i == ima_sha1_idx)
 			continue;
 
-		if (i < NR_BANKS(ima_tpm_chip)) {
-			alg_id = ima_tpm_chip->allocated_banks[i].alg_id;
-			entry->digests[i].alg_id = alg_id;
+		if (i < NR_BANKS(ima_mr)) {
+			rc = ima_mr->ops->mr_get_bank_info(ima_mr, i, &bank_info);
+			if (rc)
+				return rc;
+
+			entry->digests[i].alg_id = bank_info.alg_id;
 		}
 
 		/* for unmapped TPM algorithms digest is still a padded SHA1 */
@@ -414,87 +426,26 @@ int ima_calc_buffer_hash(const void *buf, loff_t len,
 	return rc;
 }
 
-static void ima_pcrread(u32 idx, struct tpm_digest *d)
-{
-	if (!ima_tpm_chip)
-		return;
-
-	if (tpm_pcr_read(ima_tpm_chip, idx, d) != 0)
-		pr_err("Error Communicating to TPM chip\n");
-}
-
-/*
- * The boot_aggregate is a cumulative hash over TPM registers 0 - 7.  With
- * TPM 1.2 the boot_aggregate was based on reading the SHA1 PCRs, but with
- * TPM 2.0 hash agility, TPM chips could support multiple TPM PCR banks,
- * allowing firmware to configure and enable different banks.
- *
- * Knowing which TPM bank is read to calculate the boot_aggregate digest
- * needs to be conveyed to a verifier.  For this reason, use the same
- * hash algorithm for reading the TPM PCRs as for calculating the boot
- * aggregate digest as stored in the measurement list.
- */
-static int ima_calc_boot_aggregate_tfm(char *digest, u16 alg_id,
-				       struct crypto_shash *tfm)
-{
-	struct tpm_digest d = { .alg_id = alg_id, .digest = {0} };
-	int rc;
-	u32 i;
-	SHASH_DESC_ON_STACK(shash, tfm);
-
-	shash->tfm = tfm;
-
-	pr_devel("calculating the boot-aggregate based on TPM bank: %04x\n",
-		 d.alg_id);
-
-	rc = crypto_shash_init(shash);
-	if (rc != 0)
-		return rc;
-
-	/* cumulative digest over TPM registers 0-7 */
-	for (i = TPM_PCR0; i < TPM_PCR8; i++) {
-		ima_pcrread(i, &d);
-		/* now accumulate with current aggregate */
-		rc = crypto_shash_update(shash, d.digest,
-					 crypto_shash_digestsize(tfm));
-		if (rc != 0)
-			return rc;
-	}
-	/*
-	 * Extend cumulative digest over TPM registers 8-9, which contain
-	 * measurement for the kernel command line (reg. 8) and image (reg. 9)
-	 * in a typical PCR allocation. Registers 8-9 are only included in
-	 * non-SHA1 boot_aggregate digests to avoid ambiguity.
-	 */
-	if (alg_id != TPM_ALG_SHA1) {
-		for (i = TPM_PCR8; i < TPM_PCR10; i++) {
-			ima_pcrread(i, &d);
-			rc = crypto_shash_update(shash, d.digest,
-						crypto_shash_digestsize(tfm));
-		}
-	}
-	if (!rc)
-		rc = crypto_shash_final(shash, digest);
-	return rc;
-}
-
 int ima_calc_boot_aggregate(struct ima_digest_data *hash)
 {
 	struct crypto_shash *tfm;
-	u16 crypto_id, alg_id;
+	mr_bank_info_t bank_info;
 	int rc, i, bank_idx = -1;
 
-	for (i = 0; i < ima_tpm_chip->nr_allocated_banks; i++) {
-		crypto_id = ima_tpm_chip->allocated_banks[i].crypto_id;
-		if (crypto_id == hash->algo) {
+	for (i = 0; i < NR_BANKS(ima_mr); i++) {
+		rc = ima_mr->ops->mr_get_bank_info(ima_mr, i, &bank_info);
+		if (rc)
+			return rc;
+
+		if (bank_info.crypto_id == hash->algo) {
 			bank_idx = i;
 			break;
 		}
 
-		if (crypto_id == HASH_ALGO_SHA256)
+		if (bank_info.crypto_id == HASH_ALGO_SHA256)
 			bank_idx = i;
 
-		if (bank_idx == -1 && crypto_id == HASH_ALGO_SHA1)
+		if (bank_idx == -1 && bank_info.crypto_id == HASH_ALGO_SHA1)
 			bank_idx = i;
 	}
 
@@ -503,15 +454,19 @@ int ima_calc_boot_aggregate(struct ima_digest_data *hash)
 		return 0;
 	}
 
-	hash->algo = ima_tpm_chip->allocated_banks[bank_idx].crypto_id;
+	rc = ima_mr->ops->mr_get_bank_info(ima_mr, bank_idx, &bank_info);
+	if (rc)
+		return rc;
+
+	hash->algo = bank_info.crypto_id;
 
 	tfm = ima_alloc_tfm(hash->algo);
 	if (IS_ERR(tfm))
 		return PTR_ERR(tfm);
 
 	hash->length = crypto_shash_digestsize(tfm);
-	alg_id = ima_tpm_chip->allocated_banks[bank_idx].alg_id;
-	rc = ima_calc_boot_aggregate_tfm(hash->digest, alg_id, tfm);
+	rc = ima_mr->ops->mr_calc_boot_aggregate(ima_mr, bank_idx,
+						  hash->digest, tfm);
 
 	ima_free_tfm(tfm);
 
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index 2a0bca554316..cfe1d5227e54 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -635,7 +635,9 @@ static int __init create_securityfs_measurement_lists(bool staging)
 	const struct file_operations *binary_ops = &ima_measurements_ops;
 	umode_t permissions = (S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP);
 	const char *file_suffix = "";
-	int count = NR_BANKS(ima_tpm_chip);
+	int count = NR_BANKS(ima_mr);
+	int rc;
+	mr_bank_info_t bank_info;
 
 	if (staging) {
 		ascii_ops = &ima_ascii_measurements_staged_ops;
@@ -643,7 +645,7 @@ static int __init create_securityfs_measurement_lists(bool staging)
 		file_suffix = "_staged";
 	}
 
-	if (ima_sha1_idx >= NR_BANKS(ima_tpm_chip))
+	if (ima_sha1_idx >= NR_BANKS(ima_mr))
 		count++;
 
 	for (int i = 0; i < count; i++) {
@@ -651,10 +653,16 @@ static int __init create_securityfs_measurement_lists(bool staging)
 		char file_name[NAME_MAX + 1];
 		struct dentry *dentry;
 
+		if (algo == HASH_ALGO__LAST) {
+			rc = ima_mr->ops->mr_get_bank_info(ima_mr, i, &bank_info);
+			if (rc)
+				return rc;
+		}
+
 		if (algo == HASH_ALGO__LAST)
 			snprintf(file_name, sizeof(file_name),
 				 "ascii_runtime_measurements_tpm_alg_%x%s",
-				 ima_tpm_chip->allocated_banks[i].alg_id,
+				 bank_info.alg_id,
 				 file_suffix);
 		else
 			snprintf(file_name, sizeof(file_name),
@@ -669,7 +677,7 @@ static int __init create_securityfs_measurement_lists(bool staging)
 		if (algo == HASH_ALGO__LAST)
 			snprintf(file_name, sizeof(file_name),
 				 "binary_runtime_measurements_tpm_alg_%x%s",
-				 ima_tpm_chip->allocated_banks[i].alg_id,
+				 bank_info.alg_id,
 				 file_suffix);
 		else
 			snprintf(file_name, sizeof(file_name),
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
index d53f4d89a53e..a1290e891fa4 100644
--- a/security/integrity/ima/ima_init.c
+++ b/security/integrity/ima/ima_init.c
@@ -23,7 +23,6 @@
 /* name for boot aggregate entry */
 const char boot_aggregate_name[] = "boot_aggregate";
 const char boot_aggregate_late_name[] = "boot_aggregate_late";
-struct tpm_chip *ima_tpm_chip;
 
 /* Add the boot aggregate to the IMA measurement list and extend
  * the PCR register.
@@ -78,7 +77,7 @@ static int __init ima_add_boot_aggregate(void)
 	 * Ultimately select SHA1 also for TPM 2.0 if the SHA256 PCR bank
 	 * is not found.
 	 */
-	if (ima_tpm_chip) {
+	if (ima_mr) {
 		result = ima_calc_boot_aggregate(hash_hdr);
 		if (result < 0) {
 			audit_cause = "hashing_error";
@@ -126,9 +125,7 @@ int __init ima_init(void)
 {
 	int rc;
 
-	ima_tpm_chip = tpm_default_chip();
-	if (!ima_tpm_chip)
-		pr_info("No TPM chip found, activating TPM-bypass!\n");
+	ima_init_mr();
 
 	rc = integrity_init_keyring(INTEGRITY_KEYRING_IMA);
 	if (rc)
diff --git a/security/integrity/ima/ima_mr.c b/security/integrity/ima/ima_mr.c
new file mode 100644
index 000000000000..fe58eb968954
--- /dev/null
+++ b/security/integrity/ima/ima_mr.c
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2026 Arm Ltd
+ *
+ * Author:
+ * Yeoreum Yun <yeoreum.yun@arm.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include "ima.h"
+
+struct ima_mr *ima_mr;
+
+static struct ima_mr_operations *ima_mr_ops[] = {
+	&ima_mr_tpm_operations,
+};
+
+void __init ima_init_mr(void)
+{
+	int rc, i;
+
+	ima_mr = kmalloc_obj(*ima_mr);
+	if (!ima_mr) {
+		pr_info("Out of memory creating MR, activating MR-bypass!\n");
+		return;
+	}
+
+	rc = -ENODEV;
+	for (i = 0; i < ARRAY_SIZE(ima_mr_ops); i++) {
+		if (!ima_mr_ops[i]->supported)
+			continue;
+
+		rc = ima_mr_ops[i]->mr_init(ima_mr);
+		if (!rc) {
+			pr_info("MR device found: %s\n", ima_mr_ops[i]->name);
+			break;
+		}
+	}
+
+	if (rc) {
+		pr_info("No MR device found, activating MR-bypass!\n");
+		kfree(ima_mr);
+		ima_mr = NULL;
+	}
+}
diff --git a/security/integrity/ima/ima_mr.h b/security/integrity/ima/ima_mr.h
new file mode 100644
index 000000000000..23b85522da34
--- /dev/null
+++ b/security/integrity/ima/ima_mr.h
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2026 Arm Ltd
+ *
+ * Author:
+ * Yeoreum Yun <yeoreum.yun@arm.com>
+ */
+
+#ifndef __LINUX_IMA_MR_H
+#define __LINUX_IMA_MR_H
+
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <linux/hash.h>
+#include <linux/tpm.h>
+
+#define NR_BANKS(mr) ((mr != NULL) ? mr->nr_banks : 0)
+
+typedef struct tpm_bank_info mr_bank_info_t;
+typedef struct tpm_digest    mr_digest_t;
+
+enum tpm_pcrs {
+	TPM_PCR0 = 0,
+	TPM_PCR1 = 1,
+	TPM_PCR2 = 2,
+	TPM_PCR7 = 7,
+	TPM_PCR8 = 8,
+	TPM_PCR10 = 10,
+	TPM_PCR16 = 16,
+};
+
+struct ima_mr_operations;
+
+struct ima_mr {
+	int nr_banks;
+	struct ima_mr_operations *ops;
+	void *data;
+};
+
+struct ima_mr_operations {
+	const char *name;
+	bool supported;
+	int (*mr_init)(struct ima_mr *mr);
+	int (*mr_get_bank_info)(struct ima_mr *mr, int bank,
+				mr_bank_info_t *info);
+	int (*mr_calc_boot_aggregate)(struct ima_mr *mr, int bank,
+				      char *digest, struct crypto_shash *tfm);
+	int (*mr_extend)(struct ima_mr *mr, u32 pcr_idx,
+			 mr_digest_t *digests);
+};
+
+extern struct ima_mr *ima_mr;
+extern struct ima_mr_operations ima_mr_tpm_operations;
+
+void __init ima_init_mr(void);
+
+static __always_inline u16 hash_to_alg(u16 hash_id)
+{
+	switch (hash_id) {
+	case HASH_ALGO_SHA1:
+		return TPM_ALG_SHA1;
+	case HASH_ALGO_SHA256:
+		return TPM_ALG_SHA256;
+	case HASH_ALGO_SHA384:
+		return TPM_ALG_SHA384;
+	case HASH_ALGO_SHA512:
+		return TPM_ALG_SHA512;
+	case HASH_ALGO_SM3_256:
+		return TPM_ALG_SM3_256;
+	default:
+		return TPM_ALG_ERROR;
+	}
+}
+
+#endif /* __LINUX_IMA_MR_H */
diff --git a/security/integrity/ima/ima_mr_tpm.c b/security/integrity/ima/ima_mr_tpm.c
new file mode 100644
index 000000000000..edee83d5a551
--- /dev/null
+++ b/security/integrity/ima/ima_mr_tpm.c
@@ -0,0 +1,155 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2026 Arm Ltd
+ *
+ * Author:
+ * Yeoreum Yun <yeoreum.yun@arm.com>
+ */
+
+#include <linux/kernel.h>
+
+#include "ima.h"
+
+static int tpm_mr_init(struct ima_mr *mr)
+{
+	struct tpm_chip *tpm_chip;
+
+	if (!mr)
+		return -EINVAL;
+
+	tpm_chip = tpm_default_chip();
+	if (!tpm_chip) {
+		pr_info("No TPM chip found!\n");
+		return -ENODEV;
+	}
+
+	mr->data = tpm_chip;
+	mr->nr_banks = tpm_chip->nr_allocated_banks;
+	mr->ops = &ima_mr_tpm_operations;
+
+	return 0;
+}
+
+static int tpm_mr_get_bank_info(struct ima_mr *mr, int bank,
+				mr_bank_info_t *info)
+{
+	struct tpm_chip *tpm_chip;
+
+	if (!mr || !mr->data || !info || (bank >= mr->nr_banks))
+		return -EINVAL;
+
+	tpm_chip = mr->data;
+	info->alg_id = tpm_chip->allocated_banks[bank].alg_id;
+	info->digest_size = tpm_chip->allocated_banks[bank].digest_size;
+	info->crypto_id = tpm_chip->allocated_banks[bank].crypto_id;
+
+	if (WARN_ON_ONCE((info->crypto_id != HASH_ALGO__LAST) &&
+			 (hash_to_alg(info->crypto_id) != info->alg_id)))
+		return -ENODEV;
+
+	return 0;
+}
+
+/*
+ * The boot_aggregate is a cumulative hash over TPM registers 0 - 7.  With
+ * TPM 1.2 the boot_aggregate was based on reading the SHA1 PCRs, but with
+ * TPM 2.0 hash agility, TPM chips could support multiple TPM PCR banks,
+ * allowing firmware to configure and enable different banks.
+ *
+ * Knowing which TPM bank is read to calculate the boot_aggregate digest
+ * needs to be conveyed to a verifier.  For this reason, use the same
+ * hash algorithm for reading the TPM PCRs as for calculating the boot
+ * aggregate digest as stored in the measurement list.
+ */
+static int tpm_mr_calc_boot_aggregate(struct ima_mr *mr, int bank,
+				      char *digest, struct crypto_shash *tfm)
+{
+	int rc;
+	struct tpm_chip *tpm_chip;
+	mr_digest_t d = { .digest = {0} };
+	u32 pcr_idx;
+	SHASH_DESC_ON_STACK(shash, tfm);
+
+	if (!mr || !mr->data || !tfm || (bank >= mr->nr_banks))
+		return -EINVAL;
+
+	tpm_chip = mr->data;
+	d.alg_id = tpm_chip->allocated_banks[bank].alg_id;
+
+	shash->tfm = tfm;
+
+	pr_devel("calculating the boot-aggregate based on TPM bank: %04x\n",
+		 d.alg_id);
+
+	rc = crypto_shash_init(shash);
+	if (rc)
+		return rc;
+
+	/* cumulative digest over TPM registers 0-7 */
+	for (pcr_idx = TPM_PCR0; pcr_idx < TPM_PCR8; pcr_idx++) {
+		rc = tpm_pcr_read(tpm_chip, pcr_idx, &d);
+		rc = tpm_ret_to_err(rc);
+		if (rc) {
+			pr_err("Error Communicating to TPM chip\n");
+			return rc;
+		}
+
+		/* now accumulate with current aggregate */
+		rc = crypto_shash_update(shash, d.digest,
+					 crypto_shash_digestsize(tfm));
+		if (rc)
+			return rc;
+	}
+
+	/*
+	 * Extend cumulative digest over TPM registers 8-9, which contain
+	 * measurement for the kernel command line (reg. 8) and image (reg. 9)
+	 * in a typical PCR allocation. Registers 8-9 are only included in
+	 * non-SHA1 boot_aggregate digests to avoid ambiguity.
+	 */
+	if (d.alg_id != TPM_ALG_SHA1) {
+		for (pcr_idx = TPM_PCR8; pcr_idx < TPM_PCR10; pcr_idx++) {
+			rc = tpm_pcr_read(tpm_chip, pcr_idx, &d);
+			rc = tpm_ret_to_err(rc);
+			if (rc) {
+				pr_err("Error Communicating to TPM chip\n");
+				return rc;
+			}
+
+			rc = crypto_shash_update(shash, d.digest,
+						crypto_shash_digestsize(tfm));
+		}
+	}
+
+	if (!rc)
+		rc = crypto_shash_final(shash, digest);
+	return rc;
+}
+
+static int tpm_mr_extend(struct ima_mr *mr, u32 pcr_idx,
+			 mr_digest_t *digests)
+{
+	int rc;
+	struct tpm_chip *tpm_chip;
+
+	if (!mr || !mr->data)
+		return -EINVAL;
+
+	tpm_chip = mr->data;
+
+	rc = tpm_pcr_extend(tpm_chip, pcr_idx, digests);
+	rc = tpm_ret_to_err(rc);
+	if (rc)
+		pr_err("Error Communicating to TPM chip, result: %d\n", rc);
+
+	return rc;
+}
+
+struct ima_mr_operations ima_mr_tpm_operations = {
+	.name                    = "TPM",
+	.supported               = IS_BUILTIN(CONFIG_TCG_TPM),
+	.mr_init                 = tpm_mr_init,
+	.mr_get_bank_info        = tpm_mr_get_bank_info,
+	.mr_calc_boot_aggregate  = tpm_mr_calc_boot_aggregate,
+	.mr_extend               = tpm_mr_extend,
+};
diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c
index 0f1b7e4113c4..637db7c338e2 100644
--- a/security/integrity/ima/ima_queue.c
+++ b/security/integrity/ima/ima_queue.c
@@ -217,16 +217,15 @@ unsigned long ima_get_binary_runtime_size(enum binary_lists binary_list)
 		return val + sizeof(struct ima_kexec_hdr);
 }
 
-static int ima_pcr_extend(struct tpm_digest *digests_arg, int pcr)
+static int ima_mr_extend(struct tpm_digest *digests_arg, int pcr)
 {
 	int result = 0;
 
-	if (!ima_tpm_chip)
+	if (!ima_mr)
 		return result;
 
-	result = tpm_pcr_extend(ima_tpm_chip, pcr, digests_arg);
-	if (result != 0)
-		pr_err("Error Communicating to TPM chip, result: %d\n", result);
+	result = ima_mr->ops->mr_extend(ima_mr, pcr, digests_arg);
+
 	return result;
 }
 
@@ -247,7 +246,7 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation,
 	const char *audit_cause = "hash_added";
 	char tpm_audit_cause[AUDIT_CAUSE_LEN_MAX];
 	int audit_info = 1;
-	int result = 0, tpmresult = 0;
+	int result = 0, mresult = 0;
 
 	mutex_lock(&ima_extend_list_mutex);
 
@@ -281,10 +280,10 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation,
 	if (violation)		/* invalidate pcr */
 		digests_arg = digests;
 
-	tpmresult = ima_pcr_extend(digests_arg, entry->pcr);
-	if (tpmresult != 0) {
+	mresult = ima_mr_extend(digests_arg, entry->pcr);
+	if (mresult != 0) {
 		snprintf(tpm_audit_cause, AUDIT_CAUSE_LEN_MAX, "TPM_error(%d)",
-			 tpmresult);
+			 mresult);
 		audit_cause = tpm_audit_cause;
 		audit_info = 0;
 	}
@@ -548,25 +547,27 @@ void __init ima_init_reboot_notifier(void)
 
 int __init ima_init_digests(void)
 {
+	int rc, i;
+	mr_bank_info_t bank_info;
 	u16 digest_size;
-	u16 crypto_id;
-	int i;
 
-	if (!ima_tpm_chip)
+	if (!ima_mr)
 		return 0;
 
-	digests = kzalloc_objs(*digests, ima_tpm_chip->nr_allocated_banks,
-			       GFP_NOFS);
+	digests = kzalloc_objs(*digests, NR_BANKS(ima_mr), GFP_NOFS);
 	if (!digests)
 		return -ENOMEM;
 
-	for (i = 0; i < ima_tpm_chip->nr_allocated_banks; i++) {
-		digests[i].alg_id = ima_tpm_chip->allocated_banks[i].alg_id;
-		digest_size = ima_tpm_chip->allocated_banks[i].digest_size;
-		crypto_id = ima_tpm_chip->allocated_banks[i].crypto_id;
+	for (i = 0; i < NR_BANKS(ima_mr); i++) {
+		rc = ima_mr->ops->mr_get_bank_info(ima_mr, i, &bank_info);
+		if (rc)
+			return rc;
+
+		digests[i].alg_id = bank_info.alg_id;
+		digest_size = bank_info.digest_size;
 
 		/* for unmapped TPM algorithms digest is still a padded SHA1 */
-		if (crypto_id == HASH_ALGO__LAST)
+		if (bank_info.crypto_id == HASH_ALGO__LAST)
 			digest_size = SHA1_DIGEST_SIZE;
 
 		memset(digests[i].digest, 0xff, digest_size);
diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c
index 7034573fb41e..3396e9df22a5 100644
--- a/security/integrity/ima/ima_template.c
+++ b/security/integrity/ima/ima_template.c
@@ -358,7 +358,7 @@ static int ima_restore_template_data(struct ima_template_desc *template_desc,
 				     int template_data_size,
 				     struct ima_template_entry **entry)
 {
-	struct tpm_digest *digests;
+	mr_digest_t *digests;
 	int ret = 0;
 	int i;
 
@@ -368,7 +368,7 @@ static int ima_restore_template_data(struct ima_template_desc *template_desc,
 		return -ENOMEM;
 
 	digests = kzalloc_objs(*digests,
-			       NR_BANKS(ima_tpm_chip) + ima_extra_slots,
+			       NR_BANKS(ima_mr) + ima_extra_slots,
 			       GFP_NOFS);
 	if (!digests) {
 		kfree(*entry);
diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c
index 8a89236f926c..12386241b126 100644
--- a/security/integrity/ima/ima_template_lib.c
+++ b/security/integrity/ima/ima_template_lib.c
@@ -365,7 +365,7 @@ int ima_eventdigest_init(struct ima_event_data *event_data,
 
 	if ((const char *)event_data->filename == boot_aggregate_name ||
 	    (const char *)event_data->filename == boot_aggregate_late_name) {
-		if (ima_tpm_chip) {
+		if (ima_mr) {
 			hash.hdr.algo = HASH_ALGO_SHA1;
 			result = ima_calc_boot_aggregate(hash_hdr);
 

-- 
2.43.0


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH RFC 3/3] security: IMA: use TSM measurement registers
  2026-09-30 13:43 [PATCH RFC 0/3] security: ima: support TSM measurement registers Yeoreum Yun
  2026-09-30 13:43 ` [PATCH RFC 1/3] virt: coco: introduce tsm_default_tm() and tsm_mr_read()/write() Yeoreum Yun
  2026-09-30 13:44 ` [PATCH RFC 2/3] security: IMA: introduce ima_mr structure Yeoreum Yun
@ 2026-09-30 13:44 ` Yeoreum Yun
  2026-10-01 11:27 ` [PATCH RFC 0/3] security: ima: support " Roberto Sassu
  3 siblings, 0 replies; 9+ messages in thread
From: Yeoreum Yun @ 2026-09-30 13:44 UTC (permalink / raw)
  To: linux-coco, linux-kernel, linux-arm-kernel, Eric Snowberg,
	linux-integrity, linux-security-module
  Cc: Dan Williams, Mimi Zohar, Roberto Sassu, Dmitry Kasatkin,
	Paul Moore, James Morris, Serge E. Hallyn, Catalin Marinas,
	Jason Gunthorpe, Suzuki Poulose, Steven Price, Sami Mujawar,
	Aneesh Kumar K.V, Jiri Pirko, Yeoreum Yun

IMA uses TPM PCRs to record measurement digests. When no TPM device is
available, TSM measurement registers can serve as an alternative for guest.

The following mappings are defined for Intel TDX [0] and proposed for
Arm CCA [1]:

  TPM PCR index | Intel TDX register | Arm CCA register
  --------------+--------------------+-----------------
  0             | MRTD               | RIM
  1, 7          | RTMR[0]            | REM[0]
  2-6           | RTMR[1]            | REM[1]
  8-15          | RTMR[2]            | REM[2]

Add support for extending IMA measurement digests into the corresponding
TSM measurement register when no TPM device is available.

Link: [0] https://uefi.org/specs/UEFI/2.11/38_Confidential_Computing.html#intel-trust-domain-extension
Link: [1] https://github.com/tianocore/edk2/issues/11383
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
 security/integrity/ima/Makefile     |   3 +-
 security/integrity/ima/ima_mr.c     |   1 +
 security/integrity/ima/ima_mr.h     |   1 +
 security/integrity/ima/ima_mr_tsm.c | 290 ++++++++++++++++++++++++++++++++++++
 4 files changed, 294 insertions(+), 1 deletion(-)

diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile
index f2c46b405a00..f0a22e3a5320 100644
--- a/security/integrity/ima/Makefile
+++ b/security/integrity/ima/Makefile
@@ -7,7 +7,8 @@
 obj-$(CONFIG_IMA) += ima.o ima_iint.o
 
 ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \
-	 ima_policy.o ima_template.o ima_template_lib.o ima_mr.o ima_mr_tpm.o
+	 ima_policy.o ima_template.o ima_template_lib.o ima_mr.o ima_mr_tpm.o \
+	 ima_mr_tsm.o
 ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o
 ima-$(CONFIG_IMA_APPRAISE_MODSIG) += ima_modsig.o
 ima-$(CONFIG_HAVE_IMA_KEXEC) += ima_kexec.o
diff --git a/security/integrity/ima/ima_mr.c b/security/integrity/ima/ima_mr.c
index fe58eb968954..85a66e616f64 100644
--- a/security/integrity/ima/ima_mr.c
+++ b/security/integrity/ima/ima_mr.c
@@ -15,6 +15,7 @@ struct ima_mr *ima_mr;
 
 static struct ima_mr_operations *ima_mr_ops[] = {
 	&ima_mr_tpm_operations,
+	&ima_mr_tsm_operations,
 };
 
 void __init ima_init_mr(void)
diff --git a/security/integrity/ima/ima_mr.h b/security/integrity/ima/ima_mr.h
index 23b85522da34..bc7b06c3adcd 100644
--- a/security/integrity/ima/ima_mr.h
+++ b/security/integrity/ima/ima_mr.h
@@ -51,6 +51,7 @@ struct ima_mr_operations {
 
 extern struct ima_mr *ima_mr;
 extern struct ima_mr_operations ima_mr_tpm_operations;
+extern struct ima_mr_operations ima_mr_tsm_operations;
 
 void __init ima_init_mr(void);
 
diff --git a/security/integrity/ima/ima_mr_tsm.c b/security/integrity/ima/ima_mr_tsm.c
new file mode 100644
index 000000000000..3f88edfb8511
--- /dev/null
+++ b/security/integrity/ima/ima_mr_tsm.c
@@ -0,0 +1,290 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2026 Arm Ltd
+ *
+ * Author:
+ * Yeoreum Yun <yeoreum.yun@arm.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/tsm-mr.h>
+
+#include "ima.h"
+
+#define INVALID_MR_IDX		(-1)
+
+struct tsm_context {
+	const struct tsm_measurements *tm;
+	int pcr_map[TPM2_PLATFORM_PCR];
+};
+
+static struct tsm_context tsm_ctx;
+
+static int tsm_mr_idx_by_name(const struct tsm_measurements *tm,
+			      const char *mr_name)
+{
+	int i;
+	const struct tsm_measurement_register *mr;
+
+	for (i = 0; i < tm->nr_mrs; i++) {
+		mr = &tm->mrs[i];
+		if (!strcmp(mr->mr_name, mr_name))
+			return i;
+	}
+
+	return INVALID_MR_IDX;
+}
+
+static __always_inline
+int tsm_mr_idx(const struct tsm_measurements *tm,
+	       const struct tsm_measurement_register *tmr)
+{
+	return tmr - tm->mrs;
+}
+
+static __always_inline
+void __create_tsm_pcr_map(struct tsm_context *ctx,
+			  int mr0, int mr1, int mr2, int mr3)
+{
+	int i;
+
+	ctx->pcr_map[TPM_PCR0] = mr0;
+	ctx->pcr_map[TPM_PCR1] = ctx->pcr_map[TPM_PCR7] = mr1;
+
+	for (i = TPM_PCR2; i < TPM_PCR7; i++) {
+		ctx->pcr_map[i] = mr2;
+	}
+
+	for (i = TPM_PCR8; i < TPM_PCR16; i++) {
+		ctx->pcr_map[i] = mr3;
+	}
+
+	for (i = TPM_PCR16; i < TPM2_PLATFORM_PCR; i++) {
+		ctx->pcr_map[i] = INVALID_MR_IDX;
+	}
+}
+
+static int create_tsm_arm_cca_pcr_map(struct tsm_context *ctx)
+{
+	int rim_idx, rem0_idx, rem1_idx, rem2_idx;
+
+	rim_idx = tsm_mr_idx_by_name(ctx->tm, "rim");
+	rem0_idx = tsm_mr_idx_by_name(ctx->tm, "rem0");
+	rem1_idx = tsm_mr_idx_by_name(ctx->tm, "rem1");
+	rem2_idx = tsm_mr_idx_by_name(ctx->tm, "rem2");
+
+	if ((rim_idx == INVALID_MR_IDX) || (rem0_idx == INVALID_MR_IDX) ||
+	    (rem1_idx == INVALID_MR_IDX) || (rem2_idx == INVALID_MR_IDX))
+		return -ENODEV;
+
+	__create_tsm_pcr_map(ctx, rim_idx, rem0_idx, rem1_idx, rem2_idx);
+
+	return 0;
+}
+
+static int create_tsm_tgx_pcr_map(struct tsm_context *ctx)
+{
+	int mrtd_idx, rtmr0_idx, rtmr1_idx, rtmr2_idx;
+
+	mrtd_idx = tsm_mr_idx_by_name(ctx->tm, "mrtd");
+	rtmr0_idx = tsm_mr_idx_by_name(ctx->tm, "rtmr0");
+	rtmr1_idx = tsm_mr_idx_by_name(ctx->tm, "rtmr1");
+	rtmr2_idx = tsm_mr_idx_by_name(ctx->tm, "rtmr2");
+
+	if ((mrtd_idx == INVALID_MR_IDX) || (rtmr0_idx == INVALID_MR_IDX) ||
+	    (rtmr1_idx == INVALID_MR_IDX) || (rtmr2_idx == INVALID_MR_IDX))
+		return -ENODEV;
+
+	__create_tsm_pcr_map(ctx, mrtd_idx, rtmr0_idx, rtmr1_idx, rtmr2_idx);
+
+	return 0;
+}
+
+static const struct tsm_measurement_register *
+tsm_mr_get(struct tsm_context *ctx, int pcr_idx)
+{
+	int idx;
+
+	if (pcr_idx < 0 || pcr_idx >= ARRAY_SIZE(ctx->pcr_map))
+		return NULL;
+
+	idx = ctx->pcr_map[pcr_idx];
+	if (idx == INVALID_MR_IDX)
+		return NULL;
+
+	return &ctx->tm->mrs[idx];
+}
+
+static int tsm_mr_init(struct ima_mr *mr)
+{
+	int rc;
+	const struct tsm_measurements *tm;
+
+	if (!mr)
+		return -EINVAL;
+
+	tm = tsm_default_tm();
+	if (!tm) {
+		pr_info("No TSM measurement registers found!\n");
+		return -ENODEV;
+	}
+
+	tsm_ctx.tm = tm;
+
+	if (IS_BUILTIN(CONFIG_ARM_CCA_GUEST))
+		rc = create_tsm_arm_cca_pcr_map(&tsm_ctx);
+	else
+		rc = create_tsm_tgx_pcr_map(&tsm_ctx);
+
+	if (rc) {
+		tsm_ctx.tm = NULL;
+		return rc;
+	}
+
+	mr->data = &tsm_ctx;
+	mr->nr_banks = 1;
+	mr->ops = &ima_mr_tsm_operations;
+
+	return 0;
+}
+
+static int tsm_mr_get_bank_info(struct ima_mr *mr, int bank,
+				mr_bank_info_t *info)
+{
+	struct tsm_context *ctx;
+	const struct tsm_measurement_register *tsm_mr;
+
+	if (!mr || !mr->data || !info || (bank >= mr->nr_banks))
+		return -EINVAL;
+
+	ctx = mr->data;
+	tsm_mr = tsm_mr_get(ctx, TPM_PCR0);
+	if (!tsm_mr)
+		return -ENODEV;
+
+	info->crypto_id = tsm_mr->mr_hash;
+	info->digest_size = tsm_mr->mr_size;
+	info->alg_id = hash_to_alg(info->crypto_id);
+
+	if (info->alg_id == TPM_ALG_ERROR)
+		return -ENODEV;
+
+	return 0;
+}
+
+static int tsm_mr_calc_boot_aggregate(struct ima_mr *mr, int bank,
+				      char *digest, struct crypto_shash *tfm)
+{
+	int rc;
+	struct tsm_context *ctx;
+	const struct tsm_measurement_register *tsm_mr;
+	mr_digest_t d = { .digest = {0} };
+	SHASH_DESC_ON_STACK(shash, tfm);
+	int mr_idx, pcr_idx;
+
+	if (!mr || !mr->data || !tfm || (bank >= mr->nr_banks))
+		return -EINVAL;
+
+	ctx = mr->data;
+	tsm_mr = tsm_mr_get(ctx, TPM_PCR0);
+	if (!tsm_mr)
+		return -ENODEV;
+
+	d.alg_id = hash_to_alg(tsm_mr->mr_hash);
+	if (d.alg_id == TPM_ALG_ERROR)
+		return -ENODEV;
+
+	shash->tfm = tfm;
+
+	pr_devel("calculating the boot-aggregate based on TSM bank: %04x\n",
+		 d.alg_id);
+
+	rc = crypto_shash_init(shash);
+	if (rc)
+		return rc;
+
+	/*
+	 * In TSM, PCR 0 mapped into MR 0, PCR 1,7 into MR 1 and
+	 * PCR 2-6 into MR 2. Therefore, accumulate with  MR 0-2.
+	 */
+	for (pcr_idx = TPM_PCR0; pcr_idx <= TPM_PCR2; pcr_idx++) {
+		tsm_mr = tsm_mr_get(ctx, pcr_idx);
+		if (!tsm_mr)
+			return -ENODEV;
+
+		mr_idx = tsm_mr_idx(ctx->tm, tsm_mr);
+		rc = tsm_mr_read(ctx->tm, mr_idx, d.digest, tsm_mr->mr_size);
+		if (rc) {
+			pr_err("Error Communicating to TSM(%d)\n", rc);
+			return rc;
+		}
+
+		/* now accumulate with current aggregate */
+		rc = crypto_shash_update(shash, d.digest,
+					 crypto_shash_digestsize(tfm));
+		if (rc)
+			return rc;
+	}
+
+	/*
+	 * Extend cumulative digest over MR 3 which corespondant to
+	 * TPM registers 8-9, which contain measurement for
+	 * the kernel command line (TPM_PCR8) and image (TPM_PCR9)
+	 * in a typical PCR allocation. MR 3 is only included in
+	 * non-SHA1 boot_aggregate digests to avoid ambiguity.
+	 */
+	if (d.alg_id != TPM_ALG_SHA1) {
+		tsm_mr = tsm_mr_get(ctx, TPM_PCR8);
+		if (!tsm_mr)
+			return -ENODEV;
+
+		mr_idx = tsm_mr_idx(ctx->tm, tsm_mr);
+		rc = tsm_mr_read(ctx->tm, mr_idx, d.digest, tsm_mr->mr_size);
+		if (rc) {
+			pr_err("Error Communicating to TSM(%d)\n", rc);
+			return rc;
+		}
+
+		rc = crypto_shash_update(shash, d.digest,
+					crypto_shash_digestsize(tfm));
+	}
+
+	if (!rc)
+		rc = crypto_shash_final(shash, digest);
+	return rc;
+}
+
+static int tsm_mr_extend(struct ima_mr *mr, u32 pcr_idx,
+			 mr_digest_t *digests)
+{
+	int rc, mr_idx;
+	struct tsm_context *ctx;
+	const struct tsm_measurement_register *tsm_mr;
+
+	if (!mr || !mr->data)
+		return -EINVAL;
+
+	ctx = mr->data;
+	tsm_mr = tsm_mr_get(ctx, pcr_idx);
+	if (!tsm_mr)
+		return -ENODEV;
+
+	mr_idx = tsm_mr_idx(ctx->tm, tsm_mr);
+
+	/* TSM has only one bank. */
+	rc = tsm_mr_write(ctx->tm, mr_idx, digests[0].digest, tsm_mr->mr_size);
+	if (rc)
+		pr_err("Error Communicating to TSM, result: %d\n", rc);
+
+	return rc;
+}
+
+struct ima_mr_operations ima_mr_tsm_operations = {
+	.name                    = "TSM",
+	.supported               = (IS_BUILTIN(CONFIG_ARM_CCA_GUEST) ||
+				    IS_BUILTIN(CONFIG_TDX_GUEST_DRIVER)),
+	.mr_init                 = tsm_mr_init,
+	.mr_get_bank_info        = tsm_mr_get_bank_info,
+	.mr_calc_boot_aggregate  = tsm_mr_calc_boot_aggregate,
+	.mr_extend               = tsm_mr_extend,
+};

-- 
2.43.0


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH RFC 0/3] security: ima: support TSM measurement registers
  2026-09-30 13:43 [PATCH RFC 0/3] security: ima: support TSM measurement registers Yeoreum Yun
                   ` (2 preceding siblings ...)
  2026-09-30 13:44 ` [PATCH RFC 3/3] security: IMA: use TSM measurement registers Yeoreum Yun
@ 2026-10-01 11:27 ` Roberto Sassu
  2026-10-01 11:45   ` Roberto Sassu
  3 siblings, 1 reply; 9+ messages in thread
From: Roberto Sassu @ 2026-10-01 11:27 UTC (permalink / raw)
  To: Yeoreum Yun, linux-coco, linux-kernel, linux-arm-kernel,
	Eric Snowberg, linux-integrity, linux-security-module
  Cc: Dan Williams, Mimi Zohar, Roberto Sassu, Dmitry Kasatkin,
	Paul Moore, James Morris, Serge E. Hallyn, Catalin Marinas,
	Jason Gunthorpe, Suzuki Poulose, Steven Price, Sami Mujawar,
	Aneesh Kumar K.V, Jiri Pirko

On Wed, 2026-09-30 at 14:43 +0100, Yeoreum Yun wrote:
> Confidential computing guests without a TPM can use TSM measurement
> registers to record IMA measurement digests instead of TPM PCRs.

Hi Yeoreum

a similar patch set has been sent to the linux-integrity mailing list:

https://lore.kernel.org/linux-integrity/20250630125928.765285-1-gongruiqi1@huawei.com/

Could you please work with Gong Ruiqi to have a unified proposal?

Thanks

Roberto

> This series introduces in-kernel interfaces for accessing TSM
> measurement registers, abstracts IMA's measurement-register operations,
> and adds a TSM backend for Intel TDX and Arm CCA.
> 
> The following mappings between TPM PCR indices and TSM measurement
> registers are defined for Intel TDX [0] and proposed for Arm CCA [1]:
> 
>   TPM PCR index | Intel TDX register | Arm CCA register
>   --------------+--------------------+-----------------
>   0             | MRTD               | RIM
>   1, 7          | RTMR[0]            | REM[0]
>   2-6           | RTMR[1]            | REM[1]
>   8-15          | RTMR[2]            | REM[2]
> 
> These mappings allow IMA to translate PCR indices into the corresponding
> TSM measurement registers.
> 
> The TPM backend remains preferred when it is available at IMA
> initialization. Otherwise, IMA falls back to a supported TSM backend.
> Only one backend is selected; IMA measurements are not extended to both
> TPM PCRs and TSM measurement registers.
> 
> The attestation proccess for guest with TSM measurement register will
> be done with Confidential Compute Event Log (CCEL) which is exported by
> /sys/firmware/acpi/tables/data/CCEL. Here is brief process in arm64:
> 
>   Verifier                 Realm guest              RMM / Platform
>      |                         |                           |
>      |--- Challenge (nonce) -->|                           |
>      |                         |--- Request token -------->|
>      |                         |    with challenge         |
>      |                         |                           |
>      |                         |<-- CCA token T -----------|
>      |<-- CCA token T ---------|                           |
>      |<-- CCEL event log ------|                           |
>      |<-- IMA measurement log -|                           |
>      |                         |                           |
>  Verify token T:               |                           |
>   - signatures                 |                           |
>   - Platform/Realm             |                           |
>     token binding              |                           |
>   - challenge freshness        |                           |
>   - platform/RIM policy        |                           |
>   - verify measurement logs    |                           |
>      |                         |                           |
>      | ----ACCEPT / REJECT---->|                           |
> 
> This patch based on arm-cca-mr series [3].
> 
> Link: [0] https://uefi.org/specs/UEFI/2.11/38_Confidential_Computing.html#intel-trust-domain-extension
> Link: [1] https://github.com/tianocore/edk2/issues/11383
> Link: [2] https://github.com/tianocore/edk2/issues/11384
> Link: [3] https://lore.kernel.org/all/20260929-arm_cca_mr-v2-0-1d98bba187fd@arm.com/
> 
> ---
> Yeoreum Yun (3):
>       virt: coco: introduce tsm_default_tm() and tsm_mr_read()/write()
>       security: IMA: introduce ima_mr structure
>       security: IMA: use TSM measurement registers
> 
>  drivers/virt/coco/guest/tsm-mr.c          | 159 +++++++++++++---
>  include/linux/tsm-mr.h                    |  26 +++
>  security/integrity/ima/Makefile           |   3 +-
>  security/integrity/ima/ima.h              |   7 +-
>  security/integrity/ima/ima_api.c          |   4 +-
>  security/integrity/ima/ima_crypto.c       | 137 +++++---------
>  security/integrity/ima/ima_fs.c           |  16 +-
>  security/integrity/ima/ima_init.c         |   7 +-
>  security/integrity/ima/ima_mr.c           |  48 +++++
>  security/integrity/ima/ima_mr.h           |  76 ++++++++
>  security/integrity/ima/ima_mr_tpm.c       | 155 ++++++++++++++++
>  security/integrity/ima/ima_mr_tsm.c       | 290 ++++++++++++++++++++++++++++++
>  security/integrity/ima/ima_queue.c        |  39 ++--
>  security/integrity/ima/ima_template.c     |   4 +-
>  security/integrity/ima/ima_template_lib.c |   2 +-
>  15 files changed, 819 insertions(+), 154 deletions(-)
> ---
> base-commit: b561246f45174b7472c24b75358ea95bae72b7b8
> change-id: 20260929-ima_tgx_integration_v2-1c54aeeaeaee
> 
> Best regards,


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH RFC 0/3] security: ima: support TSM measurement registers
  2026-10-01 11:27 ` [PATCH RFC 0/3] security: ima: support " Roberto Sassu
@ 2026-10-01 11:45   ` Roberto Sassu
  2026-10-01 14:24     ` Yeoreum Yun
  2026-10-01 15:18     ` Jason Gunthorpe
  0 siblings, 2 replies; 9+ messages in thread
From: Roberto Sassu @ 2026-10-01 11:45 UTC (permalink / raw)
  To: Yeoreum Yun, linux-coco, linux-kernel, linux-arm-kernel,
	Eric Snowberg, linux-integrity, linux-security-module
  Cc: Dan Williams, Mimi Zohar, Roberto Sassu, Dmitry Kasatkin,
	Paul Moore, James Morris, Serge E. Hallyn, Catalin Marinas,
	Jason Gunthorpe, Suzuki Poulose, Steven Price, Sami Mujawar,
	Aneesh Kumar K.V, Jiri Pirko, gongruiqi1

On Thu, 2026-10-01 at 13:27 +0200, Roberto Sassu wrote:
> On Wed, 2026-09-30 at 14:43 +0100, Yeoreum Yun wrote:
> > Confidential computing guests without a TPM can use TSM measurement
> > registers to record IMA measurement digests instead of TPM PCRs.

+ Gong Ruiqi, of course.

Roberto

> Hi Yeoreum
> 
> a similar patch set has been sent to the linux-integrity mailing list:
> 
> https://lore.kernel.org/linux-integrity/20250630125928.765285-1-gongruiqi1@huawei.com/
> 
> Could you please work with Gong Ruiqi to have a unified proposal?
> 
> Thanks
> 
> Roberto
> 
> > This series introduces in-kernel interfaces for accessing TSM
> > measurement registers, abstracts IMA's measurement-register operations,
> > and adds a TSM backend for Intel TDX and Arm CCA.
> > 
> > The following mappings between TPM PCR indices and TSM measurement
> > registers are defined for Intel TDX [0] and proposed for Arm CCA [1]:
> > 
> >   TPM PCR index | Intel TDX register | Arm CCA register
> >   --------------+--------------------+-----------------
> >   0             | MRTD               | RIM
> >   1, 7          | RTMR[0]            | REM[0]
> >   2-6           | RTMR[1]            | REM[1]
> >   8-15          | RTMR[2]            | REM[2]
> > 
> > These mappings allow IMA to translate PCR indices into the corresponding
> > TSM measurement registers.
> > 
> > The TPM backend remains preferred when it is available at IMA
> > initialization. Otherwise, IMA falls back to a supported TSM backend.
> > Only one backend is selected; IMA measurements are not extended to both
> > TPM PCRs and TSM measurement registers.
> > 
> > The attestation proccess for guest with TSM measurement register will
> > be done with Confidential Compute Event Log (CCEL) which is exported by
> > /sys/firmware/acpi/tables/data/CCEL. Here is brief process in arm64:
> > 
> >   Verifier                 Realm guest              RMM / Platform
> >      |                         |                           |
> >      |--- Challenge (nonce) -->|                           |
> >      |                         |--- Request token -------->|
> >      |                         |    with challenge         |
> >      |                         |                           |
> >      |                         |<-- CCA token T -----------|
> >      |<-- CCA token T ---------|                           |
> >      |<-- CCEL event log ------|                           |
> >      |<-- IMA measurement log -|                           |
> >      |                         |                           |
> >  Verify token T:               |                           |
> >   - signatures                 |                           |
> >   - Platform/Realm             |                           |
> >     token binding              |                           |
> >   - challenge freshness        |                           |
> >   - platform/RIM policy        |                           |
> >   - verify measurement logs    |                           |
> >      |                         |                           |
> >      | ----ACCEPT / REJECT---->|                           |
> > 
> > This patch based on arm-cca-mr series [3].
> > 
> > Link: [0] https://uefi.org/specs/UEFI/2.11/38_Confidential_Computing.html#intel-trust-domain-extension
> > Link: [1] https://github.com/tianocore/edk2/issues/11383
> > Link: [2] https://github.com/tianocore/edk2/issues/11384
> > Link: [3] https://lore.kernel.org/all/20260929-arm_cca_mr-v2-0-1d98bba187fd@arm.com/
> > 
> > ---
> > Yeoreum Yun (3):
> >       virt: coco: introduce tsm_default_tm() and tsm_mr_read()/write()
> >       security: IMA: introduce ima_mr structure
> >       security: IMA: use TSM measurement registers
> > 
> >  drivers/virt/coco/guest/tsm-mr.c          | 159 +++++++++++++---
> >  include/linux/tsm-mr.h                    |  26 +++
> >  security/integrity/ima/Makefile           |   3 +-
> >  security/integrity/ima/ima.h              |   7 +-
> >  security/integrity/ima/ima_api.c          |   4 +-
> >  security/integrity/ima/ima_crypto.c       | 137 +++++---------
> >  security/integrity/ima/ima_fs.c           |  16 +-
> >  security/integrity/ima/ima_init.c         |   7 +-
> >  security/integrity/ima/ima_mr.c           |  48 +++++
> >  security/integrity/ima/ima_mr.h           |  76 ++++++++
> >  security/integrity/ima/ima_mr_tpm.c       | 155 ++++++++++++++++
> >  security/integrity/ima/ima_mr_tsm.c       | 290 ++++++++++++++++++++++++++++++
> >  security/integrity/ima/ima_queue.c        |  39 ++--
> >  security/integrity/ima/ima_template.c     |   4 +-
> >  security/integrity/ima/ima_template_lib.c |   2 +-
> >  15 files changed, 819 insertions(+), 154 deletions(-)
> > ---
> > base-commit: b561246f45174b7472c24b75358ea95bae72b7b8
> > change-id: 20260929-ima_tgx_integration_v2-1c54aeeaeaee
> > 
> > Best regards,


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH RFC 0/3] security: ima: support TSM measurement registers
  2026-10-01 11:45   ` Roberto Sassu
@ 2026-10-01 14:24     ` Yeoreum Yun
  2026-10-01 15:18     ` Jason Gunthorpe
  1 sibling, 0 replies; 9+ messages in thread
From: Yeoreum Yun @ 2026-10-01 14:24 UTC (permalink / raw)
  To: Roberto Sassu
  Cc: Yeoreum Yun, linux-coco, linux-kernel, linux-arm-kernel,
	Eric Snowberg, linux-integrity, linux-security-module,
	Dan Williams, Mimi Zohar, Roberto Sassu, Dmitry Kasatkin,
	Paul Moore, James Morris, Serge E. Hallyn, Catalin Marinas,
	Jason Gunthorpe, Suzuki Poulose, Steven Price, Sami Mujawar,
	Aneesh Kumar K.V, Jiri Pirko, gongruiqi1

Hi Roberto,

> On Thu, 2026-10-01 at 13:27 +0200, Roberto Sassu wrote:
> > On Wed, 2026-09-30 at 14:43 +0100, Yeoreum Yun wrote:
> > > Confidential computing guests without a TPM can use TSM measurement
> > > registers to record IMA measurement digests instead of TPM PCRs.
> 
> + Gong Ruiqi, of course.
> 
> Roberto
> 
> > Hi Yeoreum
> > 
> > a similar patch set has been sent to the linux-integrity mailing list:
> > 
> > https://lore.kernel.org/linux-integrity/20250630125928.765285-1-gongruiqi1@huawei.com/
> > 
> > Could you please work with Gong Ruiqi to have a unified proposal?
> > 
> > Thanks
> > 
> > Roberto
> > 

Thanks for letting me know and I think the proposal is almost the same
with the different terminology only.

@Gong, what do you think?

> > > This series introduces in-kernel interfaces for accessing TSM
> > > measurement registers, abstracts IMA's measurement-register operations,
> > > and adds a TSM backend for Intel TDX and Arm CCA.
> > > 
> > > The following mappings between TPM PCR indices and TSM measurement
> > > registers are defined for Intel TDX [0] and proposed for Arm CCA [1]:
> > > 
> > >   TPM PCR index | Intel TDX register | Arm CCA register
> > >   --------------+--------------------+-----------------
> > >   0             | MRTD               | RIM
> > >   1, 7          | RTMR[0]            | REM[0]
> > >   2-6           | RTMR[1]            | REM[1]
> > >   8-15          | RTMR[2]            | REM[2]
> > > 
> > > These mappings allow IMA to translate PCR indices into the corresponding
> > > TSM measurement registers.
> > > 
> > > The TPM backend remains preferred when it is available at IMA
> > > initialization. Otherwise, IMA falls back to a supported TSM backend.
> > > Only one backend is selected; IMA measurements are not extended to both
> > > TPM PCRs and TSM measurement registers.
> > > 
> > > The attestation proccess for guest with TSM measurement register will
> > > be done with Confidential Compute Event Log (CCEL) which is exported by
> > > /sys/firmware/acpi/tables/data/CCEL. Here is brief process in arm64:
> > > 
> > >   Verifier                 Realm guest              RMM / Platform
> > >      |                         |                           |
> > >      |--- Challenge (nonce) -->|                           |
> > >      |                         |--- Request token -------->|
> > >      |                         |    with challenge         |
> > >      |                         |                           |
> > >      |                         |<-- CCA token T -----------|
> > >      |<-- CCA token T ---------|                           |
> > >      |<-- CCEL event log ------|                           |
> > >      |<-- IMA measurement log -|                           |
> > >      |                         |                           |
> > >  Verify token T:               |                           |
> > >   - signatures                 |                           |
> > >   - Platform/Realm             |                           |
> > >     token binding              |                           |
> > >   - challenge freshness        |                           |
> > >   - platform/RIM policy        |                           |
> > >   - verify measurement logs    |                           |
> > >      |                         |                           |
> > >      | ----ACCEPT / REJECT---->|                           |
> > > 
> > > This patch based on arm-cca-mr series [3].
> > > 
> > > Link: [0] https://uefi.org/specs/UEFI/2.11/38_Confidential_Computing.html#intel-trust-domain-extension
> > > Link: [1] https://github.com/tianocore/edk2/issues/11383
> > > Link: [2] https://github.com/tianocore/edk2/issues/11384
> > > Link: [3] https://lore.kernel.org/all/20260929-arm_cca_mr-v2-0-1d98bba187fd@arm.com/
> > > 
> > > ---
> > > Yeoreum Yun (3):
> > >       virt: coco: introduce tsm_default_tm() and tsm_mr_read()/write()
> > >       security: IMA: introduce ima_mr structure
> > >       security: IMA: use TSM measurement registers
> > > 
> > >  drivers/virt/coco/guest/tsm-mr.c          | 159 +++++++++++++---
> > >  include/linux/tsm-mr.h                    |  26 +++
> > >  security/integrity/ima/Makefile           |   3 +-
> > >  security/integrity/ima/ima.h              |   7 +-
> > >  security/integrity/ima/ima_api.c          |   4 +-
> > >  security/integrity/ima/ima_crypto.c       | 137 +++++---------
> > >  security/integrity/ima/ima_fs.c           |  16 +-
> > >  security/integrity/ima/ima_init.c         |   7 +-
> > >  security/integrity/ima/ima_mr.c           |  48 +++++
> > >  security/integrity/ima/ima_mr.h           |  76 ++++++++
> > >  security/integrity/ima/ima_mr_tpm.c       | 155 ++++++++++++++++
> > >  security/integrity/ima/ima_mr_tsm.c       | 290 ++++++++++++++++++++++++++++++
> > >  security/integrity/ima/ima_queue.c        |  39 ++--
> > >  security/integrity/ima/ima_template.c     |   4 +-
> > >  security/integrity/ima/ima_template_lib.c |   2 +-
> > >  15 files changed, 819 insertions(+), 154 deletions(-)
> > > ---
> > > base-commit: b561246f45174b7472c24b75358ea95bae72b7b8
> > > change-id: 20260929-ima_tgx_integration_v2-1c54aeeaeaee
> > > 
> > > Best regards,
> 

-- 
Sincerely,
Yeoreum Yun

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH RFC 0/3] security: ima: support TSM measurement registers
  2026-10-01 11:45   ` Roberto Sassu
  2026-10-01 14:24     ` Yeoreum Yun
@ 2026-10-01 15:18     ` Jason Gunthorpe
  2026-10-01 16:39       ` Yeoreum Yun
  1 sibling, 1 reply; 9+ messages in thread
From: Jason Gunthorpe @ 2026-10-01 15:18 UTC (permalink / raw)
  To: Roberto Sassu
  Cc: Yeoreum Yun, linux-coco, linux-kernel, linux-arm-kernel,
	Eric Snowberg, linux-integrity, linux-security-module,
	Mimi Zohar, Roberto Sassu, Dmitry Kasatkin, Paul Moore,
	James Morris, Serge E. Hallyn, Catalin Marinas, Suzuki Poulose,
	Steven Price, Sami Mujawar, Aneesh Kumar K.V, Jiri Pirko,
	gongruiqi1

On Thu, Oct 01, 2026 at 01:45:26PM +0200, Roberto Sassu wrote:
> On Thu, 2026-10-01 at 13:27 +0200, Roberto Sassu wrote:
> > On Wed, 2026-09-30 at 14:43 +0100, Yeoreum Yun wrote:
> > > Confidential computing guests without a TPM can use TSM measurement
> > > registers to record IMA measurement digests instead of TPM PCRs.
> 
> + Gong Ruiqi, of course.

We are working very seriously on this same problem too.

For some time we did investigate extending tsm_mr to do more things,
have a better uAPI, but that eventually evolved into the realization
that tsm_mr is simply too narrowly focused. It looks like James got to
this idea before we did. I agree with his remarks in the 2025 thread
with Gong.

So we've started work on a new comprehensive "Attestation subsytem"
that will pull in all forms of ROTs, TPM, CC stuff and SPDM use cases
to give a consistent user API to work with this class of HW. In many
ways I view this as a rename of tsm_mr (it will eventually fully
absorb it), but the name evokes the broader goal and encourages
everyone to come in, not just CC world.

Our overall goal would be for something like systemd to have a single
uniform kernel API that allows it interwork with any ROT someone may
have. A uAPI to do "Extend", "Quote", "Get Log" operations so that the
existing TPM support in systemd can be improved to work on any ROT
flexibly without having to hard code specific ROT behaviors into
systemd.

I've felt the ultimate end goal would be to make all the in-kernel tpm
users go through the proposed attestation subsystem so they can have
ROT and "PCR profile" agility. Certainly I've heard enough people
asking for this.

This is a broader topic than just IMA. For example DRTM also has to
use the TPM, and other ROTs. It also brings in a global shift of how
the system wide "PCR Profile" should work as post-DRTM has a different
TPM locality and access to the protected DRTM-only PCRs that are
normally blocked.

Jiri posted his current state here:
  https://lore.kernel.org/r/arzr32ZDComnfmny@FV6GYCPJ69

While we plan to start with SPDM and CC topics as the initial launch
Jiri has enough detailed plans now for all the main use cases, PCI
SPDM, TPM, "CC PCRS", CC attestation, and Caliptra that I'm feeling
confident something like this is the right way forward.

Jason

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH RFC 0/3] security: ima: support TSM measurement registers
  2026-10-01 15:18     ` Jason Gunthorpe
@ 2026-10-01 16:39       ` Yeoreum Yun
  0 siblings, 0 replies; 9+ messages in thread
From: Yeoreum Yun @ 2026-10-01 16:39 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: Roberto Sassu, Yeoreum Yun, linux-coco, linux-kernel,
	linux-arm-kernel, Eric Snowberg, linux-integrity,
	linux-security-module, Mimi Zohar, Roberto Sassu,
	Dmitry Kasatkin, Paul Moore, James Morris, Serge E. Hallyn,
	Catalin Marinas, Suzuki Poulose, Steven Price, Sami Mujawar,
	Aneesh Kumar K.V, Jiri Pirko, gongruiqi1

Hi Jason,

> On Thu, Oct 01, 2026 at 01:45:26PM +0200, Roberto Sassu wrote:
> > On Thu, 2026-10-01 at 13:27 +0200, Roberto Sassu wrote:
> > > On Wed, 2026-09-30 at 14:43 +0100, Yeoreum Yun wrote:
> > > > Confidential computing guests without a TPM can use TSM measurement
> > > > registers to record IMA measurement digests instead of TPM PCRs.
> > 
> > + Gong Ruiqi, of course.
> 
> We are working very seriously on this same problem too.
> 
> For some time we did investigate extending tsm_mr to do more things,
> have a better uAPI, but that eventually evolved into the realization
> that tsm_mr is simply too narrowly focused. It looks like James got to
> this idea before we did. I agree with his remarks in the 2025 thread
> with Gong.
> 
> So we've started work on a new comprehensive "Attestation subsytem"
> that will pull in all forms of ROTs, TPM, CC stuff and SPDM use cases
> to give a consistent user API to work with this class of HW. In many
> ways I view this as a rename of tsm_mr (it will eventually fully
> absorb it), but the name evokes the broader goal and encourages
> everyone to come in, not just CC world.
> 
> Our overall goal would be for something like systemd to have a single
> uniform kernel API that allows it interwork with any ROT someone may
> have. A uAPI to do "Extend", "Quote", "Get Log" operations so that the
> existing TPM support in systemd can be improved to work on any ROT
> flexibly without having to hard code specific ROT behaviors into
> systemd.
> 
> I've felt the ultimate end goal would be to make all the in-kernel tpm
> users go through the proposed attestation subsystem so they can have
> ROT and "PCR profile" agility. Certainly I've heard enough people
> asking for this.
> 
> This is a broader topic than just IMA. For example DRTM also has to
> use the TPM, and other ROTs. It also brings in a global shift of how
> the system wide "PCR Profile" should work as post-DRTM has a different
> TPM locality and access to the protected DRTM-only PCRs that are
> normally blocked.
> 
> Jiri posted his current state here:
>   https://lore.kernel.org/r/arzr32ZDComnfmny@FV6GYCPJ69

Thanks to let me know. I'll take a look for this.

-- 
Sincerely,
Yeoreum Yun

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2026-10-01 16:39 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-30 13:43 [PATCH RFC 0/3] security: ima: support TSM measurement registers Yeoreum Yun
2026-09-30 13:43 ` [PATCH RFC 1/3] virt: coco: introduce tsm_default_tm() and tsm_mr_read()/write() Yeoreum Yun
2026-09-30 13:44 ` [PATCH RFC 2/3] security: IMA: introduce ima_mr structure Yeoreum Yun
2026-09-30 13:44 ` [PATCH RFC 3/3] security: IMA: use TSM measurement registers Yeoreum Yun
2026-10-01 11:27 ` [PATCH RFC 0/3] security: ima: support " Roberto Sassu
2026-10-01 11:45   ` Roberto Sassu
2026-10-01 14:24     ` Yeoreum Yun
2026-10-01 15:18     ` Jason Gunthorpe
2026-10-01 16:39       ` Yeoreum Yun

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®