* Re: [PATCH 1/2] ima_violations.sh: Wait for ima_mmap to exit
From: Cyril Hrubis @ 2026-04-30 9:03 UTC (permalink / raw)
To: Petr Vorel
Cc: ltp, Avinesh Kumar, Wei Gao, Mimi Zohar, linux-integrity,
Martin Doucha
In-Reply-To: <20260428161034.947614-1-pvorel@suse.cz>
Hi!
> test3()
> {
> + local pid
> +
> tst_res TINFO "verify open_writers using mmapped files"
>
> local search="open_writers"
> @@ -168,6 +170,7 @@ test3()
> echo 'testing testing' > $FILE
>
> ima_mmap -f $FILE &
> + pid=$!
> # wait for violations appear in logs
> tst_sleep 1s
>
> @@ -177,7 +180,10 @@ test3()
> validate $num_violations $count $search
>
> # wait for ima_mmap to exit, so we can umount
> - tst_sleep 2s
> + wait $pid
You can simplify this just by doing 'wait' that will wait for all
background jobs (we have only one here).
Either way:
Reviewed-by: Cyril Hrubis <chrubis@suse.cz>
> + if [ $? -ne 0 ]; then
> + tst_brk TBROK "failed to execute ima_mmap"
> + fi
> }
>
> test4()
> --
> 2.54.0
>
--
Cyril Hrubis
chrubis@suse.cz
^ permalink raw reply
* Re: [PATCH 2/2] ima_violations.sh: ima_mmap.c: Replace sleep with checkpoints
From: Cyril Hrubis @ 2026-04-30 9:16 UTC (permalink / raw)
To: Petr Vorel; +Cc: ltp, Avinesh Kumar, Wei Gao, Mimi Zohar, linux-integrity
In-Reply-To: <20260428161034.947614-2-pvorel@suse.cz>
Hi!
> Using checkpoints is a proper way in LTP new API [1] to avoid races and
> waste of time. It reduces 3 sec sleep in ima_mmap.c and 1 sec sleep in
> ima_violations.sh with just checkpoints.
>
> NOTE: tst_reinit() is really needed instead of .needs_checkpoints = 1
> as documented in Shell-Test-API.asciidoc.
>
> [1] https://people.kernel.org/metan/why-sleep-is-almost-never-acceptable-in-tests
>
> Fixes: 0e4cbf753f ("security/ima: Rewrite tests into new API + fixes")
> Suggested-by: Cyril Hrubis <chrubis@suse.cz>
> Signed-off-by: Petr Vorel <pvorel@suse.cz>
> ---
> testcases/kernel/security/integrity/ima/src/ima_mmap.c | 7 ++++---
> .../kernel/security/integrity/ima/tests/ima_violations.sh | 6 +++++-
> 2 files changed, 9 insertions(+), 4 deletions(-)
>
> diff --git a/testcases/kernel/security/integrity/ima/src/ima_mmap.c b/testcases/kernel/security/integrity/ima/src/ima_mmap.c
> index 8596809ef4..09b22fd4f4 100644
> --- a/testcases/kernel/security/integrity/ima/src/ima_mmap.c
> +++ b/testcases/kernel/security/integrity/ima/src/ima_mmap.c
> @@ -9,7 +9,6 @@
>
> #include "tst_test.h"
>
> -#define SLEEP_AFTER_CLOSE 3
> #define MMAPSIZE 1024
>
> static char *filename;
> @@ -35,8 +34,10 @@ static void run(void)
> file = SAFE_MMAP(NULL, MMAPSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
> SAFE_CLOSE(fd);
>
> - tst_res(TINFO, "sleep %ds", SLEEP_AFTER_CLOSE);
> - sleep(SLEEP_AFTER_CLOSE);
> + tst_reinit();
> + TST_CHECKPOINT_WAIT(0);
> + /* keep running until ima_violations.sh open and close file */
> + TST_CHECKPOINT_WAKE_AND_WAIT(0);
>
> tst_res(TPASS, "test completed");
> }
C helpers that call tst_reinit() should implement main(). These are not
complete tests, just helpers. The main problem is that if you add
tst_reinit() to a source that defines tst_test structure you are
initializing the test library for a second time, which overwrites the
some of the already initialized variables.
We probably want:
diff --git a/lib/tst_test.c b/lib/tst_test.c
index 26f6510a0..971a184f2 100644
--- a/lib/tst_test.c
+++ b/lib/tst_test.c
@@ -196,6 +196,9 @@ void tst_reinit(void)
size_t size = getpagesize();
int fd;
+ if (ipc)
+ tst_brk(TBROK, "Test library already initialized!");
+
if (!path)
tst_brk(TBROK, IPC_ENV_VAR" is not defined");
So that this kind of mistake is caught early.
--
Cyril Hrubis
chrubis@suse.cz
^ permalink raw reply related
* Re: [PATCH] ima: debugging late_initcall_sync measurements
From: Yeoreum Yun @ 2026-04-30 9:48 UTC (permalink / raw)
To: Mimi Zohar
Cc: Jonathan McDowell, linux-security-module, linux-kernel,
linux-integrity, linux-arm-kernel, kvmarm, paul, jmorris, serge,
roberto.sassu, dmitry.kasatkin, eric.snowberg, jarkko, jgg,
sudeep.holla, maz, oupton, joey.gouly, suzuki.poulose, yuzenghui,
catalin.marinas, will, noodles, sebastianene
In-Reply-To: <7734099f5e7fda5480bca016a9e6707983325fbd.camel@linux.ibm.com>
Hi Mimi,
Thanks to share the testing code and please see the below:
> With this "[RFC PATCH v3 0/4] Fix IMA + TPM initialisation ordering
> issue" patch set, how many records would be missing if IMA
> initialization is deferred to late_initcall_sync [1]?
>
> [1]https://lore.kernel.org/linux-integrity/cover.1777036497.git.noodles@meta.com/
> ---
> Jonathan, Yeoreum, others -
>
> By going into TPM-bypass mode, we can see how many measurements are actually
> missing when deferring IMA initialization to late_initcall_sync. As this is
> system/TPM dependent, I'd appreciate your checking. Please use the boot command
> line option "ima_policy=tcb|critical_data".
>
> thanks, Mimi
>
> security/integrity/ima/ima.h | 1 +
> security/integrity/ima/ima_init.c | 6 ++++++
> security/integrity/ima/ima_main.c | 19 +++++++++++++++++++
> 3 files changed, 26 insertions(+)
>
> diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
> index 01aae19ed365..9a1117112fb2 100644
> --- a/security/integrity/ima/ima.h
> +++ b/security/integrity/ima/ima.h
> @@ -286,6 +286,7 @@ extern bool ima_canonical_fmt;
>
> /* Internal IMA function definitions */
> int ima_init_core(bool late);
> +int ima_init_debug(bool late);
> int ima_fs_init(void);
> int ima_add_template_entry(struct ima_template_entry *entry, int violation,
> const char *op, struct inode *inode,
> diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
> index 5f335834a9bb..edd063b99685 100644
> --- a/security/integrity/ima/ima_init.c
> +++ b/security/integrity/ima/ima_init.c
> @@ -122,6 +122,12 @@ void __init ima_load_x509(void)
> }
> #endif
>
> +int __init ima_init_debug(bool late)
> +{
> + ima_add_boot_aggregate(late); /* just add an additional record */
> + return 0;
> +}
> +
> int __init ima_init_core(bool late)
> {
> int rc;
> diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
> index 42099bfe7e43..23e669be54fc 100644
> --- a/security/integrity/ima/ima_main.c
> +++ b/security/integrity/ima/ima_main.c
> @@ -1254,6 +1254,7 @@ static int ima_kernel_module_request(char *kmod_name)
>
> #endif /* CONFIG_INTEGRITY_ASYMMETRIC_KEYS */
>
> +#define TESTING 1
> static int __init init_ima(bool late)
> {
> int error;
> @@ -1264,6 +1265,23 @@ static int __init init_ima(bool late)
> return 0;
> }
>
> +#ifdef TESTING
> + /*
> + * Initialize early, even if it means going into TPM-bypass mode,
> + * but add an additional boot_aggregrate message for the
> + * late_initcall_sync.
> + *
> + * If measurement list records exist between the boot_aggregate
> + * and the boot_aggregate_late records, these records would be
> + * missing when IMA initializion is deferred to late_initcall_sync.
> + */
> + if (ima_tpm_chip) {
I believe this should be:
if (late) {
...
}
> + ima_init_debug(late); /* Add an additional record */
> + return 0;
> + }
> +
> + ima_tpm_chip = tpm_default_chip();
> +#elif
> /*
> * If we found the TPM during our first attempt, or we know there's no
> * TPM, nothing further to do
> @@ -1276,6 +1294,7 @@ static int __init init_ima(bool late)
> pr_debug("TPM not available, will try later\n");
> return -EPROBE_DEFER;
> }
> +#endif
>
> if (!ima_tpm_chip)
> pr_info("No TPM chip found, activating TPM-bypass!\n");
> --
> 2.53.0
With above change I confirmed there is no meaurement log
between boot_aggregate and boot_aggregate_late except "kernel_version"
But this is ignorable since this UTS measurement is done in
"ima_init_core() (old: ima_init())" and it is part of ima initialisation.
1. ima_policy=tcb
# cat /sys/kernel/security/ima/ascii_runtime_measurements
10 0adefe762c149c7cec19da62f0da1297fcfbffff ima-ng sha256:0000000000000000000000000000000000000000000000000000000000000000 boot_aggregate
10 4e5d73ebadfd8f850cb93ce4de755ba148a9a7d5 ima-ng sha256:0000000000000000000000000000000000000000000000000000000000000000 boot_aggregate_late
10 7c23cc970eceec906f7a41bc2fbde770d7092209 ima-ng sha256:72ade6ae3d35cfe5ede7a77b1c0ed1d1782a899445fdcb219c0e994a084a70d5 /bin/busybox
10 17ec669c65c401e5e85875cf2962eb7d8c47595f ima-ng sha256:dc6b013e9768d9b13bcd6678470448090138ca831f4771a43ce3988d8e54ffce /lib/ld-linux-aarch64.so.1
10 58679a66ac1de17f02595625a8fbeafa259a4c81 ima-ng sha256:494f62bcfb2fcf1b427d5092fafa62c8df39a83b4a64402620b28846724f237f /usr/lib/libtirpc.so.3.0.0
10 42f74ee200434576e33be153830b3d55bbe6d2bf ima-ng sha256:a18856b4f6927bc2b8dd4608c0768b8f98544a161b85bf4a64419131243ad300 /lib/libresolv.so.2
10 626b4f7bd4f123d18d3a3d8719ed0ae19ee5f331 ima-ng sha256:b8d442de5d31c3f9d1bbb98785f04d4a23dc53442b286d85d4b355927cbe9af4 /lib/libc.so.6
10 655a200869696207646377a58cab417fd35b09d2 ima-ng sha256:ad46146b6dd32b47213e5327f1bb2f962ef838a4b707ef7445fa2dbc9019b44f /etc/inittab
10 81353202685e022fcd0069a3b2fc4eaa6b1db537 ima-ng sha256:74d698fe0a6862050af29083aa591c960ec1f67be960047e96bb6be5fc2bc0c0 /bin/mount
10 ae64184ee607ef8f3aa08ab52cb548318534fd4b ima-ng sha256:27846b57e8234c6a9611b00351f581a54ad6f9a1920b9aa18ceb0ae28e4f7564 /lib/libmount.so.1.1.0
10 5ea01f34e7705d1bdb936fd576e2aeb5fd78dab9 ima-ng sha256:3d2a414ec0355fcf0910224fb4a3c53e13d98731a35241edfdf4fb911ed9b210 /lib/libblkid.so.1.1.0
10 22c48b4853594a08a73ad4ae6dbe6f2c2bebc6c5 ima-ng sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 /run/utmp
10 3024ea5021f8a5d9fb4bd519d599bdca43b7fb93 ima-ng sha256:71ea9ffe2b30e5a9bdceff78785cf281cc41544474db8dc4605a06a597ce1edc /etc/fstab
10 2e7530a0f56420991ac7611734cea4774b92b9ef ima-ng sha256:df4697d699442cfe73db7cc8b4c1b37e8a31e75e01f66a0d70134ac812fa683b /bin/mkdir
10 3ad117a863aa1ed7b7c09e1d106f84abf7d2ae96 ima-ng sha256:c19a710989b43222431b02399273dba409fe10ca8eefff88eaa936fa695f8324 /bin/ln
10 4141c82cb516ac3c846e0b08abcd6abeee7efa1a ima-ng sha256:b75d7f28772f71715a941c77e07e3922815391dd9cc5718ad21f2231c2da09bb /etc/hostname
10 dfcedd3c7dc3ed42e09219804504489ab264e2e3 ima-ng sha256:dc1615df9f2012b20b81ffad8e07e16293039ba7fd897854ca3646d6cfea0c0f /etc/init.d/rcS
...
2. ima_policy=critical_data
# cat /sys/kernel/security/ima/ascii_runtime_measurements
10 0adefe762c149c7cec19da62f0da1297fcfbffff ima-ng sha256:0000000000000000000000000000000000000000000000000000000000000000 boot_aggregate
10 49ab61dd97ea2f759edcb6c6a3387ac67f0aa576 ima-buf sha256:0c907aab3261194f16b0c2a422a82f145bc9b9ecb8fdb633fa43e3e5379f0af2 kernel_version 372e312e302d7263312b // Ignorable since it's generated by ima_init(_core)().
10 4e5d73ebadfd8f850cb93ce4de755ba148a9a7d5 ima-ng sha256:0000000000000000000000000000000000000000000000000000000000000000 boot_aggregate_late
Therefore, init_ima() could move into late_initcall_sync like v1 did:
- https://lore.kernel.org/all/20260417175759.3191279-2-yeoreum.yun@arm.com/
Thanks.
--
Sincerely,
Yeoreum Yun
^ permalink raw reply
* Re: [PATCH] ima: debugging late_initcall_sync measurements
From: Mimi Zohar @ 2026-04-30 21:39 UTC (permalink / raw)
To: Yeoreum Yun
Cc: Jonathan McDowell, linux-security-module, linux-kernel,
linux-integrity, linux-arm-kernel, kvmarm, paul, jmorris, serge,
roberto.sassu, dmitry.kasatkin, eric.snowberg, jarkko, jgg,
sudeep.holla, maz, oupton, joey.gouly, suzuki.poulose, yuzenghui,
catalin.marinas, will, noodles, sebastianene
In-Reply-To: <afMlgstqahnZg68h@e129823.arm.com>
On Thu, 2026-04-30 at 10:48 +0100, Yeoreum Yun wrote:
> With above change I confirmed there is no meaurement log
> between boot_aggregate and boot_aggregate_late except "kernel_version"
> But this is ignorable since this UTS measurement is done in
> "ima_init_core() (old: ima_init())" and it is part of ima initialisation.
>
> 1. ima_policy=tcb
>
> # cat /sys/kernel/security/ima/ascii_runtime_measurements
> 10 0adefe762c149c7cec19da62f0da1297fcfbffff ima-ng sha256:0000000000000000000000000000000000000000000000000000000000000000 boot_aggregate
> 10 4e5d73ebadfd8f850cb93ce4de755ba148a9a7d5 ima-ng sha256:0000000000000000000000000000000000000000000000000000000000000000 boot_aggregate_late
> 10 7c23cc970eceec906f7a41bc2fbde770d7092209 ima-ng sha256:72ade6ae3d35cfe5ede7a77b1c0ed1d1782a899445fdcb219c0e994a084a70d5 /bin/busybox
> 10 17ec669c65c401e5e85875cf2962eb7d8c47595f ima-ng sha256:dc6b013e9768d9b13bcd6678470448090138ca831f4771a43ce3988d8e54ffce /lib/ld-linux-aarch64.so.1
> 10 58679a66ac1de17f02595625a8fbeafa259a4c81 ima-ng sha256:494f62bcfb2fcf1b427d5092fafa62c8df39a83b4a64402620b28846724f237f /usr/lib/libtirpc.so.3.0.0
> 10 42f74ee200434576e33be153830b3d55bbe6d2bf ima-ng sha256:a18856b4f6927bc2b8dd4608c0768b8f98544a161b85bf4a64419131243ad300 /lib/libresolv.so.2
> 10 626b4f7bd4f123d18d3a3d8719ed0ae19ee5f331 ima-ng sha256:b8d442de5d31c3f9d1bbb98785f04d4a23dc53442b286d85d4b355927cbe9af4 /lib/libc.so.6
> 10 655a200869696207646377a58cab417fd35b09d2 ima-ng sha256:ad46146b6dd32b47213e5327f1bb2f962ef838a4b707ef7445fa2dbc9019b44f /etc/inittab
> 10 81353202685e022fcd0069a3b2fc4eaa6b1db537 ima-ng sha256:74d698fe0a6862050af29083aa591c960ec1f67be960047e96bb6be5fc2bc0c0 /bin/mount
> 10 ae64184ee607ef8f3aa08ab52cb548318534fd4b ima-ng sha256:27846b57e8234c6a9611b00351f581a54ad6f9a1920b9aa18ceb0ae28e4f7564 /lib/libmount.so.1.1.0
> 10 5ea01f34e7705d1bdb936fd576e2aeb5fd78dab9 ima-ng sha256:3d2a414ec0355fcf0910224fb4a3c53e13d98731a35241edfdf4fb911ed9b210 /lib/libblkid.so.1.1.0
> 10 22c48b4853594a08a73ad4ae6dbe6f2c2bebc6c5 ima-ng sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 /run/utmp
> 10 3024ea5021f8a5d9fb4bd519d599bdca43b7fb93 ima-ng sha256:71ea9ffe2b30e5a9bdceff78785cf281cc41544474db8dc4605a06a597ce1edc /etc/fstab
> 10 2e7530a0f56420991ac7611734cea4774b92b9ef ima-ng sha256:df4697d699442cfe73db7cc8b4c1b37e8a31e75e01f66a0d70134ac812fa683b /bin/mkdir
> 10 3ad117a863aa1ed7b7c09e1d106f84abf7d2ae96 ima-ng sha256:c19a710989b43222431b02399273dba409fe10ca8eefff88eaa936fa695f8324 /bin/ln
> 10 4141c82cb516ac3c846e0b08abcd6abeee7efa1a ima-ng sha256:b75d7f28772f71715a941c77e07e3922815391dd9cc5718ad21f2231c2da09bb /etc/hostname
> 10 dfcedd3c7dc3ed42e09219804504489ab264e2e3 ima-ng sha256:dc1615df9f2012b20b81ffad8e07e16293039ba7fd897854ca3646d6cfea0c0f /etc/init.d/rcS
> ...
>
> 2. ima_policy=critical_data
>
> # cat /sys/kernel/security/ima/ascii_runtime_measurements
> 10 0adefe762c149c7cec19da62f0da1297fcfbffff ima-ng sha256:0000000000000000000000000000000000000000000000000000000000000000 boot_aggregate
> 10 49ab61dd97ea2f759edcb6c6a3387ac67f0aa576 ima-buf sha256:0c907aab3261194f16b0c2a422a82f145bc9b9ecb8fdb633fa43e3e5379f0af2 kernel_version 372e312e302d7263312b // Ignorable since it's generated by ima_init(_core)().
> 10 4e5d73ebadfd8f850cb93ce4de755ba148a9a7d5 ima-ng sha256:0000000000000000000000000000000000000000000000000000000000000000 boot_aggregate_late
>
> Therefore, init_ima() could move into late_initcall_sync like v1 did:
> - https://lore.kernel.org/all/20260417175759.3191279-2-yeoreum.yun@arm.com/
Thanks, Yeoreum. It's a bit premature to claim it's "safe" to move the
initcall. Hopefully others will respond.
Mimi
^ permalink raw reply
* Re: [PATCH] ima: debugging late_initcall_sync measurements
From: Paul Moore @ 2026-04-30 22:35 UTC (permalink / raw)
To: Mimi Zohar
Cc: Yeoreum Yun, Jonathan McDowell, linux-security-module,
linux-kernel, linux-integrity, linux-arm-kernel, kvmarm, jmorris,
serge, roberto.sassu, dmitry.kasatkin, eric.snowberg, jarkko, jgg,
sudeep.holla, maz, oupton, joey.gouly, suzuki.poulose, yuzenghui,
catalin.marinas, will, noodles, sebastianene
In-Reply-To: <9f188536f09a2db30877d6bfbb84aeaf2565cccf.camel@linux.ibm.com>
On Thu, Apr 30, 2026 at 5:39 PM Mimi Zohar <zohar@linux.ibm.com> wrote:
> On Thu, 2026-04-30 at 10:48 +0100, Yeoreum Yun wrote:
> > With above change I confirmed there is no meaurement log
> > between boot_aggregate and boot_aggregate_late except "kernel_version"
> > But this is ignorable since this UTS measurement is done in
> > "ima_init_core() (old: ima_init())" and it is part of ima initialisation.
> >
> > 1. ima_policy=tcb
> >
> > # cat /sys/kernel/security/ima/ascii_runtime_measurements
> > 10 0adefe762c149c7cec19da62f0da1297fcfbffff ima-ng sha256:0000000000000000000000000000000000000000000000000000000000000000 boot_aggregate
> > 10 4e5d73ebadfd8f850cb93ce4de755ba148a9a7d5 ima-ng sha256:0000000000000000000000000000000000000000000000000000000000000000 boot_aggregate_late
> > 10 7c23cc970eceec906f7a41bc2fbde770d7092209 ima-ng sha256:72ade6ae3d35cfe5ede7a77b1c0ed1d1782a899445fdcb219c0e994a084a70d5 /bin/busybox
> > 10 17ec669c65c401e5e85875cf2962eb7d8c47595f ima-ng sha256:dc6b013e9768d9b13bcd6678470448090138ca831f4771a43ce3988d8e54ffce /lib/ld-linux-aarch64.so.1
> > 10 58679a66ac1de17f02595625a8fbeafa259a4c81 ima-ng sha256:494f62bcfb2fcf1b427d5092fafa62c8df39a83b4a64402620b28846724f237f /usr/lib/libtirpc.so.3.0.0
> > 10 42f74ee200434576e33be153830b3d55bbe6d2bf ima-ng sha256:a18856b4f6927bc2b8dd4608c0768b8f98544a161b85bf4a64419131243ad300 /lib/libresolv.so.2
> > 10 626b4f7bd4f123d18d3a3d8719ed0ae19ee5f331 ima-ng sha256:b8d442de5d31c3f9d1bbb98785f04d4a23dc53442b286d85d4b355927cbe9af4 /lib/libc.so.6
> > 10 655a200869696207646377a58cab417fd35b09d2 ima-ng sha256:ad46146b6dd32b47213e5327f1bb2f962ef838a4b707ef7445fa2dbc9019b44f /etc/inittab
> > 10 81353202685e022fcd0069a3b2fc4eaa6b1db537 ima-ng sha256:74d698fe0a6862050af29083aa591c960ec1f67be960047e96bb6be5fc2bc0c0 /bin/mount
> > 10 ae64184ee607ef8f3aa08ab52cb548318534fd4b ima-ng sha256:27846b57e8234c6a9611b00351f581a54ad6f9a1920b9aa18ceb0ae28e4f7564 /lib/libmount.so.1.1.0
> > 10 5ea01f34e7705d1bdb936fd576e2aeb5fd78dab9 ima-ng sha256:3d2a414ec0355fcf0910224fb4a3c53e13d98731a35241edfdf4fb911ed9b210 /lib/libblkid.so.1.1.0
> > 10 22c48b4853594a08a73ad4ae6dbe6f2c2bebc6c5 ima-ng sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 /run/utmp
> > 10 3024ea5021f8a5d9fb4bd519d599bdca43b7fb93 ima-ng sha256:71ea9ffe2b30e5a9bdceff78785cf281cc41544474db8dc4605a06a597ce1edc /etc/fstab
> > 10 2e7530a0f56420991ac7611734cea4774b92b9ef ima-ng sha256:df4697d699442cfe73db7cc8b4c1b37e8a31e75e01f66a0d70134ac812fa683b /bin/mkdir
> > 10 3ad117a863aa1ed7b7c09e1d106f84abf7d2ae96 ima-ng sha256:c19a710989b43222431b02399273dba409fe10ca8eefff88eaa936fa695f8324 /bin/ln
> > 10 4141c82cb516ac3c846e0b08abcd6abeee7efa1a ima-ng sha256:b75d7f28772f71715a941c77e07e3922815391dd9cc5718ad21f2231c2da09bb /etc/hostname
> > 10 dfcedd3c7dc3ed42e09219804504489ab264e2e3 ima-ng sha256:dc1615df9f2012b20b81ffad8e07e16293039ba7fd897854ca3646d6cfea0c0f /etc/init.d/rcS
> > ...
> >
> > 2. ima_policy=critical_data
> >
> > # cat /sys/kernel/security/ima/ascii_runtime_measurements
> > 10 0adefe762c149c7cec19da62f0da1297fcfbffff ima-ng sha256:0000000000000000000000000000000000000000000000000000000000000000 boot_aggregate
> > 10 49ab61dd97ea2f759edcb6c6a3387ac67f0aa576 ima-buf sha256:0c907aab3261194f16b0c2a422a82f145bc9b9ecb8fdb633fa43e3e5379f0af2 kernel_version 372e312e302d7263312b // Ignorable since it's generated by ima_init(_core)().
> > 10 4e5d73ebadfd8f850cb93ce4de755ba148a9a7d5 ima-ng sha256:0000000000000000000000000000000000000000000000000000000000000000 boot_aggregate_late
> >
> > Therefore, init_ima() could move into late_initcall_sync like v1 did:
> > - https://lore.kernel.org/all/20260417175759.3191279-2-yeoreum.yun@arm.com/
>
> Thanks, Yeoreum. It's a bit premature to claim it's "safe" to move the
> initcall. Hopefully others will respond.
Is it not possible to look at the code and determine if it is safe or
not? Or is the initialization of TPM devices at boot done in a random
order with respect to the initcall levels?
--
paul-moore.com
^ permalink raw reply
* IMA: Avoid redundant rehashing on stacked filesystems backed by structurally immutable filesystems
From: Danny Hu @ 2026-04-30 23:55 UTC (permalink / raw)
To: linux-integrity
Cc: zohar, Sahil Gupta, Julien Gomes, Pierre De Abreu, Kunal Bharathi
Hi,
We observed that IMA will always invalidate the cached measurement
result and re-hash a file on overlayfs stacked on top of squashfs. The
behavior was introduced by commit b836c4d29f27 ("ima: detect changes
to the backing overlay file”). We would like some feedback on the
proposed direction we are considering before sending in any patches.
Problem:
process_measurement() in security/integrity/ima/ima_main.c includes a
stacked-filesystem re-evaluation block that clears IMA_DONE_MASK when
the backing inode is not IS_I_VERSION. This check does not
differentiate between two distinct cases:
1. The backing fs does not implement i_version but it's inodes can change
2. The backing fs does not need i_version because it's inodes cannot change
For the latter case, squashfs being an inherently immutable filesystem
with no write paths does not set the IS_I_VERSION flag and ends up
paying the cost of IMA hashing on every single IMA appraisal
operation. This is perhaps overly conservative because the contents of
squashfs cannot be modified anyways so the cached result will never be
stale.
Proposed direction:
Add an s_iflags bit, potentially SB_I_IMMUTABLE, that a filesystem can
set in fill_super to indicate that it is structurally immutable. IMA
can then leverage this bit to short circuit the stacked-fs
re-evaluation block and trust the cached appraisal value instead of
forcing a re-hash. A motivator for this approach is to follow existing
precedent. IMA already consults s_iflags for filesystem facts that
affect appraisal. The SB_I_IMA_UNVERIFIABLE_SIGNATURE flag is already
checked in the same process_measurement() in the block above the
stacked fs re-evaluation.
Happy to provide more details or clarifications if required.
Thanks,
Danny
^ permalink raw reply
* Re: [PATCH] ima: debugging late_initcall_sync measurements
From: Mimi Zohar @ 2026-05-01 1:51 UTC (permalink / raw)
To: Paul Moore
Cc: Yeoreum Yun, Jonathan McDowell, linux-security-module,
linux-kernel, linux-integrity, linux-arm-kernel, kvmarm, jmorris,
serge, roberto.sassu, dmitry.kasatkin, eric.snowberg, jarkko, jgg,
sudeep.holla, maz, oupton, joey.gouly, suzuki.poulose, yuzenghui,
catalin.marinas, will, noodles, sebastianene
In-Reply-To: <CAHC9VhRsnmPp2KmQAns5uq5qXX5EF2xQQzyfTgrPi4O9AXyPpg@mail.gmail.com>
On Thu, 2026-04-30 at 18:35 -0400, Paul Moore wrote:
> On Thu, Apr 30, 2026 at 5:39 PM Mimi Zohar <zohar@linux.ibm.com> wrote:
> > On Thu, 2026-04-30 at 10:48 +0100, Yeoreum Yun wrote:
> > > With above change I confirmed there is no meaurement log
> > > between boot_aggregate and boot_aggregate_late except "kernel_version"
> > > But this is ignorable since this UTS measurement is done in
> > > "ima_init_core() (old: ima_init())" and it is part of ima initialisation.
> > >
> > > 1. ima_policy=tcb
> > >
> > > # cat /sys/kernel/security/ima/ascii_runtime_measurements
> > > 10 0adefe762c149c7cec19da62f0da1297fcfbffff ima-ng sha256:0000000000000000000000000000000000000000000000000000000000000000 boot_aggregate
> > > 10 4e5d73ebadfd8f850cb93ce4de755ba148a9a7d5 ima-ng sha256:0000000000000000000000000000000000000000000000000000000000000000 boot_aggregate_late
> > > 10 7c23cc970eceec906f7a41bc2fbde770d7092209 ima-ng sha256:72ade6ae3d35cfe5ede7a77b1c0ed1d1782a899445fdcb219c0e994a084a70d5 /bin/busybox
> > > 10 17ec669c65c401e5e85875cf2962eb7d8c47595f ima-ng sha256:dc6b013e9768d9b13bcd6678470448090138ca831f4771a43ce3988d8e54ffce /lib/ld-linux-aarch64.so.1
> > > 10 58679a66ac1de17f02595625a8fbeafa259a4c81 ima-ng sha256:494f62bcfb2fcf1b427d5092fafa62c8df39a83b4a64402620b28846724f237f /usr/lib/libtirpc.so.3.0.0
> > > 10 42f74ee200434576e33be153830b3d55bbe6d2bf ima-ng sha256:a18856b4f6927bc2b8dd4608c0768b8f98544a161b85bf4a64419131243ad300 /lib/libresolv.so.2
> > > 10 626b4f7bd4f123d18d3a3d8719ed0ae19ee5f331 ima-ng sha256:b8d442de5d31c3f9d1bbb98785f04d4a23dc53442b286d85d4b355927cbe9af4 /lib/libc.so.6
> > > 10 655a200869696207646377a58cab417fd35b09d2 ima-ng sha256:ad46146b6dd32b47213e5327f1bb2f962ef838a4b707ef7445fa2dbc9019b44f /etc/inittab
> > > 10 81353202685e022fcd0069a3b2fc4eaa6b1db537 ima-ng sha256:74d698fe0a6862050af29083aa591c960ec1f67be960047e96bb6be5fc2bc0c0 /bin/mount
> > > 10 ae64184ee607ef8f3aa08ab52cb548318534fd4b ima-ng sha256:27846b57e8234c6a9611b00351f581a54ad6f9a1920b9aa18ceb0ae28e4f7564 /lib/libmount.so.1.1.0
> > > 10 5ea01f34e7705d1bdb936fd576e2aeb5fd78dab9 ima-ng sha256:3d2a414ec0355fcf0910224fb4a3c53e13d98731a35241edfdf4fb911ed9b210 /lib/libblkid.so.1.1.0
> > > 10 22c48b4853594a08a73ad4ae6dbe6f2c2bebc6c5 ima-ng sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 /run/utmp
> > > 10 3024ea5021f8a5d9fb4bd519d599bdca43b7fb93 ima-ng sha256:71ea9ffe2b30e5a9bdceff78785cf281cc41544474db8dc4605a06a597ce1edc /etc/fstab
> > > 10 2e7530a0f56420991ac7611734cea4774b92b9ef ima-ng sha256:df4697d699442cfe73db7cc8b4c1b37e8a31e75e01f66a0d70134ac812fa683b /bin/mkdir
> > > 10 3ad117a863aa1ed7b7c09e1d106f84abf7d2ae96 ima-ng sha256:c19a710989b43222431b02399273dba409fe10ca8eefff88eaa936fa695f8324 /bin/ln
> > > 10 4141c82cb516ac3c846e0b08abcd6abeee7efa1a ima-ng sha256:b75d7f28772f71715a941c77e07e3922815391dd9cc5718ad21f2231c2da09bb /etc/hostname
> > > 10 dfcedd3c7dc3ed42e09219804504489ab264e2e3 ima-ng sha256:dc1615df9f2012b20b81ffad8e07e16293039ba7fd897854ca3646d6cfea0c0f /etc/init.d/rcS
> > > ...
> > >
> > > 2. ima_policy=critical_data
> > >
> > > # cat /sys/kernel/security/ima/ascii_runtime_measurements
> > > 10 0adefe762c149c7cec19da62f0da1297fcfbffff ima-ng sha256:0000000000000000000000000000000000000000000000000000000000000000 boot_aggregate
> > > 10 49ab61dd97ea2f759edcb6c6a3387ac67f0aa576 ima-buf sha256:0c907aab3261194f16b0c2a422a82f145bc9b9ecb8fdb633fa43e3e5379f0af2 kernel_version 372e312e302d7263312b // Ignorable since it's generated by ima_init(_core)().
> > > 10 4e5d73ebadfd8f850cb93ce4de755ba148a9a7d5 ima-ng sha256:0000000000000000000000000000000000000000000000000000000000000000 boot_aggregate_late
> > >
> > > Therefore, init_ima() could move into late_initcall_sync like v1 did:
> > > - https://lore.kernel.org/all/20260417175759.3191279-2-yeoreum.yun@arm.com/
> >
> > Thanks, Yeoreum. It's a bit premature to claim it's "safe" to move the
> > initcall. Hopefully others will respond.
>
> Is it not possible to look at the code and determine if it is safe or
> not? Or is the initialization of TPM devices at boot done in a random
> order with respect to the initcall levels?
The TPM is normally initialized at the device_initcall, except when other
resources are not ready.
(Abbreviated) AI explanation:
If the TPM's first probe succeeds at device_initcall with no deferral, IMA
finds it fine. It is only when the TPM is pushed onto the deferred list that
late_initcall can execute before the retry succeeds, leaving
tpm_default_chip() returning NULL.
Recall that the kernel schedules a final deferred probe flush as its own
late_initcall:
This means the TPM retry and IMA init are both late_initcall, and their
relative order is determined by link order — which is not guaranteed to put
the deferred probe flush before ima_init. If ima_init happens to run before
deferred_probe_initcall, and the TPM is on the deferred list, IMA will enter
bypass mode even though the TPM is about to successfully probe moments later.
This is the precise and subtle nature of the race.
Mimi
^ permalink raw reply
* Re: IMA: Avoid redundant rehashing on stacked filesystems backed by structurally immutable filesystems
From: Mimi Zohar @ 2026-05-01 2:29 UTC (permalink / raw)
To: Danny Hu, linux-integrity
Cc: Sahil Gupta, Julien Gomes, Pierre De Abreu, Kunal Bharathi
In-Reply-To: <CAFn2k5DJNv5SDsx_-odHd3sB0Fw7r8FqhO8fWdXrraZn_vbpDw@mail.gmail.com>
On Thu, 2026-04-30 at 16:55 -0700, Danny Hu wrote:
> Hi,
>
> We observed that IMA will always invalidate the cached measurement
> result and re-hash a file on overlayfs stacked on top of squashfs. The
> behavior was introduced by commit b836c4d29f27 ("ima: detect changes
> to the backing overlay file”). We would like some feedback on the
> proposed direction we are considering before sending in any patches.
>
> Problem:
>
> process_measurement() in security/integrity/ima/ima_main.c includes a
> stacked-filesystem re-evaluation block that clears IMA_DONE_MASK when
> the backing inode is not IS_I_VERSION. This check does not
> differentiate between two distinct cases:
>
> 1. The backing fs does not implement i_version but it's inodes can change
> 2. The backing fs does not need i_version because it's inodes cannot change
>
> For the latter case, squashfs being an inherently immutable filesystem
> with no write paths does not set the IS_I_VERSION flag and ends up
> paying the cost of IMA hashing on every single IMA appraisal
> operation. This is perhaps overly conservative because the contents of
> squashfs cannot be modified anyways so the cached result will never be
> stale.
>
>
> Proposed direction:
>
> Add an s_iflags bit, potentially SB_I_IMMUTABLE, that a filesystem can
> set in fill_super to indicate that it is structurally immutable. IMA
> can then leverage this bit to short circuit the stacked-fs
> re-evaluation block and trust the cached appraisal value instead of
> forcing a re-hash. A motivator for this approach is to follow existing
> precedent. IMA already consults s_iflags for filesystem facts that
> affect appraisal. The SB_I_IMA_UNVERIFIABLE_SIGNATURE flag is already
> checked in the same process_measurement() in the block above the
> stacked fs re-evaluation.
>
> Happy to provide more details or clarifications if required.
Have you considered using IS_RDONLY(real_inode)?
Mimi
^ permalink raw reply
* Re: IMA: Avoid redundant rehashing on stacked filesystems backed by structurally immutable filesystems
From: Sahil Gupta @ 2026-05-01 2:32 UTC (permalink / raw)
To: Mimi Zohar
Cc: Danny Hu, linux-integrity, Julien Gomes, Pierre De Abreu,
Kunal Bharathi
In-Reply-To: <2b3c93a69e70b6fdf637bf9fb921d5e737a79e8e.camel@linux.ibm.com>
> Have you considered using IS_RDONLY(real_inode)?
OOC are ima caches invalidated on fs reconfigure? If that is the case,
then IS_RDONLY ought to do the trick.
Sahil
^ permalink raw reply
* Re: IMA: Avoid redundant rehashing on stacked filesystems backed by structurally immutable filesystems
From: Mimi Zohar @ 2026-05-01 11:42 UTC (permalink / raw)
To: Sahil Gupta
Cc: Danny Hu, linux-integrity, Julien Gomes, Pierre De Abreu,
Kunal Bharathi
In-Reply-To: <CABEuK14__XuRO2KOd3w+qx5_nw4iB2yPcF2R68a09A4hcJkyFw@mail.gmail.com>
On Thu, 2026-04-30 at 21:32 -0500, Sahil Gupta wrote:
> > Have you considered using IS_RDONLY(real_inode)?
>
> OOC are ima caches invalidated on fs reconfigure? If that is the case,
> then IS_RDONLY ought to do the trick.
Per-inode IMA integrity status (iint) is now stored directly in the inode's LSM
security blob rather than in a red-black tree cache. By "fs reconfiguration",
do you mean remounting the filesystem? If so, the iint stored in the LSM
security blob should be freed when the filesystem is unmounted.
Mimi
^ permalink raw reply
* Re: IMA: Avoid redundant rehashing on stacked filesystems backed by structurally immutable filesystems
From: Sahil Gupta @ 2026-05-01 16:02 UTC (permalink / raw)
To: Mimi Zohar
Cc: Danny Hu, linux-integrity, Julien Gomes, Pierre De Abreu,
Kunal Bharathi
In-Reply-To: <4cbd1b20680e2dceba8870f62f2081c333113192.camel@linux.ibm.com>
> By "fs reconfiguration", do you mean remounting the filesystem? If so, the iint stored in the LSM security blob should be freed when the filesystem is unmounted.
I'm a visitor to VFS code, but from what I surmise, a remount doesn't
seem to be equivalent to an unmount + a subsequent mount. It's clear
to me that an explicit unmount would eventually call evict_inodes() ->
... -> security_inode_free(), but I don't trace such a path when
remounting it.
Sahil
^ permalink raw reply
* Re: IMA: Avoid redundant rehashing on stacked filesystems backed by structurally immutable filesystems
From: Danny Hu @ 2026-05-01 16:16 UTC (permalink / raw)
To: Mimi Zohar
Cc: Sahil Gupta, linux-integrity, Julien Gomes, Pierre De Abreu,
Kunal Bharathi
In-Reply-To: <4cbd1b20680e2dceba8870f62f2081c333113192.camel@linux.ibm.com>
On Fri, May 1, 2026 at 4:42 AM Mimi Zohar <zohar@linux.ibm.com> wrote:
>
> On Thu, 2026-04-30 at 21:32 -0500, Sahil Gupta wrote:
> > > Have you considered using IS_RDONLY(real_inode)?
> >
> > OOC are ima caches invalidated on fs reconfigure? If that is the case,
> > then IS_RDONLY ought to do the trick.
>
> Per-inode IMA integrity status (iint) is now stored directly in the inode's LSM
> security blob rather than in a red-black tree cache. By "fs reconfiguration",
> do you mean remounting the filesystem? If so, the iint stored in the LSM
> security blob should be freed when the filesystem is unmounted.
>
We considered using IS_RDONLY(), but the concern involved the remount
path rather than an explicit unmount and subsequent mount. From my
understanding, userspace can toggle the read only flag using "mount -o
remount,rw" without freeing the inodes from memory. A malicious user
could then exploit this by caching the appraisal result, modifying the
file, remounting fs as read-only, and then IMA would trust the cached
appraisal result.
^ permalink raw reply
* Re: [PATCH] ima: debugging late_initcall_sync measurements
From: David Safford @ 2026-05-01 16:52 UTC (permalink / raw)
To: Mimi Zohar
Cc: Yeoreum Yun, Jonathan McDowell, linux-security-module,
linux-kernel, linux-integrity, linux-arm-kernel, kvmarm, paul,
jmorris, serge, roberto.sassu, dmitry.kasatkin, eric.snowberg,
jarkko, jgg, sudeep.holla, maz, oupton, joey.gouly,
suzuki.poulose, yuzenghui, catalin.marinas, will, noodles,
sebastianene
In-Reply-To: <9f188536f09a2db30877d6bfbb84aeaf2565cccf.camel@linux.ibm.com>
On Thu, Apr 30, 2026 at 5:43 PM Mimi Zohar <zohar@linux.ibm.com> wrote:
>
> On Thu, 2026-04-30 at 10:48 +0100, Yeoreum Yun wrote:
> > With above change I confirmed there is no meaurement log
> > between boot_aggregate and boot_aggregate_late except "kernel_version"
> > But this is ignorable since this UTS measurement is done in
> > "ima_init_core() (old: ima_init())" and it is part of ima initialisation.
> >
> > 1. ima_policy=tcb
> >
> > # cat /sys/kernel/security/ima/ascii_runtime_measurements
> > 10 0adefe762c149c7cec19da62f0da1297fcfbffff ima-ng sha256:0000000000000000000000000000000000000000000000000000000000000000 boot_aggregate
> > 10 4e5d73ebadfd8f850cb93ce4de755ba148a9a7d5 ima-ng sha256:0000000000000000000000000000000000000000000000000000000000000000 boot_aggregate_late
> > 10 7c23cc970eceec906f7a41bc2fbde770d7092209 ima-ng sha256:72ade6ae3d35cfe5ede7a77b1c0ed1d1782a899445fdcb219c0e994a084a70d5 /bin/busybox
snip
> >
> > 2. ima_policy=critical_data
> >
> > # cat /sys/kernel/security/ima/ascii_runtime_measurements
> > 10 0adefe762c149c7cec19da62f0da1297fcfbffff ima-ng sha256:0000000000000000000000000000000000000000000000000000000000000000 boot_aggregate
> > 10 49ab61dd97ea2f759edcb6c6a3387ac67f0aa576 ima-buf sha256:0c907aab3261194f16b0c2a422a82f145bc9b9ecb8fdb633fa43e3e5379f0af2 kernel_version 372e312e302d7263312b // Ignorable since it's generated by ima_init(_core)().
> > 10 4e5d73ebadfd8f850cb93ce4de755ba148a9a7d5 ima-ng sha256:0000000000000000000000000000000000000000000000000000000000000000 boot_aggregate_late
> >
> > Therefore, init_ima() could move into late_initcall_sync like v1 did:
> > - https://lore.kernel.org/all/20260417175759.3191279-2-yeoreum.yun@arm.com/
>
> Thanks, Yeoreum. It's a bit premature to claim it's "safe" to move the
> initcall. Hopefully others will respond.
>
> Mimi
I have also run with this patch on a number of bare metal and virtual machines,
running everything from default Fedora 44 to a version with everything turned on
(uefi secure boot, UKI with sdboot stub measurements, IMA measurement
and appraisal enabled,
all systemd measurements on, and systemd using the TPM for root
partition decryption.)
I too see only the kernel_version event between the normal and late
calls, if ima_policy=critical_data.
dave
^ permalink raw reply
* Re: IMA: Avoid redundant rehashing on stacked filesystems backed by structurally immutable filesystems
From: Mimi Zohar @ 2026-05-01 19:48 UTC (permalink / raw)
To: Danny Hu
Cc: Sahil Gupta, linux-integrity, Julien Gomes, Pierre De Abreu,
Kunal Bharathi
In-Reply-To: <CAFn2k5BciHURkQS9p-vZ70GP==1S_4GmoE=sMhA+WQXOA8nfoA@mail.gmail.com>
On Fri, 2026-05-01 at 09:16 -0700, Danny Hu wrote:
> On Fri, May 1, 2026 at 4:42 AM Mimi Zohar <zohar@linux.ibm.com> wrote:
> >
> > On Thu, 2026-04-30 at 21:32 -0500, Sahil Gupta wrote:
> > > > Have you considered using IS_RDONLY(real_inode)?
> > >
> > > OOC are ima caches invalidated on fs reconfigure? If that is the case,
> > > then IS_RDONLY ought to do the trick.
> >
> > Per-inode IMA integrity status (iint) is now stored directly in the inode's LSM
> > security blob rather than in a red-black tree cache. By "fs reconfiguration",
> > do you mean remounting the filesystem? If so, the iint stored in the LSM
> > security blob should be freed when the filesystem is unmounted.
> >
>
> We considered using IS_RDONLY(), but the concern involved the remount
> path rather than an explicit unmount and subsequent mount. From my
> understanding, userspace can toggle the read only flag using "mount -o
> remount,rw" without freeing the inodes from memory. A malicious user
> could then exploit this by caching the appraisal result, modifying the
> file, remounting fs as read-only, and then IMA would trust the cached
> appraisal result.
Thank you for the explanation. Just be aware that IS_IMMUTABLE is already
defined. Otherwise your suggestion is plausible.
Mimi
^ permalink raw reply
* Re: IMA: Avoid redundant rehashing on stacked filesystems backed by structurally immutable filesystems
From: Sahil Gupta @ 2026-05-01 20:05 UTC (permalink / raw)
To: Mimi Zohar
Cc: Danny Hu, linux-integrity, Julien Gomes, Pierre De Abreu,
Kunal Bharathi
In-Reply-To: <027d076e3ef0b22b648d024aaa7d8dd27746a624.camel@linux.ibm.com>
I don't think inode immutability would be helpful here either because
you can mark an inode as immutable after you've written to it.
Sahil
^ permalink raw reply
* Re: IMA: Avoid redundant rehashing on stacked filesystems backed by structurally immutable filesystems
From: Danny Hu @ 2026-05-01 20:22 UTC (permalink / raw)
To: Mimi Zohar
Cc: Sahil Gupta, linux-integrity, Julien Gomes, Pierre De Abreu,
Kunal Bharathi
In-Reply-To: <027d076e3ef0b22b648d024aaa7d8dd27746a624.camel@linux.ibm.com>
On Fri, May 1, 2026 at 12:48 PM Mimi Zohar <zohar@linux.ibm.com> wrote:
> Thank you for the explanation. Just be aware that IS_IMMUTABLE is already
> defined. Otherwise your suggestion is plausible.
Thanks for your input! We will likely pursue this approach internally
and send some patches upstream once more testing is complete.
^ permalink raw reply
* Re: [PATCH] ima: debugging late_initcall_sync measurements
From: Mimi Zohar @ 2026-05-03 11:36 UTC (permalink / raw)
To: David Safford
Cc: Yeoreum Yun, Jonathan McDowell, linux-security-module,
linux-kernel, linux-integrity, linux-arm-kernel, kvmarm, paul,
jmorris, serge, roberto.sassu, dmitry.kasatkin, eric.snowberg,
jarkko, jgg, sudeep.holla, maz, oupton, joey.gouly,
suzuki.poulose, yuzenghui, catalin.marinas, will, noodles,
sebastianene
In-Reply-To: <CAGWfHUW+AX0Hpuw5Vr5iTSaJKQJ+O_4nWWmU1UR8Z_3XFctHZg@mail.gmail.com>
On Fri, 2026-05-01 at 12:52 -0400, David Safford wrote:
> On Thu, Apr 30, 2026 at 5:43 PM Mimi Zohar <zohar@linux.ibm.com> wrote:
> >
> > On Thu, 2026-04-30 at 10:48 +0100, Yeoreum Yun wrote:
> > > With above change I confirmed there is no meaurement log
> > > between boot_aggregate and boot_aggregate_late except "kernel_version"
> > > But this is ignorable since this UTS measurement is done in
> > > "ima_init_core() (old: ima_init())" and it is part of ima initialisation.
> > >
> > > 1. ima_policy=tcb
> > >
> > > # cat /sys/kernel/security/ima/ascii_runtime_measurements
> > > 10 0adefe762c149c7cec19da62f0da1297fcfbffff ima-ng sha256:0000000000000000000000000000000000000000000000000000000000000000 boot_aggregate
> > > 10 4e5d73ebadfd8f850cb93ce4de755ba148a9a7d5 ima-ng sha256:0000000000000000000000000000000000000000000000000000000000000000 boot_aggregate_late
> > > 10 7c23cc970eceec906f7a41bc2fbde770d7092209 ima-ng sha256:72ade6ae3d35cfe5ede7a77b1c0ed1d1782a899445fdcb219c0e994a084a70d5 /bin/busybox
> snip
> > >
> > > 2. ima_policy=critical_data
> > >
> > > # cat /sys/kernel/security/ima/ascii_runtime_measurements
> > > 10 0adefe762c149c7cec19da62f0da1297fcfbffff ima-ng sha256:0000000000000000000000000000000000000000000000000000000000000000 boot_aggregate
> > > 10 49ab61dd97ea2f759edcb6c6a3387ac67f0aa576 ima-buf sha256:0c907aab3261194f16b0c2a422a82f145bc9b9ecb8fdb633fa43e3e5379f0af2 kernel_version 372e312e302d7263312b // Ignorable since it's generated by ima_init(_core)().
> > > 10 4e5d73ebadfd8f850cb93ce4de755ba148a9a7d5 ima-ng sha256:0000000000000000000000000000000000000000000000000000000000000000 boot_aggregate_late
> > >
> > > Therefore, init_ima() could move into late_initcall_sync like v1 did:
> > > - https://lore.kernel.org/all/20260417175759.3191279-2-yeoreum.yun@arm.com/
> >
> > Thanks, Yeoreum. It's a bit premature to claim it's "safe" to move the
> > initcall. Hopefully others will respond.
> >
> > Mimi
>
> I have also run with this patch on a number of bare metal and virtual machines,
> running everything from default Fedora 44 to a version with everything turned on
> (uefi secure boot, UKI with sdboot stub measurements, IMA measurement
> and appraisal enabled,
> all systemd measurements on, and systemd using the TPM for root
> partition decryption.)
> I too see only the kernel_version event between the normal and late
> calls, if ima_policy=critical_data.
Thanks, Dave! Were all the systems you tested x86_64? The next step would be
to test on different arch's (e.g. Z, Power).
Mimi
^ permalink raw reply
* Re: [PATCH] ima: debugging late_initcall_sync measurements
From: Mimi Zohar @ 2026-05-03 12:42 UTC (permalink / raw)
To: David Safford
Cc: Yeoreum Yun, Jonathan McDowell, linux-security-module,
linux-kernel, linux-integrity, linux-arm-kernel, kvmarm, paul,
jmorris, serge, roberto.sassu, dmitry.kasatkin, eric.snowberg,
jarkko, jgg, sudeep.holla, maz, oupton, joey.gouly,
suzuki.poulose, yuzenghui, catalin.marinas, will, noodles,
sebastianene
In-Reply-To: <202f90682fe47bb5fb9b08f8678ae00981b5290b.camel@linux.ibm.com>
On Sun, 2026-05-03 at 07:36 -0400, Mimi Zohar wrote:
> On Fri, 2026-05-01 at 12:52 -0400, David Safford wrote:
> > On Thu, Apr 30, 2026 at 5:43 PM Mimi Zohar <zohar@linux.ibm.com> wrote:
> > >
> > > On Thu, 2026-04-30 at 10:48 +0100, Yeoreum Yun wrote:
> > > > With above change I confirmed there is no meaurement log
> > > > between boot_aggregate and boot_aggregate_late except "kernel_version"
> > > > But this is ignorable since this UTS measurement is done in
> > > > "ima_init_core() (old: ima_init())" and it is part of ima initialisation.
> > > >
> > > > 1. ima_policy=tcb
> > > >
> > > > # cat /sys/kernel/security/ima/ascii_runtime_measurements
> > > > 10 0adefe762c149c7cec19da62f0da1297fcfbffff ima-ng sha256:0000000000000000000000000000000000000000000000000000000000000000 boot_aggregate
> > > > 10 4e5d73ebadfd8f850cb93ce4de755ba148a9a7d5 ima-ng sha256:0000000000000000000000000000000000000000000000000000000000000000 boot_aggregate_late
> > > > 10 7c23cc970eceec906f7a41bc2fbde770d7092209 ima-ng sha256:72ade6ae3d35cfe5ede7a77b1c0ed1d1782a899445fdcb219c0e994a084a70d5 /bin/busybox
> > snip
> > > >
> > > > 2. ima_policy=critical_data
> > > >
> > > > # cat /sys/kernel/security/ima/ascii_runtime_measurements
> > > > 10 0adefe762c149c7cec19da62f0da1297fcfbffff ima-ng sha256:0000000000000000000000000000000000000000000000000000000000000000 boot_aggregate
> > > > 10 49ab61dd97ea2f759edcb6c6a3387ac67f0aa576 ima-buf sha256:0c907aab3261194f16b0c2a422a82f145bc9b9ecb8fdb633fa43e3e5379f0af2 kernel_version 372e312e302d7263312b // Ignorable since it's generated by ima_init(_core)().
> > > > 10 4e5d73ebadfd8f850cb93ce4de755ba148a9a7d5 ima-ng sha256:0000000000000000000000000000000000000000000000000000000000000000 boot_aggregate_late
> > > >
> > > > Therefore, init_ima() could move into late_initcall_sync like v1 did:
> > > > - https://lore.kernel.org/all/20260417175759.3191279-2-yeoreum.yun@arm.com/
> > >
> > > Thanks, Yeoreum. It's a bit premature to claim it's "safe" to move the
> > > initcall. Hopefully others will respond.
> > >
> > > Mimi
> >
> > I have also run with this patch on a number of bare metal and virtual machines,
> > running everything from default Fedora 44 to a version with everything turned on
> > (uefi secure boot, UKI with sdboot stub measurements, IMA measurement
> > and appraisal enabled,
> > all systemd measurements on, and systemd using the TPM for root
> > partition decryption.)
> > I too see only the kernel_version event between the normal and late
> > calls, if ima_policy=critical_data.
>
> Thanks, Dave! Were all the systems you tested x86_64? The next step would be
> to test on different arch's (e.g. Z, Power).
On both Z and PowerVM, there are ~30 measurements between boot_aggregate and
boot_aggregate_late. For example, on PowerVM:
# grep -n boot_aggregate
/sys/kernel/security/integrity/ima/ascii_runtime_measurements
1:10 f60a05d7354fb34aabc02965216abd3428ea52bb ima-sig
sha256:9887dd089ee19a6517bca10580b02c1bb9aa6cd86c157b6ead8a1c0403f348d5
boot_aggregate
31:10 e2592b0d61da6300d3db447b143897a9792231ea ima-sig
sha256:9887dd089ee19a6517bca10580b02c1bb9aa6cd86c157b6ead8a1c0403f348d5
boot_aggregate_late
It would be interesting to the results from a Raspberry Pi 5 as well,
with/without a TPM.
Mimi
^ permalink raw reply
* Re: [PATCH] ima: debugging late_initcall_sync measurements
From: Paul Moore @ 2026-05-03 16:46 UTC (permalink / raw)
To: Mimi Zohar
Cc: Yeoreum Yun, Jonathan McDowell, linux-security-module,
linux-kernel, linux-integrity, linux-arm-kernel, kvmarm, jmorris,
serge, roberto.sassu, dmitry.kasatkin, eric.snowberg, jarkko, jgg,
sudeep.holla, maz, oupton, joey.gouly, suzuki.poulose, yuzenghui,
catalin.marinas, will, noodles, sebastianene
In-Reply-To: <ba4bf28314b679474a6a8da6298e548e54b3754c.camel@linux.ibm.com>
On Thu, Apr 30, 2026 at 9:51 PM Mimi Zohar <zohar@linux.ibm.com> wrote:
> On Thu, 2026-04-30 at 18:35 -0400, Paul Moore wrote:
> > On Thu, Apr 30, 2026 at 5:39 PM Mimi Zohar <zohar@linux.ibm.com> wrote:
> > > On Thu, 2026-04-30 at 10:48 +0100, Yeoreum Yun wrote:
> > > > With above change I confirmed there is no meaurement log
> > > > between boot_aggregate and boot_aggregate_late except "kernel_version"
> > > > But this is ignorable since this UTS measurement is done in
> > > > "ima_init_core() (old: ima_init())" and it is part of ima initialisation.
> > > >
> > > > 1. ima_policy=tcb
> > > >
> > > > # cat /sys/kernel/security/ima/ascii_runtime_measurements
> > > > 10 0adefe762c149c7cec19da62f0da1297fcfbffff ima-ng sha256:0000000000000000000000000000000000000000000000000000000000000000 boot_aggregate
> > > > 10 4e5d73ebadfd8f850cb93ce4de755ba148a9a7d5 ima-ng sha256:0000000000000000000000000000000000000000000000000000000000000000 boot_aggregate_late
> > > > 10 7c23cc970eceec906f7a41bc2fbde770d7092209 ima-ng sha256:72ade6ae3d35cfe5ede7a77b1c0ed1d1782a899445fdcb219c0e994a084a70d5 /bin/busybox
> > > > 10 17ec669c65c401e5e85875cf2962eb7d8c47595f ima-ng sha256:dc6b013e9768d9b13bcd6678470448090138ca831f4771a43ce3988d8e54ffce /lib/ld-linux-aarch64.so.1
> > > > 10 58679a66ac1de17f02595625a8fbeafa259a4c81 ima-ng sha256:494f62bcfb2fcf1b427d5092fafa62c8df39a83b4a64402620b28846724f237f /usr/lib/libtirpc.so.3.0.0
> > > > 10 42f74ee200434576e33be153830b3d55bbe6d2bf ima-ng sha256:a18856b4f6927bc2b8dd4608c0768b8f98544a161b85bf4a64419131243ad300 /lib/libresolv.so.2
> > > > 10 626b4f7bd4f123d18d3a3d8719ed0ae19ee5f331 ima-ng sha256:b8d442de5d31c3f9d1bbb98785f04d4a23dc53442b286d85d4b355927cbe9af4 /lib/libc.so.6
> > > > 10 655a200869696207646377a58cab417fd35b09d2 ima-ng sha256:ad46146b6dd32b47213e5327f1bb2f962ef838a4b707ef7445fa2dbc9019b44f /etc/inittab
> > > > 10 81353202685e022fcd0069a3b2fc4eaa6b1db537 ima-ng sha256:74d698fe0a6862050af29083aa591c960ec1f67be960047e96bb6be5fc2bc0c0 /bin/mount
> > > > 10 ae64184ee607ef8f3aa08ab52cb548318534fd4b ima-ng sha256:27846b57e8234c6a9611b00351f581a54ad6f9a1920b9aa18ceb0ae28e4f7564 /lib/libmount.so.1.1.0
> > > > 10 5ea01f34e7705d1bdb936fd576e2aeb5fd78dab9 ima-ng sha256:3d2a414ec0355fcf0910224fb4a3c53e13d98731a35241edfdf4fb911ed9b210 /lib/libblkid.so.1.1.0
> > > > 10 22c48b4853594a08a73ad4ae6dbe6f2c2bebc6c5 ima-ng sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 /run/utmp
> > > > 10 3024ea5021f8a5d9fb4bd519d599bdca43b7fb93 ima-ng sha256:71ea9ffe2b30e5a9bdceff78785cf281cc41544474db8dc4605a06a597ce1edc /etc/fstab
> > > > 10 2e7530a0f56420991ac7611734cea4774b92b9ef ima-ng sha256:df4697d699442cfe73db7cc8b4c1b37e8a31e75e01f66a0d70134ac812fa683b /bin/mkdir
> > > > 10 3ad117a863aa1ed7b7c09e1d106f84abf7d2ae96 ima-ng sha256:c19a710989b43222431b02399273dba409fe10ca8eefff88eaa936fa695f8324 /bin/ln
> > > > 10 4141c82cb516ac3c846e0b08abcd6abeee7efa1a ima-ng sha256:b75d7f28772f71715a941c77e07e3922815391dd9cc5718ad21f2231c2da09bb /etc/hostname
> > > > 10 dfcedd3c7dc3ed42e09219804504489ab264e2e3 ima-ng sha256:dc1615df9f2012b20b81ffad8e07e16293039ba7fd897854ca3646d6cfea0c0f /etc/init.d/rcS
> > > > ...
> > > >
> > > > 2. ima_policy=critical_data
> > > >
> > > > # cat /sys/kernel/security/ima/ascii_runtime_measurements
> > > > 10 0adefe762c149c7cec19da62f0da1297fcfbffff ima-ng sha256:0000000000000000000000000000000000000000000000000000000000000000 boot_aggregate
> > > > 10 49ab61dd97ea2f759edcb6c6a3387ac67f0aa576 ima-buf sha256:0c907aab3261194f16b0c2a422a82f145bc9b9ecb8fdb633fa43e3e5379f0af2 kernel_version 372e312e302d7263312b // Ignorable since it's generated by ima_init(_core)().
> > > > 10 4e5d73ebadfd8f850cb93ce4de755ba148a9a7d5 ima-ng sha256:0000000000000000000000000000000000000000000000000000000000000000 boot_aggregate_late
> > > >
> > > > Therefore, init_ima() could move into late_initcall_sync like v1 did:
> > > > - https://lore.kernel.org/all/20260417175759.3191279-2-yeoreum.yun@arm.com/
> > >
> > > Thanks, Yeoreum. It's a bit premature to claim it's "safe" to move the
> > > initcall. Hopefully others will respond.
> >
> > Is it not possible to look at the code and determine if it is safe or
> > not? Or is the initialization of TPM devices at boot done in a random
> > order with respect to the initcall levels?
>
> The TPM is normally initialized at the device_initcall, except when other
> resources are not ready.
>
> (Abbreviated) AI explanation:
> If the TPM's first probe succeeds at device_initcall with no deferral, IMA
> finds it fine. It is only when the TPM is pushed onto the deferred list that
> late_initcall can execute before the retry succeeds, leaving
> tpm_default_chip() returning NULL.
I really hope you are using AI only to phrase a response and not as a
substitute for actually investigating the code and determining what is
happening.
Regardless, assuming you always want IMA to leverage a TPMs when they
exist, your reply suggests that using an initcall based IMA init
scheme, even a late-sync initcall, may not be sufficient because
deferred TPM initialization could happen later, yes?
--
paul-moore.com
^ permalink raw reply
* [PATCH v2 1/2] bpf: add bpf_init_inode_xattr kfunc for atomic inode labeling
From: David Windsor @ 2026-05-03 21:18 UTC (permalink / raw)
To: Alexander Viro, Christian Brauner, Alexei Starovoitov,
Daniel Borkmann, Andrii Nakryiko, Eduard Zingerman,
Kumar Kartikeya Dwivedi, KP Singh, Matt Bobrowski, Paul Moore,
James Morris, Serge E. Hallyn, Mimi Zohar, Roberto Sassu,
Dmitry Kasatkin, Stephen Smalley, Casey Schaufler
Cc: Song Liu, Jan Kara, John Fastabend, Martin KaFai Lau,
Yonghong Song, Jiri Olsa, Eric Snowberg, Ondrej Mosnacek,
linux-fsdevel, linux-kernel, bpf, linux-security-module,
linux-integrity, selinux
In-Reply-To: <20260503211835.16103-1-dwindsor@gmail.com>
Add bpf_init_inode_xattr() kfunc for BPF LSM programs to atomically set
xattrs via the inode_init_security hook using lsm_get_xattr_slot().
The inode_init_security hook previously took the xattr array and count
as two separate output parameters (struct xattr *xattrs, int
*xattr_count), which BPF programs cannot write to. Pass the xattr state
as a single context object (struct lsm_xattr_ctx) instead, and have
bpf_init_inode_xattr() take that context directly. Update the existing
in-tree callers of inode_init_security to take and forward the new
lsm_xattr_ctx.
Because we rely on the hook-specific ctx layout, the kfunc is
restricted to lsm/inode_init_security. Restrict the xattr names that
may be set via this kfunc to the bpf.* namespace.
Suggested-by: Song Liu <song@kernel.org>
Signed-off-by: David Windsor <dwindsor@gmail.com>
---
fs/bpf_fs_kfuncs.c | 106 +++++++++++++++++++++++++++++-
include/linux/bpf_lsm.h | 3 +
include/linux/evm.h | 9 +--
include/linux/lsm_hook_defs.h | 4 +-
include/linux/lsm_hooks.h | 16 ++---
include/linux/security.h | 5 ++
kernel/bpf/bpf_lsm.c | 1 +
security/bpf/hooks.c | 1 +
security/integrity/evm/evm_main.c | 8 ++-
security/security.c | 7 +-
security/selinux/hooks.c | 4 +-
security/smack/smack_lsm.c | 13 ++--
12 files changed, 147 insertions(+), 30 deletions(-)
diff --git a/fs/bpf_fs_kfuncs.c b/fs/bpf_fs_kfuncs.c
index 9d27be058494..193accc00796 100644
--- a/fs/bpf_fs_kfuncs.c
+++ b/fs/bpf_fs_kfuncs.c
@@ -10,6 +10,7 @@
#include <linux/fsnotify.h>
#include <linux/file.h>
#include <linux/kernfs.h>
+#include <linux/lsm_hooks.h>
#include <linux/mm.h>
#include <linux/xattr.h>
@@ -353,6 +354,97 @@ __bpf_kfunc int bpf_cgroup_read_xattr(struct cgroup *cgroup, const char *name__s
}
#endif /* CONFIG_CGROUPS */
+static int bpf_xattrs_used(const struct lsm_xattr_ctx *ctx)
+{
+ const size_t prefix_len = sizeof(XATTR_BPF_LSM_SUFFIX) - 1;
+ int i, n = 0;
+
+ for (i = 0; i < *ctx->xattr_count; i++) {
+ const char *name = ctx->xattrs[i].name;
+
+ if (name && !strncmp(name, XATTR_BPF_LSM_SUFFIX, prefix_len))
+ n++;
+ }
+ return n;
+}
+
+static int __bpf_init_inode_xattr(struct lsm_xattr_ctx *xattr_ctx,
+ const char *name__str,
+ const struct bpf_dynptr *value_p)
+{
+ struct bpf_dynptr_kern *value_ptr = (struct bpf_dynptr_kern *)value_p;
+ size_t name_len;
+ void *xattr_value;
+ struct xattr *xattr;
+ struct xattr *xattrs;
+ int *xattr_count;
+ const void *value;
+ u32 value_len;
+
+ if (!xattr_ctx || !name__str)
+ return -EINVAL;
+
+ xattrs = xattr_ctx->xattrs;
+ xattr_count = xattr_ctx->xattr_count;
+ if (!xattrs || !xattr_count)
+ return -EINVAL;
+ if (bpf_xattrs_used(xattr_ctx) >= BPF_LSM_INODE_INIT_XATTRS)
+ return -ENOSPC;
+
+ name_len = strlen(name__str);
+ if (name_len == 0 || name_len > XATTR_NAME_MAX)
+ return -EINVAL;
+ if (strncmp(name__str, XATTR_BPF_LSM_SUFFIX,
+ sizeof(XATTR_BPF_LSM_SUFFIX) - 1))
+ return -EPERM;
+
+ value_len = __bpf_dynptr_size(value_ptr);
+ if (value_len == 0 || value_len > XATTR_SIZE_MAX)
+ return -EINVAL;
+
+ value = __bpf_dynptr_data(value_ptr, value_len);
+ if (!value)
+ return -EINVAL;
+
+ /* Combine xattr value + name into one allocation. */
+ xattr_value = kmalloc(value_len + name_len + 1, GFP_KERNEL);
+ if (!xattr_value)
+ return -ENOMEM;
+
+ memcpy(xattr_value, value, value_len);
+ memcpy(xattr_value + value_len, name__str, name_len);
+ ((char *)xattr_value)[value_len + name_len] = '\0';
+
+ xattr = lsm_get_xattr_slot(xattr_ctx);
+ if (!xattr) {
+ kfree(xattr_value);
+ return -ENOSPC;
+ }
+
+ xattr->value = xattr_value;
+ xattr->name = (const char *)xattr_value + value_len;
+ xattr->value_len = value_len;
+
+ return 0;
+}
+
+/**
+ * bpf_init_inode_xattr - set an xattr on a new inode from inode_init_security
+ * @xattr_ctx: inode_init_security xattr state from the hook context
+ * @name__str: xattr name (e.g., "bpf.file_label")
+ * @value_p: dynptr containing the xattr value
+ *
+ * Only callable from lsm/inode_init_security programs.
+ *
+ * Return: 0 on success, negative error on failure.
+ */
+__bpf_kfunc int bpf_init_inode_xattr(struct lsm_xattr_ctx *xattr_ctx,
+ const char *name__str,
+ const struct bpf_dynptr *value_p)
+{
+ return __bpf_init_inode_xattr(xattr_ctx, name__str, value_p);
+}
+
__bpf_kfunc_end_defs();
BTF_KFUNCS_START(bpf_fs_kfunc_set_ids)
@@ -363,13 +455,25 @@ BTF_ID_FLAGS(func, bpf_get_dentry_xattr, KF_SLEEPABLE)
BTF_ID_FLAGS(func, bpf_get_file_xattr, KF_SLEEPABLE)
BTF_ID_FLAGS(func, bpf_set_dentry_xattr, KF_SLEEPABLE)
BTF_ID_FLAGS(func, bpf_remove_dentry_xattr, KF_SLEEPABLE)
+BTF_ID_FLAGS(func, bpf_init_inode_xattr, KF_SLEEPABLE)
BTF_KFUNCS_END(bpf_fs_kfunc_set_ids)
+BTF_ID_LIST(bpf_lsm_inode_init_security_btf_ids)
+BTF_ID(func, bpf_lsm_inode_init_security)
+
+BTF_ID_LIST(bpf_init_inode_xattr_btf_ids)
+BTF_ID(func, bpf_init_inode_xattr)
+
static int bpf_fs_kfuncs_filter(const struct bpf_prog *prog, u32 kfunc_id)
{
if (!btf_id_set8_contains(&bpf_fs_kfunc_set_ids, kfunc_id) ||
- prog->type == BPF_PROG_TYPE_LSM)
+ prog->type == BPF_PROG_TYPE_LSM) {
+ /* bpf_init_inode_xattr only attaches to inode_init_security. */
+ if (kfunc_id == bpf_init_inode_xattr_btf_ids[0] &&
+ prog->aux->attach_btf_id != bpf_lsm_inode_init_security_btf_ids[0])
+ return -EACCES;
return 0;
+ }
return -EACCES;
}
diff --git a/include/linux/bpf_lsm.h b/include/linux/bpf_lsm.h
index 643809cc78c3..b97a3d79529d 100644
--- a/include/linux/bpf_lsm.h
+++ b/include/linux/bpf_lsm.h
@@ -19,6 +19,9 @@
#include <linux/lsm_hook_defs.h>
#undef LSM_HOOK
+/* max bpf xattrs per inode */
+#define BPF_LSM_INODE_INIT_XATTRS 1
+
struct bpf_storage_blob {
struct bpf_local_storage __rcu *storage;
};
diff --git a/include/linux/evm.h b/include/linux/evm.h
index 913f4573b203..dff930bc10ba 100644
--- a/include/linux/evm.h
+++ b/include/linux/evm.h
@@ -12,6 +12,8 @@
#include <linux/integrity.h>
#include <linux/xattr.h>
+struct lsm_xattr_ctx;
+
#ifdef CONFIG_EVM
extern int evm_set_key(void *key, size_t keylen);
extern enum integrity_status evm_verifyxattr(struct dentry *dentry,
@@ -21,8 +23,8 @@ extern enum integrity_status evm_verifyxattr(struct dentry *dentry,
int evm_fix_hmac(struct dentry *dentry, const char *xattr_name,
const char *xattr_value, size_t xattr_value_len);
int evm_inode_init_security(struct inode *inode, struct inode *dir,
- const struct qstr *qstr, struct xattr *xattrs,
- int *xattr_count);
+ const struct qstr *qstr,
+ struct lsm_xattr_ctx *xattr_ctx);
extern bool evm_revalidate_status(const char *xattr_name);
extern int evm_protected_xattr_if_enabled(const char *req_xattr_name);
extern int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer,
@@ -63,8 +65,7 @@ static inline int evm_fix_hmac(struct dentry *dentry, const char *xattr_name,
static inline int evm_inode_init_security(struct inode *inode, struct inode *dir,
const struct qstr *qstr,
- struct xattr *xattrs,
- int *xattr_count)
+ struct lsm_xattr_ctx *xattr_ctx)
{
return 0;
}
diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index 2b8dfb35caed..0df364ebb0a5 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -116,8 +116,8 @@ LSM_HOOK(int, 0, inode_alloc_security, struct inode *inode)
LSM_HOOK(void, LSM_RET_VOID, inode_free_security, struct inode *inode)
LSM_HOOK(void, LSM_RET_VOID, inode_free_security_rcu, void *inode_security)
LSM_HOOK(int, -EOPNOTSUPP, inode_init_security, struct inode *inode,
- struct inode *dir, const struct qstr *qstr, struct xattr *xattrs,
- int *xattr_count)
+ struct inode *dir, const struct qstr *qstr,
+ struct lsm_xattr_ctx *xattr_ctx)
LSM_HOOK(int, 0, inode_init_security_anon, struct inode *inode,
const struct qstr *name, const struct inode *context_inode)
LSM_HOOK(int, 0, inode_create, struct inode *dir, struct dentry *dentry,
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index b4f8cad53ddb..2133b729e87d 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -200,20 +200,18 @@ extern struct lsm_static_calls_table static_calls_table __ro_after_init;
/**
* lsm_get_xattr_slot - Return the next available slot and increment the index
- * @xattrs: array storing LSM-provided xattrs
- * @xattr_count: number of already stored xattrs (updated)
+ * @ctx: xattr state shared by inode_init_security hooks
*
- * Retrieve the first available slot in the @xattrs array to fill with an xattr,
- * and increment @xattr_count.
+ * Retrieve the first available slot in the @ctx->xattrs array to fill with an
+ * xattr, and increment @ctx->xattr_count.
*
- * Return: The slot to fill in @xattrs if non-NULL, NULL otherwise.
+ * Return: The slot to fill in @ctx->xattrs if non-NULL, NULL otherwise.
*/
-static inline struct xattr *lsm_get_xattr_slot(struct xattr *xattrs,
- int *xattr_count)
+static inline struct xattr *lsm_get_xattr_slot(struct lsm_xattr_ctx *ctx)
{
- if (unlikely(!xattrs))
+ if (unlikely(!ctx || !ctx->xattrs || !ctx->xattr_count))
return NULL;
- return &xattrs[(*xattr_count)++];
+ return &ctx->xattrs[(*ctx->xattr_count)++];
}
#endif /* ! __LINUX_LSM_HOOKS_H */
diff --git a/include/linux/security.h b/include/linux/security.h
index 41d7367cf403..a2fc72e63ada 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -68,6 +68,11 @@ struct watch;
struct watch_notification;
struct lsm_ctx;
+struct lsm_xattr_ctx {
+ struct xattr *xattrs;
+ int *xattr_count;
+};
+
/* Default (no) options for the capable function */
#define CAP_OPT_NONE 0x0
/* If capable should audit the security request */
diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c
index c5c925f00202..fbbb4e1c04fc 100644
--- a/kernel/bpf/bpf_lsm.c
+++ b/kernel/bpf/bpf_lsm.c
@@ -315,6 +315,7 @@ BTF_ID(func, bpf_lsm_inode_create)
BTF_ID(func, bpf_lsm_inode_free_security)
BTF_ID(func, bpf_lsm_inode_getattr)
BTF_ID(func, bpf_lsm_inode_getxattr)
+BTF_ID(func, bpf_lsm_inode_init_security)
BTF_ID(func, bpf_lsm_inode_mknod)
BTF_ID(func, bpf_lsm_inode_need_killpriv)
BTF_ID(func, bpf_lsm_inode_post_setxattr)
diff --git a/security/bpf/hooks.c b/security/bpf/hooks.c
index 40efde233f3a..d7c44c5c0e30 100644
--- a/security/bpf/hooks.c
+++ b/security/bpf/hooks.c
@@ -30,6 +30,7 @@ static int __init bpf_lsm_init(void)
struct lsm_blob_sizes bpf_lsm_blob_sizes __ro_after_init = {
.lbs_inode = sizeof(struct bpf_storage_blob),
+ .lbs_xattr_count = BPF_LSM_INODE_INIT_XATTRS,
};
DEFINE_LSM(bpf) = {
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index b59e3f121b8a..c25301f25a0a 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -1062,14 +1062,16 @@ static int evm_inode_copy_up_xattr(struct dentry *src, const char *name)
* evm_inode_init_security - initializes security.evm HMAC value
*/
int evm_inode_init_security(struct inode *inode, struct inode *dir,
- const struct qstr *qstr, struct xattr *xattrs,
- int *xattr_count)
+ const struct qstr *qstr,
+ struct lsm_xattr_ctx *xattr_ctx)
{
struct evm_xattr *xattr_data;
struct xattr *xattr, *evm_xattr;
+ struct xattr *xattrs;
bool evm_protected_xattrs = false;
int rc;
+ xattrs = xattr_ctx ? xattr_ctx->xattrs : NULL;
if (!(evm_initialized & EVM_INIT_HMAC) || !xattrs)
return 0;
@@ -1087,7 +1089,7 @@ int evm_inode_init_security(struct inode *inode, struct inode *dir,
if (!evm_protected_xattrs)
return 0;
- evm_xattr = lsm_get_xattr_slot(xattrs, xattr_count);
+ evm_xattr = lsm_get_xattr_slot(xattr_ctx);
/*
* Array terminator (xattr name = NULL) must be the first non-filled
* xattr slot.
diff --git a/security/security.c b/security/security.c
index 4e999f023651..4cd43914ce93 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1334,6 +1334,7 @@ int security_inode_init_security(struct inode *inode, struct inode *dir,
{
struct lsm_static_call *scall;
struct xattr *new_xattrs = NULL;
+ struct lsm_xattr_ctx xattr_ctx;
int ret = -EOPNOTSUPP, xattr_count = 0;
if (unlikely(IS_PRIVATE(inode)))
@@ -1349,10 +1350,12 @@ int security_inode_init_security(struct inode *inode, struct inode *dir,
if (!new_xattrs)
return -ENOMEM;
}
+ xattr_ctx.xattrs = new_xattrs;
+ xattr_ctx.xattr_count = &xattr_count;
lsm_for_each_hook(scall, inode_init_security) {
- ret = scall->hl->hook.inode_init_security(inode, dir, qstr, new_xattrs,
- &xattr_count);
+ ret = scall->hl->hook.inode_init_security(inode, dir, qstr,
+ &xattr_ctx);
if (ret && ret != -EOPNOTSUPP)
goto out;
/*
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 97801966bf32..dca81a22bf83 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2962,11 +2962,11 @@ static int selinux_dentry_create_files_as(struct dentry *dentry, int mode,
static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
const struct qstr *qstr,
- struct xattr *xattrs, int *xattr_count)
+ struct lsm_xattr_ctx *xattr_ctx)
{
const struct cred_security_struct *crsec = selinux_cred(current_cred());
struct superblock_security_struct *sbsec;
- struct xattr *xattr = lsm_get_xattr_slot(xattrs, xattr_count);
+ struct xattr *xattr = lsm_get_xattr_slot(xattr_ctx);
u32 newsid, clen;
u16 newsclass;
int rc;
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 3f9ae05039a2..ea9549c666a1 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -981,10 +981,10 @@ smk_rule_transmutes(struct smack_known *subject,
}
static int
-xattr_dupval(struct xattr *xattrs, int *xattr_count,
+xattr_dupval(struct lsm_xattr_ctx *xattr_ctx,
const char *name, const void *value, unsigned int vallen)
{
- struct xattr * const xattr = lsm_get_xattr_slot(xattrs, xattr_count);
+ struct xattr * const xattr = lsm_get_xattr_slot(xattr_ctx);
if (!xattr)
return 0;
@@ -1003,14 +1003,13 @@ xattr_dupval(struct xattr *xattrs, int *xattr_count,
* @inode: the newly created inode
* @dir: containing directory object
* @qstr: unused
- * @xattrs: where to put the attributes
- * @xattr_count: current number of LSM-provided xattrs (updated)
+ * @xattr_ctx: where to put attributes and update count
*
* Returns 0 if it all works out, -ENOMEM if there's no memory
*/
static int smack_inode_init_security(struct inode *inode, struct inode *dir,
const struct qstr *qstr,
- struct xattr *xattrs, int *xattr_count)
+ struct lsm_xattr_ctx *xattr_ctx)
{
struct task_smack *tsp = smack_cred(current_cred());
struct inode_smack * const issp = smack_inode(inode);
@@ -1057,7 +1056,7 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
if (S_ISDIR(inode->i_mode)) {
transflag = SMK_INODE_TRANSMUTE;
- if (xattr_dupval(xattrs, xattr_count,
+ if (xattr_dupval(xattr_ctx,
XATTR_SMACK_TRANSMUTE,
TRANS_TRUE,
TRANS_TRUE_SIZE
@@ -1067,7 +1066,7 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
}
if (rc == 0)
- if (xattr_dupval(xattrs, xattr_count,
+ if (xattr_dupval(xattr_ctx,
XATTR_SMACK_SUFFIX,
issp->smk_inode->smk_known,
strlen(issp->smk_inode->smk_known)
--
2.53.0
^ permalink raw reply related
* Re: [PATCH v3 0/4] Add support for ML-DSA signature for EVM and IMA
From: Kamlesh Kumar @ 2026-05-04 11:02 UTC (permalink / raw)
To: stefanb; +Cc: linux-integrity, Kamlesh Kumar
In-Reply-To: <20260416154039.1648083-1-stefanb@linux.ibm.com>
On 4/16/26 11:40 AM, Stefan Berger wrote:
> Based on IMA sigv3 type of signatures, add support for ML-DSA signature
> for EVM and IMA. Use the existing ML-DSA hashless signing mode (pure mode).
>
> Stefan
>
> v3:
> - new patches 1/4 and 2/4
> - addressed Mimi's comments on v2
>
> v2:
> - Dropped 1/3
> - Using "none" as hash_algo in 2/2
>
> Stefan Berger (4):
> integrity: Check for NULL returned by asymmetric_key_public_key
> integrity: Check that algo parameter is within valid range
> integrity: Refactor asymmetric_verify for reusability
> integrity: Add support for sigv3 verification using ML-DSA keys
>
> security/integrity/digsig_asymmetric.c | 152 +++++++++++++++++++++----
> 1 file changed, 131 insertions(+), 21 deletions(-)
>
>
> base-commit: 82bbd447199ff1441031d2eaf9afe041550cf525
> --
> 2.53.0
>
Hi Stefan,
I have tested this patch series on x86_64 and IMA signature v3 appraisal
works correctly with ML-DSA keys and appraise_type=sigv3. Signature v3
works with appraise_type=imasig also and I think it is intentional for
backward compatibility of ima policies.
Tested-by: Kamlesh Kumar <kam@juniper.net>
^ permalink raw reply
* Re: [PATCH] ima: debugging late_initcall_sync measurements
From: Mimi Zohar @ 2026-05-04 12:02 UTC (permalink / raw)
To: Paul Moore
Cc: Yeoreum Yun, Jonathan McDowell, linux-security-module,
linux-kernel, linux-integrity, linux-arm-kernel, kvmarm, jmorris,
serge, roberto.sassu, dmitry.kasatkin, eric.snowberg, jarkko, jgg,
sudeep.holla, maz, oupton, joey.gouly, suzuki.poulose, yuzenghui,
catalin.marinas, will, noodles, sebastianene
In-Reply-To: <CAHC9VhRE2kRr1fdDf6xgQgpSrtvqtP8Vy9LVGJhDZFUbzLKGmQ@mail.gmail.com>
On Sun, 2026-05-03 at 12:46 -0400, Paul Moore wrote:
> Regardless, assuming you always want IMA to leverage a TPMs when they
> exist, your reply suggests that using an initcall based IMA init
> scheme, even a late-sync initcall, may not be sufficient because
> deferred TPM initialization could happen later, yes?
Well yeah. The TPM could be configured as a module, but that scenario is not of
interest. That's way too late. The case being addressed in this patch set is
when the TPM driver tries to initialize at device_initcall, returns
EPROBE_DEFER, and is retried at deferred_probe_initcall (late_initcall). Since
ordering within an initcall is not supported, this patch attempts to initialize
IMA at late_initcall and similarly retries, in this case, at late_initcall_sync.
Mimi
^ permalink raw reply
* Re: [PATCH v5 09/13] ima: Add support for staging measurements with prompt
From: Roberto Sassu @ 2026-05-04 12:51 UTC (permalink / raw)
To: corbet, skhan, zohar, dmitry.kasatkin, eric.snowberg, paul,
jmorris, serge
Cc: linux-doc, linux-kernel, linux-integrity, linux-security-module,
gregorylumen, chenste, nramas, Roberto Sassu
In-Reply-To: <20260429160319.4162918-10-roberto.sassu@huaweicloud.com>
On Wed, 2026-04-29 at 18:03 +0200, Roberto Sassu wrote:
> From: Roberto Sassu <roberto.sassu@huawei.com>
>
> Introduce the ability of staging the IMA measurement list and deleting them
> with a prompt.
>
> Staging means moving the current content of the measurement list to a
> separate location, and allowing users to read and delete it. This causes
> the measurement list to be atomically truncated before new measurements can
> be added. Staging can be done only once at a time. In the event of kexec(),
> staging is reverted and staged entries will be carried over to the new
> kernel.
>
> Introduce ascii_runtime_measurements_<algo>_staged and
> binary_runtime_measurements_<algo>_staged interfaces to access and delete
> the measurements. Also, add write permission to the original measurement
> interfaces.
>
> Use 'echo A > <IMA original interface>' and
> 'echo D > <IMA _staged interface>' to respectively stage and delete the
> entire measurements list. Locking of these interfaces is also mediated with
> a call to _ima_measurements_open() and with ima_measurements_release().
While doing the staging in the original interface looks more intuitive,
since it is interface the user operates on, it causes loss of
transaction atomicity.
An agent opening the original interface has to close it, open the
staged interface to read and delete the staged measurement. Other
agents can open the staged interface first and do operations the
original agent didn't intend to do.
Will restore the previous behavior of staging/reading/deleting on the
staged interface. Will keep deleting N entries on the original
interface, since there is no risk of races.
Roberto
> Implement the staging functionality by introducing the new global
> measurements list ima_measurements_staged, and ima_queue_stage() and
> ima_queue_staged_delete_all() to respectively move measurements from the
> current measurements list to the staged one, and to move staged
> measurements to the ima_measurements_trim list for deletion. Introduce
> ima_queue_delete() to delete the measurements.
>
> Finally, introduce the BINARY_STAGED and BINARY_FULL binary measurements
> list types, to maintain the counters and the binary size of staged
> measurements and the full measurements list (including entries that were
> staged). BINARY still represents the current binary measurements list.
>
> Use the binary size for the BINARY + BINARY_STAGED types in
> ima_add_kexec_buffer(), since both measurements list types are copied to
> the secondary kernel during kexec. Use BINARY_FULL in
> ima_measure_kexec_event(), to generate a critical data record.
>
> It should be noted that the BINARY_FULL counter is not passed through
> kexec. Thus, the number of entries included in the kexec critical data
> records refers to the entries since the previous kexec records.
>
> Note: This code derives from the Alt-IMA Huawei project, whose license is
> GPL-2.0 OR MIT.
>
> Link: https://github.com/linux-integrity/linux/issues/1
> Suggested-by: Gregory Lumen <gregorylumen@linux.microsoft.com> (staging revert)
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> ---
> security/integrity/ima/Kconfig | 13 +++
> security/integrity/ima/ima.h | 8 +-
> security/integrity/ima/ima_fs.c | 181 ++++++++++++++++++++++++++---
> security/integrity/ima/ima_kexec.c | 24 +++-
> security/integrity/ima/ima_queue.c | 97 +++++++++++++++-
> 5 files changed, 302 insertions(+), 21 deletions(-)
>
> diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
> index 862fbee2b174..48c906793efb 100644
> --- a/security/integrity/ima/Kconfig
> +++ b/security/integrity/ima/Kconfig
> @@ -332,4 +332,17 @@ config IMA_KEXEC_EXTRA_MEMORY_KB
> If set to the default value of 0, an extra half page of memory for those
> additional measurements will be allocated.
>
> +config IMA_STAGING
> + bool "Support for staging the measurements list"
> + default y
> + help
> + Add support for staging the measurements list.
> +
> + It allows user space to stage the measurements list for deletion and
> + to delete the staged measurements after confirmation.
> +
> + On kexec, staging is reverted and staged measurements are prepended
> + to the current measurements list when measurements are copied to the
> + secondary kernel.
> +
> endif
> diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
> index f8ab6b604c0d..ca8fa43ec72b 100644
> --- a/security/integrity/ima/ima.h
> +++ b/security/integrity/ima/ima.h
> @@ -30,9 +30,11 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8, TPM_PCR10 = 10 };
>
> /*
> * BINARY: current binary measurements list
> + * BINARY_STAGED: staged binary measurements list
> + * BINARY_FULL: binary measurements list since IMA init (lost after kexec)
> */
> enum binary_lists {
> - BINARY, BINARY__LAST
> + BINARY, BINARY_STAGED, BINARY_FULL, BINARY__LAST
> };
>
> /* digest size for IMA, fits SHA1 or MD5 */
> @@ -125,6 +127,7 @@ struct ima_queue_entry {
> struct ima_template_entry *entry;
> };
> extern struct list_head ima_measurements; /* list of all measurements */
> +extern struct list_head ima_measurements_staged; /* list of staged meas. */
>
> /* Some details preceding the binary serialized measurement list */
> struct ima_kexec_hdr {
> @@ -315,6 +318,8 @@ struct ima_template_desc *ima_template_desc_current(void);
> struct ima_template_desc *ima_template_desc_buf(void);
> struct ima_template_desc *lookup_template_desc(const char *name);
> bool ima_template_has_modsig(const struct ima_template_desc *ima_template);
> +int ima_queue_stage(void);
> +int ima_queue_staged_delete_all(void);
> int ima_restore_measurement_entry(struct ima_template_entry *entry);
> int ima_restore_measurement_list(loff_t bufsize, void *buf);
> int ima_measurements_show(struct seq_file *m, void *v);
> @@ -335,6 +340,7 @@ extern spinlock_t ima_queue_lock;
> extern atomic_long_t ima_num_entries[BINARY__LAST];
> extern atomic_long_t ima_num_violations;
> extern struct hlist_head __rcu *ima_htable;
> +extern struct mutex ima_extend_list_mutex;
>
> static inline unsigned int ima_hash_key(u8 *digest)
> {
> diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
> index 7709a4576322..088d5a69aa92 100644
> --- a/security/integrity/ima/ima_fs.c
> +++ b/security/integrity/ima/ima_fs.c
> @@ -24,6 +24,13 @@
>
> #include "ima.h"
>
> +/*
> + * Requests:
> + * 'A\n': stage the entire measurements list
> + * 'D\n': delete all staged measurements
> + */
> +#define STAGED_REQ_LENGTH 21
> +
> static DEFINE_MUTEX(ima_write_mutex);
> static DEFINE_MUTEX(ima_measure_mutex);
> static long ima_measure_users;
> @@ -97,6 +104,11 @@ static void *ima_measurements_start(struct seq_file *m, loff_t *pos)
> return _ima_measurements_start(m, pos, &ima_measurements);
> }
>
> +static void *ima_measurements_staged_start(struct seq_file *m, loff_t *pos)
> +{
> + return _ima_measurements_start(m, pos, &ima_measurements_staged);
> +}
> +
> static void *_ima_measurements_next(struct seq_file *m, void *v, loff_t *pos,
> struct list_head *head)
> {
> @@ -118,6 +130,12 @@ static void *ima_measurements_next(struct seq_file *m, void *v, loff_t *pos)
> return _ima_measurements_next(m, v, pos, &ima_measurements);
> }
>
> +static void *ima_measurements_staged_next(struct seq_file *m, void *v,
> + loff_t *pos)
> +{
> + return _ima_measurements_next(m, v, pos, &ima_measurements_staged);
> +}
> +
> static void ima_measurements_stop(struct seq_file *m, void *v)
> {
> }
> @@ -211,6 +229,13 @@ static const struct seq_operations ima_measurments_seqops = {
> .show = ima_measurements_show
> };
>
> +static const struct seq_operations ima_measurments_staged_seqops = {
> + .start = ima_measurements_staged_start,
> + .next = ima_measurements_staged_next,
> + .stop = ima_measurements_stop,
> + .show = ima_measurements_show
> +};
> +
> static int ima_measure_lock(bool write)
> {
> mutex_lock(&ima_measure_mutex);
> @@ -276,9 +301,78 @@ static int ima_measurements_release(struct inode *inode, struct file *file)
> return ret;
> }
>
> +static int ima_measurements_staged_open(struct inode *inode, struct file *file)
> +{
> + return _ima_measurements_open(inode, file,
> + &ima_measurments_staged_seqops);
> +}
> +
> +static ssize_t _ima_measurements_write(struct file *file,
> + const char __user *buf, size_t datalen,
> + loff_t *ppos, bool staged_interface)
> +{
> + char req[STAGED_REQ_LENGTH];
> + int ret;
> +
> + if (*ppos > 0 || datalen < 2 || datalen > STAGED_REQ_LENGTH)
> + return -EINVAL;
> +
> + if (copy_from_user(req, buf, datalen) != 0)
> + return -EFAULT;
> +
> + if (req[datalen - 1] != '\n')
> + return -EINVAL;
> +
> + req[datalen - 1] = '\0';
> +
> + switch (req[0]) {
> + case 'A':
> + if (datalen != 2 || staged_interface)
> + return -EINVAL;
> +
> + ret = ima_queue_stage();
> + break;
> + case 'D':
> + if (datalen != 2 || !staged_interface)
> + return -EINVAL;
> +
> + ret = ima_queue_staged_delete_all();
> + break;
> + default:
> + ret = -EINVAL;
> + }
> +
> + if (ret < 0)
> + return ret;
> +
> + return datalen;
> +}
> +
> +static ssize_t ima_measurements_write(struct file *file, const char __user *buf,
> + size_t datalen, loff_t *ppos)
> +{
> + return _ima_measurements_write(file, buf, datalen, ppos, false);
> +}
> +
> +static ssize_t ima_measurements_staged_write(struct file *file,
> + const char __user *buf,
> + size_t datalen, loff_t *ppos)
> +{
> + return _ima_measurements_write(file, buf, datalen, ppos, true);
> +}
> +
> static const struct file_operations ima_measurements_ops = {
> .open = ima_measurements_open,
> .read = seq_read,
> + .write = ima_measurements_write,
> + .llseek = seq_lseek,
> + .release = ima_measurements_release,
> +};
> +
> +static const struct file_operations ima_measurements_staged_ops = {
> + .open = ima_measurements_staged_open,
> + .read = seq_read,
> + .write = ima_measurements_staged_write,
> .llseek = seq_lseek,
> .release = ima_measurements_release,
> };
> @@ -352,6 +446,29 @@ static int ima_ascii_measurements_open(struct inode *inode, struct file *file)
> static const struct file_operations ima_ascii_measurements_ops = {
> .open = ima_ascii_measurements_open,
> .read = seq_read,
> + .write = ima_measurements_write,
> + .llseek = seq_lseek,
> + .release = ima_measurements_release,
> +};
> +
> +static const struct seq_operations ima_ascii_measurements_staged_seqops = {
> + .start = ima_measurements_staged_start,
> + .next = ima_measurements_staged_next,
> + .stop = ima_measurements_stop,
> + .show = ima_ascii_measurements_show
> +};
> +
> +static int ima_ascii_measurements_staged_open(struct inode *inode,
> + struct file *file)
> +{
> + return _ima_measurements_open(inode, file,
> + &ima_ascii_measurements_staged_seqops);
> +}
> +
> +static const struct file_operations ima_ascii_measurements_staged_ops = {
> + .open = ima_ascii_measurements_staged_open,
> + .read = seq_read,
> + .write = ima_measurements_staged_write,
> .llseek = seq_lseek,
> .release = ima_measurements_release,
> };
> @@ -459,10 +576,20 @@ static const struct seq_operations ima_policy_seqops = {
> };
> #endif
>
> -static int __init create_securityfs_measurement_lists(void)
> +static int __init create_securityfs_measurement_lists(bool staging)
> {
> + const struct file_operations *ascii_ops = &ima_ascii_measurements_ops;
> + const struct file_operations *binary_ops = &ima_measurements_ops;
> + mode_t permissions = (S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP);
> + const char *file_suffix = "";
> int count = NR_BANKS(ima_tpm_chip);
>
> + if (staging) {
> + ascii_ops = &ima_ascii_measurements_staged_ops;
> + binary_ops = &ima_measurements_staged_ops;
> + file_suffix = "_staged";
> + }
> +
> if (ima_sha1_idx >= NR_BANKS(ima_tpm_chip))
> count++;
>
> @@ -473,29 +600,32 @@ static int __init create_securityfs_measurement_lists(void)
>
> if (algo == HASH_ALGO__LAST)
> snprintf(file_name, sizeof(file_name),
> - "ascii_runtime_measurements_tpm_alg_%x",
> - ima_tpm_chip->allocated_banks[i].alg_id);
> + "ascii_runtime_measurements_tpm_alg_%x%s",
> + ima_tpm_chip->allocated_banks[i].alg_id,
> + file_suffix);
> else
> snprintf(file_name, sizeof(file_name),
> - "ascii_runtime_measurements_%s",
> - hash_algo_name[algo]);
> - dentry = securityfs_create_file(file_name, S_IRUSR | S_IRGRP,
> + "ascii_runtime_measurements_%s%s",
> + hash_algo_name[algo], file_suffix);
> + dentry = securityfs_create_file(file_name, permissions,
> ima_dir, (void *)(uintptr_t)i,
> - &ima_ascii_measurements_ops);
> + ascii_ops);
> if (IS_ERR(dentry))
> return PTR_ERR(dentry);
>
> if (algo == HASH_ALGO__LAST)
> snprintf(file_name, sizeof(file_name),
> - "binary_runtime_measurements_tpm_alg_%x",
> - ima_tpm_chip->allocated_banks[i].alg_id);
> + "binary_runtime_measurements_tpm_alg_%x%s",
> + ima_tpm_chip->allocated_banks[i].alg_id,
> + file_suffix);
> else
> snprintf(file_name, sizeof(file_name),
> - "binary_runtime_measurements_%s",
> - hash_algo_name[algo]);
> - dentry = securityfs_create_file(file_name, S_IRUSR | S_IRGRP,
> + "binary_runtime_measurements_%s%s",
> + hash_algo_name[algo], file_suffix);
> +
> + dentry = securityfs_create_file(file_name, permissions,
> ima_dir, (void *)(uintptr_t)i,
> - &ima_measurements_ops);
> + binary_ops);
> if (IS_ERR(dentry))
> return PTR_ERR(dentry);
> }
> @@ -503,6 +633,23 @@ static int __init create_securityfs_measurement_lists(void)
> return 0;
> }
>
> +static int __init create_securityfs_staging_links(void)
> +{
> + struct dentry *dentry;
> +
> + dentry = securityfs_create_symlink("binary_runtime_measurements_staged",
> + ima_dir, "binary_runtime_measurements_sha1_staged", NULL);
> + if (IS_ERR(dentry))
> + return PTR_ERR(dentry);
> +
> + dentry = securityfs_create_symlink("ascii_runtime_measurements_staged",
> + ima_dir, "ascii_runtime_measurements_sha1_staged", NULL);
> + if (IS_ERR(dentry))
> + return PTR_ERR(dentry);
> +
> + return 0;
> +}
> +
> /*
> * ima_open_policy: sequentialize access to the policy file
> */
> @@ -595,7 +742,13 @@ int __init ima_fs_init(void)
> goto out;
> }
>
> - ret = create_securityfs_measurement_lists();
> + ret = create_securityfs_measurement_lists(false);
> + if (ret == 0 && IS_ENABLED(CONFIG_IMA_STAGING)) {
> + ret = create_securityfs_measurement_lists(true);
> + if (ret == 0)
> + ret = create_securityfs_staging_links();
> + }
> +
> if (ret != 0)
> goto out;
>
> diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c
> index d7d0fb639d99..064cfce0c318 100644
> --- a/security/integrity/ima/ima_kexec.c
> +++ b/security/integrity/ima/ima_kexec.c
> @@ -42,8 +42,8 @@ void ima_measure_kexec_event(const char *event_name)
> long len;
> int n;
>
> - buf_size = ima_get_binary_runtime_size(BINARY);
> - len = atomic_long_read(&ima_num_entries[BINARY]);
> + buf_size = ima_get_binary_runtime_size(BINARY_FULL);
> + len = atomic_long_read(&ima_num_entries[BINARY_FULL]);
>
> n = scnprintf(ima_kexec_event, IMA_KEXEC_EVENT_LEN,
> "kexec_segment_size=%lu;ima_binary_runtime_size=%lu;"
> @@ -106,13 +106,28 @@ static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer,
>
> memset(&khdr, 0, sizeof(khdr));
> khdr.version = 1;
> - /* This is an append-only list, no need to hold the RCU read lock */
> - list_for_each_entry_rcu(qe, &ima_measurements, later, true) {
> + /*
> + * It can race with ima_queue_stage() and ima_queue_staged_delete_all().
> + */
> + mutex_lock(&ima_extend_list_mutex);
> +
> + list_for_each_entry_rcu(qe, &ima_measurements_staged, later,
> + lockdep_is_held(&ima_extend_list_mutex)) {
> ret = ima_dump_measurement(&khdr, qe);
> if (ret < 0)
> break;
> }
>
> + list_for_each_entry_rcu(qe, &ima_measurements, later,
> + lockdep_is_held(&ima_extend_list_mutex)) {
> + if (!ret)
> + ret = ima_dump_measurement(&khdr, qe);
> + if (ret < 0)
> + break;
> + }
> +
> + mutex_unlock(&ima_extend_list_mutex);
> +
> /*
> * fill in reserved space with some buffer details
> * (eg. version, buffer size, number of measurements)
> @@ -167,6 +182,7 @@ void ima_add_kexec_buffer(struct kimage *image)
> extra_memory = CONFIG_IMA_KEXEC_EXTRA_MEMORY_KB * 1024;
>
> binary_runtime_size = ima_get_binary_runtime_size(BINARY) +
> + ima_get_binary_runtime_size(BINARY_STAGED) +
> extra_memory;
>
> if (binary_runtime_size >= ULONG_MAX - PAGE_SIZE)
> diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c
> index b6d10dceb669..50519ed837d4 100644
> --- a/security/integrity/ima/ima_queue.c
> +++ b/security/integrity/ima/ima_queue.c
> @@ -26,6 +26,7 @@
> static struct tpm_digest *digests;
>
> LIST_HEAD(ima_measurements); /* list of all measurements */
> +LIST_HEAD(ima_measurements_staged); /* list of staged measurements */
> #ifdef CONFIG_IMA_KEXEC
> static unsigned long binary_runtime_size[BINARY__LAST];
> #else
> @@ -45,11 +46,11 @@ atomic_long_t ima_num_violations = ATOMIC_LONG_INIT(0);
> /* key: inode (before secure-hashing a file) */
> struct hlist_head __rcu *ima_htable;
>
> -/* mutex protects atomicity of extending measurement list
> +/* mutex protects atomicity of extending and staging measurement list
> * and extending the TPM PCR aggregate. Since tpm_extend can take
> * long (and the tpm driver uses a mutex), we can't use the spinlock.
> */
> -static DEFINE_MUTEX(ima_extend_list_mutex);
> +DEFINE_MUTEX(ima_extend_list_mutex);
>
> /*
> * Used internally by the kernel to suspend measurements.
> @@ -174,12 +175,16 @@ static int ima_add_digest_entry(struct ima_template_entry *entry,
> lockdep_is_held(&ima_extend_list_mutex));
>
> atomic_long_inc(&ima_num_entries[BINARY]);
> + atomic_long_inc(&ima_num_entries[BINARY_FULL]);
> +
> if (update_htable) {
> key = ima_hash_key(entry->digests[ima_hash_algo_idx].digest);
> hlist_add_head_rcu(&qe->hnext, &htable[key]);
> }
>
> ima_update_binary_runtime_size(entry, BINARY);
> + ima_update_binary_runtime_size(entry, BINARY_FULL);
> +
> return 0;
> }
>
> @@ -280,6 +285,94 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation,
> return result;
> }
>
> +int ima_queue_stage(void)
> +{
> + int ret = 0;
> +
> + mutex_lock(&ima_extend_list_mutex);
> + if (!list_empty(&ima_measurements_staged)) {
> + ret = -EEXIST;
> + goto out_unlock;
> + }
> +
> + if (list_empty(&ima_measurements)) {
> + ret = -ENOENT;
> + goto out_unlock;
> + }
> +
> + list_replace(&ima_measurements, &ima_measurements_staged);
> + INIT_LIST_HEAD(&ima_measurements);
> +
> + atomic_long_set(&ima_num_entries[BINARY_STAGED],
> + atomic_long_read(&ima_num_entries[BINARY]));
> + atomic_long_set(&ima_num_entries[BINARY], 0);
> +
> + if (IS_ENABLED(CONFIG_IMA_KEXEC)) {
> + binary_runtime_size[BINARY_STAGED] =
> + binary_runtime_size[BINARY];
> + binary_runtime_size[BINARY] = 0;
> + }
> +out_unlock:
> + mutex_unlock(&ima_extend_list_mutex);
> + return ret;
> +}
> +
> +static void ima_queue_delete(struct list_head *head);
> +
> +int ima_queue_staged_delete_all(void)
> +{
> + LIST_HEAD(ima_measurements_trim);
> +
> + mutex_lock(&ima_extend_list_mutex);
> + if (list_empty(&ima_measurements_staged)) {
> + mutex_unlock(&ima_extend_list_mutex);
> + return -ENOENT;
> + }
> +
> + list_replace(&ima_measurements_staged, &ima_measurements_trim);
> + INIT_LIST_HEAD(&ima_measurements_staged);
> +
> + atomic_long_set(&ima_num_entries[BINARY_STAGED], 0);
> +
> + if (IS_ENABLED(CONFIG_IMA_KEXEC))
> + binary_runtime_size[BINARY_STAGED] = 0;
> +
> + mutex_unlock(&ima_extend_list_mutex);
> +
> + ima_queue_delete(&ima_measurements_trim);
> + return 0;
> +}
> +
> +static void ima_queue_delete(struct list_head *head)
> +{
> + struct ima_queue_entry *qe, *qe_tmp;
> + unsigned int i;
> +
> + list_for_each_entry_safe(qe, qe_tmp, head, later) {
> + /*
> + * Safe to free template_data here without synchronize_rcu()
> + * because the only htable reader, ima_lookup_digest_entry(),
> + * accesses only entry->digests, not template_data. If new
> + * htable readers are added that access template_data, a
> + * synchronize_rcu() is required here.
> + */
> + for (i = 0; i < qe->entry->template_desc->num_fields; i++) {
> + kfree(qe->entry->template_data[i].data);
> + qe->entry->template_data[i].data = NULL;
> + qe->entry->template_data[i].len = 0;
> + }
> +
> + list_del(&qe->later);
> +
> + /* No leak if condition is false, referenced by ima_htable. */
> + if (IS_ENABLED(CONFIG_IMA_DISABLE_HTABLE)) {
> + kfree(qe->entry->digests);
> + kfree(qe->entry);
> + kfree(qe);
> + }
> + }
> +}
> +
> int ima_restore_measurement_entry(struct ima_template_entry *entry)
> {
> int result = 0;
^ permalink raw reply
* Re: tpm: spi: do not call blocking ops when !TASK_RUNNING; during shutdown
From: Jarkko Sakkinen @ 2026-05-04 13:42 UTC (permalink / raw)
To: Stefan Wahren
Cc: Peter Huewe, Jason Gunthorpe, linux-arm-kernel, linux-integrity,
kernel, Frank Li, Sascha Hauer, imx@lists.linux.dev
In-Reply-To: <e7974d35-0d50-4742-8747-822f28915e00@gmx.net>
Hi Stefan,
On Mon, Apr 20, 2026 at 12:25:21PM +0200, Stefan Wahren wrote:
> Hi,
> we use a custom i.MX93 board, which based on Phytec Phycore i.MX93 with a
> TPM connected via SPI. If I enable CONFIG_DEBUG_ATOMIC_SLEEP=y in our kernel
> config with mainline kernel 6.18.23 and reboot our board, I will get the
> following warning:
Please provide results with the latest mainline kernel.
>
> [ 43.287416] do not call blocking ops when !TASK_RUNNING; state=1 set at
> [<000000005a2107f3>] prepare_to_wait_event+0x54/0x14c
> [ 43.299009] WARNING: CPU: 0 PID: 1 at kernel/sched/core.c:8857
> __might_sleep+0x74/0x7c
> [ 43.306920] Modules linked in: polyval_ce flexcan rtc_rv3028 can_dev
> mse102x phy_can_transceiver fuse autofs4
> [ 43.316838] CPU: 0 UID: 0 PID: 1 Comm: systemd-shutdow Not tainted
> 6.18.23-00002-g626a194342f0 #2 PREEMPT
> [ 43.326471] Hardware name: chargebyte Charge SOM Evaluation Kit (DT)
> [ 43.332807] pstate: 60400009 (nZCv daif +PAN -UAO -TCO -DIT -SSBS
> BTYPE=--)
> [ 43.339757] pc : __might_sleep+0x74/0x7c
> [ 43.343675] lr : __might_sleep+0x74/0x7c
> [ 43.347592] sp : ffff800081aab720
> [ 43.350894] x29: ffff800081aab720 x28: 0000000000000080 x27:
> ffff000000235880
> [ 43.358018] x26: ffff800081897000 x25: 0000000000000018 x24:
> 0000000000000000
> [ 43.365142] x23: ffff800081aab907 x22: 0000000000000000 x21:
> 0000000000000080
> [ 43.372266] x20: 000000000000010f x19: ffff80008131cd00 x18:
> 0000000000000001
> [ 43.379390] x17: 0000000000000000 x16: 000000000017d600 x15:
> ffff00003fda4680
> [ 43.386514] x14: 0000000000017e01 x13: 0000000000000209 x12:
> 0000000000000000
> [ 43.393638] x11: 00000000000000c0 x10: 0000000000000950 x9 :
> ffff800081aab5a0
> [ 43.400762] x8 : ffff0000000d89b0 x7 : ffff00003fda3f00 x6 :
> 000000013417d29a
> [ 43.407886] x5 : 0000000000000000 x4 : 0000000000000002 x3 :
> 0000000000000010
> [ 43.415010] x2 : 0000000000000000 x1 : 0000000000000000 x0 :
> ffff0000000d8000
> [ 43.422135] Call trace:
> [ 43.424570] __might_sleep+0x74/0x7c (P)
> [ 43.428487] mutex_lock+0x24/0x80
> [ 43.431797] spi_bus_lock+0x20/0x50
> [ 43.435281] tpm_tis_spi_transfer_full+0x70/0x2c4
> [ 43.439979] tpm_tis_spi_read_bytes+0x3c/0x48
> [ 43.444321] tpm_tis_status+0x58/0xf8
> [ 43.447978] wait_for_tpm_stat_cond+0x30/0x90
> [ 43.452329] wait_for_tpm_stat+0x1cc/0x2e0
> [ 43.456419] tpm_tis_send_data+0xdc/0x334
> [ 43.460423] tpm_tis_send_main+0x74/0x160
> [ 43.464427] tpm_tis_send+0xd4/0x13c
> [ 43.467998] tpm_transmit+0xc4/0x3c4
> [ 43.471569] tpm_transmit_cmd+0x38/0xd4
> [ 43.475399] tpm2_shutdown+0x6c/0xa4
> [ 43.478970] tpm_class_shutdown+0x60/0x88
> [ 43.482974] device_shutdown+0x130/0x25c
> [ 43.486891] kernel_restart+0x44/0xa4
> [ 43.490549] __do_sys_reboot+0x114/0x254
> [ 43.494466] __arm64_sys_reboot+0x24/0x30
> [ 43.498470] invoke_syscall+0x48/0x10c
> [ 43.502214] el0_svc_common.constprop.0+0x40/0xe0
> [ 43.506911] do_el0_svc+0x1c/0x28
> [ 43.510222] el0_svc+0x34/0xec
> [ 43.513273] el0t_64_sync_handler+0xa0/0xe4
> [ 43.517441] el0t_64_sync+0x198/0x19c
>
> Best regards
BR, Jarkko
^ permalink raw reply
* Re: [PATCH v2] tpm: restore timeout for key creation commands
From: Jarkko Sakkinen @ 2026-05-04 15:13 UTC (permalink / raw)
To: Baoli Zhang
Cc: Peter Huewe, Jason Gunthorpe, Serge Hallyn, Lili Li,
linux-integrity, linux-kernel
In-Reply-To: <20260421005021.13765-1-baoli.zhang@linux.intel.com>
On Tue, Apr 21, 2026 at 08:50:20AM +0800, Baoli Zhang wrote:
> From: "Baoli Zhang" <baoli.zhang@linux.intel.com>
>
> Commit 207696b17f38 ("tpm: use a map for tpm2_calc_ordinal_duration()")
> inadvertently reduced the timeout for TPM2 key creation commands
> (`CREATE_PRIMARY`, `CREATE`, `CREATE_LOADED`) from 300 seconds to 30
> seconds.
>
> This causes intermittent timeout failures, with several failures observed
> across hundreds of test runs on some Intel platforms using Infineon
> SLB9670 and SLB9672 TPM modules. Restore the timeout to 300 seconds to
> avoid spurious failures.
Is this a production case?
I'm not sure if there is anything to fix tbh. I mean it is
pretty much the same as "maintaining compatibility to OTT driver"
to addresses issues on undisclosed hardware.
Please correct me if I'm wrong. Otherwise, I'd carry out internal patch
to tweak this for pre-production hardware (presumably).
>
> Fixes: 207696b17f38 ("tpm: use a map for tpm2_calc_ordinal_duration()")
> Co-developed-by: Lili Li <lili.li@intel.com>
> Signed-off-by: Lili Li <lili.li@intel.com>
> Signed-off-by: Baoli Zhang <baoli.zhang@linux.intel.com>
> ---
> Changes in v2:
> - Add description of intermittent nature of the timeout issue.
> - Fix Co-developed-by and Signed-off-by tag ordering.
>
> v1: https://patchwork.kernel.org/project/linux-integrity/patch/20260410014940.3557934-1-baoli.zhang@linux.intel.com/
>
> 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
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