* [GIT PULL] TPM DEVICE DRIVER: for-next-tpm-7.2-rc1-fixed
From: Jarkko Sakkinen @ 2026-06-22 15:31 UTC (permalink / raw)
To: Linus Torvalds
Cc: Peter Huewe, Jason Gunthorpe, David Howells, keyrings,
linux-integrity, linux-kernel
The following changes since commit 1a3746ccbb0a97bed3c06ccde6b880013b1dddc1:
Merge tag 'strncpy-removal-v7.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux (2026-06-19 14:56:45 -0700)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd.git tags/for-next-tpm-7.2-rc1-fixed
for you to fetch changes up to 1a58f6115bfb34eabcc7de8a3a9745b219179781:
tpm: fix event_size output in tpm1_binary_bios_measurements_show (2026-06-21 04:25:28 +0300)
----------------------------------------------------------------
Hi
Correctly rebased version of [1] now that for-next-tpm was mirrored
today to linux-next by Mark today. Contains only bug fixes.
[1] https://lore.kernel.org/linux-integrity/ajc9JcxcH8eGqxbX@kernel.org/T/#t
BR, Jarkko
----------------------------------------------------------------
Baoli Zhang (1):
tpm: restore timeout for key creation commands
David Windsor (1):
tpm: svsm: constify tpm_chip_ops
Gunnar Kudrjavets (1):
tpm: Initialize name_size_alg for non-NULL name in tpm_buf_append_name()
Jarkko Sakkinen (1):
tpm: tpm_tis_spi: Use wait_woken() in wait_for_tmp_stat()
Jim Broadus (2):
tpm: tpm_tis: store entire did_vid
tpm: tpm_tis: Add settle time for some TPMs
Michael Bommarito (1):
tpm: tpm2-sessions: wait for async KPP completion in tpm_buf_append_salt
Rafael J. Wysocki (1):
tpm_crb: Check ACPI_COMPANION() against NULL during probe
Thorsten Blum (1):
tpm: fix event_size output in tpm1_binary_bios_measurements_show
Yeoreum Yun (1):
tpm: tpm_crb_ffa: revert defered_probed when tpm_crb_ffa is built-in
drivers/char/tpm/eventlog/tpm1.c | 4 +--
drivers/char/tpm/tpm2-cmd.c | 6 ++--
drivers/char/tpm/tpm2-sessions.c | 56 +++++++++++++++++++++++++----------
drivers/char/tpm/tpm_crb.c | 6 +++-
drivers/char/tpm/tpm_crb_ffa.c | 18 ++----------
drivers/char/tpm/tpm_svsm.c | 2 +-
drivers/char/tpm/tpm_tis_core.c | 63 ++++++++++++++++++++++++++--------------
drivers/char/tpm/tpm_tis_core.h | 3 +-
8 files changed, 98 insertions(+), 60 deletions(-)
^ permalink raw reply
* Re: [PATCH] keys: trusted: dcp: Make dcp_trusted_key_ops const
From: Jarkko Sakkinen @ 2026-06-22 15:24 UTC (permalink / raw)
To: Berkay Yürekli
Cc: david, upstream+dcp, James.Bottomley, zohar, linux-integrity,
keyrings, linux-security-module
In-Reply-To: <CAMyZDTsA-m0R1Ziy74Ck0EPj8UFJhUw-vE0_ACrQ3hiLLaNaKQ@mail.gmail.com>
On Sun, Jun 21, 2026 at 09:05:40PM -0400, Berkay Yürekli wrote:
> Mark the dcp_trusted_key_ops structure as const to improve kernel
> self-protection. This structure contains function pointers that are
> initialized once during module initialization and never modified.
>
> Making function pointers read-only protects against memory corruption
> attacks where an attacker might overwrite these pointers to redirect
> execution flow, as recommended in Documentation/security/self-protection.rst.
>
> Signed-off-by: mcss <ps1296@owsa.nl>
full name please
>
> ---
> include/keys/trusted_dcp.h | 2 +-
> security/keys/trusted-keys/trusted_dcp.c | 2 +-
> 2 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/include/keys/trusted_dcp.h b/include/keys/trusted_dcp.h
> index 9aaa42075b40..8ee24f2d21ff 100644
> --- a/include/keys/trusted_dcp.h
> +++ b/include/keys/trusted_dcp.h
> @@ -6,6 +6,6 @@
> #ifndef TRUSTED_DCP_H
> #define TRUSTED_DCP_H
>
> -extern struct trusted_key_ops dcp_trusted_key_ops;
> +extern const struct trusted_key_ops dcp_trusted_key_ops;
>
> #endif
> diff --git a/security/keys/trusted-keys/trusted_dcp.c b/security/keys/
> trusted-keys/trusted_dcp.c
> index 7b6eb655df0c..f638078640f9 100644
> --- a/security/keys/trusted-keys/trusted_dcp.c
> +++ b/security/keys/trusted-keys/trusted_dcp.c
> @@ -347,7 +347,7 @@ static void trusted_dcp_exit(void)
> unregister_key_type(&key_type_trusted);
> }
>
> -struct trusted_key_ops dcp_trusted_key_ops = {
> +const struct trusted_key_ops dcp_trusted_key_ops = {
> .exit = trusted_dcp_exit,
> .init = trusted_dcp_init,
> .seal = trusted_dcp_seal,
> --
> 2.54.0
>
BR, Jarkko
^ permalink raw reply
* Re: [GIT PULL] TPM DEVICE DRIVER: for-next-tpm-7.2-rc1
From: Jarkko Sakkinen @ 2026-06-21 1:23 UTC (permalink / raw)
To: Linus Torvalds
Cc: Peter Huewe, Jason Gunthorpe, David Howells, keyrings,
linux-integrity, linux-kernel
In-Reply-To: <ajboiUkyqgZxHpZS@kernel.org>
Oh crap, sorry.
I'll resend with new tag for-next-tpm-7.2-rc1-2.
Discard.
BR, Jarkko
On Sat, Jun 20, 2026 at 10:22:49PM +0300, Jarkko Sakkinen wrote:
> The following changes since commit 0e0611827f3349d0a2ac121c023a6d3260dcecdb:
>
> Merge tag 'pull-fixes' of gitolite.kernel.org:pub/scm/linux/kernel/git/viro/vfs (2026-06-15 15:53:57 +0530)
>
> are available in the Git repository at:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd.git tags/for-next-tpm-7.2-rc1
>
> for you to fetch changes up to 67c53887ebcd425f0003e7068de12eab511f80a9:
>
> tpm: fix event_size output in tpm1_binary_bios_measurements_show (2026-06-15 15:19:45 +0300)
>
> ----------------------------------------------------------------
> Hi,
>
> Please, pull. This pull request contains only bug fixes.
>
> BR, Jarkko
>
> ----------------------------------------------------------------
> Baoli Zhang (1):
> tpm: restore timeout for key creation commands
>
> David Laight (1):
> keys: Replace strcpy(derived_buf, "AUTH_KEY") with strscpy(..., HASH_SIZE)
>
> David Windsor (1):
> tpm: svsm: constify tpm_chip_ops
>
> Eric Biggers (1):
> KEYS: encrypted: Remove unnecessary selection of CRYPTO_RNG
>
> Gui-Dong Han (1):
> KEYS: Use acquire when reading state in keyring search
>
> Gunnar Kudrjavets (1):
> tpm: Initialize name_size_alg for non-NULL name in tpm_buf_append_name()
>
> Jarkko Sakkinen (3):
> KEYS: fix overflow in keyctl_pkey_params_get_2()
> KEYS: trusted: Debugging as a feature
> tpm: tpm_tis_spi: Use wait_woken() in wait_for_tmp_stat()
>
> Jim Broadus (2):
> tpm: tpm_tis: store entire did_vid
> tpm: tpm_tis: Add settle time for some TPMs
>
> Len Bao (1):
> keys/trusted_keys: mark 'migratable' as __ro_after_init
>
> Michael Bommarito (1):
> tpm: tpm2-sessions: wait for async KPP completion in tpm_buf_append_salt
>
> Mohammed EL Kadiri (3):
> keys: prevent slab cache merging for key_jar
> keys: request_key: replace BUG with return -EINVAL
> keys: keyctl_pkey: replace BUG with return -EOPNOTSUPP
>
> Rafael J. Wysocki (1):
> tpm_crb: Check ACPI_COMPANION() against NULL during probe
>
> Shaomin Chen (1):
> keys: Pin request_key_auth payload in instantiate paths
>
> Thorsten Blum (2):
> keys: use kmalloc_flex in user_preparse
> tpm: fix event_size output in tpm1_binary_bios_measurements_show
>
> Yeoreum Yun (1):
> tpm: tpm_crb_ffa: revert defered_probed when tpm_crb_ffa is built-in
>
> Documentation/admin-guide/kernel-parameters.txt | 16 +++++++
> drivers/char/tpm/eventlog/tpm1.c | 4 +-
> drivers/char/tpm/tpm2-cmd.c | 6 +--
> drivers/char/tpm/tpm2-sessions.c | 56 ++++++++++++++++------
> drivers/char/tpm/tpm_crb.c | 6 ++-
> drivers/char/tpm/tpm_crb_ffa.c | 18 ++-----
> drivers/char/tpm/tpm_svsm.c | 2 +-
> drivers/char/tpm/tpm_tis_core.c | 63 ++++++++++++++++---------
> drivers/char/tpm/tpm_tis_core.h | 3 +-
> include/keys/request_key_auth-type.h | 2 +
> include/keys/trusted-type.h | 21 +++++----
> security/keys/Kconfig | 1 -
> security/keys/encrypted-keys/encrypted.c | 4 +-
> security/keys/internal.h | 2 +
> security/keys/key.c | 2 +-
> security/keys/keyctl.c | 24 +++++++---
> security/keys/keyctl_pkey.c | 14 ++++--
> security/keys/keyring.c | 2 +-
> security/keys/request_key.c | 2 +-
> security/keys/request_key_auth.c | 33 ++++++++++++-
> security/keys/trusted-keys/Kconfig | 23 +++++++++
> security/keys/trusted-keys/trusted_caam.c | 7 ++-
> security/keys/trusted-keys/trusted_core.c | 8 +++-
> security/keys/trusted-keys/trusted_tpm1.c | 44 +++++++++--------
> security/keys/user_defined.c | 2 +-
> 25 files changed, 256 insertions(+), 109 deletions(-)
^ permalink raw reply
* [GIT PULL] TPM DEVICE DRIVER: for-next-tpm-7.2-rc1
From: Jarkko Sakkinen @ 2026-06-20 19:22 UTC (permalink / raw)
To: Linus Torvalds
Cc: Peter Huewe, Jason Gunthorpe, David Howells, keyrings,
linux-integrity, linux-kernel
The following changes since commit 0e0611827f3349d0a2ac121c023a6d3260dcecdb:
Merge tag 'pull-fixes' of gitolite.kernel.org:pub/scm/linux/kernel/git/viro/vfs (2026-06-15 15:53:57 +0530)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd.git tags/for-next-tpm-7.2-rc1
for you to fetch changes up to 67c53887ebcd425f0003e7068de12eab511f80a9:
tpm: fix event_size output in tpm1_binary_bios_measurements_show (2026-06-15 15:19:45 +0300)
----------------------------------------------------------------
Hi,
Please, pull. This pull request contains only bug fixes.
BR, Jarkko
----------------------------------------------------------------
Baoli Zhang (1):
tpm: restore timeout for key creation commands
David Laight (1):
keys: Replace strcpy(derived_buf, "AUTH_KEY") with strscpy(..., HASH_SIZE)
David Windsor (1):
tpm: svsm: constify tpm_chip_ops
Eric Biggers (1):
KEYS: encrypted: Remove unnecessary selection of CRYPTO_RNG
Gui-Dong Han (1):
KEYS: Use acquire when reading state in keyring search
Gunnar Kudrjavets (1):
tpm: Initialize name_size_alg for non-NULL name in tpm_buf_append_name()
Jarkko Sakkinen (3):
KEYS: fix overflow in keyctl_pkey_params_get_2()
KEYS: trusted: Debugging as a feature
tpm: tpm_tis_spi: Use wait_woken() in wait_for_tmp_stat()
Jim Broadus (2):
tpm: tpm_tis: store entire did_vid
tpm: tpm_tis: Add settle time for some TPMs
Len Bao (1):
keys/trusted_keys: mark 'migratable' as __ro_after_init
Michael Bommarito (1):
tpm: tpm2-sessions: wait for async KPP completion in tpm_buf_append_salt
Mohammed EL Kadiri (3):
keys: prevent slab cache merging for key_jar
keys: request_key: replace BUG with return -EINVAL
keys: keyctl_pkey: replace BUG with return -EOPNOTSUPP
Rafael J. Wysocki (1):
tpm_crb: Check ACPI_COMPANION() against NULL during probe
Shaomin Chen (1):
keys: Pin request_key_auth payload in instantiate paths
Thorsten Blum (2):
keys: use kmalloc_flex in user_preparse
tpm: fix event_size output in tpm1_binary_bios_measurements_show
Yeoreum Yun (1):
tpm: tpm_crb_ffa: revert defered_probed when tpm_crb_ffa is built-in
Documentation/admin-guide/kernel-parameters.txt | 16 +++++++
drivers/char/tpm/eventlog/tpm1.c | 4 +-
drivers/char/tpm/tpm2-cmd.c | 6 +--
drivers/char/tpm/tpm2-sessions.c | 56 ++++++++++++++++------
drivers/char/tpm/tpm_crb.c | 6 ++-
drivers/char/tpm/tpm_crb_ffa.c | 18 ++-----
drivers/char/tpm/tpm_svsm.c | 2 +-
drivers/char/tpm/tpm_tis_core.c | 63 ++++++++++++++++---------
drivers/char/tpm/tpm_tis_core.h | 3 +-
include/keys/request_key_auth-type.h | 2 +
include/keys/trusted-type.h | 21 +++++----
security/keys/Kconfig | 1 -
security/keys/encrypted-keys/encrypted.c | 4 +-
security/keys/internal.h | 2 +
security/keys/key.c | 2 +-
security/keys/keyctl.c | 24 +++++++---
security/keys/keyctl_pkey.c | 14 ++++--
security/keys/keyring.c | 2 +-
security/keys/request_key.c | 2 +-
security/keys/request_key_auth.c | 33 ++++++++++++-
security/keys/trusted-keys/Kconfig | 23 +++++++++
security/keys/trusted-keys/trusted_caam.c | 7 ++-
security/keys/trusted-keys/trusted_core.c | 8 +++-
security/keys/trusted-keys/trusted_tpm1.c | 44 +++++++++--------
security/keys/user_defined.c | 2 +-
25 files changed, 256 insertions(+), 109 deletions(-)
^ permalink raw reply
* Re: [GIT PULL] TPM DEVICE DRIVER: for-next-keys-7.2-rc1
From: pr-tracker-bot @ 2026-06-19 19:24 UTC (permalink / raw)
To: Jarkko Sakkinen
Cc: Linus Torvalds, Peter Huewe, Jason Gunthorpe, David Howells,
keyrings, linux-integrity, linux-kernel
In-Reply-To: <ajSR22PC_X6HWjo2@kernel.org>
The pull request you sent on Fri, 19 Jun 2026 03:48:27 +0300:
> git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd.git tags/for-next-keys-7.2-rc1
has been merged into torvalds/linux.git:
https://git.kernel.org/torvalds/c/e2c0595b56e9526e67ddd228fc35fa9ff20724ec
Thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/prtracker.html
^ permalink raw reply
* Re: [GIT PULL] integrity: subsystem fixes for v7.2
From: pr-tracker-bot @ 2026-06-19 19:24 UTC (permalink / raw)
To: Mimi Zohar; +Cc: Linus Torvalds, linux-integrity, linux-kernel, Roberto Sassu
In-Reply-To: <2a5a07ef24454c295c3a63ae8cedcd6c47578101.camel@linux.ibm.com>
The pull request you sent on Thu, 18 Jun 2026 10:06:01 -0400:
> https://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity.git/ tags/integrity-v7.2
has been merged into torvalds/linux.git:
https://git.kernel.org/torvalds/c/0798268aa4c26ece25020b3ddeeef9a5941209c0
Thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/prtracker.html
^ permalink raw reply
* [PATCH] ima: correctly recover number of violations after kexec
From: Enrico Bravi @ 2026-06-19 19:14 UTC (permalink / raw)
To: linux-integrity, zohar, dmitry.kasatkin, roberto.sassu
Cc: eric.snowberg, Enrico Bravi
When recovering the measurement list after kexec(), the number of
violations is not recovered as well, causing a mismatch between the
number reported by the <securityfs>/ima/violations user interface and
the actual value. In addition, currently it is assumed that when
recovering an entry, this is a violation if the template data hash
read from the kexec buffer is an all-zero hash, which can actually be a
valid hash.
Verify that an all-zero hash corresponds to a violation and consequently
correctly recover the number of violations.
Reported-by: Roberto Sassu <roberto.sassu@huawei.com>
Closes: https://github.com/linux-integrity/linux/issues/13
Signed-off-by: Enrico Bravi <enrico.bravi@polito.it>
---
security/integrity/ima/ima_template.c | 28 ++++++++++++++++++++-------
1 file changed, 21 insertions(+), 7 deletions(-)
diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c
index 7034573fb41e..147f228ed246 100644
--- a/security/integrity/ima/ima_template.c
+++ b/security/integrity/ima/ima_template.c
@@ -430,6 +430,7 @@ int ima_restore_measurement_list(loff_t size, void *buf)
DECLARE_BITMAP(hdr_mask, HDR__LAST);
unsigned long count = 0;
int ret = 0;
+ int i;
if (!buf || size < sizeof(*khdr))
return 0;
@@ -515,15 +516,28 @@ int ima_restore_measurement_list(loff_t size, void *buf)
if (ret < 0)
break;
- if (memcmp(hdr[HDR_DIGEST].data, zero, sizeof(zero))) {
- ret = ima_calc_field_array_hash(
- &entry->template_data[0],
+ ret = ima_calc_field_array_hash(&entry->template_data[0],
entry);
- if (ret < 0) {
- pr_err("cannot calculate template digest\n");
- ret = -EINVAL;
- break;
+ if (ret < 0) {
+ pr_err("cannot calculate template digest\n");
+ ret = -EINVAL;
+ break;
+ }
+
+ if (!memcmp(hdr[HDR_DIGEST].data, zero, sizeof(zero)) &&
+ memcmp(entry->digests[ima_sha1_idx].digest, zero, sizeof(zero))) {
+ for (i = 0; i < NR_BANKS(ima_tpm_chip) + ima_extra_slots; i++) {
+ /* Unmapped TPM algorithms */
+ if (!ima_algo_array[i].tfm) {
+ memset(entry->digests[i].digest, 0,
+ TPM_DIGEST_SIZE);
+ continue;
+ }
+
+ memset(entry->digests[i].digest, 0,
+ ima_algo_array[i].digest_size);
}
+ atomic_long_inc(&ima_htable.violations);
}
entry->pcr = !ima_canonical_fmt ? *(u32 *)(hdr[HDR_PCR].data) :
base-commit: 8cd9520d35a6c38db6567e97dd93b1f11f185dc6
--
2.52.0
^ permalink raw reply related
* Re: [PATCH bpf-next v3 1/2] bpf: add bpf_init_inode_xattr kfunc for atomic inode labeling
From: Christian Brauner @ 2026-06-19 10:25 UTC (permalink / raw)
To: David Windsor
Cc: viro, jack, ast, daniel, john.fastabend, andrii, eddyz87, memxor,
martin.lau, song, yonghong.song, jolsa, emil, kpsingh,
mattbobrowski, paul, jmorris, serge, zohar, roberto.sassu,
dmitry.kasatkin, eric.snowberg, stephen.smalley.work, omosnace,
casey, shuah, linux-kernel, linux-fsdevel, bpf,
linux-security-module, linux-integrity, selinux, linux-kselftest
In-Reply-To: <20260618203411.73917-2-dwindsor@gmail.com>
On Thu, Jun 18, 2026 at 04:34:10PM -0400, David Windsor wrote:
> 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 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
> xattr_ctx.
>
> A previous attempt [1] required a kmalloc string output protocol for
> the xattr name. Since commit 6bcdfd2cac55 ("security: Allow all LSMs to
> provide xattrs for inode_init_security hook") [2], the xattr name is no
> longer allocated; it is a static constant.
>
> 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.
>
> Link: https://kernsec.org/pipermail/linux-security-module-archive/2022-October/034878.html [1]
> Link: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=6bcdfd2cac55 [2]
> Suggested-by: Song Liu <song@kernel.org>
> Signed-off-by: David Windsor <dwindsor@gmail.com>
> ---
> fs/bpf_fs_kfuncs.c | 106 +++++++++++++++++++++++++++++-
Please split this into the VFS changes and lsm changes required for
this. The api change to the lsm layer can be done independently of any
of the actual VFS level wiring. Will also make it a lot nicer to
review...
^ permalink raw reply
* [GIT PULL] KEYS: for-next-keys-7.2-rc1-2
From: Jarkko Sakkinen @ 2026-06-19 0:51 UTC (permalink / raw)
To: Linus Torvalds
Cc: David Howells, Herbert Xu, David S. Miller, keyrings,
linux-integrity
The following changes since commit 0e0611827f3349d0a2ac121c023a6d3260dcecdb:
Merge tag 'pull-fixes' of gitolite.kernel.org:pub/scm/linux/kernel/git/viro/vfs (2026-06-15 15:53:57 +0530)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd.git tags/for-next-keys-7.2-rc1-2
for you to fetch changes up to 1b9524250996b1f2f49833a1b2ae21c34e486f85:
keys: keyctl_pkey: replace BUG with return -EOPNOTSUPP (2026-06-15 15:19:13 +0300)
----------------------------------------------------------------
Hi,
Please, pull. This pull request contains only bug fixes.
BR, Jarkko
----------------------------------------------------------------
David Laight (1):
keys: Replace strcpy(derived_buf, "AUTH_KEY") with strscpy(..., HASH_SIZE)
Eric Biggers (1):
KEYS: encrypted: Remove unnecessary selection of CRYPTO_RNG
Gui-Dong Han (1):
KEYS: Use acquire when reading state in keyring search
Jarkko Sakkinen (2):
KEYS: fix overflow in keyctl_pkey_params_get_2()
KEYS: trusted: Debugging as a feature
Len Bao (1):
keys/trusted_keys: mark 'migratable' as __ro_after_init
Mohammed EL Kadiri (3):
keys: prevent slab cache merging for key_jar
keys: request_key: replace BUG with return -EINVAL
keys: keyctl_pkey: replace BUG with return -EOPNOTSUPP
Shaomin Chen (1):
keys: Pin request_key_auth payload in instantiate paths
Thorsten Blum (1):
keys: use kmalloc_flex in user_preparse
Documentation/admin-guide/kernel-parameters.txt | 16 +++++++++
include/keys/request_key_auth-type.h | 2 ++
include/keys/trusted-type.h | 21 +++++++-----
security/keys/Kconfig | 1 -
security/keys/encrypted-keys/encrypted.c | 4 +--
security/keys/internal.h | 2 ++
security/keys/key.c | 2 +-
security/keys/keyctl.c | 24 ++++++++++----
security/keys/keyctl_pkey.c | 14 ++++++--
security/keys/keyring.c | 2 +-
security/keys/request_key.c | 2 +-
security/keys/request_key_auth.c | 33 +++++++++++++++++--
security/keys/trusted-keys/Kconfig | 23 +++++++++++++
security/keys/trusted-keys/trusted_caam.c | 7 ++--
security/keys/trusted-keys/trusted_core.c | 8 ++++-
security/keys/trusted-keys/trusted_tpm1.c | 44 ++++++++++++++-----------
security/keys/user_defined.c | 2 +-
17 files changed, 158 insertions(+), 49 deletions(-)
^ permalink raw reply
* Re: [GIT PULL] TPM DEVICE DRIVER: for-next-keys-7.2-rc1
From: Jarkko Sakkinen @ 2026-06-19 0:49 UTC (permalink / raw)
To: Linus Torvalds
Cc: Peter Huewe, Jason Gunthorpe, David Howells, keyrings,
linux-integrity, linux-kernel
OOPS please ignore I'll resend this!
Wrong template apologies.
BR, Jarkko
On Fri, Jun 19, 2026 at 12:47:08AM +0000, jarkko@kernel.org wrote:
> The following changes since commit 0e0611827f3349d0a2ac121c023a6d3260dcecdb:
>
> Merge tag 'pull-fixes' of gitolite.kernel.org:pub/scm/linux/kernel/git/viro/vfs (2026-06-15 15:53:57 +0530)
>
> are available in the Git repository at:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd.git tags/for-next-keys-7.2-rc1
>
> for you to fetch changes up to 1b9524250996b1f2f49833a1b2ae21c34e486f85:
>
> keys: keyctl_pkey: replace BUG with return -EOPNOTSUPP (2026-06-15 15:19:13 +0300)
>
> ----------------------------------------------------------------
> Hi
>
> Please, pull. This pull request contains only fixes.
>
> BR, Jarkko
>
> ----------------------------------------------------------------
> David Laight (1):
> keys: Replace strcpy(derived_buf, "AUTH_KEY") with strscpy(..., HASH_SIZE)
>
> Eric Biggers (1):
> KEYS: encrypted: Remove unnecessary selection of CRYPTO_RNG
>
> Gui-Dong Han (1):
> KEYS: Use acquire when reading state in keyring search
>
> Jarkko Sakkinen (2):
> KEYS: fix overflow in keyctl_pkey_params_get_2()
> KEYS: trusted: Debugging as a feature
>
> Len Bao (1):
> keys/trusted_keys: mark 'migratable' as __ro_after_init
>
> Mohammed EL Kadiri (3):
> keys: prevent slab cache merging for key_jar
> keys: request_key: replace BUG with return -EINVAL
> keys: keyctl_pkey: replace BUG with return -EOPNOTSUPP
>
> Shaomin Chen (1):
> keys: Pin request_key_auth payload in instantiate paths
>
> Thorsten Blum (1):
> keys: use kmalloc_flex in user_preparse
>
> Documentation/admin-guide/kernel-parameters.txt | 16 +++++++++
> include/keys/request_key_auth-type.h | 2 ++
> include/keys/trusted-type.h | 21 +++++++-----
> security/keys/Kconfig | 1 -
> security/keys/encrypted-keys/encrypted.c | 4 +--
> security/keys/internal.h | 2 ++
> security/keys/key.c | 2 +-
> security/keys/keyctl.c | 24 ++++++++++----
> security/keys/keyctl_pkey.c | 14 ++++++--
> security/keys/keyring.c | 2 +-
> security/keys/request_key.c | 2 +-
> security/keys/request_key_auth.c | 33 +++++++++++++++++--
> security/keys/trusted-keys/Kconfig | 23 +++++++++++++
> security/keys/trusted-keys/trusted_caam.c | 7 ++--
> security/keys/trusted-keys/trusted_core.c | 8 ++++-
> security/keys/trusted-keys/trusted_tpm1.c | 44 ++++++++++++++-----------
> security/keys/user_defined.c | 2 +-
> 17 files changed, 158 insertions(+), 49 deletions(-)
^ permalink raw reply
* [GIT PULL] TPM DEVICE DRIVER: for-next-keys-7.2-rc1
From: Jarkko Sakkinen @ 2026-06-19 0:48 UTC (permalink / raw)
To: Linus Torvalds
Cc: Peter Huewe, Jason Gunthorpe, David Howells, keyrings,
linux-integrity, linux-kernel
The following changes since commit 0e0611827f3349d0a2ac121c023a6d3260dcecdb:
Merge tag 'pull-fixes' of gitolite.kernel.org:pub/scm/linux/kernel/git/viro/vfs (2026-06-15 15:53:57 +0530)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd.git tags/for-next-keys-7.2-rc1
for you to fetch changes up to 1b9524250996b1f2f49833a1b2ae21c34e486f85:
keys: keyctl_pkey: replace BUG with return -EOPNOTSUPP (2026-06-15 15:19:13 +0300)
----------------------------------------------------------------
Hi
Please, pull. This pull request contains only fixes.
BR, Jarkko
----------------------------------------------------------------
David Laight (1):
keys: Replace strcpy(derived_buf, "AUTH_KEY") with strscpy(..., HASH_SIZE)
Eric Biggers (1):
KEYS: encrypted: Remove unnecessary selection of CRYPTO_RNG
Gui-Dong Han (1):
KEYS: Use acquire when reading state in keyring search
Jarkko Sakkinen (2):
KEYS: fix overflow in keyctl_pkey_params_get_2()
KEYS: trusted: Debugging as a feature
Len Bao (1):
keys/trusted_keys: mark 'migratable' as __ro_after_init
Mohammed EL Kadiri (3):
keys: prevent slab cache merging for key_jar
keys: request_key: replace BUG with return -EINVAL
keys: keyctl_pkey: replace BUG with return -EOPNOTSUPP
Shaomin Chen (1):
keys: Pin request_key_auth payload in instantiate paths
Thorsten Blum (1):
keys: use kmalloc_flex in user_preparse
Documentation/admin-guide/kernel-parameters.txt | 16 +++++++++
include/keys/request_key_auth-type.h | 2 ++
include/keys/trusted-type.h | 21 +++++++-----
security/keys/Kconfig | 1 -
security/keys/encrypted-keys/encrypted.c | 4 +--
security/keys/internal.h | 2 ++
security/keys/key.c | 2 +-
security/keys/keyctl.c | 24 ++++++++++----
security/keys/keyctl_pkey.c | 14 ++++++--
security/keys/keyring.c | 2 +-
security/keys/request_key.c | 2 +-
security/keys/request_key_auth.c | 33 +++++++++++++++++--
security/keys/trusted-keys/Kconfig | 23 +++++++++++++
security/keys/trusted-keys/trusted_caam.c | 7 ++--
security/keys/trusted-keys/trusted_core.c | 8 ++++-
security/keys/trusted-keys/trusted_tpm1.c | 44 ++++++++++++++-----------
security/keys/user_defined.c | 2 +-
17 files changed, 158 insertions(+), 49 deletions(-)
^ permalink raw reply
* Re: inherit null-key across hibernate (was: Re: regression: kernel log "flooded" with tpm tpm0: A TPM error (2306) occurred attempting to create NULL primary)
From: Jarkko Sakkinen @ 2026-06-19 0:38 UTC (permalink / raw)
To: Daniel Golle; +Cc: James Bottomley, Christoph Anton Mitterer, linux-integrity
In-Reply-To: <ajDIDcW_EzgLB0qX@makrotopia.org>
On Tue, Jun 16, 2026 at 04:50:37AM +0100, Daniel Golle wrote:
> Hi Jarkko,
> Hi James,
>
> first of all, sorry for hijacking a thread from 2 years ago.
>
> On Thu, Nov 14, 2024 at 12:34:30AM +0200, Jarkko Sakkinen wrote:
> > On Wed Nov 13, 2024 at 8:12 PM EET, James Bottomley wrote:
> > > > I think we might have to expect the NULL name to change on actual
> > > > hibernation because unlike suspend to ram it does power off the TPM.
> > >
> > > I checked the code: we're coming in on the correct path to renew the
> > > null seed after hibernation, so it should all work. The problem seems
> > > to be that your TPM itself is doing something invalid because the name
> > > we calculate for the primary key doesn't match what your TPM says it
> > > should be. Absent some form of attack or bus integrity problem, that
> > > shouldn't ever happen, so I'm even more curious to know why it worked
> > > in 6.11.5 and before and whether current upstream works.
> > >
> > > I haven't found it yet, but I think the every 10s signature is because
> > > the hibernation path is trying to restart the TPM device and won't take
> > > no for an answer.
> >
> > My fix returned the behavior how it was before my earlier fix in this
> > corner case (i.e. disable TPM). The issue has gone unnoticed before
> > since it has emitted only a single klog entry.
> >
> > On suspend this has not happened to me so obvious deduction is that
> > hibernate resets the null seed.
> >
> > Hibernate needs an addition a fix to disable bus encryption from kernel
> > command-line completely, i.e. tpm.disable_integrity following the
> > convention from my earlier fix [1].
>
> I'd like to offer a way it might be resolvable with the null key after
> all, without provisioning a persistent NV key -- by changing the
> question from "re-derive the null primary and compare" to "inherit the
> trust the resume has already established".
>
> Resume-from-hibernation is a TPM Restart (Shutdown(STATE) ->
> Startup(CLEAR)), i.e. a firmware cold-init of the (f)TPM, after which
> the boot/initramfs kernel establishes a fresh, genuine null primary.
> In the common configuration (FDE with the resume/swap device inside
> a TPM-sealed LUKS2 container) that same TPM has, moments earlier and
> *before* the hibernation image is restored, cryptographically attested
> itself by unsealing the resume device. A substituted or interposed TPM
> cannot produce that unseal.
>
> So rather than letting the resumed kernel re-derive the null name,
> find a mismatch and disable the chip, the boot kernel's
> freshly-established and unseal-validated null primary could be
> inherited by the resumed image. The existing null-seed TOFU model is
> preserved; nothing new is provisioned.
>
> The gate is the unseal, and the adversary case shows why it is the
> right gate:
>
> Malice swaps (or interposes on) the TPM while the machine is
> hibernated, then leaves. Alice powers on. The initramfs attempts the
> TPM unseal of the resume device; with a foreign TPM it fails, so
> systemd-cryptsetup falls back to the passphrase, which Alice --
> seeing a prompt -- types. The disk opens and the system resumes.
>
> If trust were re-established here, Alice would have personally vouched
> for Malice's TPM. But the unseal *failed*, so under this scheme
> nothing is inherited and the chip stays fail-closed exactly as today.
> The passphrase proves a human is present; it never proves the TPM is
> the genuine one.
> Hence: unseal succeeded -> inherit the validated null primary;
> passphrase fallback -> trust is lost, stay disabled.
>
> This keeps the property the null-seed design wants -- an in-session
> reset is not on the hibernate-restore path and is still caught --
> while removing the false positive only where the platform has already
> re-attested the TPM.
>
> The hard parts, and where I'd value direction:
>
> - systemd-cryptsetup would need to signal "the resume device was
> unsealed by the TPM this boot" (vs. the passphrase fallback).
> This is per-resume runtime state; a static command-line parameter
> (and obviously build-time config as well) cannot represent it.
>
> - the validated null primary has to cross the boot -> resumed memory
> discontinuity (the initramfs kernel's state is overwritten by the
> restored image). Boot and image kernel are the same binary, so
> patching chip->null_key_name in the restored image is mechanically
> possible; a small reserved/nosave hand-off area may be cleaner.
> I don't know the hibernate path well enough to say which is right.
>
> It is admittedly cross-subsystem (tpm + pm/hibernate +
> systemd/cryptsetup), which is presumably why it hasn't been done.
> Compared with the persistent NV-key route
> (tpm.integrity_key=<handle>): that avoids the carry-across but needs
> the key provisioned and managed, and a persistent key's name no longer
> changes on a genuine reset, so the implicit reset detection has to be
> reconstructed. The null-key-inherit approach keeps the existing model
> and defers "is this the same TPM?" to the unseal that has already
> happened.
>
> Does this seem viable, or is there a reason the unseal-as-attestation
> gate does not hold that I'm missing?
>
> (For motivation: on a firmware TPM -- Intel PTT here -- there is no
> external bus to interpose, so the protection has no benefit on this
> class of hardware at all, yet the legitimate hibernation power-cycle
> still trips the disable. For fTPMs specifically, not enabling the
> feature is arguably the better answer; but for discrete TPMs that
> hibernate, a real solution seems a good idea if doable.)
I think this has at least changed since 2024: bootc container type
of deployment is where you can realistically configure hibernate,
and use it in a real application.
>
>
> Cheers
>
>
> Daniel
BR, Jarkko
^ permalink raw reply
* Re: [PATCH bpf-next v3 1/2] bpf: add bpf_init_inode_xattr kfunc for atomic inode labeling
From: David Windsor @ 2026-06-18 22:50 UTC (permalink / raw)
To: bot+bpf-ci
Cc: viro, brauner, jack, ast, daniel, john.fastabend, andrii, eddyz87,
memxor, martin.lau, song, yonghong.song, jolsa, emil, kpsingh,
mattbobrowski, paul, jmorris, serge, zohar, roberto.sassu,
dmitry.kasatkin, eric.snowberg, stephen.smalley.work, omosnace,
casey, shuah, linux-kernel, linux-fsdevel, bpf,
linux-security-module, linux-integrity, selinux, linux-kselftest,
martin.lau, clm, ihor.solodrai
In-Reply-To: <e9ec622a8a49be299cbbfd459e2fc10693bcd65c6dbf00c9e2645281564e5579@mail.kernel.org>
On Thu, Jun 18, 2026 at 5:22 PM <bot+bpf-ci@kernel.org> wrote:
>
> [ ... ]
> >
> > +struct xattr_ctx {
> > + struct xattr *xattrs;
> > + int *xattr_count;
> > +};
> > +
>
> Paul Moore suggested in v2 renaming this to 'struct lsm_xattrs' to avoid
> overloading the term 'ctx' in the LSM space. The struct was renamed from
> 'lsm_xattr_ctx' to 'xattr_ctx' in v3, but 'ctx' is still in the name. Was
> there a reason to keep 'ctx' in the name, or would renaming to 'lsm_xattrs'
> as Paul suggested be preferable?
>
Indeed he did; I mistakenly inverted his original request.
Will send a fix for this, as well as converting GFP_KERNEL to GFP_NOFS
in the allocation in __bpf_init_inode_xattr.
> > /* 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 564071a92d7d..86a8e188b900 100644
> > --- a/kernel/bpf/bpf_lsm.c
> > +++ b/kernel/bpf/bpf_lsm.c
> > @@ -113,6 +113,9 @@ void bpf_lsm_find_cgroup_shim(const struct bpf_prog *prog,
> > }
> > #endif
> >
> > +BTF_ID_LIST_SINGLE(bpf_lsm_inode_init_security_btf_ids, func,
> > + bpf_lsm_inode_init_security)
> > +
> > int bpf_lsm_verify_prog(struct bpf_verifier_log *vlog,
> > const struct bpf_prog *prog)
> > {
> > @@ -137,6 +140,12 @@ int bpf_lsm_verify_prog(struct bpf_verifier_log *vlog,
> > return -EINVAL;
> > }
> >
> > + /* bpf reserves a fixed number of xattr slots for itself.
> > + * Set the attach limit so the trampoline rejects excess attaches.
> > + */
>
> This isn't a bug, but a subsystem pattern flags this as potentially
> concerning: the BPF subsystem comment-style rule for files under kernel/bpf/
> requires multi-line comments to have the opening /* on its own line, with
> comment text starting on the next line. The preferred form would be:
>
> /*
> * bpf reserves a fixed number of xattr slots for itself.
> * Set the attach limit so the trampoline rejects excess attaches.
> */
>
> > + if (btf_id == bpf_lsm_inode_init_security_btf_ids[0])
> > + prog->aux->attach_limit = BPF_LSM_INODE_INIT_XATTRS;
> > +
> > return 0;
> > }
> >
>
> [ ... ]
>
>
> ---
> AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
> See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
>
> CI run summary: https://github.com/kernel-patches/bpf/actions/runs/27788616397
^ permalink raw reply
* Re: [PATCH bpf-next v3 1/2] bpf: add bpf_init_inode_xattr kfunc for atomic inode labeling
From: bot+bpf-ci @ 2026-06-18 21:22 UTC (permalink / raw)
To: dwindsor, viro, brauner, jack, ast, daniel, john.fastabend,
andrii, eddyz87, memxor, martin.lau, song, yonghong.song, jolsa,
emil, kpsingh, mattbobrowski, paul, jmorris, serge, zohar,
roberto.sassu, dmitry.kasatkin, eric.snowberg,
stephen.smalley.work, omosnace, casey, shuah
Cc: linux-kernel, linux-fsdevel, bpf, linux-security-module,
linux-integrity, selinux, linux-kselftest, dwindsor, ast, andrii,
daniel, martin.lau, eddyz87, yonghong.song, clm, ihor.solodrai
In-Reply-To: <20260618203411.73917-2-dwindsor@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 2507 bytes --]
> diff --git a/fs/bpf_fs_kfuncs.c b/fs/bpf_fs_kfuncs.c
> index 768aca2dc0f0..7abc3f3d1a67 100644
> --- a/fs/bpf_fs_kfuncs.c
> +++ b/fs/bpf_fs_kfuncs.c
[ ... ]
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 153e9043058f..1f8e84e7dd7e 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -68,6 +68,11 @@ struct watch;
> struct watch_notification;
> struct lsm_ctx;
>
> +struct xattr_ctx {
> + struct xattr *xattrs;
> + int *xattr_count;
> +};
> +
Paul Moore suggested in v2 renaming this to 'struct lsm_xattrs' to avoid
overloading the term 'ctx' in the LSM space. The struct was renamed from
'lsm_xattr_ctx' to 'xattr_ctx' in v3, but 'ctx' is still in the name. Was
there a reason to keep 'ctx' in the name, or would renaming to 'lsm_xattrs'
as Paul suggested be preferable?
> /* 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 564071a92d7d..86a8e188b900 100644
> --- a/kernel/bpf/bpf_lsm.c
> +++ b/kernel/bpf/bpf_lsm.c
> @@ -113,6 +113,9 @@ void bpf_lsm_find_cgroup_shim(const struct bpf_prog *prog,
> }
> #endif
>
> +BTF_ID_LIST_SINGLE(bpf_lsm_inode_init_security_btf_ids, func,
> + bpf_lsm_inode_init_security)
> +
> int bpf_lsm_verify_prog(struct bpf_verifier_log *vlog,
> const struct bpf_prog *prog)
> {
> @@ -137,6 +140,12 @@ int bpf_lsm_verify_prog(struct bpf_verifier_log *vlog,
> return -EINVAL;
> }
>
> + /* bpf reserves a fixed number of xattr slots for itself.
> + * Set the attach limit so the trampoline rejects excess attaches.
> + */
This isn't a bug, but a subsystem pattern flags this as potentially
concerning: the BPF subsystem comment-style rule for files under kernel/bpf/
requires multi-line comments to have the opening /* on its own line, with
comment text starting on the next line. The preferred form would be:
/*
* bpf reserves a fixed number of xattr slots for itself.
* Set the attach limit so the trampoline rejects excess attaches.
*/
> + if (btf_id == bpf_lsm_inode_init_security_btf_ids[0])
> + prog->aux->attach_limit = BPF_LSM_INODE_INIT_XATTRS;
> +
> return 0;
> }
>
[ ... ]
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/27788616397
^ permalink raw reply
* [PATCH bpf-next v3 2/2] selftests/bpf: add tests for bpf_init_inode_xattr kfunc
From: David Windsor @ 2026-06-18 20:34 UTC (permalink / raw)
To: viro, brauner, jack, ast, daniel, john.fastabend, andrii, eddyz87,
memxor, martin.lau, song, yonghong.song, jolsa, emil, kpsingh,
mattbobrowski, paul, jmorris, serge, zohar, roberto.sassu,
dmitry.kasatkin, eric.snowberg, stephen.smalley.work, omosnace,
casey, shuah
Cc: linux-kernel, linux-fsdevel, bpf, linux-security-module,
linux-integrity, selinux, linux-kselftest, David Windsor
In-Reply-To: <20260618203411.73917-1-dwindsor@gmail.com>
Test bpf atomic inode xattr labeling in inode_init_security.
Signed-off-by: David Windsor <dwindsor@gmail.com>
---
tools/testing/selftests/bpf/bpf_kfuncs.h | 5 +
.../selftests/bpf/prog_tests/fs_kfuncs.c | 105 +++++++++++++++++-
.../bpf/progs/test_init_inode_xattr.c | 31 ++++++
3 files changed, 140 insertions(+), 1 deletion(-)
create mode 100644 tools/testing/selftests/bpf/progs/test_init_inode_xattr.c
diff --git a/tools/testing/selftests/bpf/bpf_kfuncs.h b/tools/testing/selftests/bpf/bpf_kfuncs.h
index ae71e9b69051..69d3641ee2d8 100644
--- a/tools/testing/selftests/bpf/bpf_kfuncs.h
+++ b/tools/testing/selftests/bpf/bpf_kfuncs.h
@@ -92,4 +92,9 @@ extern int bpf_set_dentry_xattr(struct dentry *dentry, const char *name__str,
const struct bpf_dynptr *value_p, int flags) __ksym __weak;
extern int bpf_remove_dentry_xattr(struct dentry *dentry, const char *name__str) __ksym __weak;
+struct xattr_ctx;
+extern int bpf_init_inode_xattr(struct xattr_ctx *xattr_ctx,
+ const char *name__str,
+ const struct bpf_dynptr *value_p) __ksym __weak;
+
#endif
diff --git a/tools/testing/selftests/bpf/prog_tests/fs_kfuncs.c b/tools/testing/selftests/bpf/prog_tests/fs_kfuncs.c
index 43a26ec69a8e..0898898fb125 100644
--- a/tools/testing/selftests/bpf/prog_tests/fs_kfuncs.c
+++ b/tools/testing/selftests/bpf/prog_tests/fs_kfuncs.c
@@ -9,9 +9,10 @@
#include <test_progs.h>
#include "test_get_xattr.skel.h"
#include "test_set_remove_xattr.skel.h"
+#include "test_init_inode_xattr.skel.h"
#include "test_fsverity.skel.h"
-static const char testfile[] = "/tmp/test_progs_fs_kfuncs";
+static const char testfile[] = "/tmp/labelme";
static void test_get_xattr(const char *name, const char *value, bool allow_access)
{
@@ -268,6 +269,102 @@ static void test_fsverity(void)
remove(testfile);
}
+static void test_init_inode_xattr(void)
+{
+ struct test_init_inode_xattr *skel = NULL;
+ int fd = -1, err;
+ char value_out[64];
+ const char *testfile_new = "/tmp/test_progs_fs_kfuncs_new";
+
+ skel = test_init_inode_xattr__open_and_load();
+ if (!ASSERT_OK_PTR(skel, "test_init_inode_xattr__open_and_load"))
+ return;
+
+ skel->bss->monitored_pid = getpid();
+ err = test_init_inode_xattr__attach(skel);
+ if (!ASSERT_OK(err, "test_init_inode_xattr__attach"))
+ goto out;
+
+ /* Trigger inode_init_security */
+ fd = open(testfile_new, O_CREAT | O_RDWR, 0644);
+ if (!ASSERT_GE(fd, 0, "create_file"))
+ goto out;
+
+ ASSERT_EQ(skel->data->init_result, 0, "init_result");
+
+ /* initxattrs prepends "security." to the name. */
+ err = getxattr(testfile_new, "security.bpf.test_label", value_out,
+ sizeof(value_out));
+ if (err < 0 && errno == ENODATA) {
+ printf("%s:SKIP:filesystem did not apply LSM xattrs\n",
+ __func__);
+ test__skip();
+ goto out;
+ }
+ if (!ASSERT_GE(err, 0, "getxattr"))
+ goto out;
+
+ ASSERT_EQ(err, (int)sizeof(skel->data->xattr_value), "xattr_size");
+ ASSERT_EQ(strncmp(value_out, "unconfined_u:object_r:user_home_t:s0",
+ sizeof("unconfined_u:object_r:user_home_t:s0")), 0,
+ "xattr_value");
+
+out:
+ close(fd);
+ test_init_inode_xattr__destroy(skel);
+ remove(testfile_new);
+}
+
+/* Keep in sync with BPF_LSM_INODE_INIT_XATTRS in include/linux/bpf_lsm.h. */
+#define INIT_INODE_XATTR_MAX 4
+
+/* At most INIT_INODE_XATTR_MAX programs can attach to inode_init_security. */
+static void test_init_inode_xattr_attach_cap(void)
+{
+ struct test_init_inode_xattr *skel[INIT_INODE_XATTR_MAX + 1] = {};
+ struct bpf_link *link[INIT_INODE_XATTR_MAX + 1] = {};
+ struct bpf_link *extra = NULL;
+ int i, err;
+
+ /* Fill all available xattr slots */
+ for (i = 0; i < INIT_INODE_XATTR_MAX; i++) {
+ skel[i] = test_init_inode_xattr__open_and_load();
+ if (!ASSERT_OK_PTR(skel[i], "open_and_load"))
+ goto out;
+
+ link[i] = bpf_program__attach_lsm(skel[i]->progs.test_init_inode_xattr);
+ if (!ASSERT_OK_PTR(link[i], "attach_within_cap"))
+ goto out;
+ }
+
+ skel[INIT_INODE_XATTR_MAX] = test_init_inode_xattr__open_and_load();
+ if (!ASSERT_OK_PTR(skel[INIT_INODE_XATTR_MAX], "open_and_load_extra"))
+ goto out;
+
+ /* New additions fail with -E2BIG */
+ extra = bpf_program__attach_lsm(skel[INIT_INODE_XATTR_MAX]->progs.test_init_inode_xattr);
+ err = -errno;
+ if (!ASSERT_ERR_PTR(extra, "attach_over_cap_should_fail")) {
+ bpf_link__destroy(extra);
+ goto out;
+ }
+ ASSERT_EQ(err, -E2BIG, "attach_over_cap_errno");
+
+ bpf_link__destroy(link[0]);
+ link[0] = NULL; /* avoid double free in cleanup */
+
+ /* Freeing a slot lets the extra program attach */
+ extra = bpf_program__attach_lsm(skel[INIT_INODE_XATTR_MAX]->progs.test_init_inode_xattr);
+ ASSERT_OK_PTR(extra, "attach_after_detach");
+
+out:
+ bpf_link__destroy(extra);
+ for (i = 0; i <= INIT_INODE_XATTR_MAX; i++) {
+ bpf_link__destroy(link[i]);
+ test_init_inode_xattr__destroy(skel[i]);
+ }
+}
+
void test_fs_kfuncs(void)
{
/* Matches xattr_names in progs/test_get_xattr.c */
@@ -286,6 +383,12 @@ void test_fs_kfuncs(void)
if (test__start_subtest("set_remove_xattr"))
test_set_remove_xattr();
+ if (test__start_subtest("init_inode_xattr"))
+ test_init_inode_xattr();
+
+ if (test__start_subtest("init_inode_xattr_attach_cap"))
+ test_init_inode_xattr_attach_cap();
+
if (test__start_subtest("fsverity"))
test_fsverity();
}
diff --git a/tools/testing/selftests/bpf/progs/test_init_inode_xattr.c b/tools/testing/selftests/bpf/progs/test_init_inode_xattr.c
new file mode 100644
index 000000000000..6f0e8b02ff88
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/test_init_inode_xattr.c
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2026 Cisco Systems, Inc. */
+
+#include "vmlinux.h"
+#include <bpf/bpf_tracing.h>
+#include "bpf_kfuncs.h"
+
+char _license[] SEC("license") = "GPL";
+
+__u32 monitored_pid;
+int init_result = -1;
+
+static const char xattr_name[] = "bpf.test_label";
+char xattr_value[] = "unconfined_u:object_r:user_home_t:s0";
+
+SEC("lsm.s/inode_init_security")
+int BPF_PROG(test_init_inode_xattr, struct inode *inode, struct inode *dir,
+ const struct qstr *qstr, struct xattr_ctx *xattr_ctx)
+{
+ struct bpf_dynptr value_ptr;
+ __u32 pid;
+
+ pid = bpf_get_current_pid_tgid() >> 32;
+ if (pid != monitored_pid)
+ return 0;
+
+ bpf_dynptr_from_mem(xattr_value, sizeof(xattr_value), 0, &value_ptr);
+ init_result = bpf_init_inode_xattr(xattr_ctx, xattr_name, &value_ptr);
+
+ return 0;
+}
--
2.53.0
^ permalink raw reply related
* [PATCH bpf-next v3 1/2] bpf: add bpf_init_inode_xattr kfunc for atomic inode labeling
From: David Windsor @ 2026-06-18 20:34 UTC (permalink / raw)
To: viro, brauner, jack, ast, daniel, john.fastabend, andrii, eddyz87,
memxor, martin.lau, song, yonghong.song, jolsa, emil, kpsingh,
mattbobrowski, paul, jmorris, serge, zohar, roberto.sassu,
dmitry.kasatkin, eric.snowberg, stephen.smalley.work, omosnace,
casey, shuah
Cc: linux-kernel, linux-fsdevel, bpf, linux-security-module,
linux-integrity, selinux, linux-kselftest, David Windsor
In-Reply-To: <20260618203411.73917-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 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
xattr_ctx.
A previous attempt [1] required a kmalloc string output protocol for
the xattr name. Since commit 6bcdfd2cac55 ("security: Allow all LSMs to
provide xattrs for inode_init_security hook") [2], the xattr name is no
longer allocated; it is a static constant.
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.
Link: https://kernsec.org/pipermail/linux-security-module-archive/2022-October/034878.html [1]
Link: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=6bcdfd2cac55 [2]
Suggested-by: Song Liu <song@kernel.org>
Signed-off-by: David Windsor <dwindsor@gmail.com>
---
fs/bpf_fs_kfuncs.c | 106 +++++++++++++++++++++++++++++-
include/linux/bpf.h | 1 +
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 | 10 +++
kernel/bpf/trampoline.c | 3 +
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 | 27 ++++----
14 files changed, 166 insertions(+), 38 deletions(-)
diff --git a/fs/bpf_fs_kfuncs.c b/fs/bpf_fs_kfuncs.c
index 768aca2dc0f0..7abc3f3d1a67 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>
@@ -374,6 +375,97 @@ __bpf_kfunc struct inode *bpf_real_inode(struct dentry *dentry)
return d_real_inode(dentry);
}
+static int bpf_xattrs_used(const struct 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 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 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)
@@ -385,13 +477,25 @@ 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_real_inode, KF_SLEEPABLE | KF_RET_NULL)
+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.h b/include/linux/bpf.h
index 7719f6528445..f14bfcda78db 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -1752,6 +1752,7 @@ struct bpf_prog_aux {
u32 real_func_cnt; /* includes hidden progs, only used for JIT and freeing progs */
u32 func_idx; /* 0 for non-func prog, the index in func array for func prog */
u32 attach_btf_id; /* in-kernel BTF type id to attach to */
+ u32 attach_limit; /* max concurrent attachments (0 = unlimited) */
u32 attach_st_ops_member_off;
u32 ctx_arg_info_size;
u32 max_rdonly_access;
diff --git a/include/linux/bpf_lsm.h b/include/linux/bpf_lsm.h
index 143775a27a2a..b655c708818e 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 4
+
struct bpf_storage_blob {
struct bpf_local_storage __rcu *storage;
};
diff --git a/include/linux/evm.h b/include/linux/evm.h
index 913f4573b203..0aa151288b36 100644
--- a/include/linux/evm.h
+++ b/include/linux/evm.h
@@ -12,6 +12,8 @@
#include <linux/integrity.h>
#include <linux/xattr.h>
+struct 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 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 xattr_ctx *xattr_ctx)
{
return 0;
}
diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index 65c9609ec207..f62780fbeb9e 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 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..710e48caaeba 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 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 153e9043058f..1f8e84e7dd7e 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -68,6 +68,11 @@ struct watch;
struct watch_notification;
struct lsm_ctx;
+struct 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 564071a92d7d..86a8e188b900 100644
--- a/kernel/bpf/bpf_lsm.c
+++ b/kernel/bpf/bpf_lsm.c
@@ -113,6 +113,9 @@ void bpf_lsm_find_cgroup_shim(const struct bpf_prog *prog,
}
#endif
+BTF_ID_LIST_SINGLE(bpf_lsm_inode_init_security_btf_ids, func,
+ bpf_lsm_inode_init_security)
+
int bpf_lsm_verify_prog(struct bpf_verifier_log *vlog,
const struct bpf_prog *prog)
{
@@ -137,6 +140,12 @@ int bpf_lsm_verify_prog(struct bpf_verifier_log *vlog,
return -EINVAL;
}
+ /* bpf reserves a fixed number of xattr slots for itself.
+ * Set the attach limit so the trampoline rejects excess attaches.
+ */
+ if (btf_id == bpf_lsm_inode_init_security_btf_ids[0])
+ prog->aux->attach_limit = BPF_LSM_INODE_INIT_XATTRS;
+
return 0;
}
@@ -315,6 +324,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/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
index 1a721fc4bef5..b41b02173e24 100644
--- a/kernel/bpf/trampoline.c
+++ b/kernel/bpf/trampoline.c
@@ -859,6 +859,9 @@ static int bpf_trampoline_add_prog(struct bpf_trampoline *tr,
}
if (cnt >= BPF_MAX_TRAMP_LINKS)
return -E2BIG;
+ if (node->link->prog->aux->attach_limit &&
+ tr->progs_cnt[kind] >= node->link->prog->aux->attach_limit)
+ return -E2BIG;
if (!hlist_unhashed(&node->tramp_hlist))
/* prog already linked */
return -EBUSY;
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..e0a05162accc 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 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 71aea8fdf014..8f82a1352356 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 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 1a713d96206f..faa8a6b9c45b 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2962,7 +2962,7 @@ 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 xattr_ctx *xattr_ctx)
{
const struct cred_security_struct *crsec = selinux_cred(current_cred());
struct superblock_security_struct *sbsec;
@@ -2992,7 +2992,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
!(sbsec->flags & SBLABEL_MNT))
return -EOPNOTSUPP;
- xattr = lsm_get_xattr_slot(xattrs, xattr_count);
+ xattr = lsm_get_xattr_slot(xattr_ctx);
if (xattr) {
rc = security_sid_to_context_force(newsid,
&context, &clen);
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index ff115068c5c0..8ed5648a0116 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 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 xattr_ctx *xattr_ctx)
{
struct task_smack *tsp = smack_cred(current_cred());
struct inode_smack * const issp = smack_inode(inode);
@@ -1057,21 +1056,19 @@ 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,
- XATTR_SMACK_TRANSMUTE,
- TRANS_TRUE,
- TRANS_TRUE_SIZE
- ))
+ if (xattr_dupval(xattr_ctx,
+ XATTR_SMACK_TRANSMUTE,
+ TRANS_TRUE,
+ TRANS_TRUE_SIZE))
rc = -ENOMEM;
}
}
if (rc == 0)
- if (xattr_dupval(xattrs, xattr_count,
- XATTR_SMACK_SUFFIX,
- issp->smk_inode->smk_known,
- strlen(issp->smk_inode->smk_known)
- ))
+ if (xattr_dupval(xattr_ctx,
+ XATTR_SMACK_SUFFIX,
+ issp->smk_inode->smk_known,
+ strlen(issp->smk_inode->smk_known)))
rc = -ENOMEM;
instant_inode:
issp->smk_flags |= (SMK_INODE_INSTANT | transflag);
--
2.53.0
^ permalink raw reply related
* [PATCH bpf-next v3 0/2] bpf: add bpf_init_inode_xattr kfunc for atomic inode labeling
From: David Windsor @ 2026-06-18 20:34 UTC (permalink / raw)
To: viro, brauner, jack, ast, daniel, john.fastabend, andrii, eddyz87,
memxor, martin.lau, song, yonghong.song, jolsa, emil, kpsingh,
mattbobrowski, paul, jmorris, serge, zohar, roberto.sassu,
dmitry.kasatkin, eric.snowberg, stephen.smalley.work, omosnace,
casey, shuah
Cc: linux-kernel, linux-fsdevel, bpf, linux-security-module,
linux-integrity, selinux, linux-kselftest, David Windsor
Many in-kernel LSMs (SELinux, Smack, IMA) store security labels in
extended attributes. For these LSMs, atomic labeling during inode
creation is critical: if the inode becomes accessible before its xattr
is set, it is briefly unlabeled, which can disrupt LSMs making policy
decisions based on file labels.
Existing LSMs solve this by setting xattrs directly in the
inode_init_security hook, which runs before the inode becomes
accessible. BPF LSM programs currently lack this capability because
the hook uses an output parameter (xattr_count) that BPF programs
cannot write to, and existing kfuncs like bpf_set_dentry_xattr
require a dentry that isn't available until after the inode is
accessible.
This series introduces the bpf_init_inode_xattr() kfunc, which takes
the combined inode_init_security xattr context argument to access
xattrs and xattr_count, and internally writes to xattr_count via
lsm_get_xattr_slot().
v3:
- rename struct lsm_xattr_ctx to struct xattr_ctx (Paul)
- increase BPF_LSM_INODE_INIT_XATTRS to 4 (Song)
- enforce per-hook attachment cap at attach time to prevent
runtime rejection (Paul)
- add init_inode_xattr_attach_cap selftest
v2:
- pass the xattr state as a combined context object and drop the
verifier fixup path (Kumar)
- restrict bpf_init_inode_xattr labels to bpf.* namespace (Matt)
- cap bpf_init_inode_xattr() at BPF_LSM_INODE_INIT_XATTRS slots per
invocation (AI)
Link: https://lore.kernel.org/all/20260503211835.16103-1-dwindsor@gmail.com/ [v2]
David Windsor (2):
bpf: add bpf_init_inode_xattr kfunc for atomic inode labeling
selftests/bpf: add tests for bpf_init_inode_xattr kfunc
fs/bpf_fs_kfuncs.c | 106 +++++++++++++++++-
include/linux/bpf.h | 1 +
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 | 10 ++
kernel/bpf/trampoline.c | 3 +
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 | 27 ++---
tools/testing/selftests/bpf/bpf_kfuncs.h | 5 +
.../selftests/bpf/prog_tests/fs_kfuncs.c | 105 ++++++++++++++++-
.../bpf/progs/test_init_inode_xattr.c | 31 +++++
17 files changed, 306 insertions(+), 39 deletions(-)
create mode 100644 tools/testing/selftests/bpf/progs/test_init_inode_xattr.c
base-commit: e771677c937da5808f7b6c1f0e4a97ec1a84f8a8
--
2.53.0
^ permalink raw reply
* [GIT PULL] integrity: subsystem fixes for v7.2
From: Mimi Zohar @ 2026-06-18 14:58 UTC (permalink / raw)
To: Linus Torvalds; +Cc: linux-integrity, linux-kernel, Roberto Sassu
[Resending pull request with minor wording tweaks.]
Hi Linus,
There are 2 main changes, some code cleanup, and a couple of bug fixes.
Main changes:
- Introduce IMA and EVM post-quantum ML-DSA signature support
ML-DSA signature support for IMA and EVM is limited to sigv3 signatures, which
calculates and verifies a hash of a compact structure containing the file
data/metadata hash, hash type, and hash algorithm. IMA and EVM still calculate
the file data/metadata hashes respectively.
- Introduce support for removing IMA measurement list records stored in kernel
memory
The IMA measurement list can grow large depending on policy, but removing
records breaks remote attestation, unless they are safely preserved and made
available for attestation requests. Until environments are prepared to preserve
the measurement records, a new CONFIG_IMA_STAGING Kconfig option is introduced
to guard against deletion.
Several approaches for removing measurement list records were evaluated but
rejected due to filesystem constraints, the introduction of a new critical data
record, and locking concerns. Two methods are being upstreamed: staged deletion
with confirmation, and staged deletion of N records without confirmation. Both
methods minimize the period during which new measurements are blocked from being
appended to the measurement list by staging the measurement list.` A comparison
of the two methods is included in the documentation.
Thanks,
Mimi
The following changes since commit 254f49634ee16a731174d2ae34bc50bd5f45e731:
Linux 7.1-rc1 (2026-04-26 14:19:00 -0700)
are available in the Git repository at:
https://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity.git/ tags/integrity-v7.2
for you to fetch changes up to 35d6f5e788dae0dcc4c42d1280360f19aef9ab52:
doc: security: Add documentation of exporting and deleting IMA measurements (2026-06-08 11:43:36 -0400)
----------------------------------------------------------------
integrity-v7.2
----------------------------------------------------------------
Goldwyn Rodrigues (1):
ima: return error early if file xattr cannot be changed
Kamlesh Kumar (1):
ima: Fix sigv3 signature handling for EVM_IMA_XATTR_DIGSIG
Pengpeng Hou (1):
evm: terminate and bound the evm_xattrs read buffer
Roberto Sassu (12):
ima: Remove ima_h_table structure
ima: Replace static htable queue with dynamically allocated array
ima: Introduce per binary measurements list type ima_num_records counter
ima: Introduce per binary measurements list type binary_runtime_size value
ima: Introduce _ima_measurements_start() and _ima_measurements_next()
ima: Mediate open/release method of the measurements list
ima: Use snprintf() in create_securityfs_measurement_lists
ima: Introduce ima_dump_measurement()
ima: Add support for staging measurements with prompt
ima: Add support for flushing the hash table when staging measurements
ima: Support staging and deleting N measurements records
doc: security: Add documentation of exporting and deleting IMA measurements
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
Documentation/admin-guide/kernel-parameters.txt | 6 +
Documentation/security/IMA-export-delete.rst | 203 ++++++++++++++
Documentation/security/index.rst | 1 +
MAINTAINERS | 2 +
security/integrity/digsig_asymmetric.c | 152 +++++++++--
security/integrity/evm/evm_secfs.c | 16 +-
security/integrity/ima/Kconfig | 15 +
security/integrity/ima/ima.h | 28 +-
security/integrity/ima/ima_api.c | 2 +-
security/integrity/ima/ima_appraise.c | 10 +-
security/integrity/ima/ima_fs.c | 346 +++++++++++++++++++++---
security/integrity/ima/ima_init.c | 5 +
security/integrity/ima/ima_kexec.c | 42 ++-
security/integrity/ima/ima_policy.c | 3 +-
security/integrity/ima/ima_queue.c | 327 ++++++++++++++++++++--
15 files changed, 1057 insertions(+), 101 deletions(-)
create mode 100644 Documentation/security/IMA-export-delete.rst
^ permalink raw reply
* [GIT PULL] integrity: subsystem fixes for v7.2
From: Mimi Zohar @ 2026-06-18 14:06 UTC (permalink / raw)
To: Linus Torvalds; +Cc: linux-integrity, linux-kernel, Roberto Sassu
Hi Linus,
There are 2 main changes, some code cleanup, and a couple of bug fixes.
Main changes:
- Introduce IMA and EVM post-quantum ML-DSA signature support
ML-DSA signature support for IMA and EVM is limited to sigv3 signatures, which
signs a hash of a compact structure containing the file data/metadata hash, hash
type, and hash algorithm. IMA and EVM still calculate the file data/metadata
hashes respectively.
- Introduce support for removing IMA measurement list records stored in kernel
memory
The IMA measurement list can grow large depending on policy, but removing
records breaks remote attestation, unless they are safely preserved and made
available for attestation requests. Until environments are prepared to preserve
the measurement records, a new CONFIG_IMA_STAGING Kconfig option is introduced
to guard against deletion.
Several approaches for removing measurement list records were evaluated but
rejected due to filesystem constraints, the introduction of a new critical data
record, and locking concerns. Two methods are being upstreamed: staged deletion
with confirmation, and staged deletion of N records without confirmation. Both
methods reduce the period during which new measurements are blocked from being
appended to the measurement list by staging the measurement list.` A comparison
of the two methods is included in the documentation.
Thanks,
Mimi
The following changes since commit 254f49634ee16a731174d2ae34bc50bd5f45e731:
Linux 7.1-rc1 (2026-04-26 14:19:00 -0700)
are available in the Git repository at:
https://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity.git/ tags/integrity-v7.2
for you to fetch changes up to 35d6f5e788dae0dcc4c42d1280360f19aef9ab52:
doc: security: Add documentation of exporting and deleting IMA measurements (2026-06-08 11:43:36 -0400)
----------------------------------------------------------------
integrity-v7.2
----------------------------------------------------------------
Goldwyn Rodrigues (1):
ima: return error early if file xattr cannot be changed
Kamlesh Kumar (1):
ima: Fix sigv3 signature handling for EVM_IMA_XATTR_DIGSIG
Pengpeng Hou (1):
evm: terminate and bound the evm_xattrs read buffer
Roberto Sassu (12):
ima: Remove ima_h_table structure
ima: Replace static htable queue with dynamically allocated array
ima: Introduce per binary measurements list type ima_num_records counter
ima: Introduce per binary measurements list type binary_runtime_size value
ima: Introduce _ima_measurements_start() and _ima_measurements_next()
ima: Mediate open/release method of the measurements list
ima: Use snprintf() in create_securityfs_measurement_lists
ima: Introduce ima_dump_measurement()
ima: Add support for staging measurements with prompt
ima: Add support for flushing the hash table when staging measurements
ima: Support staging and deleting N measurements records
doc: security: Add documentation of exporting and deleting IMA measurements
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
Documentation/admin-guide/kernel-parameters.txt | 6 +
Documentation/security/IMA-export-delete.rst | 203 ++++++++++++++
Documentation/security/index.rst | 1 +
MAINTAINERS | 2 +
security/integrity/digsig_asymmetric.c | 152 +++++++++--
security/integrity/evm/evm_secfs.c | 16 +-
security/integrity/ima/Kconfig | 15 +
security/integrity/ima/ima.h | 28 +-
security/integrity/ima/ima_api.c | 2 +-
security/integrity/ima/ima_appraise.c | 10 +-
security/integrity/ima/ima_fs.c | 346 +++++++++++++++++++++---
security/integrity/ima/ima_init.c | 5 +
security/integrity/ima/ima_kexec.c | 42 ++-
security/integrity/ima/ima_policy.c | 3 +-
security/integrity/ima/ima_queue.c | 327 ++++++++++++++++++++--
15 files changed, 1057 insertions(+), 101 deletions(-)
create mode 100644 Documentation/security/IMA-export-delete.rst
^ permalink raw reply
* [PATCH v4 2/2] ima: measure buffer sent to securityfs policy file
From: Enrico Bravi @ 2026-06-17 15:58 UTC (permalink / raw)
To: linux-integrity, zohar, dmitry.kasatkin, roberto.sassu
Cc: eric.snowberg, Enrico Bravi
In-Reply-To: <20260617155832.434517-1-enrico.bravi@polito.it>
When a signed policy is not mandatory, it is possible to write the IMA
policy directly on the corresponding securityfs file:
echo -e "measure func=BPRM_CHECK mask=MAY_EXEC\n" \
"audit func=BPRM_CHECK mask=MAY_EXEC\n" \
> /sys/kernel/security/ima/policy
or by cat'ing the entire IMA custom policy file:
cat ima-policy-file > /sys/kernel/security/ima/policy
Add input buffer measurement, regardless of whether the new policy
will be accepted or not, that can be caught when
'measure func=POLICY_CHECK' is enabled (e.g., ima_policy=tcb). The
measurement template is forced to ima-buf.
This follows the "measure & load" paradigm, exposing potential bugs in
the policy code and detecting attempts to corrupt IMA. It also completes
the POLICY_CHECK hook, which already measures partial policy load by file.
To verify the template data hash value, convert the buffer policy data
to binary:
grep "ima_policy_written" \
/sys/kernel/security/integrity/ima/ascii_runtime_measurements | \
tail -1 | cut -d' ' -f 6 | xxd -r -p | sha256sum
Suggested-by: Roberto Sassu <roberto.sassu@huawei.com>
Signed-off-by: Enrico Bravi <enrico.bravi@polito.it>
---
security/integrity/ima/ima.h | 1 +
security/integrity/ima/ima_fs.c | 1 +
security/integrity/ima/ima_main.c | 19 +++++++++++++++++++
security/integrity/ima/ima_policy.c | 3 +++
4 files changed, 24 insertions(+)
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index befa221716e5..d477fc06821f 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -455,6 +455,7 @@ void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos);
void ima_policy_stop(struct seq_file *m, void *v);
int ima_policy_show(struct seq_file *m, void *v);
void ima_measure_loaded_policy(void);
+int ima_measure_policy_buf(const char *buf, size_t buf_len);
/* Appraise integrity measurements */
#define IMA_APPRAISE_ENFORCE 0x01
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index 65e7812c702f..a277c9135944 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -356,6 +356,7 @@ static ssize_t ima_write_policy(struct file *file, const char __user *buf,
1, 0);
result = -EACCES;
} else {
+ ima_measure_policy_buf(data, datalen);
result = ima_parse_add_rule(data);
}
mutex_unlock(&ima_write_mutex);
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 5cea53fc36df..599495304712 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -1221,6 +1221,25 @@ int ima_measure_critical_data(const char *event_label,
}
EXPORT_SYMBOL_GPL(ima_measure_critical_data);
+/**
+ * ima_measure_policy_buf - Measure the policy write buffer
+ * @buf: pointer to the buffer containing the policy write data
+ * @buf_len: size of the buffer
+ *
+ * Measure the buffer sent to the IMA policy securityfs file.
+ *
+ * Return 0 on success, a negative value otherwise.
+ */
+int ima_measure_policy_buf(const char *buf, size_t buf_len)
+{
+ if (!buf || !buf_len)
+ return -EINVAL;
+
+ return process_buffer_measurement(&nop_mnt_idmap, NULL, buf, buf_len,
+ "ima_policy_written", POLICY_CHECK, 0,
+ NULL, false, NULL, 0);
+}
+
#ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS
/**
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index 0a70d10da70a..fc747f391e41 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -541,6 +541,8 @@ static bool ima_match_rule_data(struct ima_rule_entry *rule,
opt_list = rule->label;
break;
+ case POLICY_CHECK:
+ return true;
default:
return false;
}
@@ -589,6 +591,7 @@ static bool ima_match_rules(struct ima_rule_entry *rule,
switch (func) {
case KEY_CHECK:
case CRITICAL_DATA:
+ case POLICY_CHECK:
return ((rule->func == func) &&
ima_match_rule_data(rule, func_data, cred));
default:
--
2.52.0
^ permalink raw reply related
* [PATCH v4 1/2] ima: measure loaded policy after write on securityfs policy file
From: Enrico Bravi @ 2026-06-17 15:58 UTC (permalink / raw)
To: linux-integrity, zohar, dmitry.kasatkin, roberto.sassu
Cc: eric.snowberg, Enrico Bravi
In-Reply-To: <20260617155832.434517-1-enrico.bravi@polito.it>
IMA policy can be written multiple times in the securityfs policy file
at runtime if CONFIG_IMA_WRITE_POLICY=y. When IMA_APPRAISE_POLICY is
required, the policy needs to be signed to be loaded, writing the absolute
path of the file containing the new policy:
echo /path/of/custom_ima_policy > /sys/kernel/security/ima/policy
When this is not required, policy can be written directly, rule by rule:
echo -e "measure func=BPRM_CHECK mask=MAY_EXEC\n" \
"audit func=BPRM_CHECK mask=MAY_EXEC\n" \
> /sys/kernel/security/ima/policy
In this case, a new policy can be loaded without being measured or
appraised.
Add a new critical data record to measure the textual policy
representation when it becomes effective. Include in the
architecture-specific policy the new critical data record only when it
is not mandatory to load a signed policy. Additionally, enable the
policy serialization code even when CONFIG_IMA_READ_POLICY=n.
To verify the template data hash value, convert the buffer policy data
to binary:
grep "ima_policy_loaded" \
/sys/kernel/security/integrity/ima/ascii_runtime_measurements | \
tail -1 | cut -d' ' -f 6 | xxd -r -p | sha256sum
Signed-off-by: Enrico Bravi <enrico.bravi@polito.it>
---
security/integrity/ima/ima.h | 3 ++
security/integrity/ima/ima_efi.c | 2 +
security/integrity/ima/ima_fs.c | 6 ++-
security/integrity/ima/ima_policy.c | 70 ++++++++++++++++++++++++++++-
4 files changed, 78 insertions(+), 3 deletions(-)
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 69e9bf0b82c6..befa221716e5 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -46,6 +46,8 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8, TPM_PCR10 = 10 };
/* current content of the policy */
extern int ima_policy_flag;
+extern struct mutex ima_write_mutex;
+
/* bitset of digests algorithms allowed in the setxattr hook */
extern atomic_t ima_setxattr_allowed_hash_algorithms;
@@ -452,6 +454,7 @@ void *ima_policy_start(struct seq_file *m, loff_t *pos);
void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos);
void ima_policy_stop(struct seq_file *m, void *v);
int ima_policy_show(struct seq_file *m, void *v);
+void ima_measure_loaded_policy(void);
/* Appraise integrity measurements */
#define IMA_APPRAISE_ENFORCE 0x01
diff --git a/security/integrity/ima/ima_efi.c b/security/integrity/ima/ima_efi.c
index bca57d836cb9..be7911009454 100644
--- a/security/integrity/ima/ima_efi.c
+++ b/security/integrity/ima/ima_efi.c
@@ -17,6 +17,8 @@ static const char * const sb_arch_rules[] = {
#endif
#if IS_ENABLED(CONFIG_INTEGRITY_MACHINE_KEYRING) && IS_ENABLED(CONFIG_IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY)
"appraise func=POLICY_CHECK appraise_type=imasig",
+#else
+ "measure func=CRITICAL_DATA label=ima_policy",
#endif
"measure func=MODULE_CHECK",
NULL
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index ca4931a95098..65e7812c702f 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -24,7 +24,7 @@
#include "ima.h"
-static DEFINE_MUTEX(ima_write_mutex);
+DEFINE_MUTEX(ima_write_mutex);
bool ima_canonical_fmt;
static int __init default_canonical_fmt_setup(char *str)
@@ -478,6 +478,10 @@ static int ima_release_policy(struct inode *inode, struct file *file)
}
ima_update_policy();
+
+ mutex_lock(&ima_write_mutex);
+ ima_measure_loaded_policy();
+ mutex_unlock(&ima_write_mutex);
#if !defined(CONFIG_IMA_WRITE_POLICY) && !defined(CONFIG_IMA_READ_POLICY)
securityfs_remove(file->f_path.dentry);
#elif defined(CONFIG_IMA_WRITE_POLICY)
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index f7f940a76922..0a70d10da70a 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -17,6 +17,7 @@
#include <linux/slab.h>
#include <linux/rculist.h>
#include <linux/seq_file.h>
+#include <linux/vmalloc.h>
#include <linux/ima.h>
#include "ima.h"
@@ -2020,7 +2021,6 @@ const char *const func_tokens[] = {
__ima_hooks(__ima_hook_stringify)
};
-#ifdef CONFIG_IMA_READ_POLICY
enum {
mask_exec = 0, mask_write, mask_read, mask_append
};
@@ -2322,7 +2322,6 @@ int ima_policy_show(struct seq_file *m, void *v)
seq_puts(m, "\n");
return 0;
}
-#endif /* CONFIG_IMA_READ_POLICY */
#if defined(CONFIG_IMA_APPRAISE) && defined(CONFIG_INTEGRITY_TRUSTED_KEYRING)
/*
@@ -2379,3 +2378,70 @@ bool ima_appraise_signature(enum kernel_read_file_id id)
return found;
}
#endif /* CONFIG_IMA_APPRAISE && CONFIG_INTEGRITY_TRUSTED_KEYRING */
+
+/**
+* ima_measure_loaded_policy - measure the active IMA policy ruleset
+*
+* Must be called with ima_write_mutex held, as it performs two
+* separate RCU read passes over ima_rules and relies on the mutex
+* to prevent concurrent policy updates between them.
+*/
+void ima_measure_loaded_policy(void)
+{
+ const char *event_name = "ima_policy_loaded";
+ const char *op = "measure_loaded_ima_policy";
+ struct ima_rule_entry *rule_entry;
+ struct list_head *ima_rules_tmp;
+ struct seq_file file;
+ int result = -ENOMEM;
+ size_t file_len = 0;
+ char rule[512];
+
+ /* calculate IMA policy rules memory size */
+ file.buf = rule;
+ file.read_pos = 0;
+ file.size = 512;
+ file.count = 0;
+
+ lockdep_assert_held(&ima_write_mutex);
+
+ rcu_read_lock();
+ ima_rules_tmp = rcu_dereference(ima_rules);
+ list_for_each_entry_rcu(rule_entry, ima_rules_tmp, list) {
+ ima_policy_show(&file, rule_entry);
+ if (seq_has_overflowed(&file)) {
+ result = -E2BIG;
+ integrity_audit_msg(AUDIT_INTEGRITY_PCR, NULL, event_name,
+ op, "rule_length", result, 1);
+ return;
+ }
+
+ file_len += file.count;
+ file.count = 0;
+ }
+ rcu_read_unlock();
+
+ /* copy IMA policy rules to a buffer for measuring */
+ file.buf = vmalloc(file_len);
+ if (!file.buf) {
+ integrity_audit_msg(AUDIT_INTEGRITY_PCR, NULL, event_name,
+ op, "ENOMEM", result, 1);
+ return;
+ }
+
+ file.read_pos = 0;
+ file.size = file_len;
+ file.count = 0;
+
+ rcu_read_lock();
+ ima_rules_tmp = rcu_dereference(ima_rules);
+ list_for_each_entry_rcu(rule_entry, ima_rules_tmp, list) {
+ ima_policy_show(&file, rule_entry);
+ }
+ rcu_read_unlock();
+
+ ima_measure_critical_data("ima_policy", event_name, file.buf,
+ file.count, false, NULL, 0);
+
+ vfree(file.buf);
+}
--
2.52.0
^ permalink raw reply related
* [PATCH v4 0/2] ima: measure write on securityfs policy file
From: Enrico Bravi @ 2026-06-17 15:58 UTC (permalink / raw)
To: linux-integrity, zohar, dmitry.kasatkin, roberto.sassu
Cc: eric.snowberg, Enrico Bravi
This series aims to introduce integrity measurements when the IMA policy is
written on the securityfs file.
In particular, when a signed policy is not mandatory, it can be written
directly on the securityfs file. This allows to override the boot policy
at the first write, and append new policy rules at the subsequent writes (if
CONFIG_IMA_WRITE_POLICY=y). In this case new policy can be loaded
without being measured.
The patch #1 introduces a new critical-data record for the newly loaded
policy. The measurement is performed over the textual representation of the
new policy once it becomes effective (after ima_update_policy()). As
suggested by Mimi, the new critical-data rule is added to the arch
specific policy rules (only when a signed policy is not mandatory).
The patch #2, following what was suggested by Roberto, measures the input
buffer sent to the securityfs policy file, regardless of whether the new
policy will be accepted or not. This is done by calling
process_buffer_measurement(), enabling POLICY_CHECK in ima_match_rules() and
ima_match_rule_data() in order to catch it when 'measure func=POLICY_CHECK'
is defined (e.g., ima_policy=tcb).
Changes in v4:
- Added kernel-doc for the new ima_measure_loaded_policy() function as
suggested by Mimi.
- Increased the rule buffer size in ima_measure_loaded_policy() (suggested
by Mimi) checking if seq_has_overflowed() calculating the policy length.
- Acquire ima_write_mutex in before calling ima_measure_loaded_policy()
and verify lockdep_assert_held(&ima_write_mutex) as suggested by Mimi.
- Initialize file_len to zero in ima_measure_loaded_policy() as
suggested by Mimi.
- Changed ima_measure_policy_buf() returned error from -ENOPARAM to
-EINVAL as suggested by Mimi.
- Changed event name from "ima_write_policy_buf" to "ima_policy_written"
as suggested by Mimi.
- Updated patches description.
Changes in v3:
- Include the newly defined critical-data rule only if a signed policy is
not mandatory as suggested by Mimi.
- Removed the ima_policy_text_len() function as suggested by Mimi.
- Moved policy input buffer measurement from process_measurement() to
process_buffer_measurement() as suggested by Mimi.
- Changed ima_measure_policy_write() function name to ima_measure_policy_buf()
as suggested by Mimi.
- Updated patches description.
Changes in v2:
- Set a new critical-data rule for measuring the loaded IMA policy.
- Add the new critical-data rule to the specific arch policy rules.
- Add patch #2 for measuring the input buffer sent to the securityfs
policy file.
Enrico Bravi (2):
ima: measure loaded policy after write on securityfs policy file
ima: measure buffer sent to securityfs policy file
security/integrity/ima/ima.h | 4 ++
security/integrity/ima/ima_efi.c | 2 +
security/integrity/ima/ima_fs.c | 7 ++-
security/integrity/ima/ima_main.c | 19 ++++++++
security/integrity/ima/ima_policy.c | 73 ++++++++++++++++++++++++++++-
5 files changed, 102 insertions(+), 3 deletions(-)
base-commit: 8cd9520d35a6c38db6567e97dd93b1f11f185dc6
--
2.52.0
^ permalink raw reply
* inherit null-key across hibernate (was: Re: regression: kernel log "flooded" with tpm tpm0: A TPM error (2306) occurred attempting to create NULL primary)
From: Daniel Golle @ 2026-06-16 3:50 UTC (permalink / raw)
To: Jarkko Sakkinen
Cc: James Bottomley, Christoph Anton Mitterer, linux-integrity
In-Reply-To: <D5LEQGJ9X3NF.3K3YVPNE6KQJK@kernel.org>
Hi Jarkko,
Hi James,
first of all, sorry for hijacking a thread from 2 years ago.
On Thu, Nov 14, 2024 at 12:34:30AM +0200, Jarkko Sakkinen wrote:
> On Wed Nov 13, 2024 at 8:12 PM EET, James Bottomley wrote:
> > > I think we might have to expect the NULL name to change on actual
> > > hibernation because unlike suspend to ram it does power off the TPM.
> >
> > I checked the code: we're coming in on the correct path to renew the
> > null seed after hibernation, so it should all work. The problem seems
> > to be that your TPM itself is doing something invalid because the name
> > we calculate for the primary key doesn't match what your TPM says it
> > should be. Absent some form of attack or bus integrity problem, that
> > shouldn't ever happen, so I'm even more curious to know why it worked
> > in 6.11.5 and before and whether current upstream works.
> >
> > I haven't found it yet, but I think the every 10s signature is because
> > the hibernation path is trying to restart the TPM device and won't take
> > no for an answer.
>
> My fix returned the behavior how it was before my earlier fix in this
> corner case (i.e. disable TPM). The issue has gone unnoticed before
> since it has emitted only a single klog entry.
>
> On suspend this has not happened to me so obvious deduction is that
> hibernate resets the null seed.
>
> Hibernate needs an addition a fix to disable bus encryption from kernel
> command-line completely, i.e. tpm.disable_integrity following the
> convention from my earlier fix [1].
I'd like to offer a way it might be resolvable with the null key after
all, without provisioning a persistent NV key -- by changing the
question from "re-derive the null primary and compare" to "inherit the
trust the resume has already established".
Resume-from-hibernation is a TPM Restart (Shutdown(STATE) ->
Startup(CLEAR)), i.e. a firmware cold-init of the (f)TPM, after which
the boot/initramfs kernel establishes a fresh, genuine null primary.
In the common configuration (FDE with the resume/swap device inside
a TPM-sealed LUKS2 container) that same TPM has, moments earlier and
*before* the hibernation image is restored, cryptographically attested
itself by unsealing the resume device. A substituted or interposed TPM
cannot produce that unseal.
So rather than letting the resumed kernel re-derive the null name,
find a mismatch and disable the chip, the boot kernel's
freshly-established and unseal-validated null primary could be
inherited by the resumed image. The existing null-seed TOFU model is
preserved; nothing new is provisioned.
The gate is the unseal, and the adversary case shows why it is the
right gate:
Malice swaps (or interposes on) the TPM while the machine is
hibernated, then leaves. Alice powers on. The initramfs attempts the
TPM unseal of the resume device; with a foreign TPM it fails, so
systemd-cryptsetup falls back to the passphrase, which Alice --
seeing a prompt -- types. The disk opens and the system resumes.
If trust were re-established here, Alice would have personally vouched
for Malice's TPM. But the unseal *failed*, so under this scheme
nothing is inherited and the chip stays fail-closed exactly as today.
The passphrase proves a human is present; it never proves the TPM is
the genuine one.
Hence: unseal succeeded -> inherit the validated null primary;
passphrase fallback -> trust is lost, stay disabled.
This keeps the property the null-seed design wants -- an in-session
reset is not on the hibernate-restore path and is still caught --
while removing the false positive only where the platform has already
re-attested the TPM.
The hard parts, and where I'd value direction:
- systemd-cryptsetup would need to signal "the resume device was
unsealed by the TPM this boot" (vs. the passphrase fallback).
This is per-resume runtime state; a static command-line parameter
(and obviously build-time config as well) cannot represent it.
- the validated null primary has to cross the boot -> resumed memory
discontinuity (the initramfs kernel's state is overwritten by the
restored image). Boot and image kernel are the same binary, so
patching chip->null_key_name in the restored image is mechanically
possible; a small reserved/nosave hand-off area may be cleaner.
I don't know the hibernate path well enough to say which is right.
It is admittedly cross-subsystem (tpm + pm/hibernate +
systemd/cryptsetup), which is presumably why it hasn't been done.
Compared with the persistent NV-key route
(tpm.integrity_key=<handle>): that avoids the carry-across but needs
the key provisioned and managed, and a persistent key's name no longer
changes on a genuine reset, so the implicit reset detection has to be
reconstructed. The null-key-inherit approach keeps the existing model
and defers "is this the same TPM?" to the unseal that has already
happened.
Does this seem viable, or is there a reason the unseal-as-attestation
gate does not hold that I'm missing?
(For motivation: on a firmware TPM -- Intel PTT here -- there is no
external bus to interpose, so the protection has no benefit on this
class of hardware at all, yet the legitimate hibernation power-cycle
still trips the disable. For fTPMs specifically, not enabling the
feature is arguably the better answer; but for discrete TPMs that
hibernate, a real solution seems a good idea if doable.)
Cheers
Daniel
^ permalink raw reply
* Re: [PATCH] tpm: tpm_tis: add settle delay after releasing locality
From: Daniel Golle @ 2026-06-15 12:50 UTC (permalink / raw)
To: Jarkko Sakkinen
Cc: Peter Huewe, Jason Gunthorpe, Chen Jun, linux-integrity,
linux-kernel
In-Reply-To: <ai_tZ0VM9PDCRMfl@kernel.org>
On Mon, Jun 15, 2026 at 03:17:43PM +0300, Jarkko Sakkinen wrote:
> On Mon, Jun 15, 2026 at 05:48:43AM +0100, Daniel Golle wrote:
> > tpm_tis_core_init() releases locality 0 then immediately reclaims it via
> > tpm_chip_start(); some TPMs (e.g. Nuvoton NPCT, TPM 2.0) need a few ms
> > before granting it again, so probe fails with -1. This back-to-back
> > release/request was added with the locality claim around TPM_INT_ENABLE.
> >
> > Wait for the chip to settle after releasing the locality. A delay of
> > TPM_TIMEOUT (5 ms) in __tpm_tis_relinquish_locality() is reliable; values
> > below 3 ms are not.
> >
> > Fixes: 0ef333f5ba7f ("tpm: add request_locality before write TPM_INT_ENABLE")
> > Cc: stable@vger.kernel.org
> > Signed-off-by: Daniel Golle <daniel@makrotopia.org>
>
> Can rebase to my for-next-tpm and resend v2?
I figured the fix is already in place in your tree, added by
34bc0fabf166 ("tpm: tpm_tis: Add settle time for some TPMs")
device_id 0x00FE, vendor_id 0x1050 exactly matches my TPM as well,
so please drop my patch.
Sorry for the noise...
^ permalink raw reply
* Re: [PATCH] tpm: tpm_tis: add settle delay after releasing locality
From: Jarkko Sakkinen @ 2026-06-15 12:17 UTC (permalink / raw)
To: Daniel Golle
Cc: Peter Huewe, Jason Gunthorpe, Chen Jun, linux-integrity,
linux-kernel
In-Reply-To: <086949bcf2c10bead892b0b4befd98da370cd3ee.1781498837.git.daniel@makrotopia.org>
On Mon, Jun 15, 2026 at 05:48:43AM +0100, Daniel Golle wrote:
> tpm_tis_core_init() releases locality 0 then immediately reclaims it via
> tpm_chip_start(); some TPMs (e.g. Nuvoton NPCT, TPM 2.0) need a few ms
> before granting it again, so probe fails with -1. This back-to-back
> release/request was added with the locality claim around TPM_INT_ENABLE.
>
> Wait for the chip to settle after releasing the locality. A delay of
> TPM_TIMEOUT (5 ms) in __tpm_tis_relinquish_locality() is reliable; values
> below 3 ms are not.
>
> Fixes: 0ef333f5ba7f ("tpm: add request_locality before write TPM_INT_ENABLE")
> Cc: stable@vger.kernel.org
> Signed-off-by: Daniel Golle <daniel@makrotopia.org>
> ---
> drivers/char/tpm/tpm_tis_core.c | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c
> index 21d79ad3b164..6b90ff50c78d 100644
> --- a/drivers/char/tpm/tpm_tis_core.c
> +++ b/drivers/char/tpm/tpm_tis_core.c
> @@ -171,6 +171,8 @@ static int __tpm_tis_relinquish_locality(struct tpm_tis_data *priv, int l)
> {
> tpm_tis_write8(priv, TPM_ACCESS(l), TPM_ACCESS_ACTIVE_LOCALITY);
>
> + tpm_msleep(TPM_TIMEOUT);
> +
> return 0;
> }
>
> --
> 2.54.0
>
Can rebase to my for-next-tpm and resend v2?
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