* [PATCH v3 0/2] tpm_tis: fix retry exhaustion and add logging
From: Jacqueline Wong @ 2026-04-15 16:00 UTC (permalink / raw)
To: linux-integrity
Cc: jarkko, peterhuewe, jgg, axelrasmussen, jhand, Jacqueline Wong
The Fix:
- Patch 1: Adds error logs to identify the specific hardware status mismatch.
- Patch 2: Stops execution immediately when retries are exhausted.
v3 changes:
- Improved code alignment to pass checkpatch --strict.
v2 changes:
- Split logging and logic into separate patches.
- Added retry count to the error message.
- Included dmesg traces below.
Testing:
Dmesg traces obtained using error injection to simulate status register mismatches.
Before:
[ 130.288751] tpm tpm0: Operation Timed out
[ 250.306070] tpm tpm0: Operation Timed out
[ 250.310173] tpm tpm0: A TPM error (-62) occurred attempting to determine the timeouts
After:
[ 10.271547] tpm tpm0: TPM_STS_DATA_EXPECT should be unset. sts = 0x00000080
...
[ 10.646283] tpm tpm0: TPM_STS_DATA_EXPECT should be unset. sts = 0x00000080
[ 10.653461] tpm tpm0: Exhausted 50 tpm_tis_send_data retries
[ 10.659304] tpm tpm0: tpm_try_transmit: send(): error -5
[ 10.665435] tpm tpm0: TPM_STS_DATA_EXPECT should be unset. sts = 0x00000080
...
[ 11.037198] tpm tpm0: TPM_STS_DATA_EXPECT should be unset. sts = 0x00000080
[ 11.044441] tpm tpm0: Exhausted 50 tpm_tis_send_data retries
[ 11.050288] tpm tpm0: tpm_try_transmit: send(): error -5
[ 11.055723] tpm tpm0: A TPM error (-5) occurred attempting to determine the timeouts
Jacqueline Wong (2):
tpm: tpm_tis: add error logging for data transfer
tpm: tpm_tis: stop transmit if retries are exhausted
drivers/char/tpm/tpm_tis_core.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
--
2.54.0.rc0.605.g598a273b03-goog
^ permalink raw reply
* [PATCH v4] KEYS: trusted: Debugging as a feature
From: Jarkko Sakkinen @ 2026-04-15 11:12 UTC (permalink / raw)
To: linux-integrity
Cc: Jarkko Sakkinen, Nayna Jain, Srish Srinivasan, Jonathan Corbet,
Shuah Khan, James Bottomley, Mimi Zohar, David Howells,
Paul Moore, James Morris, Serge E. Hallyn, Ahmad Fatoum,
Pengutronix Kernel Team, Andrew Morton, Borislav Petkov (AMD),
Randy Dunlap, Dave Hansen, Pawan Gupta, Feng Tang, Dapeng Mi,
Kees Cook, Marco Elver, Li RongQing, Paul E. McKenney,
Thomas Gleixner, Bjorn Helgaas, linux-doc, linux-kernel, keyrings,
linux-security-module
TPM_DEBUG, and other similar flags, are a non-standard way to specify a
feature in Linux kernel. Introduce CONFIG_TRUSTED_KEYS_DEBUG for trusted
keys, and use it to replace these ad-hoc feature flags.
Given that trusted keys debug dumps can contain sensitive data, harden the
feature as follows:
1. In the Kconfig description postulate that pr_debug() statements must be
used.
2. Use pr_debug() statements in TPM 1.x driver to print the protocol dump.
3. Require trusted.debug=1 on the kernel command line (default: 0) to
activate dumps at runtime, even when CONFIG_TRUSTED_KEYS_DEBUG=y.
Traces, when actually needed, can be easily enabled by providing
trusted.dyndbg='+p' and trusted.debug=1 in the kernel command-line.
Reported-by: Nayna Jain <nayna@linux.ibm.com>
Closes: https://lore.kernel.org/all/7f8b8478-5cd8-4d97-bfd0-341fd5cf10f9@linux.ibm.com/
Reviewed-by: Nayna Jain <nayna@linux.ibm.com>
Tested-by: Srish Srinivasan <ssrish@linux.ibm.com>
Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
---
v4:
- Added kernel parameter documentation.t
- Added tags from Srishand and Nayna.
- Sanity check round. This version will be applied unless there is
something specific to address.
v3:
- Add kernel-command line option for enabling the traces.
- Add safety information to the Kconfig entry.
v2:
- Implement for all trusted keys backends.
- Add HAVE_TRUSTED_KEYS_DEBUG as it is a good practice despite full
coverage.
---
.../admin-guide/kernel-parameters.txt | 16 +++++++
include/keys/trusted-type.h | 21 +++++----
security/keys/trusted-keys/Kconfig | 23 ++++++++++
security/keys/trusted-keys/trusted_caam.c | 7 ++-
security/keys/trusted-keys/trusted_core.c | 6 +++
security/keys/trusted-keys/trusted_tpm1.c | 44 +++++++++++--------
6 files changed, 87 insertions(+), 30 deletions(-)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index f2ce1f4975c1..f1515668c8ab 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -7917,6 +7917,22 @@ Kernel parameters
first trust source as a backend which is initialized
successfully during iteration.
+ trusted.debug= [KEYS]
+ Format: <bool>
+ Enable trusted keys debug traces at runtime when
+ CONFIG_TRUSTED_KEYS_DEBUG=y.
+
+ To make the traces visible after enabling the option,
+ use trusted.dyndbg='+p' as needed. By convention,
+ the subsystem uses pr_debug() for these traces.
+
+ SAFETY: The traces can leak sensitive data, so be
+ cautious before enabling this. They remain inactive
+ unless this parameter is set this option to a true
+ value.
+
+ Default: false
+
trusted.rng= [KEYS]
Format: <string>
The RNG used to generate key material for trusted keys.
diff --git a/include/keys/trusted-type.h b/include/keys/trusted-type.h
index 03527162613f..9f9940482da4 100644
--- a/include/keys/trusted-type.h
+++ b/include/keys/trusted-type.h
@@ -83,18 +83,21 @@ struct trusted_key_source {
extern struct key_type key_type_trusted;
-#define TRUSTED_DEBUG 0
+#ifdef CONFIG_TRUSTED_KEYS_DEBUG
+extern bool trusted_debug;
-#if TRUSTED_DEBUG
static inline void dump_payload(struct trusted_key_payload *p)
{
- pr_info("key_len %d\n", p->key_len);
- print_hex_dump(KERN_INFO, "key ", DUMP_PREFIX_NONE,
- 16, 1, p->key, p->key_len, 0);
- pr_info("bloblen %d\n", p->blob_len);
- print_hex_dump(KERN_INFO, "blob ", DUMP_PREFIX_NONE,
- 16, 1, p->blob, p->blob_len, 0);
- pr_info("migratable %d\n", p->migratable);
+ if (!trusted_debug)
+ return;
+
+ pr_debug("key_len %d\n", p->key_len);
+ print_hex_dump_debug("key ", DUMP_PREFIX_NONE,
+ 16, 1, p->key, p->key_len, 0);
+ pr_debug("bloblen %d\n", p->blob_len);
+ print_hex_dump_debug("blob ", DUMP_PREFIX_NONE,
+ 16, 1, p->blob, p->blob_len, 0);
+ pr_debug("migratable %d\n", p->migratable);
}
#else
static inline void dump_payload(struct trusted_key_payload *p)
diff --git a/security/keys/trusted-keys/Kconfig b/security/keys/trusted-keys/Kconfig
index 9e00482d886a..e5a4a53aeab2 100644
--- a/security/keys/trusted-keys/Kconfig
+++ b/security/keys/trusted-keys/Kconfig
@@ -1,10 +1,29 @@
config HAVE_TRUSTED_KEYS
bool
+config HAVE_TRUSTED_KEYS_DEBUG
+ bool
+
+config TRUSTED_KEYS_DEBUG
+ bool "Debug trusted keys"
+ depends on HAVE_TRUSTED_KEYS_DEBUG
+ default n
+ help
+ Trusted key backends and core code that support debug traces can
+ opt-in that feature here. Traces must only use debug level output, as
+ sensitive data may pass by. In the kernel-command line traces can be
+ enabled via trusted.dyndbg='+p'.
+
+ SAFETY: Debug dumps are inactive at runtime until trusted.debug is set
+ to a true value on the kernel command-line. Use at your utmost
+ consideration when enabling this feature on a production build. The
+ general advice is not to do this.
+
config TRUSTED_KEYS_TPM
bool "TPM-based trusted keys"
depends on TCG_TPM >= TRUSTED_KEYS
default y
+ select HAVE_TRUSTED_KEYS_DEBUG
select CRYPTO_HASH_INFO
select CRYPTO_LIB_SHA1
select CRYPTO_LIB_UTILS
@@ -23,6 +42,7 @@ config TRUSTED_KEYS_TEE
bool "TEE-based trusted keys"
depends on TEE >= TRUSTED_KEYS
default y
+ select HAVE_TRUSTED_KEYS_DEBUG
select HAVE_TRUSTED_KEYS
help
Enable use of the Trusted Execution Environment (TEE) as trusted
@@ -33,6 +53,7 @@ config TRUSTED_KEYS_CAAM
depends on CRYPTO_DEV_FSL_CAAM_JR >= TRUSTED_KEYS
select CRYPTO_DEV_FSL_CAAM_BLOB_GEN
default y
+ select HAVE_TRUSTED_KEYS_DEBUG
select HAVE_TRUSTED_KEYS
help
Enable use of NXP's Cryptographic Accelerator and Assurance Module
@@ -42,6 +63,7 @@ config TRUSTED_KEYS_DCP
bool "DCP-based trusted keys"
depends on CRYPTO_DEV_MXS_DCP >= TRUSTED_KEYS
default y
+ select HAVE_TRUSTED_KEYS_DEBUG
select HAVE_TRUSTED_KEYS
help
Enable use of NXP's DCP (Data Co-Processor) as trusted key backend.
@@ -50,6 +72,7 @@ config TRUSTED_KEYS_PKWM
bool "PKWM-based trusted keys"
depends on PSERIES_PLPKS >= TRUSTED_KEYS
default y
+ select HAVE_TRUSTED_KEYS_DEBUG
select HAVE_TRUSTED_KEYS
help
Enable use of IBM PowerVM Key Wrapping Module (PKWM) as a trusted key backend.
diff --git a/security/keys/trusted-keys/trusted_caam.c b/security/keys/trusted-keys/trusted_caam.c
index 601943ce0d60..6a33dbf2a7f5 100644
--- a/security/keys/trusted-keys/trusted_caam.c
+++ b/security/keys/trusted-keys/trusted_caam.c
@@ -28,10 +28,13 @@ static const match_table_t key_tokens = {
{opt_err, NULL}
};
-#ifdef CAAM_DEBUG
+#ifdef CONFIG_TRUSTED_KEYS_DEBUG
static inline void dump_options(const struct caam_pkey_info *pkey_info)
{
- pr_info("key encryption algo %d\n", pkey_info->key_enc_algo);
+ if (!trusted_debug)
+ return;
+
+ pr_debug("key encryption algo %d\n", pkey_info->key_enc_algo);
}
#else
static inline void dump_options(const struct caam_pkey_info *pkey_info)
diff --git a/security/keys/trusted-keys/trusted_core.c b/security/keys/trusted-keys/trusted_core.c
index 0b142d941cd2..6aed17bee09d 100644
--- a/security/keys/trusted-keys/trusted_core.c
+++ b/security/keys/trusted-keys/trusted_core.c
@@ -31,6 +31,12 @@ static char *trusted_rng = "default";
module_param_named(rng, trusted_rng, charp, 0);
MODULE_PARM_DESC(rng, "Select trusted key RNG");
+#ifdef CONFIG_TRUSTED_KEYS_DEBUG
+bool trusted_debug;
+module_param_named(debug, trusted_debug, bool, 0);
+MODULE_PARM_DESC(debug, "Enable trusted keys debug traces (default: 0)");
+#endif
+
static char *trusted_key_source;
module_param_named(source, trusted_key_source, charp, 0);
MODULE_PARM_DESC(source, "Select trusted keys source (tpm, tee, caam, dcp or pkwm)");
diff --git a/security/keys/trusted-keys/trusted_tpm1.c b/security/keys/trusted-keys/trusted_tpm1.c
index 6ea728f1eae6..13513819991e 100644
--- a/security/keys/trusted-keys/trusted_tpm1.c
+++ b/security/keys/trusted-keys/trusted_tpm1.c
@@ -46,38 +46,44 @@ enum {
SRK_keytype = 4
};
-#define TPM_DEBUG 0
-
-#if TPM_DEBUG
+#ifdef CONFIG_TRUSTED_KEYS_DEBUG
static inline void dump_options(struct trusted_key_options *o)
{
- pr_info("sealing key type %d\n", o->keytype);
- pr_info("sealing key handle %0X\n", o->keyhandle);
- pr_info("pcrlock %d\n", o->pcrlock);
- pr_info("pcrinfo %d\n", o->pcrinfo_len);
- print_hex_dump(KERN_INFO, "pcrinfo ", DUMP_PREFIX_NONE,
- 16, 1, o->pcrinfo, o->pcrinfo_len, 0);
+ if (!trusted_debug)
+ return;
+
+ pr_debug("sealing key type %d\n", o->keytype);
+ pr_debug("sealing key handle %0X\n", o->keyhandle);
+ pr_debug("pcrlock %d\n", o->pcrlock);
+ pr_debug("pcrinfo %d\n", o->pcrinfo_len);
+ print_hex_dump_debug("pcrinfo ", DUMP_PREFIX_NONE,
+ 16, 1, o->pcrinfo, o->pcrinfo_len, 0);
}
static inline void dump_sess(struct osapsess *s)
{
- print_hex_dump(KERN_INFO, "trusted-key: handle ", DUMP_PREFIX_NONE,
- 16, 1, &s->handle, 4, 0);
- pr_info("secret:\n");
- print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE,
- 16, 1, &s->secret, SHA1_DIGEST_SIZE, 0);
- pr_info("trusted-key: enonce:\n");
- print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE,
- 16, 1, &s->enonce, SHA1_DIGEST_SIZE, 0);
+ if (!trusted_debug)
+ return;
+
+ print_hex_dump_debug("trusted-key: handle ", DUMP_PREFIX_NONE,
+ 16, 1, &s->handle, 4, 0);
+ pr_debug("secret:\n");
+ print_hex_dump_debug("", DUMP_PREFIX_NONE,
+ 16, 1, &s->secret, SHA1_DIGEST_SIZE, 0);
+ pr_debug("trusted-key: enonce:\n");
+ print_hex_dump_debug("", DUMP_PREFIX_NONE,
+ 16, 1, &s->enonce, SHA1_DIGEST_SIZE, 0);
}
static inline void dump_tpm_buf(unsigned char *buf)
{
int len;
- pr_info("\ntpm buffer\n");
+ if (!trusted_debug)
+ return;
+ pr_debug("\ntpm buffer\n");
len = LOAD32(buf, TPM_SIZE_OFFSET);
- print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, buf, len, 0);
+ print_hex_dump_debug("", DUMP_PREFIX_NONE, 16, 1, buf, len, 0);
}
#else
static inline void dump_options(struct trusted_key_options *o)
--
2.39.5
^ permalink raw reply related
* [PATCH] ima: Use KEXEC_SIG_FORCE for rejecting unsigned kexec images
From: Chi Wang @ 2026-04-15 10:23 UTC (permalink / raw)
To: zohar, roberto.sassu, dmitry.kasatkin, eric.snowberg
Cc: paul, jmorris, serge, linux-integrity, linux-security-module,
linux-kernel, Chi Wang
From: Chi Wang <wangchi@kylinos.cn>
Following the split of KEXEC_VERIFY_SIG into KEXEC_SIG and KEXEC_SIG_FORCE,
only KEXEC_SIG_FORCE indicates that unsigned kernel images must be rejected.
KEXEC_SIG alone enables signature verification but permits unsigned images,
so it should not trigger the IMA appraisal denial for kexec_load.
Update the condition in ima_load_data() to check for KEXEC_SIG_FORCE
instead of KEXEC_SIG.
Fixes: 99d5cadfde2b ("kexec_file: split KEXEC_VERIFY_SIG into KEXEC_SIG and KEXEC_SIG_FORCE")
Signed-off-by: Chi Wang <wangchi@kylinos.cn>
---
security/integrity/ima/ima_main.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 1d6229b156fb..ec70e78ab8cd 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -953,7 +953,7 @@ static int ima_load_data(enum kernel_load_data_id id, bool contents)
switch (id) {
case LOADING_KEXEC_IMAGE:
- if (IS_ENABLED(CONFIG_KEXEC_SIG)
+ if (IS_ENABLED(CONFIG_KEXEC_SIG_FORCE)
&& arch_ima_get_secureboot()) {
pr_err("impossible to appraise a kernel image without a file descriptor; try using kexec_file_load syscall.\n");
return -EACCES;
--
2.25.1
^ permalink raw reply related
* Re: [PATCH] tpm: aovid -Wunused-but-set-variable
From: Jarkko Sakkinen @ 2026-04-15 2:48 UTC (permalink / raw)
To: Thorsten Blum
Cc: Arnd Bergmann, Matthew Garrett, Bartosz Szczepanek,
Ard Biesheuvel, Arnd Bergmann, Peter Huewe, Jason Gunthorpe,
linux-integrity, linux-kernel
In-Reply-To: <adwroOsSnGrGi5OM@linux.dev>
On Mon, Apr 13, 2026 at 01:32:48AM +0200, Thorsten Blum wrote:
> On Fri, Mar 22, 2024 at 02:22:48PM +0100, Arnd Bergmann wrote:
> > From: Arnd Bergmann <arnd@arndb.de>
> >
> > Outside of the EFI tpm code, the TPM_MEMREMAP()/TPM_MEMUNMAP functions are
> > defined as trivial macros, leading to the mapping_size variable ending
> > up unused:
> >
> > In file included from drivers/char/tpm/tpm-sysfs.c:16:
> > In file included from drivers/char/tpm/tpm.h:28:
> > include/linux/tpm_eventlog.h:167:6: error: variable 'mapping_size' set but not used [-Werror,-Wunused-but-set-variable]
> > 167 | int mapping_size;
> >
> > Turn the stubs into inline functions to avoid this warning.
> >
> > Fixes: c46f3405692d ("tpm: Reserve the TPM final events table")
> > Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> > ---
> > include/linux/tpm_eventlog.h | 9 +++++++--
> > 1 file changed, 7 insertions(+), 2 deletions(-)
> >
> > diff --git a/include/linux/tpm_eventlog.h b/include/linux/tpm_eventlog.h
> > index 7d68a5cc5881..6e5be15029fb 100644
> > --- a/include/linux/tpm_eventlog.h
> > +++ b/include/linux/tpm_eventlog.h
> > @@ -131,11 +131,16 @@ struct tcg_algorithm_info {
> > };
> >
> > #ifndef TPM_MEMREMAP
> > -#define TPM_MEMREMAP(start, size) NULL
> > +static inline void *TPM_MEMREMAP(unsigned long start, size_t size)
> > +{
> > + return NULL;
> > +}
> > #endif
> >
> > #ifndef TPM_MEMUNMAP
> > -#define TPM_MEMUNMAP(start, size) do{} while(0)
> > +static inline void TPM_MEMUNMAP(void *mapping, size_t size)
> > +{
> > +}
> > #endif
> >
> > /**
>
> I just stumbled upon the same problem and found this patch from 2024,
> which still applies. I cc'ed the current maintainers - maybe someone can
> pick this up? Thanks!
>
> Reviewed-by: Thorsten Blum <thorsten.blum@linux.dev>
Thanks.
Arnd, I fixed typo in short summary and applied with that modification.
BR, Jarkko
^ permalink raw reply
* Re: [PATCH] trusted-keys: move pr_fmt out of trusted-type.h
From: Jarkko Sakkinen @ 2026-04-15 2:44 UTC (permalink / raw)
To: Ahmad Fatoum
Cc: Marco Felsch, Josh Snyder, James Bottomley, Mimi Zohar,
David Howells, Pengutronix Kernel Team, Paul Moore, James Morris,
Serge E. Hallyn, David Gstir, sigma star Kernel Team,
Srish Srinivasan, Nayna Jain, Sumit Garg, linux-security-module,
linux-integrity, keyrings, linux-kernel
In-Reply-To: <20e9f021-f6b3-4e19-9e1b-93b1e00eb803@pengutronix.de>
On Mon, Apr 13, 2026 at 01:03:30PM +0200, Ahmad Fatoum wrote:
> Hi,
>
> On 4/13/26 1:01 PM, Marco Felsch wrote:
> > Hi Josh,
> >
> > On 26-04-11, Josh Snyder wrote:
> >> Defining pr_fmt in a widely-included header leaks the "trusted_key: "
> >> prefix into every translation unit that transitively includes
> >> <keys/trusted-type.h>. dm-crypt, for example, ends up printing
> >>
> >> trusted_key: device-mapper: crypt: dm-10: INTEGRITY AEAD ERROR ...
> >>
> >> dm-crypt began including <keys/trusted-type.h> in commit 363880c4eb36
> >> ("dm crypt: support using trusted keys"), which predates the pr_fmt
> >> addition, so the regression has been live from the moment the header
> >> gained its own pr_fmt definition.
> >>
> >> Move the pr_fmt definition into the trusted-keys source files that
> >> actually want the prefix.
> >>
> >> Fixes: 5d0682be3189 ("KEYS: trusted: Add generic trusted keys framework")
> >> Assisted-by: Claude:claude-opus-4-6
> >> Signed-off-by: Josh Snyder <josh@code406.com>
> >> ---
> >> include/keys/trusted-type.h | 6 ------
> >> security/keys/trusted-keys/trusted_caam.c | 2 ++
> >> security/keys/trusted-keys/trusted_core.c | 2 ++
> >> security/keys/trusted-keys/trusted_dcp.c | 2 ++
> >> security/keys/trusted-keys/trusted_pkwm.c | 2 ++
> >> security/keys/trusted-keys/trusted_tpm1.c | 2 ++
> >> security/keys/trusted-keys/trusted_tpm2.c | 2 ++
> >> 7 files changed, 12 insertions(+), 6 deletions(-)
> >>
> >> diff --git a/include/keys/trusted-type.h b/include/keys/trusted-type.h
> >> index 03527162613f7..54da1f174aeab 100644
> >> --- a/include/keys/trusted-type.h
> >> +++ b/include/keys/trusted-type.h
> >> @@ -11,12 +11,6 @@
> >> #include <linux/rcupdate.h>
> >> #include <linux/tpm.h>
> >>
> >> -#ifdef pr_fmt
> >> -#undef pr_fmt
> >> -#endif
> >> -
> >> -#define pr_fmt(fmt) "trusted_key: " fmt
> >> -
> >> #define MIN_KEY_SIZE 32
> >> #define MAX_KEY_SIZE 128
> >> #if IS_ENABLED(CONFIG_TRUSTED_KEYS_PKWM)
> >> diff --git a/security/keys/trusted-keys/trusted_caam.c b/security/keys/trusted-keys/trusted_caam.c
> >> index 601943ce0d60f..a31fd89c0e5c5 100644
> >> --- a/security/keys/trusted-keys/trusted_caam.c
> >> +++ b/security/keys/trusted-keys/trusted_caam.c
> >> @@ -4,6 +4,8 @@
> >> * Copyright 2025 NXP
> >> */
> >>
> >> +#define pr_fmt(fmt) "trusted_key: " fmt
> >
> > Can we adapt this patch further to include the trusted-key type as well?
> > E.g. 'trusted_key-caam'.
>
> Agreed, if we move it into the individual files, we can use the occasion
> to make it a bit more descriptive.
>
> I would suggest "trusted_key: caam: ", so the prefix stays the same.
>
> Cheers,
> Ahmad
+1
BR, Jarkko
^ permalink raw reply
* Re: [PATCH v2 0/2] tpm_tis: fix retry exhaustion and add logging
From: Jarkko Sakkinen @ 2026-04-15 2:40 UTC (permalink / raw)
To: Jacqueline Wong; +Cc: linux-integrity, peterhuewe, jgg, axelrasmussen
In-Reply-To: <20260411003300.1823020-1-jacqwong@google.com>
On Sat, Apr 11, 2026 at 12:32:58AM +0000, Jacqueline Wong wrote:
> The Fix:
> - Patch 1: Adds error logs to identify the specific hardware status mismatch.
> - Patch 2: Stops execution immediately when retries are exhausted.
>
> v2 changes:
> - Split logging and logic into separate patches.
> - Added retry count to the error message.
> - Included dmesg traces below.
>
> Testing:
> Dmesg traces obtained using error injection to simulate status register mismatches.
>
> Before:
> [ 130.288751] tpm tpm0: Operation Timed out
> [ 250.306070] tpm tpm0: Operation Timed out
> [ 250.310173] tpm tpm0: A TPM error (-62) occurred attempting to determine the timeouts
>
> After:
> [ 10.271547] tpm tpm0: TPM_STS_DATA_EXPECT should be unset. sts = 0x00000080
> ...
> [ 10.646283] tpm tpm0: TPM_STS_DATA_EXPECT should be unset. sts = 0x00000080
> [ 10.653461] tpm tpm0: Exhausted 50 tpm_tis_send_data retries
> [ 10.659304] tpm tpm0: tpm_try_transmit: send(): error -5
> [ 10.665435] tpm tpm0: TPM_STS_DATA_EXPECT should be unset. sts = 0x00000080
> ...
> [ 11.037198] tpm tpm0: TPM_STS_DATA_EXPECT should be unset. sts = 0x00000080
> [ 11.044441] tpm tpm0: Exhausted 50 tpm_tis_send_data retries
> [ 11.050288] tpm tpm0: tpm_try_transmit: send(): error -5
> [ 11.055723] tpm tpm0: A TPM error (-5) occurred attempting to determine the timeouts
>
> Jacqueline Wong (2):
> tpm: tpm_tis: add error logging for data transfer
> tpm: tpm_tis: stop transmit if retries are exhausted
>
> drivers/char/tpm/tpm_tis_core.c | 11 ++++++++++-
> 1 file changed, 10 insertions(+), 1 deletion(-)
>
> --
> 2.53.0.1213.gd9a14994de-goog
>
OK, I dropped the patch that as I applied as I did not see this :-)
Now that we are cycling, please send v3 with checkpatch --strict passing
BR, Jarkko
^ permalink raw reply
* Re: [PATCH] tpm_tis: Check for an error after exhausting send retires
From: Jarkko Sakkinen @ 2026-04-15 2:38 UTC (permalink / raw)
To: Jacqueline Wong
Cc: peterhuewe, jgg, Alexander.Steffen, linux-integrity, linux-kernel,
axelrasmussen, Jordan Hand
In-Reply-To: <20260410211350.1132611-1-jacqwong@google.com>
On Fri, Apr 10, 2026 at 09:13:50PM +0000, Jacqueline Wong wrote:
> From: Jordan Hand <jhand@google.com>
>
> tpm_tis_send_main() will attempt to retry sending data TPM_RETRY times.
> Currently, if those retries are exhausted, the driver will attempt to
> call execute. The TPM will be in the wrong state, leading to the
> operation simply timing out.
>
> Instead, if there is still an error after retries are exhausted, return
> that error immediately.
>
> Additionally, add logging to more easily determine reason for transmit
> failure.
>
> Fixes: 280db21e153d8 ("tpm_tis: Resend command to recover from data transfer errors")
> Signed-off-by: Jordan Hand <jhand@google.com>
> ---
> drivers/char/tpm/tpm_tis_core.c | 11 ++++++++++-
> 1 file changed, 10 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c
> index e2a1769081b1..b78937841879 100644
> --- a/drivers/char/tpm/tpm_tis_core.c
> +++ b/drivers/char/tpm/tpm_tis_core.c
> @@ -471,6 +471,8 @@ static int tpm_tis_send_data(struct tpm_chip *chip, const u8 *buf, size_t len)
> status = tpm_tis_status(chip);
> if (!itpm && (status & TPM_STS_DATA_EXPECT) == 0) {
> rc = -EIO;
> + dev_err(&chip->dev, "TPM_STS_DATA_EXPECT should be set. sts = 0x%08x\n",
> + status);
> goto out_err;
> }
> }
> @@ -491,6 +493,8 @@ static int tpm_tis_send_data(struct tpm_chip *chip, const u8 *buf, size_t len)
> status = tpm_tis_status(chip);
> if (!itpm && (status & TPM_STS_DATA_EXPECT) != 0) {
> rc = -EIO;
> + dev_err(&chip->dev, "TPM_STS_DATA_EXPECT should be unset. sts = 0x%08x\n",
> + status);
> goto out_err;
> }
>
> @@ -552,11 +556,16 @@ static int tpm_tis_send_main(struct tpm_chip *chip, const u8 *buf, size_t len)
> break;
> else if (rc != -EAGAIN && rc != -EIO)
> /* Data transfer failed, not recoverable */
> - return rc;
> + goto out_err;
>
> usleep_range(priv->timeout_min, priv->timeout_max);
> }
>
> + if (rc == -EAGAIN || rc == -EIO) {
> + dev_err(&chip->dev, "Exhausted tpm_tis_send_data retries\n");
> + goto out_err;
> + }
> +
> /* go and do it */
> rc = tpm_tis_write8(priv, TPM_STS(priv->locality), TPM_STS_GO);
> if (rc < 0)
> --
> 2.53.0.1213.gd9a14994de-goog
>
CHECK: Alignment should match open parenthesis
#35: FILE: drivers/char/tpm/tpm_tis_core.c:475:
+ dev_err(&chip->dev, "TPM_STS_DATA_EXPECT should be set. sts = 0x%08x\n",
+ status);
CHECK: Alignment should match open parenthesis
#44: FILE: drivers/char/tpm/tpm_tis_core.c:497:
+ dev_err(&chip->dev, "TPM_STS_DATA_EXPECT should be unset. sts = 0x%08x\n",
+ status);
I fixed these manually.
Good catch, thanks:
Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>
Applied.
BR, Jarkko
^ permalink raw reply
* Re: [PATCH v1] tpm: restore timeout for key creation commands
From: Jarkko Sakkinen @ 2026-04-15 2:31 UTC (permalink / raw)
To: Baoli.Zhang
Cc: Peter Huewe, Jason Gunthorpe, Serge Hallyn, lili . li,
linux-integrity, linux-kernel
In-Reply-To: <20260410014940.3557934-1-baoli.zhang@linux.intel.com>
On Fri, Apr 10, 2026 at 09:49:39AM +0800, Baoli.Zhang wrote:
> After the per-command duration map was introduced, TPM2 key creation
> commands (`CREATE_PRIMARY`, `CREATE`, `CREATE_LOADED`) were limited to
> 30 seconds.
>
> On some platforms this is not sufficient and key creation can time out.
> Commit 207696b17f38 ("tpm: use a map for tpm2_calc_ordinal_duration()")
> inadvertently reduced these command timeouts from 300 seconds to 30
> seconds. Restore them to 300 seconds to avoid spurious failures.
Is this like pre-silicon (FPGA) type of situation? I have doubts these
latencies happening on ASIC.
If it is pre-release hardware, maybe there should be option to extend
the delay, or does this happen on actual production hardware?
Just want to understand this better...
>
> Fixes: 207696b17f38 ("tpm: use a map for tpm2_calc_ordinal_duration()")
>
Extra empty line.
> Signed-off-by: Baoli.Zhang <baoli.zhang@linux.intel.com>
> Co-developed-by: lili.li <lili.li@intel.com>
"Co-developed-by: states that the patch was co-created by several
developers; it is a used to give attribution to co-authors (in addition
to the author attributed by the From: tag) when multiple people work on
a single patch. Every Co-developed-by: must be immediately followed by a
Signed-off-by: of the associated co-author. Details and examples can be
found in Documentation/process/submitting-patches.rst." [1]
[1] https://docs.kernel.org/process/5.Posting.html
> ---
> drivers/char/tpm/tpm2-cmd.c | 6 +++---
> 1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
> index 3a77be7ebf4aa..430022f695f24 100644
> --- a/drivers/char/tpm/tpm2-cmd.c
> +++ b/drivers/char/tpm/tpm2-cmd.c
> @@ -71,9 +71,9 @@ static const struct {
> {TPM2_CC_HIERARCHY_CHANGE_AUTH, 2000},
> {TPM2_CC_GET_CAPABILITY, 750},
> {TPM2_CC_NV_READ, 2000},
> - {TPM2_CC_CREATE_PRIMARY, 30000},
> - {TPM2_CC_CREATE, 30000},
> - {TPM2_CC_CREATE_LOADED, 30000},
> + {TPM2_CC_CREATE_PRIMARY, 300000},
> + {TPM2_CC_CREATE, 300000},
> + {TPM2_CC_CREATE_LOADED, 300000},
> };
>
> /**
> --
> 2.43.0
>
BR, Jarkko
^ permalink raw reply
* Re: [PATCH] tpm: Use kfree_sensitive() to free auth session in tpm_dev_release()
From: Jarkko Sakkinen @ 2026-04-15 2:22 UTC (permalink / raw)
To: Gunnar Kudrjavets
Cc: peterhuewe, jgg, James.Bottomley, ardb, linux-integrity,
linux-kernel, Justinien Bouron
In-Reply-To: <20260409172108.11600-1-gunnarku@amazon.com>
On Thu, Apr 09, 2026 at 05:20:54PM +0000, Gunnar Kudrjavets wrote:
> tpm_dev_release() uses plain kfree() to free chip->auth, which contains
> sensitive cryptographic material including HMAC session keys, nonces,
> and passphrase data (struct tpm2_auth).
>
> Every other code path that frees this structure uses kfree_sensitive()
> to zero the memory before releasing it: both tpm2_end_auth_session()
> and tpm_buf_check_hmac_response() do so. The tpm_dev_release() path
> is the only one that does not, leaving key material in freed slab
> memory until it is eventually overwritten.
>
> Use kfree_sensitive() for consistency with the rest of the driver and
> to ensure session keys are scrubbed during device teardown.
>
> Fixes: 699e3efd6c64 ("tpm: Add HMAC session start and end functions")
> Signed-off-by: Gunnar Kudrjavets <gunnarku@amazon.com>
> Reviewed-by: Justinien Bouron <jbouron@amazon.com>
> ---
> drivers/char/tpm/tpm-chip.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
> index 082b910ddf0d..17d9d71774ec 100644
> --- a/drivers/char/tpm/tpm-chip.c
> +++ b/drivers/char/tpm/tpm-chip.c
> @@ -247,7 +247,7 @@ static void tpm_dev_release(struct device *dev)
> kfree(chip->work_space.context_buf);
> kfree(chip->work_space.session_buf);
> #ifdef CONFIG_TCG_TPM2_HMAC
> - kfree(chip->auth);
> + kfree_sensitive(chip->auth);
> #endif
> kfree(chip);
> }
>
> base-commit: 03e5553f5fb99cb47c315e167a604a9c69e6f724
> --
> 2.47.3
>
Applied.
Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>
BR, Jarkko
^ permalink raw reply
* Re: [RFC PATCH 00/10] Fix dm-ima bugs
From: Mimi Zohar @ 2026-04-15 2:06 UTC (permalink / raw)
To: Mike Snitzer, Benjamin Marzinski
Cc: Mikulas Patocka, dm-devel, linux-integrity, Roberto Sassu,
Dmitry Kasatkin, Lakshmi Ramasubramanian, steven chen
In-Reply-To: <ad51kuxJuU84Amep@kernel.org>
[Cc: Lakshmi Ramasubramanian, steven chen]
On Tue, 2026-04-14 at 13:12 -0400, Mike Snitzer wrote:
> On Mon, Apr 13, 2026 at 08:22:34PM -0400, Benjamin Marzinski wrote:
> > The dm-ima code does not guarantee that the dm_ima_measure_on_*
> > functions will not be called at the same time. Since they modify and
> > free shared memory, this can lead to Use-After-Free errors or garbage
> > measurements. Further, they don't make sure that the state they measure
> > corresponds to the actual device state. For instance if table_load()
> > runs at the same time as do_resume() on a table swap,
> > dm_ima_measure_on_device_resume() can end up thinking the wrong table is
> > active. Or a concurrent dm_hash_rename() and a table swap, can end up
> > with a the new active table still using the old name. This patchset
> > makes sure the the dm-ima function are serialized and report the correct
> > device state.
> >
> > However, the code is still messier that in could be. This is because
> > it duplicates the current measurement events and format. I would really
> > like to know if that is necessary. Specifically, it currently measures
> > the following dm device and table actions:
> >
> > load
> > clear
> > rename
> > resume
> > remove
> >
> > I don't see the benefit of reporting changes to the inactive table, or
> > resumes where the device does not change state. From the user's point of
> > view, the device is still the same after these events. At the same
> > time, it doesn't measure device creates if no table was loaded, so you
> > can have situations where the the first measurement for a device is a
> > rename or a remove. A more sensible set of actions to measure would be:
> >
> > create
> > table_swap
> > rename
> > remove
> >
> > Also, the measurement format doesn't map well to how dm device's are
> > actually set up, in a way that makes it harder for the code and records
> > extraneous information. First, like I mentioned before, I don't see the
> > benefit of measuring the inactive table. Second, the name, uuid, and
> > major/minor numbers are properties of the device, not it's table (and dm
> > devices can't have partitions, so the minor count will always be 1). I
> > don't see a reason to store and occasinally log this information twice,
> > if there is an active and incative table, and it forces extra
> > coordination between the dm_ima_measure_on_* functions.
> >
> > I'm wondering it we are stuck with the current events and format, now
> > that this has been released? Or could we bump the version, and change
> > what events we measure, and how we format the output?
> >
> > Benjamin Marzinski (10):
> > dm-ima: remove dm_ima_reset_data()
> > dm-ima: remove broken last_target_measured logic
> > dm-ima: Remove status_flags from dm_ima_measure_on_table_load()
> > dm-ima: don't copy the active table to the inactive table
> > dm-ima: Fix UAF errors and measuring incorrect context
> > dm-ima: remove new_map from dm_ima_measure_on_device_clear
> > dm-ima: Fix issues with dm_ima_measure_on_device_rename
> > dm-ima: Handle race between rename and table swap
> > dm-ima: Fail more gracefully in dm_ima_measure_on_*
> > dm-ima: use active table's size if available
> >
> > drivers/md/dm-ima.c | 506 +++++++++++++++++++-----------------------
> > drivers/md/dm-ima.h | 67 ++++--
> > drivers/md/dm-ioctl.c | 146 +++++++++++-
> > drivers/md/dm.c | 2 +-
> > 4 files changed, 421 insertions(+), 300 deletions(-)
>
> Pretty extensive changes needed here all things considered.
>
> SO I'm aware, who is using dm-ima? I see that Tushar Sugandhi is no
> longer at Microsoft and so he isn't cc'd on these changes. I can
> infer from Cc some potential users, but I just want to make sure this
> code isn't just technical debt that we're having to carry in DM now?
>
> Thanks,
> Mike
^ permalink raw reply
* Re: [PATCH v2 2/2] integrity: Add support for sigv3 verification using ML-DSA keys
From: Mimi Zohar @ 2026-04-15 2:01 UTC (permalink / raw)
To: Stefan Berger, linux-integrity, linux-security-module
Cc: linux-kernel, roberto.sassu, ebiggers
In-Reply-To: <20260408174154.139606-3-stefanb@linux.ibm.com>
On Wed, 2026-04-08 at 13:41 -0400, Stefan Berger wrote:
> Add support for sigv3 signature verification using ML-DSA in pure mode.
> When a sigv3 signature is verified, first check whether the key to use
> for verification is an ML-DSA key and therefore uses a hashless signature
> verification scheme. The hashless signature verification method uses the
> ima_file_id structure directly for signature verification rather than
> its digest.
>
> Suggested-by: Eric Biggers <ebiggers@kernel.org>
> Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
>
Thanks, Stefan.
> ---
> v2: Set hash_algo in public_key_signature to "none"
> ---
> security/integrity/digsig_asymmetric.c | 84 ++++++++++++++++++++++++--
> 1 file changed, 79 insertions(+), 5 deletions(-)
>
> diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c
> index e29ed73f15cd..c80cb2b117a6 100644
> --- a/security/integrity/digsig_asymmetric.c
> +++ b/security/integrity/digsig_asymmetric.c
> @@ -190,17 +190,91 @@ static int calc_file_id_hash(enum evm_ima_xattr_type type,
> return rc;
> }
>
> +/*
kernel-doc starts with "/**".
> + * asymmetric_verify_v3_hashless - Use hashless signature verification on sigv3
> + * @key: The key to use for signature verification
> + * @pk: The associated public key
> + * @encoding: The encoding the key type uses
> + * @sig: The signature
> + * @siglen: The length of the xattr signature
> + * @algo: The hash algorithm
> + * @digest: The file digest
> + *
> + * Create an ima_file_id structure and use it for signature verification
> + * directly. This can be used for ML-DSA in pure mode for example.
Like the comments on 1/2, please add a comment here indicating that all callers
must verify the signature length (siglen) and the public key (pk) is not NULL,
before calling asymmetric_verify_v3_hashless(). Also indicate that the caller
must free the key.
> + */
> +static int asymmetric_verify_v3_hashless(struct key *key,
> + const struct public_key *pk,
> + const char *encoding,
> + const char *sig, int siglen,
> + u8 algo,
> + const u8 *digest)
> +{
> + struct signature_v2_hdr *hdr = (struct signature_v2_hdr *)sig;
> + struct ima_file_id file_id = {
> + .hash_type = hdr->type,
> + .hash_algorithm = algo,
> + };
> + size_t digest_size = hash_digest_size[algo];
Defer initializing the digest_size and .m_size, below, until after checking the
hash algorithm is valid.
> + struct public_key_signature pks = {
> + .m = (u8 *)&file_id,
> + .m_size = sizeof(file_id) - (HASH_MAX_DIGESTSIZE - digest_size),
> + .s = hdr->sig,
> + .s_size = siglen - sizeof(*hdr),
> + .pkey_algo = pk->pkey_algo,
> + .hash_algo = "none",
> + .encoding = encoding,
> + };
> + int ret;
> +
> + if (hdr->type != IMA_VERITY_DIGSIG &&
> + hdr->type != EVM_IMA_XATTR_DIGSIG &&
> + hdr->type != EVM_XATTR_PORTABLE_DIGSIG)
> + return -EINVAL;
> +
> + if (pks.s_size != be16_to_cpu(hdr->sig_size))
> + return -EBADMSG;
> +
> + memcpy(file_id.hash, digest, digest_size);
First check the hash algorithm is valid, before using digest_size.
> +
> + ret = verify_signature(key, &pks);
> + pr_debug("%s() = %d\n", __func__, ret);
> + return ret;
> +}
> +
> int asymmetric_verify_v3(struct key *keyring, const char *sig, int siglen,
> const char *data, int datalen, u8 algo)
> {
> struct signature_v2_hdr *hdr = (struct signature_v2_hdr *)sig;
> struct ima_max_digest_data hash;
> + const struct public_key *pk;
> + struct key *key;
> int rc;
>
> - rc = calc_file_id_hash(hdr->type, algo, data, &hash);
> - if (rc)
> - return -EINVAL;
> + if (siglen <= sizeof(*hdr))
> + return -EBADMSG;
> +
> + key = request_asymmetric_key(keyring, be32_to_cpu(hdr->keyid));
> + if (IS_ERR(key))
> + return PTR_ERR(key);
>
> - return asymmetric_verify(keyring, sig, siglen, hash.digest,
> - hash.hdr.length);
> + pk = asymmetric_key_public_key(key);
Please add a test to check that 'pk' isn't null.
> + if (!strncmp(pk->pkey_algo, "mldsa", 5)) {
> + rc = asymmetric_verify_v3_hashless(key, pk, "raw",
> + sig, siglen, algo, data);
> + } else {
> + rc = calc_file_id_hash(hdr->type, algo, data, &hash);
> + if (rc) {
> + rc = -EINVAL;
> + goto err_exit;
> + }
> +
> + rc = asymmetric_verify_common(key, pk, sig, siglen, hash.digest,
> + hash.hdr.length);
> + }
> +
> +err_exit:
Normally a label named 'err*' would be preceded by a return. Here, the label
"err_exit" is always called, not only when there is an error. Please rename the
label to something more appropriate - out, cleanup, etc.
> + key_put(key);
> +
> + return rc;
> }
thanks,
Mimi
^ permalink raw reply
* Re: [PATCH v2 1/2] integrity: Refactor asymmetric_verify for reusability
From: Mimi Zohar @ 2026-04-15 2:00 UTC (permalink / raw)
To: Stefan Berger, linux-integrity, linux-security-module
Cc: linux-kernel, roberto.sassu, ebiggers
In-Reply-To: <20260408174154.139606-2-stefanb@linux.ibm.com>
On Wed, 2026-04-08 at 13:41 -0400, Stefan Berger wrote:
> Refactor asymmetric_verify for reusability. Have it call
> asymmetric_verify_common with the signature verification key and the
> public_key structure as parameters. sigv3 support for ML-DSA will need to
> check the public key type first to decide how to do the signature
> verification and therefore will have these parameters available for
> calling asymmetric_verify_common.
>
> Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
Thanks, Stefan.
> ---
> security/integrity/digsig_asymmetric.c | 42 +++++++++++++++++---------
> 1 file changed, 28 insertions(+), 14 deletions(-)
>
> diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c
> index 6e68ec3becbd..e29ed73f15cd 100644
> --- a/security/integrity/digsig_asymmetric.c
> +++ b/security/integrity/digsig_asymmetric.c
> @@ -79,18 +79,15 @@ static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid)
> return key;
> }
>
> -int asymmetric_verify(struct key *keyring, const char *sig,
> - int siglen, const char *data, int datalen)
> +static int asymmetric_verify_common(const struct key *key,
> + const struct public_key *pk,
> + const char *sig, int siglen,
> + const char *data, int datalen)
> {
> - struct public_key_signature pks;
> struct signature_v2_hdr *hdr = (struct signature_v2_hdr *)sig;
> - const struct public_key *pk;
> - struct key *key;
> + struct public_key_signature pks;
> int ret;
>
> - if (siglen <= sizeof(*hdr))
> - return -EBADMSG;
> -
> siglen -= sizeof(*hdr);
Normally kernel-doc is unnecessary for static functions. Here, however, since
only the caller verifies the signature length, there should be a kernel-doc
function definition. It should indicate that all callers must verify the
signature length (siglen) and that the public key (pk) is not NULL, before
calling asymmetric_verify_common().
>
> if (siglen != be16_to_cpu(hdr->sig_size))
> @@ -99,15 +96,10 @@ int asymmetric_verify(struct key *keyring, const char *sig,
> if (hdr->hash_algo >= HASH_ALGO__LAST)
> return -ENOPKG;
>
> - key = request_asymmetric_key(keyring, be32_to_cpu(hdr->keyid));
> - if (IS_ERR(key))
> - return PTR_ERR(key);
> -
> memset(&pks, 0, sizeof(pks));
>
> pks.hash_algo = hash_algo_name[hdr->hash_algo];
>
> - pk = asymmetric_key_public_key(key);
> pks.pkey_algo = pk->pkey_algo;
> if (!strcmp(pk->pkey_algo, "rsa")) {
> pks.encoding = "pkcs1";
> @@ -127,11 +119,33 @@ int asymmetric_verify(struct key *keyring, const char *sig,
> pks.s_size = siglen;
> ret = verify_signature(key, &pks);
> out:
> - key_put(key);
The kernel-doc function definition should also indicate that the caller must
free the key.
> pr_debug("%s() = %d\n", __func__, ret);
> return ret;
> }
>
> +int asymmetric_verify(struct key *keyring, const char *sig,
> + int siglen, const char *data, int datalen)
> +{
> + struct signature_v2_hdr *hdr = (struct signature_v2_hdr *)sig;
> + const struct public_key *pk;
> + struct key *key;
> + int ret;
> +
> + if (siglen <= sizeof(*hdr))
> + return -EBADMSG;
> +
> + key = request_asymmetric_key(keyring, be32_to_cpu(hdr->keyid));
> + if (IS_ERR(key))
> + return PTR_ERR(key);
> + pk = asymmetric_key_public_key(key);
Please add a test here making sure pk is not null.
thanks,
Mimi
> +
> + ret = asymmetric_verify_common(key, pk, sig, siglen, data, datalen);
> +
> + key_put(key);
> +
> + return ret;
> +}
> +
> /*
> * calc_file_id_hash - calculate the hash of the ima_file_id struct data
> * @type: xattr type [enum evm_ima_xattr_type]
^ permalink raw reply
* Re: [PATCH v3] KEYS: trusted: Debugging as a feature
From: Jarkko Sakkinen @ 2026-04-15 0:05 UTC (permalink / raw)
To: Nayna Jain
Cc: linux-integrity, keyrings, Srish Srinivasan, James Bottomley,
Mimi Zohar, David Howells, Paul Moore, James Morris,
Serge E. Hallyn, Ahmad Fatoum, Pengutronix Kernel Team,
linux-kernel, linux-security-module
In-Reply-To: <129b137c-be9b-4b01-824f-beec7111377c@linux.ibm.com>
On Sun, Apr 12, 2026 at 02:47:20PM -0400, Nayna Jain wrote:
>
> On 4/9/26 12:07 PM, Jarkko Sakinen wrote:
> > From: Jarkko Sakkinen <jarkko@kernel.org>
> >
> > TPM_DEBUG, and other similar flags, are a non-standard way to specify a
> > feature in Linux kernel. Introduce CONFIG_TRUSTED_KEYS_DEBUG for trusted
> > keys, and use it to replace these ad-hoc feature flags.
> >
> > Given that trusted keys debug dumps can contain sensitive data, harden the
> > feature as follows:
> >
> > 1. In the Kconfig description postulate that pr_debug() statements must be
> > used.
> > 2. Use pr_debug() statements in TPM 1.x driver to print the protocol dump.
> > 3. Require trusted.debug=1 on the kernel command line (default: 0) to
> > activate dumps at runtime, even when CONFIG_TRUSTED_KEYS_DEBUG=y.
> >
> > Traces, when actually needed, can be easily enabled by providing
> > trusted.dyndbg='+p' and trusted.debug=1 in the kernel command-line.
>
> Thanks Jarkko. Additional changes looks good to me. I just realized that the
> kernel command-line parameters document may need to be updated to include
> these parameters.
Good point. I will bake that to my PR version of patch. It's low risk as
per corrateral damage. Thanks for pointing this out.
>
> Apart from that, feel free to add my
>
> Reviewed-by: Nayna Jain <nayna@linux.ibm.com>
Thank you! These defines have been a huge itch for me for a while :-)
>
> Thanks & Regards,
>
> - Nayna
>
>
BR, Jarkko
^ permalink raw reply
* Re: [PATCH v3] KEYS: trusted: Debugging as a feature
From: Jarkko Sakkinen @ 2026-04-15 0:03 UTC (permalink / raw)
To: Srish Srinivasan
Cc: linux-integrity, keyrings, Nayna Jain, James Bottomley,
Mimi Zohar, David Howells, Paul Moore, James Morris,
Serge E. Hallyn, Ahmad Fatoum, Pengutronix Kernel Team,
linux-kernel, linux-security-module
In-Reply-To: <05c9a2c3-8077-4a1c-87f8-4e240ee1e5c4@linux.ibm.com>
On Fri, Apr 10, 2026 at 11:03:58PM +0530, Srish Srinivasan wrote:
>
> On 4/9/26 9:37 PM, Jarkko Sakinen wrote:
> > From: Jarkko Sakkinen <jarkko@kernel.org>
> >
> > TPM_DEBUG, and other similar flags, are a non-standard way to specify a
> > feature in Linux kernel. Introduce CONFIG_TRUSTED_KEYS_DEBUG for trusted
> > keys, and use it to replace these ad-hoc feature flags.
> >
> > Given that trusted keys debug dumps can contain sensitive data, harden the
> > feature as follows:
> >
> > 1. In the Kconfig description postulate that pr_debug() statements must be
> > used.
> > 2. Use pr_debug() statements in TPM 1.x driver to print the protocol dump.
> > 3. Require trusted.debug=1 on the kernel command line (default: 0) to
> > activate dumps at runtime, even when CONFIG_TRUSTED_KEYS_DEBUG=y.
> >
> > Traces, when actually needed, can be easily enabled by providing
> > trusted.dyndbg='+p' and trusted.debug=1 in the kernel command-line.
> >
> > Cc: Srish Srinivasan <ssrish@linux.ibm.com>
> > Reported-by: Nayna Jain <nayna@linux.ibm.com>
> > Closes: https://lore.kernel.org/all/7f8b8478-5cd8-4d97-bfd0-341fd5cf10f9@linux.ibm.com/
> > Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
>
>
> Tested on PKWM and emulated TPM backends.
>
> Tested-by: Srish Srinivasan <ssrish@linux.ibm.com>
Thank you!
BR, Jarkko
^ permalink raw reply
* Re: [PATCH] tpm2-sessions: Fix missing tpm_buf_destroy() in tpm2_read_public()
From: Jarkko Sakkinen @ 2026-04-15 0:00 UTC (permalink / raw)
To: Gunnar Kudrjavets
Cc: peterhuewe, jgg, noodles, linux-integrity, linux-kernel,
Justinien Bouron
In-Reply-To: <20260408164359.24968-1-gunnarku@amazon.com>
On Wed, Apr 08, 2026 at 04:43:37PM +0000, Gunnar Kudrjavets wrote:
> tpm2_read_public() calls tpm_buf_init() but fails to call
> tpm_buf_destroy() on two exit paths, leaking a page allocation:
>
> 1. When name_size() returns an error (unrecognized hash algorithm),
> the function returns directly without destroying the buffer.
>
> 2. On the success path, the buffer is never destroyed before
> returning.
>
> All other error paths in the function correctly call
> tpm_buf_destroy() before returning.
>
> Fix both by adding the missing tpm_buf_destroy() calls.
>
> Fixes: bda1cbf73c6e ("tpm2-sessions: Fix tpm2_read_public range checks")
> Signed-off-by: Gunnar Kudrjavets <gunnarku@amazon.com>
> Reviewed-by: Justinien Bouron <jbouron@amazon.com>
> ---
> drivers/char/tpm/tpm2-sessions.c | 5 ++++-
> 1 file changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/char/tpm/tpm2-sessions.c b/drivers/char/tpm/tpm2-sessions.c
> index 09df6353ef04..f7c6c043fef4 100644
> --- a/drivers/char/tpm/tpm2-sessions.c
> +++ b/drivers/char/tpm/tpm2-sessions.c
> @@ -203,8 +203,10 @@ static int tpm2_read_public(struct tpm_chip *chip, u32 handle, void *name)
> rc = tpm_buf_read_u16(&buf, &offset);
> name_size_alg = name_size(&buf.data[offset]);
>
> - if (name_size_alg < 0)
> + if (name_size_alg < 0) {
> + tpm_buf_destroy(&buf);
> return name_size_alg;
> + }
>
> if (rc != name_size_alg) {
> tpm_buf_destroy(&buf);
> @@ -217,6 +219,7 @@ static int tpm2_read_public(struct tpm_chip *chip, u32 handle, void *name)
> }
>
> memcpy(name, &buf.data[offset], rc);
> + tpm_buf_destroy(&buf);
> return name_size_alg;
> }
> #endif /* CONFIG_TCG_TPM2_HMAC */
>
> base-commit: 03e5553f5fb99cb47c315e167a604a9c69e6f724
> --
> 2.47.3
>
Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>
Applied.
BR, Jarkko
^ permalink raw reply
* Re: [RFC PATCH 00/10] Fix dm-ima bugs
From: Benjamin Marzinski @ 2026-04-14 18:35 UTC (permalink / raw)
To: Mike Snitzer
Cc: Mikulas Patocka, dm-devel, linux-integrity, Mimi Zohar,
Roberto Sassu, Dmitry Kasatkin
In-Reply-To: <ad51kuxJuU84Amep@kernel.org>
On Tue, Apr 14, 2026 at 01:12:50PM -0400, Mike Snitzer wrote:
> On Mon, Apr 13, 2026 at 08:22:34PM -0400, Benjamin Marzinski wrote:
> > The dm-ima code does not guarantee that the dm_ima_measure_on_*
> > functions will not be called at the same time. Since they modify and
> > free shared memory, this can lead to Use-After-Free errors or garbage
> > measurements. Further, they don't make sure that the state they measure
> > corresponds to the actual device state. For instance if table_load()
> > runs at the same time as do_resume() on a table swap,
> > dm_ima_measure_on_device_resume() can end up thinking the wrong table is
> > active. Or a concurrent dm_hash_rename() and a table swap, can end up
> > with a the new active table still using the old name. This patchset
> > makes sure the the dm-ima function are serialized and report the correct
> > device state.
> >
> > However, the code is still messier that in could be. This is because
> > it duplicates the current measurement events and format. I would really
> > like to know if that is necessary. Specifically, it currently measures
> > the following dm device and table actions:
> >
> > load
> > clear
> > rename
> > resume
> > remove
> >
> > I don't see the benefit of reporting changes to the inactive table, or
> > resumes where the device does not change state. From the user's point of
> > view, the device is still the same after these events. At the same
> > time, it doesn't measure device creates if no table was loaded, so you
> > can have situations where the the first measurement for a device is a
> > rename or a remove. A more sensible set of actions to measure would be:
> >
> > create
> > table_swap
> > rename
> > remove
> >
> > Also, the measurement format doesn't map well to how dm device's are
> > actually set up, in a way that makes it harder for the code and records
> > extraneous information. First, like I mentioned before, I don't see the
> > benefit of measuring the inactive table. Second, the name, uuid, and
> > major/minor numbers are properties of the device, not it's table (and dm
> > devices can't have partitions, so the minor count will always be 1). I
> > don't see a reason to store and occasinally log this information twice,
> > if there is an active and incative table, and it forces extra
> > coordination between the dm_ima_measure_on_* functions.
> >
> > I'm wondering it we are stuck with the current events and format, now
> > that this has been released? Or could we bump the version, and change
> > what events we measure, and how we format the output?
> >
> > Benjamin Marzinski (10):
> > dm-ima: remove dm_ima_reset_data()
> > dm-ima: remove broken last_target_measured logic
> > dm-ima: Remove status_flags from dm_ima_measure_on_table_load()
> > dm-ima: don't copy the active table to the inactive table
> > dm-ima: Fix UAF errors and measuring incorrect context
> > dm-ima: remove new_map from dm_ima_measure_on_device_clear
> > dm-ima: Fix issues with dm_ima_measure_on_device_rename
> > dm-ima: Handle race between rename and table swap
> > dm-ima: Fail more gracefully in dm_ima_measure_on_*
> > dm-ima: use active table's size if available
> >
> > drivers/md/dm-ima.c | 506 +++++++++++++++++++-----------------------
> > drivers/md/dm-ima.h | 67 ++++--
> > drivers/md/dm-ioctl.c | 146 +++++++++++-
> > drivers/md/dm.c | 2 +-
> > 4 files changed, 421 insertions(+), 300 deletions(-)
>
> Pretty extensive changes needed here all things considered.
>
> SO I'm aware, who is using dm-ima? I see that Tushar Sugandhi is no
> longer at Microsoft and so he isn't cc'd on these changes. I can
> infer from Cc some potential users, but I just want to make sure this
> code isn't just technical debt that we're having to carry in DM now?
I don't actually know if anyone is. The issue is that the Use After Free
crashes can happen as long as CONFIG_IMA is set, regardless of whether
or not you have any IMA policy set.
If we don't need to care, we could just serialize the
dm_ima_measure_on_* functions to keep them from having concurrent access
to shared memory, and let them keep reporting bogus data if there are
races (or simply unfortunate orderings. load then rename then resume
currently forgets the rename, even without a race) That's a much smaller
change, and if they're currently good enough for any users, it won't
make them any worse.
-Ben
>
> Thanks,
> Mike
^ permalink raw reply
* Re: [RFC PATCH 00/10] Fix dm-ima bugs
From: Mike Snitzer @ 2026-04-14 17:12 UTC (permalink / raw)
To: Benjamin Marzinski
Cc: Mikulas Patocka, dm-devel, linux-integrity, Mimi Zohar,
Roberto Sassu, Dmitry Kasatkin
In-Reply-To: <20260414002244.1917447-1-bmarzins@redhat.com>
On Mon, Apr 13, 2026 at 08:22:34PM -0400, Benjamin Marzinski wrote:
> The dm-ima code does not guarantee that the dm_ima_measure_on_*
> functions will not be called at the same time. Since they modify and
> free shared memory, this can lead to Use-After-Free errors or garbage
> measurements. Further, they don't make sure that the state they measure
> corresponds to the actual device state. For instance if table_load()
> runs at the same time as do_resume() on a table swap,
> dm_ima_measure_on_device_resume() can end up thinking the wrong table is
> active. Or a concurrent dm_hash_rename() and a table swap, can end up
> with a the new active table still using the old name. This patchset
> makes sure the the dm-ima function are serialized and report the correct
> device state.
>
> However, the code is still messier that in could be. This is because
> it duplicates the current measurement events and format. I would really
> like to know if that is necessary. Specifically, it currently measures
> the following dm device and table actions:
>
> load
> clear
> rename
> resume
> remove
>
> I don't see the benefit of reporting changes to the inactive table, or
> resumes where the device does not change state. From the user's point of
> view, the device is still the same after these events. At the same
> time, it doesn't measure device creates if no table was loaded, so you
> can have situations where the the first measurement for a device is a
> rename or a remove. A more sensible set of actions to measure would be:
>
> create
> table_swap
> rename
> remove
>
> Also, the measurement format doesn't map well to how dm device's are
> actually set up, in a way that makes it harder for the code and records
> extraneous information. First, like I mentioned before, I don't see the
> benefit of measuring the inactive table. Second, the name, uuid, and
> major/minor numbers are properties of the device, not it's table (and dm
> devices can't have partitions, so the minor count will always be 1). I
> don't see a reason to store and occasinally log this information twice,
> if there is an active and incative table, and it forces extra
> coordination between the dm_ima_measure_on_* functions.
>
> I'm wondering it we are stuck with the current events and format, now
> that this has been released? Or could we bump the version, and change
> what events we measure, and how we format the output?
>
> Benjamin Marzinski (10):
> dm-ima: remove dm_ima_reset_data()
> dm-ima: remove broken last_target_measured logic
> dm-ima: Remove status_flags from dm_ima_measure_on_table_load()
> dm-ima: don't copy the active table to the inactive table
> dm-ima: Fix UAF errors and measuring incorrect context
> dm-ima: remove new_map from dm_ima_measure_on_device_clear
> dm-ima: Fix issues with dm_ima_measure_on_device_rename
> dm-ima: Handle race between rename and table swap
> dm-ima: Fail more gracefully in dm_ima_measure_on_*
> dm-ima: use active table's size if available
>
> drivers/md/dm-ima.c | 506 +++++++++++++++++++-----------------------
> drivers/md/dm-ima.h | 67 ++++--
> drivers/md/dm-ioctl.c | 146 +++++++++++-
> drivers/md/dm.c | 2 +-
> 4 files changed, 421 insertions(+), 300 deletions(-)
Pretty extensive changes needed here all things considered.
SO I'm aware, who is using dm-ima? I see that Tushar Sugandhi is no
longer at Microsoft and so he isn't cc'd on these changes. I can
infer from Cc some potential users, but I just want to make sure this
code isn't just technical debt that we're having to carry in DM now?
Thanks,
Mike
^ permalink raw reply
* [PATCH 10/10] dm-ima: use active table's size if available
From: Benjamin Marzinski @ 2026-04-14 0:22 UTC (permalink / raw)
To: Mikulas Patocka, Mike Snitzer
Cc: dm-devel, linux-integrity, Mimi Zohar, Roberto Sassu,
Dmitry Kasatkin
In-Reply-To: <20260414002244.1917447-1-bmarzins@redhat.com>
It is possible that the dm_ima_measure_on_* functions run at the same
time as a table is getting swapped, but before the md->ima.active_table
is updated by dm_ima_measure_on_device_resume(). Instead of using the
current device size, use the size of the active table that is being
measured (assuming there is one), so the information is consistent.
Also, don't allocate a separate string to hold the capactiy. Just
print it directly to the measurement buffer.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
drivers/md/dm-ima.c | 79 +++++++++++----------------------------------
drivers/md/dm-ima.h | 1 +
2 files changed, 20 insertions(+), 60 deletions(-)
diff --git a/drivers/md/dm-ima.c b/drivers/md/dm-ima.c
index 45038bd65f7b..ca6a33a0275e 100644
--- a/drivers/md/dm-ima.c
+++ b/drivers/md/dm-ima.c
@@ -151,22 +151,10 @@ static void dm_ima_measure_data(const char *event_name, const void *buf, size_t
memalloc_noio_restore(noio_flag);
}
-/*
- * Internal function to allocate and copy current device capacity for IMA measurements.
- */
-static int dm_ima_alloc_and_copy_capacity_str(struct mapped_device *md, char **capacity_str,
- bool noio)
+static sector_t dm_ima_capacity(struct mapped_device *md)
{
- sector_t capacity;
-
- capacity = get_capacity(md->disk);
-
- *capacity_str = dm_ima_alloc(DM_IMA_DEVICE_CAPACITY_BUF_LEN, noio);
- if (!(*capacity_str))
- return -ENOMEM;
-
- return scnprintf(*capacity_str, DM_IMA_DEVICE_BUF_LEN, "current_device_capacity=%llu;",
- capacity);
+ return (md->ima.active_table.device_metadata) ?
+ md->ima.active_table.capacity : get_capacity(md->disk);
}
/*
@@ -309,6 +297,7 @@ void dm_ima_measure_on_table_load(struct dm_table *table,
table->md->ima.inactive_table.hash = digest_buf;
table->md->ima.inactive_table.hash_len = strlen(digest_buf);
table->md->ima.inactive_table.num_targets = num_targets;
+ table->md->ima.inactive_table.capacity = dm_table_get_size(table);
kfree(table->md->ima.inactive_table.device_metadata);
@@ -335,13 +324,12 @@ void dm_ima_measure_on_table_load(struct dm_table *table,
void dm_ima_measure_on_device_resume(struct mapped_device *md, bool swap,
struct dm_ima_context *context)
{
- char *device_table_data = NULL, *capacity_str = NULL;
+ char *device_table_data = NULL;
char active[] = "active_table_hash=";
unsigned int active_len = strlen(active);
unsigned int l = 0;
bool noio = true;
bool nodata = true;
- int capacity_len;
if (unlikely(!context))
return;
@@ -375,10 +363,6 @@ void dm_ima_measure_on_device_resume(struct mapped_device *md, bool swap,
if (!device_table_data)
goto error;
- capacity_len = dm_ima_alloc_and_copy_capacity_str(md, &capacity_str, noio);
- if (capacity_len < 0)
- goto error;
-
memcpy(device_table_data + l, DM_IMA_VERSION_STR, strlen(DM_IMA_VERSION_STR));
l += strlen(DM_IMA_VERSION_STR);
@@ -411,14 +395,12 @@ void dm_ima_measure_on_device_resume(struct mapped_device *md, bool swap,
DM_IMA_VERSION_STR, context->dev_name,
context->dev_uuid);
}
-
- memcpy(device_table_data + l, capacity_str, capacity_len);
- l += capacity_len;
+ l += scnprintf(device_table_data + l, DM_IMA_DEVICE_BUF_LEN - l,
+ "current_device_capacity=%llu;", dm_ima_capacity(md));
dm_ima_measure_data("dm_device_resume", device_table_data, l, noio);
error:
- kfree(capacity_str);
kfree(device_table_data);
smp_mb__before_atomic();
@@ -433,21 +415,18 @@ void dm_ima_measure_on_device_remove(struct mapped_device *md, bool remove_all,
struct dm_ima_context *context,
unsigned int idx)
{
- char *device_table_data, *capacity_str = NULL;
+ char *device_table_data;
char active_table_str[] = "active_table_hash=";
char inactive_table_str[] = "inactive_table_hash=";
char device_active_str[] = "device_active_metadata=";
char device_inactive_str[] = "device_inactive_metadata=";
- char remove_all_str[] = "remove_all=";
unsigned int active_table_len = strlen(active_table_str);
unsigned int inactive_table_len = strlen(inactive_table_str);
unsigned int device_active_len = strlen(device_active_str);
unsigned int device_inactive_len = strlen(device_inactive_str);
- unsigned int remove_all_len = strlen(remove_all_str);
unsigned int l = 0;
bool noio = true;
bool nodata = true;
- int capacity_len;
wait_event(md->ima.ima_wq,
((unsigned int)(atomic_read(&md->ima.measure_idx)) == idx));
@@ -460,12 +439,6 @@ void dm_ima_measure_on_device_remove(struct mapped_device *md, bool remove_all,
if (!device_table_data)
goto exit;
- capacity_len = dm_ima_alloc_and_copy_capacity_str(md, &capacity_str, noio);
- if (capacity_len < 0) {
- kfree(device_table_data);
- goto exit;
- }
-
memcpy(device_table_data + l, DM_IMA_VERSION_STR, strlen(DM_IMA_VERSION_STR));
l += strlen(DM_IMA_VERSION_STR);
@@ -531,18 +504,13 @@ void dm_ima_measure_on_device_remove(struct mapped_device *md, bool remove_all,
context->dev_uuid);
}
- memcpy(device_table_data + l, remove_all_str, remove_all_len);
- l += remove_all_len;
- memcpy(device_table_data + l, remove_all ? "y;" : "n;", 2);
- l += 2;
-
- memcpy(device_table_data + l, capacity_str, capacity_len);
- l += capacity_len;
+ l += scnprintf(device_table_data + l, (DM_IMA_DEVICE_BUF_LEN * 2) - l,
+ "remove_all=%c;current_device_capacity=%llu;",
+ remove_all ? 'y' : 'n', dm_ima_capacity(md));
dm_ima_measure_data("dm_device_remove", device_table_data, l, noio);
kfree(device_table_data);
- kfree(capacity_str);
exit:
kfree(md->ima.active_table.device_metadata);
kfree(md->ima.inactive_table.device_metadata);
@@ -565,12 +533,11 @@ void dm_ima_measure_on_table_clear(struct mapped_device *md,
struct dm_ima_context *context)
{
unsigned int l = 0;
- char *device_table_data = NULL, *capacity_str = NULL;
+ char *device_table_data = NULL;
char inactive_str[] = "inactive_table_hash=";
unsigned int inactive_len = strlen(inactive_str);
bool noio = true;
bool nodata = true;
- int capacity_len;
if (unlikely(!context))
return;
@@ -584,10 +551,6 @@ void dm_ima_measure_on_table_clear(struct mapped_device *md,
if (!device_table_data)
goto error;
- capacity_len = dm_ima_alloc_and_copy_capacity_str(md, &capacity_str, noio);
- if (capacity_len < 0)
- goto error;
-
memcpy(device_table_data + l, DM_IMA_VERSION_STR, strlen(DM_IMA_VERSION_STR));
l += strlen(DM_IMA_VERSION_STR);
@@ -619,8 +582,8 @@ void dm_ima_measure_on_table_clear(struct mapped_device *md,
context->dev_uuid);
}
- memcpy(device_table_data + l, capacity_str, capacity_len);
- l += capacity_len;
+ l += scnprintf(device_table_data + l, DM_IMA_DEVICE_BUF_LEN - l,
+ "current_device_capacity=%llu;", dm_ima_capacity(md));
dm_ima_measure_data("dm_table_clear", device_table_data, l, noio);
@@ -629,7 +592,6 @@ void dm_ima_measure_on_table_clear(struct mapped_device *md,
kfree(md->ima.inactive_table.device_metadata);
memset(&md->ima.inactive_table, 0, sizeof(md->ima.inactive_table));
- kfree(capacity_str);
kfree(device_table_data);
smp_mb__before_atomic();
@@ -644,7 +606,7 @@ void dm_ima_measure_on_device_rename(struct mapped_device *md,
struct dm_ima_context *context)
{
char *old_device_data = NULL;
- char *combined_device_data = NULL, *capacity_str = NULL;
+ char *combined_device_data = NULL;
bool noio = true;
int len;
struct dm_ima_device_table_metadata *table;
@@ -663,9 +625,6 @@ void dm_ima_measure_on_device_rename(struct mapped_device *md,
if (!combined_device_data)
goto exit;
- if (dm_ima_alloc_and_copy_capacity_str(md, &capacity_str, noio) < 0)
- goto exit;
-
if (md->ima.active_table.device_metadata)
old_device_data = md->ima.active_table.device_metadata;
else if (md->ima.inactive_table.device_metadata)
@@ -673,14 +632,14 @@ void dm_ima_measure_on_device_rename(struct mapped_device *md,
else
old_device_data = "table_rename=no_data;";
len = scnprintf(combined_device_data, DM_IMA_DEVICE_BUF_LEN * 2,
- "%s%snew_name=%s,new_uuid=%s;%s", DM_IMA_VERSION_STR, old_device_data,
- context->dev_name, context->dev_uuid, capacity_str);
+ "%s%snew_name=%s,new_uuid=%s;current_device_capacity=%llu;",
+ DM_IMA_VERSION_STR, old_device_data, context->dev_name,
+ context->dev_uuid, dm_ima_capacity(md));
dm_ima_measure_data("dm_device_rename", combined_device_data, len, noio);
-exit:
- kfree(capacity_str);
kfree(combined_device_data);
+exit:
if (md->ima.active_table.device_metadata) {
table = &md->ima.active_table;
dm_ima_copy_device_data(md, table->device_metadata, context,
diff --git a/drivers/md/dm-ima.h b/drivers/md/dm-ima.h
index 2f2ac69042f2..d8b2438f1571 100644
--- a/drivers/md/dm-ima.h
+++ b/drivers/md/dm-ima.h
@@ -41,6 +41,7 @@ struct dm_ima_device_table_metadata {
char *device_metadata;
unsigned int device_metadata_len;
unsigned int num_targets;
+ sector_t capacity;
/*
* Contains the sha256 hashes of the IMA measurements of the target
--
2.53.0
^ permalink raw reply related
* [PATCH 09/10] dm-ima: Fail more gracefully in dm_ima_measure_on_*
From: Benjamin Marzinski @ 2026-04-14 0:22 UTC (permalink / raw)
To: Mikulas Patocka, Mike Snitzer
Cc: dm-devel, linux-integrity, Mimi Zohar, Roberto Sassu,
Dmitry Kasatkin
In-Reply-To: <20260414002244.1917447-1-bmarzins@redhat.com>
In all the dm_ima_measure_on_* functions besides
dm_ima_measure_on_table_load(), even if measuring the event fails, it's
still possible to update dm->ima, so that it continues to correctly
track the device state. This means that one measurement failure won't
cause future measurements to record the wrong data.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
drivers/md/dm-ima.c | 38 +++++++++++++++++++-------------------
1 file changed, 19 insertions(+), 19 deletions(-)
diff --git a/drivers/md/dm-ima.c b/drivers/md/dm-ima.c
index 4631dc2a6d4d..45038bd65f7b 100644
--- a/drivers/md/dm-ima.c
+++ b/drivers/md/dm-ima.c
@@ -351,17 +351,6 @@ void dm_ima_measure_on_device_resume(struct mapped_device *md, bool swap,
context->update_idx));
smp_mb();
- device_table_data = dm_ima_alloc(DM_IMA_DEVICE_BUF_LEN, noio);
- if (!device_table_data)
- goto error;
-
- capacity_len = dm_ima_alloc_and_copy_capacity_str(md, &capacity_str, noio);
- if (capacity_len < 0)
- goto error;
-
- memcpy(device_table_data + l, DM_IMA_VERSION_STR, strlen(DM_IMA_VERSION_STR));
- l += strlen(DM_IMA_VERSION_STR);
-
if (swap) {
kfree(md->ima.active_table.hash);
kfree(md->ima.active_table.device_metadata);
@@ -382,6 +371,17 @@ void dm_ima_measure_on_device_resume(struct mapped_device *md, bool swap,
}
}
+ device_table_data = dm_ima_alloc(DM_IMA_DEVICE_BUF_LEN, noio);
+ if (!device_table_data)
+ goto error;
+
+ capacity_len = dm_ima_alloc_and_copy_capacity_str(md, &capacity_str, noio);
+ if (capacity_len < 0)
+ goto error;
+
+ memcpy(device_table_data + l, DM_IMA_VERSION_STR, strlen(DM_IMA_VERSION_STR));
+ l += strlen(DM_IMA_VERSION_STR);
+
if (md->ima.active_table.device_metadata) {
memcpy(device_table_data + l, md->ima.active_table.device_metadata,
md->ima.active_table.device_metadata_len);
@@ -624,11 +624,11 @@ void dm_ima_measure_on_table_clear(struct mapped_device *md,
dm_ima_measure_data("dm_table_clear", device_table_data, l, noio);
+error:
kfree(md->ima.inactive_table.hash);
kfree(md->ima.inactive_table.device_metadata);
memset(&md->ima.inactive_table, 0, sizeof(md->ima.inactive_table));
-error:
kfree(capacity_str);
kfree(device_table_data);
@@ -657,6 +657,8 @@ void dm_ima_measure_on_device_rename(struct mapped_device *md,
context->update_idx));
smp_mb();
+ fix_context_strings(context);
+
combined_device_data = dm_ima_alloc(DM_IMA_DEVICE_BUF_LEN * 2, noio);
if (!combined_device_data)
goto exit;
@@ -670,11 +672,15 @@ void dm_ima_measure_on_device_rename(struct mapped_device *md,
old_device_data = md->ima.inactive_table.device_metadata;
else
old_device_data = "table_rename=no_data;";
- fix_context_strings(context);
len = scnprintf(combined_device_data, DM_IMA_DEVICE_BUF_LEN * 2,
"%s%snew_name=%s,new_uuid=%s;%s", DM_IMA_VERSION_STR, old_device_data,
context->dev_name, context->dev_uuid, capacity_str);
+ dm_ima_measure_data("dm_device_rename", combined_device_data, len, noio);
+exit:
+ kfree(capacity_str);
+ kfree(combined_device_data);
+
if (md->ima.active_table.device_metadata) {
table = &md->ima.active_table;
dm_ima_copy_device_data(md, table->device_metadata, context,
@@ -689,12 +695,6 @@ void dm_ima_measure_on_device_rename(struct mapped_device *md,
table->device_metadata_len = strlen(table->device_metadata);
}
- dm_ima_measure_data("dm_device_rename", combined_device_data, len, noio);
-
-exit:
- kfree(capacity_str);
- kfree(combined_device_data);
-
smp_mb__before_atomic();
atomic_inc(&md->ima.measure_idx);
wake_up_all(&md->ima.ima_wq);
--
2.53.0
^ permalink raw reply related
* [PATCH 04/10] dm-ima: don't copy the active table to the inactive table
From: Benjamin Marzinski @ 2026-04-14 0:22 UTC (permalink / raw)
To: Mikulas Patocka, Mike Snitzer
Cc: dm-devel, linux-integrity, Mimi Zohar, Roberto Sassu,
Dmitry Kasatkin
In-Reply-To: <20260414002244.1917447-1-bmarzins@redhat.com>
If an inactive table was cleared, dm_ima_measure_on_table_clear() was
copying the ima.active_table to ima.inactive_table. This is not what
device-mapper does, and it makes the IMA measurements show an inactive
table when there isn't one. Also, once this is removed, the code no
longer needs to keep checking if the active and the inactive table point
to the same memory.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
drivers/md/dm-ima.c | 64 +++++++--------------------------------------
1 file changed, 10 insertions(+), 54 deletions(-)
diff --git a/drivers/md/dm-ima.c b/drivers/md/dm-ima.c
index 8b84b676cad4..c141068bc6b4 100644
--- a/drivers/md/dm-ima.c
+++ b/drivers/md/dm-ima.c
@@ -281,17 +281,13 @@ void dm_ima_measure_on_table_load(struct dm_table *table)
if (!digest_buf)
goto error;
- if (table->md->ima.active_table.hash != table->md->ima.inactive_table.hash)
- kfree(table->md->ima.inactive_table.hash);
-
+ kfree(table->md->ima.inactive_table.hash);
table->md->ima.inactive_table.hash = digest_buf;
table->md->ima.inactive_table.hash_len = strlen(digest_buf);
table->md->ima.inactive_table.num_targets = num_targets;
- if (table->md->ima.active_table.device_metadata !=
- table->md->ima.inactive_table.device_metadata)
- kfree(table->md->ima.inactive_table.device_metadata);
+ kfree(table->md->ima.inactive_table.device_metadata);
table->md->ima.inactive_table.device_metadata = device_data_buf;
table->md->ima.inactive_table.device_metadata_len = device_data_buf_len;
@@ -330,19 +326,9 @@ void dm_ima_measure_on_device_resume(struct mapped_device *md, bool swap)
l += strlen(DM_IMA_VERSION_STR);
if (swap) {
- if (md->ima.active_table.hash != md->ima.inactive_table.hash)
- kfree(md->ima.active_table.hash);
-
- md->ima.active_table.hash = NULL;
- md->ima.active_table.hash_len = 0;
-
- if (md->ima.active_table.device_metadata !=
- md->ima.inactive_table.device_metadata)
- kfree(md->ima.active_table.device_metadata);
-
- md->ima.active_table.device_metadata = NULL;
- md->ima.active_table.device_metadata_len = 0;
- md->ima.active_table.num_targets = 0;
+ kfree(md->ima.active_table.hash);
+ kfree(md->ima.active_table.device_metadata);
+ memset(&md->ima.active_table, 0, sizeof(md->ima.active_table));
if (md->ima.inactive_table.hash) {
md->ima.active_table.hash = md->ima.inactive_table.hash;
@@ -518,15 +504,10 @@ void dm_ima_measure_on_device_remove(struct mapped_device *md, bool remove_all)
kfree(capacity_str);
exit:
kfree(md->ima.active_table.device_metadata);
-
- if (md->ima.active_table.device_metadata !=
- md->ima.inactive_table.device_metadata)
- kfree(md->ima.inactive_table.device_metadata);
+ kfree(md->ima.inactive_table.device_metadata);
kfree(md->ima.active_table.hash);
-
- if (md->ima.active_table.hash != md->ima.inactive_table.hash)
- kfree(md->ima.inactive_table.hash);
+ kfree(md->ima.inactive_table.hash);
memset(&md->ima.active_table, 0, sizeof(md->ima.active_table));
memset(&md->ima.inactive_table, 0, sizeof(md->ima.inactive_table));
@@ -594,34 +575,9 @@ void dm_ima_measure_on_table_clear(struct mapped_device *md, bool new_map)
dm_ima_measure_data("dm_table_clear", device_table_data, l, noio);
if (new_map) {
- if (md->ima.inactive_table.hash &&
- md->ima.inactive_table.hash != md->ima.active_table.hash)
- kfree(md->ima.inactive_table.hash);
-
- md->ima.inactive_table.hash = NULL;
- md->ima.inactive_table.hash_len = 0;
-
- if (md->ima.inactive_table.device_metadata &&
- md->ima.inactive_table.device_metadata != md->ima.active_table.device_metadata)
- kfree(md->ima.inactive_table.device_metadata);
-
- md->ima.inactive_table.device_metadata = NULL;
- md->ima.inactive_table.device_metadata_len = 0;
- md->ima.inactive_table.num_targets = 0;
-
- if (md->ima.active_table.hash) {
- md->ima.inactive_table.hash = md->ima.active_table.hash;
- md->ima.inactive_table.hash_len = md->ima.active_table.hash_len;
- }
-
- if (md->ima.active_table.device_metadata) {
- md->ima.inactive_table.device_metadata =
- md->ima.active_table.device_metadata;
- md->ima.inactive_table.device_metadata_len =
- md->ima.active_table.device_metadata_len;
- md->ima.inactive_table.num_targets =
- md->ima.active_table.num_targets;
- }
+ kfree(md->ima.inactive_table.hash);
+ kfree(md->ima.inactive_table.device_metadata);
+ memset(&md->ima.inactive_table, 0, sizeof(md->ima.inactive_table));
}
kfree(dev_name);
--
2.53.0
^ permalink raw reply related
* [PATCH 07/10] dm-ima: Fix issues with dm_ima_measure_on_device_rename
From: Benjamin Marzinski @ 2026-04-14 0:22 UTC (permalink / raw)
To: Mikulas Patocka, Mike Snitzer
Cc: dm-devel, linux-integrity, Mimi Zohar, Roberto Sassu,
Dmitry Kasatkin
In-Reply-To: <20260414002244.1917447-1-bmarzins@redhat.com>
dm_ima_measure_on_device_rename() can be called on a device before it
ever loads a table, so it needs to handle the case where there is no
table metadata. Also, it was only updating the table_metadata on the
active table. If there was an inactive table when the device was
and that table was later swapped in as the active table, it would
still have the old name. dm_ima_measure_on_device_rename() was also
needlessly allocating new memory for the updated table metadata, instead
of just reusing the existing memory.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
drivers/md/dm-ima.c | 69 ++++++++++++++++++++++++---------------------
1 file changed, 37 insertions(+), 32 deletions(-)
diff --git a/drivers/md/dm-ima.c b/drivers/md/dm-ima.c
index 317f6d7e0e5e..5c6f3f8761a8 100644
--- a/drivers/md/dm-ima.c
+++ b/drivers/md/dm-ima.c
@@ -119,22 +119,18 @@ void dm_ima_context_table_op(struct mapped_device *md,
}
/*
- * Internal function to allocate and copy device data for IMA measurements.
+ * Internal function to copy device data for IMA measurements.
*/
-static int dm_ima_alloc_and_copy_device_data(struct mapped_device *md, char **device_data,
- struct dm_ima_context *context,
- unsigned int num_targets, bool noio)
+static void dm_ima_copy_device_data(struct mapped_device *md, char *device_data,
+ struct dm_ima_context *context,
+ unsigned int num_targets)
{
- *device_data = dm_ima_alloc(DM_IMA_DEVICE_BUF_LEN, noio);
- if (!(*device_data))
- return -ENOMEM;
-
- scnprintf(*device_data, DM_IMA_DEVICE_BUF_LEN,
+ memset(device_data, 0, DM_IMA_DEVICE_BUF_LEN);
+ scnprintf(device_data, DM_IMA_DEVICE_BUF_LEN,
"name=%s,uuid=%s,major=%d,minor=%d,minor_count=%d,num_targets=%u;",
context->dev_name, context->dev_uuid, md->disk->major,
md->disk->first_minor, md->disk->minors, num_targets);
- return 0;
}
/*
@@ -212,11 +208,14 @@ void dm_ima_measure_on_table_load(struct dm_table *table,
num_targets = table->num_targets;
- fix_context_strings(context);
- if (dm_ima_alloc_and_copy_device_data(table->md, &device_data_buf,
- context, num_targets, noio))
+ device_data_buf = dm_ima_alloc(DM_IMA_DEVICE_BUF_LEN, noio);
+ if (!device_data_buf)
goto error;
+ fix_context_strings(context);
+ dm_ima_copy_device_data(table->md, device_data_buf, context,
+ num_targets);
+
sha256_init(&hash_ctx);
memcpy(ima_buf + l, DM_IMA_VERSION_STR, strlen(DM_IMA_VERSION_STR));
@@ -631,10 +630,11 @@ void dm_ima_measure_on_table_clear(struct mapped_device *md,
void dm_ima_measure_on_device_rename(struct mapped_device *md,
struct dm_ima_context *context)
{
- char *old_device_data = NULL, *new_device_data = NULL;
+ char *old_device_data = NULL;
char *combined_device_data = NULL, *capacity_str = NULL;
bool noio = true;
int len;
+ struct dm_ima_device_table_metadata *table;
if (unlikely(!context))
return;
@@ -644,38 +644,43 @@ void dm_ima_measure_on_device_rename(struct mapped_device *md,
context->update_idx));
smp_mb();
- fix_context_strings(context);
- if (dm_ima_alloc_and_copy_device_data(md, &new_device_data, context,
- md->ima.active_table.num_targets,
- noio))
- goto error;
-
combined_device_data = dm_ima_alloc(DM_IMA_DEVICE_BUF_LEN * 2, noio);
if (!combined_device_data)
- goto error;
+ goto exit;
if (dm_ima_alloc_and_copy_capacity_str(md, &capacity_str, noio) < 0)
- goto error;
-
- old_device_data = md->ima.active_table.device_metadata;
-
- md->ima.active_table.device_metadata = new_device_data;
- md->ima.active_table.device_metadata_len = strlen(new_device_data);
+ goto exit;
+ if (md->ima.active_table.device_metadata)
+ old_device_data = md->ima.active_table.device_metadata;
+ else if (md->ima.inactive_table.device_metadata)
+ old_device_data = md->ima.inactive_table.device_metadata;
+ else
+ old_device_data = "table_rename=no_data;";
+ fix_context_strings(context);
len = scnprintf(combined_device_data, DM_IMA_DEVICE_BUF_LEN * 2,
"%s%snew_name=%s,new_uuid=%s;%s", DM_IMA_VERSION_STR, old_device_data,
context->dev_name, context->dev_uuid, capacity_str);
- dm_ima_measure_data("dm_device_rename", combined_device_data, len, noio);
+ if (md->ima.active_table.device_metadata) {
+ table = &md->ima.active_table;
+ dm_ima_copy_device_data(md, table->device_metadata, context,
+ table->num_targets);
+ table->device_metadata_len = strlen(table->device_metadata);
+ }
- goto exit;
+ if (md->ima.inactive_table.device_metadata) {
+ table = &md->ima.inactive_table;
+ dm_ima_copy_device_data(md, table->device_metadata, context,
+ table->num_targets);
+ table->device_metadata_len = strlen(table->device_metadata);
+ }
+
+ dm_ima_measure_data("dm_device_rename", combined_device_data, len, noio);
-error:
- kfree(new_device_data);
exit:
kfree(capacity_str);
kfree(combined_device_data);
- kfree(old_device_data);
smp_mb__before_atomic();
atomic_inc(&md->ima.measure_idx);
--
2.53.0
^ permalink raw reply related
* [RFC PATCH 00/10] Fix dm-ima bugs
From: Benjamin Marzinski @ 2026-04-14 0:22 UTC (permalink / raw)
To: Mikulas Patocka, Mike Snitzer
Cc: dm-devel, linux-integrity, Mimi Zohar, Roberto Sassu,
Dmitry Kasatkin
The dm-ima code does not guarantee that the dm_ima_measure_on_*
functions will not be called at the same time. Since they modify and
free shared memory, this can lead to Use-After-Free errors or garbage
measurements. Further, they don't make sure that the state they measure
corresponds to the actual device state. For instance if table_load()
runs at the same time as do_resume() on a table swap,
dm_ima_measure_on_device_resume() can end up thinking the wrong table is
active. Or a concurrent dm_hash_rename() and a table swap, can end up
with a the new active table still using the old name. This patchset
makes sure the the dm-ima function are serialized and report the correct
device state.
However, the code is still messier that in could be. This is because
it duplicates the current measurement events and format. I would really
like to know if that is necessary. Specifically, it currently measures
the following dm device and table actions:
load
clear
rename
resume
remove
I don't see the benefit of reporting changes to the inactive table, or
resumes where the device does not change state. From the user's point of
view, the device is still the same after these events. At the same
time, it doesn't measure device creates if no table was loaded, so you
can have situations where the the first measurement for a device is a
rename or a remove. A more sensible set of actions to measure would be:
create
table_swap
rename
remove
Also, the measurement format doesn't map well to how dm device's are
actually set up, in a way that makes it harder for the code and records
extraneous information. First, like I mentioned before, I don't see the
benefit of measuring the inactive table. Second, the name, uuid, and
major/minor numbers are properties of the device, not it's table (and dm
devices can't have partitions, so the minor count will always be 1). I
don't see a reason to store and occasinally log this information twice,
if there is an active and incative table, and it forces extra
coordination between the dm_ima_measure_on_* functions.
I'm wondering it we are stuck with the current events and format, now
that this has been released? Or could we bump the version, and change
what events we measure, and how we format the output?
Benjamin Marzinski (10):
dm-ima: remove dm_ima_reset_data()
dm-ima: remove broken last_target_measured logic
dm-ima: Remove status_flags from dm_ima_measure_on_table_load()
dm-ima: don't copy the active table to the inactive table
dm-ima: Fix UAF errors and measuring incorrect context
dm-ima: remove new_map from dm_ima_measure_on_device_clear
dm-ima: Fix issues with dm_ima_measure_on_device_rename
dm-ima: Handle race between rename and table swap
dm-ima: Fail more gracefully in dm_ima_measure_on_*
dm-ima: use active table's size if available
drivers/md/dm-ima.c | 506 +++++++++++++++++++-----------------------
drivers/md/dm-ima.h | 67 ++++--
drivers/md/dm-ioctl.c | 146 +++++++++++-
drivers/md/dm.c | 2 +-
4 files changed, 421 insertions(+), 300 deletions(-)
--
2.53.0
^ permalink raw reply
* [PATCH 06/10] dm-ima: remove new_map from dm_ima_measure_on_device_clear
From: Benjamin Marzinski @ 2026-04-14 0:22 UTC (permalink / raw)
To: Mikulas Patocka, Mike Snitzer
Cc: dm-devel, linux-integrity, Mimi Zohar, Roberto Sassu,
Dmitry Kasatkin
In-Reply-To: <20260414002244.1917447-1-bmarzins@redhat.com>
Now that two processes can't modify md->ima in
dm_ima_measure_on_device_clear() at the same time, there's no need to
track if an inactive table was actually removed. We might as well
clean it up unconditionally, on the off chance that a previous
ima measurement failed and left md->ima.inactive_table behind.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
drivers/md/dm-ima.c | 10 ++++------
drivers/md/dm-ima.h | 3 +--
drivers/md/dm-ioctl.c | 4 +---
3 files changed, 6 insertions(+), 11 deletions(-)
diff --git a/drivers/md/dm-ima.c b/drivers/md/dm-ima.c
index e8fa049c6317..317f6d7e0e5e 100644
--- a/drivers/md/dm-ima.c
+++ b/drivers/md/dm-ima.c
@@ -549,7 +549,7 @@ void dm_ima_measure_on_device_remove(struct mapped_device *md, bool remove_all,
/*
* Measure ima data on table clear.
*/
-void dm_ima_measure_on_table_clear(struct mapped_device *md, bool new_map,
+void dm_ima_measure_on_table_clear(struct mapped_device *md,
struct dm_ima_context *context)
{
unsigned int l = 0;
@@ -612,11 +612,9 @@ void dm_ima_measure_on_table_clear(struct mapped_device *md, bool new_map,
dm_ima_measure_data("dm_table_clear", device_table_data, l, noio);
- if (new_map) {
- kfree(md->ima.inactive_table.hash);
- kfree(md->ima.inactive_table.device_metadata);
- memset(&md->ima.inactive_table, 0, sizeof(md->ima.inactive_table));
- }
+ kfree(md->ima.inactive_table.hash);
+ kfree(md->ima.inactive_table.device_metadata);
+ memset(&md->ima.inactive_table, 0, sizeof(md->ima.inactive_table));
error:
kfree(capacity_str);
diff --git a/drivers/md/dm-ima.h b/drivers/md/dm-ima.h
index 9e1b654867d9..2f2ac69042f2 100644
--- a/drivers/md/dm-ima.h
+++ b/drivers/md/dm-ima.h
@@ -82,7 +82,7 @@ void dm_ima_measure_on_device_resume(struct mapped_device *md, bool swap,
void dm_ima_measure_on_device_remove(struct mapped_device *md, bool remove_all,
struct dm_ima_context *context,
unsigned int idx);
-void dm_ima_measure_on_table_clear(struct mapped_device *md, bool new_map,
+void dm_ima_measure_on_table_clear(struct mapped_device *md,
struct dm_ima_context *context);
void dm_ima_measure_on_device_rename(struct mapped_device *md,
struct dm_ima_context *context);
@@ -107,7 +107,6 @@ static inline void dm_ima_measure_on_device_remove(struct mapped_device *md,
struct dm_ima_context *context,
unsigned int idx) {}
static inline void dm_ima_measure_on_table_clear(struct mapped_device *md,
- bool new_map,
struct dm_ima_context *context) {}
static inline void dm_ima_measure_on_device_rename(struct mapped_device *md,
struct dm_ima_context *context) {}
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index 16609882aa92..2288f3d58ce9 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -1737,7 +1737,6 @@ static int table_clear(struct file *filp, struct dm_ioctl *param, size_t param_s
struct hash_cell *hc;
struct mapped_device *md;
struct dm_table *old_map = NULL;
- bool has_new_map = false;
struct dm_ima_context *ima_context = NULL;
dm_ima_alloc_context(&ima_context, true);
@@ -1754,13 +1753,12 @@ static int table_clear(struct file *filp, struct dm_ioctl *param, size_t param_s
if (hc->new_map) {
old_map = hc->new_map;
hc->new_map = NULL;
- has_new_map = true;
}
dm_ima_init_context(hc, ima_context, false);
md = hc->md;
up_write(&_hash_lock);
- dm_ima_measure_on_table_clear(md, has_new_map, ima_context);
+ dm_ima_measure_on_table_clear(md, ima_context);
dm_ima_free_context(ima_context);
param->flags &= ~DM_INACTIVE_PRESENT_FLAG;
--
2.53.0
^ permalink raw reply related
* [PATCH 03/10] dm-ima: Remove status_flags from dm_ima_measure_on_table_load()
From: Benjamin Marzinski @ 2026-04-14 0:22 UTC (permalink / raw)
To: Mikulas Patocka, Mike Snitzer
Cc: dm-devel, linux-integrity, Mimi Zohar, Roberto Sassu,
Dmitry Kasatkin
In-Reply-To: <20260414002244.1917447-1-bmarzins@redhat.com>
There is no status flag that is is used for STATUSTYPE_IMA type
status() calls, and STATUSTYPE_IMA itself is not a valid
status flag.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
drivers/md/dm-ima.c | 4 ++--
drivers/md/dm-ima.h | 4 ++--
drivers/md/dm-ioctl.c | 2 +-
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/md/dm-ima.c b/drivers/md/dm-ima.c
index 209221fa8bc5..8b84b676cad4 100644
--- a/drivers/md/dm-ima.c
+++ b/drivers/md/dm-ima.c
@@ -162,7 +162,7 @@ static int dm_ima_alloc_and_copy_capacity_str(struct mapped_device *md, char **c
/*
* Build up the IMA data for each target, and finally measure.
*/
-void dm_ima_measure_on_table_load(struct dm_table *table, unsigned int status_flags)
+void dm_ima_measure_on_table_load(struct dm_table *table)
{
size_t device_data_buf_len, target_metadata_buf_len, target_data_buf_len, l = 0;
char *target_metadata_buf = NULL, *target_data_buf = NULL, *digest_buf = NULL;
@@ -217,7 +217,7 @@ void dm_ima_measure_on_table_load(struct dm_table *table, unsigned int status_fl
* Then retrieve the actual target data.
*/
if (ti->type->status)
- ti->type->status(ti, type, status_flags, target_data_buf,
+ ti->type->status(ti, type, 0, target_data_buf,
DM_IMA_TARGET_DATA_BUF_LEN);
else
target_data_buf[0] = '\0';
diff --git a/drivers/md/dm-ima.h b/drivers/md/dm-ima.h
index b0b166aa2283..c0548492bef0 100644
--- a/drivers/md/dm-ima.h
+++ b/drivers/md/dm-ima.h
@@ -54,7 +54,7 @@ struct dm_ima_measurements {
struct dm_ima_device_table_metadata inactive_table;
};
-void dm_ima_measure_on_table_load(struct dm_table *table, unsigned int status_flags);
+void dm_ima_measure_on_table_load(struct dm_table *table);
void dm_ima_measure_on_device_resume(struct mapped_device *md, bool swap);
void dm_ima_measure_on_device_remove(struct mapped_device *md, bool remove_all);
void dm_ima_measure_on_table_clear(struct mapped_device *md, bool new_map);
@@ -62,7 +62,7 @@ void dm_ima_measure_on_device_rename(struct mapped_device *md);
#else
-static inline void dm_ima_measure_on_table_load(struct dm_table *table, unsigned int status_flags) {}
+static inline void dm_ima_measure_on_table_load(struct dm_table *table) {}
static inline void dm_ima_measure_on_device_resume(struct mapped_device *md, bool swap) {}
static inline void dm_ima_measure_on_device_remove(struct mapped_device *md, bool remove_all) {}
static inline void dm_ima_measure_on_table_clear(struct mapped_device *md, bool new_map) {}
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index 405acc14d718..1a0dd4981d03 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -1548,7 +1548,7 @@ static int table_load(struct file *filp, struct dm_ioctl *param, size_t param_si
if (r)
goto err_unlock_md_type;
- dm_ima_measure_on_table_load(t, STATUSTYPE_IMA);
+ dm_ima_measure_on_table_load(t);
immutable_target_type = dm_get_immutable_target_type(md);
if (immutable_target_type &&
--
2.53.0
^ permalink raw reply related
* [PATCH 01/10] dm-ima: remove dm_ima_reset_data()
From: Benjamin Marzinski @ 2026-04-14 0:22 UTC (permalink / raw)
To: Mikulas Patocka, Mike Snitzer
Cc: dm-devel, linux-integrity, Mimi Zohar, Roberto Sassu,
Dmitry Kasatkin
In-Reply-To: <20260414002244.1917447-1-bmarzins@redhat.com>
There's no point in saving the string length of DM_IMA_VERSION_STR. It's
a constant, so the compiler will precompute it. dm_create() will already
zero out the rest of dm->ima.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
drivers/md/dm-ima.c | 32 ++++++++++++--------------------
drivers/md/dm-ima.h | 3 ---
drivers/md/dm.c | 2 --
3 files changed, 12 insertions(+), 25 deletions(-)
diff --git a/drivers/md/dm-ima.c b/drivers/md/dm-ima.c
index 9495ca035056..a639bb0fe6c3 100644
--- a/drivers/md/dm-ima.c
+++ b/drivers/md/dm-ima.c
@@ -159,15 +159,6 @@ static int dm_ima_alloc_and_copy_capacity_str(struct mapped_device *md, char **c
capacity);
}
-/*
- * Initialize/reset the dm ima related data structure variables.
- */
-void dm_ima_reset_data(struct mapped_device *md)
-{
- memset(&(md->ima), 0, sizeof(md->ima));
- md->ima.dm_version_str_len = strlen(DM_IMA_VERSION_STR);
-}
-
/*
* Build up the IMA data for each target, and finally measure.
*/
@@ -204,8 +195,8 @@ void dm_ima_measure_on_table_load(struct dm_table *table, unsigned int status_fl
sha256_init(&hash_ctx);
- memcpy(ima_buf + l, DM_IMA_VERSION_STR, table->md->ima.dm_version_str_len);
- l += table->md->ima.dm_version_str_len;
+ memcpy(ima_buf + l, DM_IMA_VERSION_STR, strlen(DM_IMA_VERSION_STR));
+ l += strlen(DM_IMA_VERSION_STR);
device_data_buf_len = strlen(device_data_buf);
memcpy(ima_buf + l, device_data_buf, device_data_buf_len);
@@ -260,8 +251,8 @@ void dm_ima_measure_on_table_load(struct dm_table *table, unsigned int status_fl
* prefix, so that multiple records from the same "dm_table_load" for
* a given device can be linked together.
*/
- memcpy(ima_buf + l, DM_IMA_VERSION_STR, table->md->ima.dm_version_str_len);
- l += table->md->ima.dm_version_str_len;
+ memcpy(ima_buf + l, DM_IMA_VERSION_STR, strlen(DM_IMA_VERSION_STR));
+ l += strlen(DM_IMA_VERSION_STR);
memcpy(ima_buf + l, device_data_buf, device_data_buf_len);
l += device_data_buf_len;
@@ -349,8 +340,8 @@ void dm_ima_measure_on_device_resume(struct mapped_device *md, bool swap)
if (capacity_len < 0)
goto error;
- memcpy(device_table_data + l, DM_IMA_VERSION_STR, md->ima.dm_version_str_len);
- l += md->ima.dm_version_str_len;
+ memcpy(device_table_data + l, DM_IMA_VERSION_STR, strlen(DM_IMA_VERSION_STR));
+ l += strlen(DM_IMA_VERSION_STR);
if (swap) {
if (md->ima.active_table.hash != md->ima.inactive_table.hash)
@@ -460,8 +451,8 @@ void dm_ima_measure_on_device_remove(struct mapped_device *md, bool remove_all)
goto exit;
}
- memcpy(device_table_data + l, DM_IMA_VERSION_STR, md->ima.dm_version_str_len);
- l += md->ima.dm_version_str_len;
+ memcpy(device_table_data + l, DM_IMA_VERSION_STR, strlen(DM_IMA_VERSION_STR));
+ l += strlen(DM_IMA_VERSION_STR);
if (md->ima.active_table.device_metadata) {
memcpy(device_table_data + l, device_active_str, device_active_len);
@@ -551,7 +542,8 @@ void dm_ima_measure_on_device_remove(struct mapped_device *md, bool remove_all)
if (md->ima.active_table.hash != md->ima.inactive_table.hash)
kfree(md->ima.inactive_table.hash);
- dm_ima_reset_data(md);
+ memset(&md->ima.active_table, 0, sizeof(md->ima.active_table));
+ memset(&md->ima.inactive_table, 0, sizeof(md->ima.inactive_table));
kfree(dev_name);
kfree(dev_uuid);
@@ -578,8 +570,8 @@ void dm_ima_measure_on_table_clear(struct mapped_device *md, bool new_map)
if (capacity_len < 0)
goto error1;
- memcpy(device_table_data + l, DM_IMA_VERSION_STR, md->ima.dm_version_str_len);
- l += md->ima.dm_version_str_len;
+ memcpy(device_table_data + l, DM_IMA_VERSION_STR, strlen(DM_IMA_VERSION_STR));
+ l += strlen(DM_IMA_VERSION_STR);
if (md->ima.inactive_table.device_metadata_len &&
md->ima.inactive_table.hash_len) {
diff --git a/drivers/md/dm-ima.h b/drivers/md/dm-ima.h
index a403deca6093..b0b166aa2283 100644
--- a/drivers/md/dm-ima.h
+++ b/drivers/md/dm-ima.h
@@ -52,10 +52,8 @@ struct dm_ima_device_table_metadata {
struct dm_ima_measurements {
struct dm_ima_device_table_metadata active_table;
struct dm_ima_device_table_metadata inactive_table;
- unsigned int dm_version_str_len;
};
-void dm_ima_reset_data(struct mapped_device *md);
void dm_ima_measure_on_table_load(struct dm_table *table, unsigned int status_flags);
void dm_ima_measure_on_device_resume(struct mapped_device *md, bool swap);
void dm_ima_measure_on_device_remove(struct mapped_device *md, bool remove_all);
@@ -64,7 +62,6 @@ void dm_ima_measure_on_device_rename(struct mapped_device *md);
#else
-static inline void dm_ima_reset_data(struct mapped_device *md) {}
static inline void dm_ima_measure_on_table_load(struct dm_table *table, unsigned int status_flags) {}
static inline void dm_ima_measure_on_device_resume(struct mapped_device *md, bool swap) {}
static inline void dm_ima_measure_on_device_remove(struct mapped_device *md, bool remove_all) {}
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index e178fe19973e..8b60c9804f5b 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -2546,8 +2546,6 @@ int dm_create(int minor, struct mapped_device **result)
if (!md)
return -ENXIO;
- dm_ima_reset_data(md);
-
*result = md;
return 0;
}
--
2.53.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox