Linux Security Modules development
 help / color / mirror / Atom feed
* [PATCH] ipe: document AT_EXECVE_CHECK TOCTOU issue on OverlayFS
From: wufan @ 2026-01-30  0:14 UTC (permalink / raw)
  To: linux-security-module
  Cc: linux-doc, linux-kernel, corbet, mic, miklos, amir73il,
	linux-unionfs, Fan Wu

From: Fan Wu <wufan@kernel.org>

Document a known TOCTOU (time-of-check to time-of-use) issue when using
AT_EXECVE_CHECK with read() on OverlayFS. The deny_write_access()
protection is only held during the syscall, allowing a copy-up operation
to be triggered afterward, causing subsequent read() calls to return
content from the unprotected upper layer.

This is generally not a concern for typical IPE deployments since
dm-verity and fs-verity protected files are effectively read-only.
However, OverlayFS with a writable upper layer presents a special case.

Document mitigation strategies including mounting overlay as read-only
and using mmap() instead of read(). Note that the mmap() mitigation
relies on current OverlayFS implementation details and should not be
considered a security guarantee.

Signed-off-by: Fan Wu <wufan@kernel.org>
---
 Documentation/admin-guide/LSM/ipe.rst | 32 +++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/Documentation/admin-guide/LSM/ipe.rst b/Documentation/admin-guide/LSM/ipe.rst
index a756d8158531..b621a98fe5e2 100644
--- a/Documentation/admin-guide/LSM/ipe.rst
+++ b/Documentation/admin-guide/LSM/ipe.rst
@@ -110,6 +110,34 @@ intercepts during the execution process, this mechanism needs the interpreter
 to take the initiative, and existing interpreters won't be automatically
 supported unless the signal call is added.
 
+.. WARNING::
+
+   There is a known TOCTOU (time-of-check to time-of-use) issue with
+   ``AT_EXECVE_CHECK`` when interpreters use ``read()`` to obtain script
+   contents after the check [#atacexecvecheck_toctou]_. The ``AT_EXECVE_CHECK``
+   protection (via ``deny_write_access()``) is only held during the syscall.
+   After it returns, the file can be modified before the interpreter reads it.
+
+   In typical IPE deployments, this is not a concern because files protected
+   by dm-verity or fs-verity are effectively read-only and cannot be modified.
+   However, OverlayFS presents a special case: when the lower layer is
+   dm-verity protected (read-only) but the upper layer is writable, an
+   attacker with write access can trigger a copy-up operation after the
+   ``AT_EXECVE_CHECK`` returns, causing subsequent ``read()`` calls to return
+   content from the unprotected upper layer instead of the verified lower layer.
+
+   To mitigate this issue on OverlayFS:
+
+   -  Mount the overlay as read-only, or restrict write access to the upper
+      layer.
+   -  Interpreters may use ``mmap()`` instead of ``read()`` to obtain script
+      contents. Currently, OverlayFS fixes the underlying real file reference
+      at ``open()`` time for mmap operations, so mmap will continue to access
+      the original lower layer file even after a copy-up. However, this
+      behavior is an implementation detail of OverlayFS and is not guaranteed
+      to remain stable across kernel versions. Do not rely on this as a
+      security guarantee.
+
 Threat Model
 ------------
 
@@ -833,3 +861,7 @@ A:
                      kernel's fsverity support; IPE does not impose any
                      restrictions on the digest algorithm itself;
                      thus, this list may be out of date.
+
+.. [#atacexecvecheck_toctou] See the O_DENY_WRITE RFC discussion for details on
+                             this TOCTOU issue:
+                             https://lore.kernel.org/all/20250822170800.2116980-1-mic@digikod.net/
-- 
2.52.0


^ permalink raw reply related

* Re: [PATCH] lsm: preserve /proc/sys/vm/mmap_min_addr when !CONFIG_SECURITY
From: Kees Cook @ 2026-01-30  1:31 UTC (permalink / raw)
  To: Paul Moore; +Cc: linux-security-module, linux-mm, lorenzo.stoakes
In-Reply-To: <20260129225132.420484-2-paul@paul-moore.com>

On Thu, Jan 29, 2026 at 05:51:33PM -0500, Paul Moore wrote:
> While reworking the LSM initialization code the
> /proc/sys/vm/mmap_min_addr handler was inadvertently caught up in the
> change and the procfs entry wasn't setup when CONFIG_SECURITY was not
> selected at kernel build time.  This patch restores the previous behavior
> and ensures that the procfs entry is setup regardless of the
> CONFIG_SECURITY state.
> 
> Future work will improve upon this, likely by moving the procfs handler
> into the mm subsystem, but this patch should resolve the immediate
> regression.
> 
> Fixes: 4ab5efcc2829 ("lsm: consolidate all of the LSM framework initcalls")
> Reported-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
> Signed-off-by: Paul Moore <paul@paul-moore.com>

Good catch and fix!

Reviewed-by: Kees Cook <kees@kernel.org>

-Kees

> ---
>  security/lsm.h      | 9 ---------
>  security/lsm_init.c | 7 +------
>  security/min_addr.c | 5 ++---
>  3 files changed, 3 insertions(+), 18 deletions(-)
> 
> diff --git a/security/lsm.h b/security/lsm.h
> index 81aadbc61685..db77cc83e158 100644
> --- a/security/lsm.h
> +++ b/security/lsm.h
> @@ -37,15 +37,6 @@ int lsm_task_alloc(struct task_struct *task);
>  
>  /* LSM framework initializers */
>  
> -#ifdef CONFIG_MMU
> -int min_addr_init(void);
> -#else
> -static inline int min_addr_init(void)
> -{
> -	return 0;
> -}
> -#endif /* CONFIG_MMU */
> -
>  #ifdef CONFIG_SECURITYFS
>  int securityfs_init(void);
>  #else
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index 05bd52e6b1f2..573e2a7250c4 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -489,12 +489,7 @@ int __init security_init(void)
>   */
>  static int __init security_initcall_pure(void)
>  {
> -	int rc_adr, rc_lsm;
> -
> -	rc_adr = min_addr_init();
> -	rc_lsm = lsm_initcall(pure);
> -
> -	return (rc_adr ? rc_adr : rc_lsm);
> +	return lsm_initcall(pure);
>  }
>  pure_initcall(security_initcall_pure);
>  
> diff --git a/security/min_addr.c b/security/min_addr.c
> index 0fde5ec9abc8..56e4f9d25929 100644
> --- a/security/min_addr.c
> +++ b/security/min_addr.c
> @@ -5,8 +5,6 @@
>  #include <linux/sysctl.h>
>  #include <linux/minmax.h>
>  
> -#include "lsm.h"
> -
>  /* amount of vm to protect from userspace access by both DAC and the LSM*/
>  unsigned long mmap_min_addr;
>  /* amount of vm to protect from userspace using CAP_SYS_RAWIO (DAC) */
> @@ -54,10 +52,11 @@ static const struct ctl_table min_addr_sysctl_table[] = {
>  	},
>  };
>  
> -int __init min_addr_init(void)
> +static int __init mmap_min_addr_init(void)
>  {
>  	register_sysctl_init("vm", min_addr_sysctl_table);
>  	update_mmap_min_addr();
>  
>  	return 0;
>  }
> +pure_initcall(mmap_min_addr_init);
> -- 
> 2.52.0
> 

-- 
Kees Cook

^ permalink raw reply

* Re: [PATCH v4] ima: Fallback to ctime check for FS without kstat.change_cookie
From: Mimi Zohar @ 2026-01-30  2:32 UTC (permalink / raw)
  To: Frederick Lawler, Roberto Sassu, Dmitry Kasatkin, Eric Snowberg,
	Paul Moore, James Morris, Serge E. Hallyn, Darrick J. Wong,
	Christian Brauner, Josef Bacik, Jeff Layton
  Cc: linux-kernel, linux-integrity, linux-security-module, kernel-team
In-Reply-To: <20260129-xfs-ima-fixup-v4-1-6bb89df7b6a3@cloudflare.com>

On Thu, 2026-01-29 at 12:07 -0600, Frederick Lawler wrote:
> Commit 1cf7e834a6fb ("xfs: switch to multigrain timestamps")
> introduced a means to track change detection for an inode
> via ctime updates, opposed to setting kstat.change_cookie to
> an i_version when calling into xfs_vn_getattr().
> 
> This introduced a regression for IMA such that an action
> performed on a LOWER inode on a stacked file systems always
> requires a re-evaluation if the LOWER file system does not
> leverage kstat.change_cookie to track inode i_version or lacks
> i_version support all together.

Please describe the change in behavior that needs to be fixed.  Are there too
many, too few measurements, or both?

Examples are fine, but first describe the problem - not detecting file change on
xfs.

> 
> In the case of stacking XFS on XFS, an action on either the LOWER or UPPER
> will require re-evaluation. Stacking TMPFS on XFS for instance, once the
> inode is UPPER is mutated, IMA resumes normal behavior because TMPFS
> leverages generic_fillattr() to update the change cookie.

This sounds like the same issue - not detecting file change on xfs.  The problem
is simply manifesting itself on stacked filesystems.

> 
> This is because IMA caches kstat.change_cookie to compare against an
> inode's i_version directly in integrity_inode_attrs_changed(), and thus
> could be out of date depending on how file systems set
> kstat.change_cookie.
> 
> To address this, require integrity_inode_attrs_changed() to query
> vfs_getattr_nosec() to compare the cached version against
> kstat.change_cookie directly. This ensures that when updates occur,
> we're accessing the same changed inode version on changes, and fallback
> to compare against kstat.ctime when STATX_CHANGE_COOKIE is missing from
> result mask.
> 
> Lastly, because EVM still relies on querying and caching a inode's
> i_version directly, the integrity_inode_attrs_changed() falls back to the
> original inode.i_version != cached comparison.
> 
> Link: https://lore.kernel.org/all/aTspr4_h9IU4EyrR@CMGLRV3
> Fixes: 1cf7e834a6fb ("xfs: switch to multigrain timestamps")
> Suggested-by: Jeff Layton <jlayton@kernel.org>
> Reviewed-by: Jeff Layton <jlayton@kernel.org>
> Signed-off-by: Frederick Lawler <fred@cloudflare.com>
> ---
>  include/linux/integrity.h         | 35 +++++++++++++++++++++++++++++++----
>  security/integrity/evm/evm_main.c |  5 ++---
>  security/integrity/ima/ima_api.c  | 11 ++++++++---
>  security/integrity/ima/ima_main.c | 17 ++++++++++-------
>  4 files changed, 51 insertions(+), 17 deletions(-)
> 
> diff --git a/include/linux/integrity.h b/include/linux/integrity.h
> index f5842372359be5341b6870a43b92e695e8fc78af..034f0a1ed48ca8c19c764e302bbfc555dad92cde 100644
> --- a/include/linux/integrity.h
> +++ b/include/linux/integrity.h
> @@ -9,6 +9,8 @@
>  
>  #include <linux/fs.h>
>  #include <linux/iversion.h>
> +#include <linux/kernel.h>
> +#include <linux/time64.h>
>  
>  enum integrity_status {
>  	INTEGRITY_PASS = 0,
> @@ -51,14 +53,39 @@ integrity_inode_attrs_store(struct integrity_inode_attributes *attrs,
>  
>  /*
>   * On stacked filesystems detect whether the inode or its content has changed.
> + *
> + * Must be called in process context.
>   */
>  static inline bool
>  integrity_inode_attrs_changed(const struct integrity_inode_attributes *attrs,
> -			      const struct inode *inode)
> +			      struct file *file, struct inode *inode)
>  {
> -	return (inode->i_sb->s_dev != attrs->dev ||
> -		inode->i_ino != attrs->ino ||
> -		!inode_eq_iversion(inode, attrs->version));
> +	struct kstat stat;
> +
> +	might_sleep();
> +
> +	if (inode->i_sb->s_dev != attrs->dev || inode->i_ino != attrs->ino)
> +		return true;
> +
> +	/*
> +	 * EVM currently relies on backing inode i_version. While IS_I_VERSION
> +	 * is not a good indicator of i_version support, this still retains
> +	 * the logic such that a re-evaluation should still occur for EVM, and
> +	 * only for IMA if vfs_getattr_nosec() fails.
> +	 */
> +	if (!file || vfs_getattr_nosec(&file->f_path, &stat,
> +				       STATX_CHANGE_COOKIE | STATX_CTIME,
> +				       AT_STATX_SYNC_AS_STAT))
> +		return !IS_I_VERSION(inode) ||
> +			!inode_eq_iversion(inode, attrs->version);
> +
> +	if (stat.result_mask & STATX_CHANGE_COOKIE)
> +		return stat.change_cookie != attrs->version;
> +
> +	if (stat.result_mask & STATX_CTIME)
> +		return timespec64_to_ns(&stat.ctime) != (s64)attrs->version;
> +
> +	return true;
>  }
>  
>  
> diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
> index 5770cf691912aa912fc65280c59f5baac35dd725..8ac42b03740eb93bf23b15cb9039af6cd32aa999 100644
> --- a/security/integrity/ima/ima_main.c
> +++ b/security/integrity/ima/ima_main.c
> @@ -28,6 +28,7 @@
>  #include <linux/iversion.h>
>  #include <linux/evm.h>
>  #include <linux/crash_dump.h>
> +#include <linux/time64.h>
>  
>  #include "ima.h"
>  
> @@ -199,10 +200,13 @@ static void ima_check_last_writer(struct ima_iint_cache *iint,
>  					    &iint->atomic_flags);
>  		if ((iint->flags & IMA_NEW_FILE) ||
>  		    vfs_getattr_nosec(&file->f_path, &stat,
> -				      STATX_CHANGE_COOKIE,
> -				      AT_STATX_SYNC_AS_STAT) ||
> -		    !(stat.result_mask & STATX_CHANGE_COOKIE) ||
> -		    stat.change_cookie != iint->real_inode.version) {
> +			    STATX_CHANGE_COOKIE | STATX_CTIME,
> +			    AT_STATX_SYNC_AS_STAT) ||
> +		    ((stat.result_mask & STATX_CHANGE_COOKIE) ?
> +		      stat.change_cookie != iint->real_inode.version :
> +		      (!(stat.result_mask & STATX_CTIME) ||
> +			timespec64_to_ns(&stat.ctime) !=
> +			(s64)iint->real_inode.version))) {
>  			iint->flags &= ~(IMA_DONE_MASK | IMA_NEW_FILE);
>  			iint->measured_pcrs = 0;
>  			if (update)

The original i_version test was clear.  This code has become really hard to
understand and needs to be cleaned up.  Defining a helper function, will also
avoid code duplication.

Mimi

^ permalink raw reply

* [syzbot] Monthly lsm report (Jan 2026)
From: syzbot @ 2026-01-30 10:09 UTC (permalink / raw)
  To: linux-kernel, linux-security-module, syzkaller-bugs

Hello lsm maintainers/developers,

This is a 31-day syzbot report for the lsm subsystem.
All related reports/information can be found at:
https://syzkaller.appspot.com/upstream/s/lsm

During the period, 1 new issues were detected and 0 were fixed.
In total, 5 issues are still open and 42 have already been fixed.

Some of the still happening issues:

Ref Crashes Repro Title
<1> 65      Yes   INFO: task hung in process_measurement (3)
                  https://syzkaller.appspot.com/bug?extid=cb9e66807bcb882cd0c5
<2> 44      Yes   possible deadlock in keyring_clear (3)
                  https://syzkaller.appspot.com/bug?extid=f55b043dacf43776b50c
<3> 1       Yes   memory leak in prepare_creds (6)
                  https://syzkaller.appspot.com/bug?extid=dd3b43aa0204089217ee

---
This report is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzkaller@googlegroups.com.

To disable reminders for individual bugs, reply with the following command:
#syz set <Ref> no-reminders

To change bug's subsystems, reply with:
#syz set <Ref> subsystems: new-subsystem

You may send multiple commands in a single email message.

^ permalink raw reply

* Re: [PATCH net-next v2 1/4] selftests: net: Move some UAPI header inclusions after libc ones
From: Thomas Weißschuh @ 2026-01-30 10:22 UTC (permalink / raw)
  To: Matthieu Baerts
  Cc: netdev, linux-kernel, linux-api, Arnd Bergmann, linux-kselftest,
	mptcp, linux-security-module, bpf, libc-alpha
In-Reply-To: <4e673f7f-c49c-46b0-85b4-bae6e4efcb3a@kernel.org>

(trimmed the recipient list)

Hi Matt,

On Mon, Jan 26, 2026 at 07:13:50PM +0100, Matthieu Baerts wrote:
> On 20/01/2026 15:10, Thomas Weißschuh wrote:
> > Interleaving inclusions of UAPI headers and libc headers is problematic.
> > Both sets of headers define conflicting symbols. To enable their
> > coexistence a compatibility-mechanism is in place.
> > 
> > An upcoming change will define 'struct sockaddr' from linux/socket.h.
> > However sys/socket.h from libc does not yet handle this case and a
> > symbol conflict will arise.
> > 
> > Furthermore libc-compat.h evaluates the state of the libc
> > inclusions only once, at the point it is included first. If another
> > problematic header from libc is included later, symbol conflicts arise.
> > This will trigger other duplicate definitions when linux/libc-compat.h
> > is added to linux/socket.h
> > 
> > Move the inclusion of UAPI headers after the inclusion of the glibc
> > ones, so the libc-compat.h continues to work correctly.
> 
> Thank you for looking at this!
> 
> Here is my (late, sorry) review for the modifications related to MPTCP:
> > diff --git a/tools/testing/selftests/net/mptcp/mptcp_diag.c b/tools/testing/selftests/net/mptcp/mptcp_diag.c
> > index 8e0b1b8d84b6..af25ebfd2915 100644
> > --- a/tools/testing/selftests/net/mptcp/mptcp_diag.c
> > +++ b/tools/testing/selftests/net/mptcp/mptcp_diag.c
> > @@ -1,11 +1,6 @@
> >  // SPDX-License-Identifier: GPL-2.0
> >  /* Copyright (c) 2025, Kylin Software */
> >  
> > -#include <linux/sock_diag.h>
> > -#include <linux/rtnetlink.h>
> > -#include <linux/inet_diag.h>
> > -#include <linux/netlink.h>
> > -#include <linux/compiler.h>
> >  #include <sys/socket.h>
> >  #include <netinet/in.h>
> >  #include <linux/tcp.h>
> 
> There is a remaining one (linux/tcp.h) here that you might want to move
> below too.

Good point.

> > @@ -17,6 +12,12 @@
> >  #include <errno.h>
> >  #include <stdio.h>
> >  
> > +#include <linux/sock_diag.h>
> > +#include <linux/rtnetlink.h>
> > +#include <linux/inet_diag.h>
> > +#include <linux/netlink.h>
> > +#include <linux/compiler.h>
> 
> Note that I just noticed this is the only file from this directory where
> the "includes" are not sorted by type and alphabetical order, see
> pm_nl_ctl.c as an example. A bit of a detail, but if you plan to send a
> v2, do you mind doing that too here while at it, please?

I'll send a v3 during the next cycle.

> If not, I can look at that later, but better to avoid doing that in
> parallel.

If you want to fix this up already during this cycle,
that would also be most welcome.


Thomas

^ permalink raw reply

* Re: [PATCH net-next v2 0/4] net: uapi: Provide an UAPI definition of 'struct sockaddr'
From: Thomas Weißschuh @ 2026-01-30 10:34 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: Eric Dumazet, Kuniyuki Iwashima, Paolo Abeni, Willem de Bruijn,
	David S. Miller, Simon Horman, Shuah Khan, Matthieu Baerts,
	Mat Martineau, Geliang Tang, Mickaël Salaün,
	Günther Noack, Alexei Starovoitov, Daniel Borkmann,
	Jesper Dangaard Brouer, John Fastabend, Stanislav Fomichev,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, KP Singh, Hao Luo, Jiri Olsa, netdev, linux-kernel,
	linux-api, Arnd Bergmann, linux-kselftest, mptcp,
	linux-security-module, bpf, libc-alpha, Carlos O'Donell,
	Adhemerval Zanella, Rich Felker, klibc, Florian Weimer
In-Reply-To: <20260121192729.2095aa25@kernel.org>

On Wed, Jan 21, 2026 at 07:27:29PM -0800, Jakub Kicinski wrote:
> On Tue, 20 Jan 2026 15:10:30 +0100 Thomas Weißschuh wrote:
> > Various UAPI headers reference 'struct sockaddr'. Currently the
> > definition of this struct is pulled in from the libc header
> > sys/socket.h. This is problematic as it introduces a dependency
> > on a full userspace toolchain.
> > 
> > Add a definition of 'struct sockaddr' to the UAPI headers.
> > Before that, reorder some problematic header inclusions in the selftests.
> 
> >  include/linux/socket.h                             | 10 ----------
> >  include/uapi/linux/if.h                            |  4 ----
> >  include/uapi/linux/libc-compat.h                   | 12 ++++++++++++
> >  include/uapi/linux/socket.h                        | 14 ++++++++++++++
> >  samples/bpf/xdp_adjust_tail_user.c                 |  6 ++++--
> >  samples/bpf/xdp_fwd_user.c                         |  7 ++++---
> >  samples/bpf/xdp_router_ipv4_user.c                 |  6 +++---
> >  samples/bpf/xdp_sample_user.c                      | 15 ++++++++-------
> >  samples/bpf/xdp_tx_iptunnel_user.c                 |  4 ++--
> >  tools/testing/selftests/landlock/audit.h           |  7 ++++---
> >  tools/testing/selftests/net/af_unix/diag_uid.c     |  9 +++++----
> >  tools/testing/selftests/net/busy_poller.c          |  3 ++-
> >  tools/testing/selftests/net/mptcp/mptcp_diag.c     | 11 ++++++-----
> >  tools/testing/selftests/net/nettest.c              |  4 ++--
> >  tools/testing/selftests/net/tcp_ao/icmps-discard.c |  6 +++---
> >  tools/testing/selftests/net/tcp_ao/lib/netlink.c   |  9 +++++----
> >  tools/testing/selftests/net/tun.c                  |  5 +++--
> >  17 files changed, 77 insertions(+), 55 deletions(-)
> 
> Are all those selftests / samples getting broken by this patch set?

Yes.

Some of them get broken by the new 'struct sockaddr', but some others are
already broken just by the new transitive inclusion of libc-compat.h.
So any header starting to use the compatibility machinery may trigger breakage
in code including UAPI headers before libc header, even for completely new type
definitions which themselves would not conflict with libc.

> I understand that we should avoid libc dependencies in uAPI but at
> least speaking for networking - building selftests without libc is..
> not a practical proposition?

I am not sure I understand. Some sort of libc will always be necessary.
And as the selftests are intended to exercise the low-level kernel APIs,
even those not supported by libc, the UAPI headers will also be necessary.

There is nolibc (tools/include/nolibc/) which is using the UAPI headers in
most cases, and aims to be compatible. And can be and already is used for
selftests, but it will be too limited for all of the networking selftests.
(Disclaimer: I am maintaining nolibc)

My goal is *not* to make the different headers less compatible on purpose.
But by removing the existing dependencies we can now enforce the checks in
CONFIG_UAPI_HEADER_TEST to prevent any new ones from creeping in. Therefore
preventing compatiblity issues in any new UAPI.


Thomas

^ permalink raw reply

* Re: [PATCH net-next v2 1/4] selftests: net: Move some UAPI header inclusions after libc ones
From: Matthieu Baerts @ 2026-01-30 10:39 UTC (permalink / raw)
  To: Thomas Weißschuh
  Cc: netdev, linux-kernel, linux-api, Arnd Bergmann, linux-kselftest,
	mptcp, linux-security-module, bpf, libc-alpha
In-Reply-To: <20260130111949-4b4eb870-6df7-4026-a48c-730fa8660ad6@linutronix.de>

Hi Thomas,

On 30/01/2026 11:22, Thomas Weißschuh wrote:

(...)

>> Note that I just noticed this is the only file from this directory where
>> the "includes" are not sorted by type and alphabetical order, see
>> pm_nl_ctl.c as an example. A bit of a detail, but if you plan to send a
>> v2, do you mind doing that too here while at it, please?
> 
> I'll send a v3 during the next cycle.

Thanks!
>> If not, I can look at that later, but better to avoid doing that in
>> parallel.
> 
> If you want to fix this up already during this cycle,
> that would also be most welcome.

Sure, I can do that.

Cheers,
Matt
-- 
Sponsored by the NGI0 Core fund.


^ permalink raw reply

* Re: [PATCH] ipe: document AT_EXECVE_CHECK TOCTOU issue on OverlayFS
From: Amir Goldstein @ 2026-01-30 11:05 UTC (permalink / raw)
  To: wufan
  Cc: linux-security-module, linux-doc, linux-kernel, corbet, mic,
	miklos, linux-unionfs
In-Reply-To: <20260130001418.18414-1-wufan@kernel.org>

On Fri, Jan 30, 2026 at 1:14 AM <wufan@kernel.org> wrote:
>
> From: Fan Wu <wufan@kernel.org>
>
> Document a known TOCTOU (time-of-check to time-of-use) issue when using
> AT_EXECVE_CHECK with read() on OverlayFS.

Hi Fan Wu,

TBH, I don't like the way that this problem is being framed.
IIUC, the problem is using IPE on a non-read-only fs.
Is that correct?

That fact that IPE metadata is usually coupled with read-only fs
is interesting for the understanding of the use case, but unless
IPE feature mandates read-only fs, this is a generic problem.

OverlayFS is just one private case, which happens to be common
in Android or containers? IDK, you did not mention this.

Please describe the problem as a generic problem and give
overlayfs as an example, preferable with references to the
real world use cases.

If I misunderstood, please explain why this problem is exclusive
to overlayfs.

Thanks,
Amir.

> The deny_write_access()
> protection is only held during the syscall, allowing a copy-up operation
> to be triggered afterward, causing subsequent read() calls to return
> content from the unprotected upper layer.
>
> This is generally not a concern for typical IPE deployments since
> dm-verity and fs-verity protected files are effectively read-only.
> However, OverlayFS with a writable upper layer presents a special case.
>
> Document mitigation strategies including mounting overlay as read-only
> and using mmap() instead of read(). Note that the mmap() mitigation
> relies on current OverlayFS implementation details and should not be
> considered a security guarantee.
>
> Signed-off-by: Fan Wu <wufan@kernel.org>
> ---
>  Documentation/admin-guide/LSM/ipe.rst | 32 +++++++++++++++++++++++++++
>  1 file changed, 32 insertions(+)
>
> diff --git a/Documentation/admin-guide/LSM/ipe.rst b/Documentation/admin-guide/LSM/ipe.rst
> index a756d8158531..b621a98fe5e2 100644
> --- a/Documentation/admin-guide/LSM/ipe.rst
> +++ b/Documentation/admin-guide/LSM/ipe.rst
> @@ -110,6 +110,34 @@ intercepts during the execution process, this mechanism needs the interpreter
>  to take the initiative, and existing interpreters won't be automatically
>  supported unless the signal call is added.
>
> +.. WARNING::
> +
> +   There is a known TOCTOU (time-of-check to time-of-use) issue with
> +   ``AT_EXECVE_CHECK`` when interpreters use ``read()`` to obtain script
> +   contents after the check [#atacexecvecheck_toctou]_. The ``AT_EXECVE_CHECK``
> +   protection (via ``deny_write_access()``) is only held during the syscall.
> +   After it returns, the file can be modified before the interpreter reads it.
> +
> +   In typical IPE deployments, this is not a concern because files protected
> +   by dm-verity or fs-verity are effectively read-only and cannot be modified.
> +   However, OverlayFS presents a special case: when the lower layer is
> +   dm-verity protected (read-only) but the upper layer is writable, an
> +   attacker with write access can trigger a copy-up operation after the
> +   ``AT_EXECVE_CHECK`` returns, causing subsequent ``read()`` calls to return
> +   content from the unprotected upper layer instead of the verified lower layer.
> +
> +   To mitigate this issue on OverlayFS:
> +
> +   -  Mount the overlay as read-only, or restrict write access to the upper
> +      layer.
> +   -  Interpreters may use ``mmap()`` instead of ``read()`` to obtain script
> +      contents. Currently, OverlayFS fixes the underlying real file reference
> +      at ``open()`` time for mmap operations, so mmap will continue to access
> +      the original lower layer file even after a copy-up. However, this
> +      behavior is an implementation detail of OverlayFS and is not guaranteed
> +      to remain stable across kernel versions. Do not rely on this as a
> +      security guarantee.
> +
>  Threat Model
>  ------------
>
> @@ -833,3 +861,7 @@ A:
>                       kernel's fsverity support; IPE does not impose any
>                       restrictions on the digest algorithm itself;
>                       thus, this list may be out of date.
> +
> +.. [#atacexecvecheck_toctou] See the O_DENY_WRITE RFC discussion for details on
> +                             this TOCTOU issue:
> +                             https://lore.kernel.org/all/20250822170800.2116980-1-mic@digikod.net/
> --
> 2.52.0
>

^ permalink raw reply

* Re: [PATCH v4] ima: Fallback to ctime check for FS without kstat.change_cookie
From: Mimi Zohar @ 2026-01-30 13:00 UTC (permalink / raw)
  To: Frederick Lawler, Roberto Sassu, Dmitry Kasatkin, Eric Snowberg,
	Paul Moore, James Morris, Serge E. Hallyn, Darrick J. Wong,
	Christian Brauner, Josef Bacik, Jeff Layton
  Cc: linux-kernel, linux-integrity, linux-security-module, kernel-team
In-Reply-To: <42da6a2c72b1093b7aa5106cdce4d0efdbd785ee.camel@linux.ibm.com>

On Thu, 2026-01-29 at 21:32 -0500, Mimi Zohar wrote:
> On Thu, 2026-01-29 at 12:07 -0600, Frederick Lawler wrote:
> > Commit 1cf7e834a6fb ("xfs: switch to multigrain timestamps")
> > introduced a means to track change detection for an inode
> > via ctime updates, opposed to setting kstat.change_cookie to
> > an i_version when calling into xfs_vn_getattr().
> > 
> > This introduced a regression for IMA such that an action
> > performed on a LOWER inode on a stacked file systems always
> > requires a re-evaluation if the LOWER file system does not
> > leverage kstat.change_cookie to track inode i_version or lacks
> > i_version support all together.
> 
> Please describe the change in behavior that needs to be fixed.  Are there too
> many, too few measurements, or both?
> 
> Examples are fine, but first describe the problem - not detecting file change on
> xfs.
> 
> > 
> > In the case of stacking XFS on XFS, an action on either the LOWER or UPPER
> > will require re-evaluation. Stacking TMPFS on XFS for instance, once the
> > inode is UPPER is mutated, IMA resumes normal behavior because TMPFS
> > leverages generic_fillattr() to update the change cookie.
> 
> This sounds like the same issue - not detecting file change on xfs.  The problem
> is simply manifesting itself on stacked filesystems.

Splitting this patch, so that the base XFS changes are in one patch and the
stacked filesystem changes are in the other, would really help clarify what is
needed and the reason why.

Mimi

> 
> > 
> > This is because IMA caches kstat.change_cookie to compare against an
> > inode's i_version directly in integrity_inode_attrs_changed(), and thus
> > could be out of date depending on how file systems set
> > kstat.change_cookie.
> > 
> > To address this, require integrity_inode_attrs_changed() to query
> > vfs_getattr_nosec() to compare the cached version against
> > kstat.change_cookie directly. This ensures that when updates occur,
> > we're accessing the same changed inode version on changes, and fallback
> > to compare against kstat.ctime when STATX_CHANGE_COOKIE is missing from
> > result mask.
> > 
> > Lastly, because EVM still relies on querying and caching a inode's
> > i_version directly, the integrity_inode_attrs_changed() falls back to the
> > original inode.i_version != cached comparison.
> > 
> > Link: https://lore.kernel.org/all/aTspr4_h9IU4EyrR@CMGLRV3
> > Fixes: 1cf7e834a6fb ("xfs: switch to multigrain timestamps")
> > Suggested-by: Jeff Layton <jlayton@kernel.org>
> > Reviewed-by: Jeff Layton <jlayton@kernel.org>
> > Signed-off-by: Frederick Lawler <fred@cloudflare.com>
> > ---
> >  include/linux/integrity.h         | 35 +++++++++++++++++++++++++++++++----
> >  security/integrity/evm/evm_main.c |  5 ++---
> >  security/integrity/ima/ima_api.c  | 11 ++++++++---
> >  security/integrity/ima/ima_main.c | 17 ++++++++++-------
> >  4 files changed, 51 insertions(+), 17 deletions(-)
> > 
> > diff --git a/include/linux/integrity.h b/include/linux/integrity.h
> > index f5842372359be5341b6870a43b92e695e8fc78af..034f0a1ed48ca8c19c764e302bbfc555dad92cde 100644
> > --- a/include/linux/integrity.h
> > +++ b/include/linux/integrity.h
> > @@ -9,6 +9,8 @@
> >  
> >  #include <linux/fs.h>
> >  #include <linux/iversion.h>
> > +#include <linux/kernel.h>
> > +#include <linux/time64.h>
> >  
> >  enum integrity_status {
> >  	INTEGRITY_PASS = 0,
> > @@ -51,14 +53,39 @@ integrity_inode_attrs_store(struct integrity_inode_attributes *attrs,
> >  
> >  /*
> >   * On stacked filesystems detect whether the inode or its content has changed.
> > + *
> > + * Must be called in process context.
> >   */
> >  static inline bool
> >  integrity_inode_attrs_changed(const struct integrity_inode_attributes *attrs,
> > -			      const struct inode *inode)
> > +			      struct file *file, struct inode *inode)
> >  {
> > -	return (inode->i_sb->s_dev != attrs->dev ||
> > -		inode->i_ino != attrs->ino ||
> > -		!inode_eq_iversion(inode, attrs->version));
> > +	struct kstat stat;
> > +
> > +	might_sleep();
> > +
> > +	if (inode->i_sb->s_dev != attrs->dev || inode->i_ino != attrs->ino)
> > +		return true;
> > +
> > +	/*
> > +	 * EVM currently relies on backing inode i_version. While IS_I_VERSION
> > +	 * is not a good indicator of i_version support, this still retains
> > +	 * the logic such that a re-evaluation should still occur for EVM, and
> > +	 * only for IMA if vfs_getattr_nosec() fails.
> > +	 */
> > +	if (!file || vfs_getattr_nosec(&file->f_path, &stat,
> > +				       STATX_CHANGE_COOKIE | STATX_CTIME,
> > +				       AT_STATX_SYNC_AS_STAT))
> > +		return !IS_I_VERSION(inode) ||
> > +			!inode_eq_iversion(inode, attrs->version);
> > +
> > +	if (stat.result_mask & STATX_CHANGE_COOKIE)
> > +		return stat.change_cookie != attrs->version;
> > +
> > +	if (stat.result_mask & STATX_CTIME)
> > +		return timespec64_to_ns(&stat.ctime) != (s64)attrs->version;
> > +
> > +	return true;
> >  }
> >  
> >  
> > diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
> > index 5770cf691912aa912fc65280c59f5baac35dd725..8ac42b03740eb93bf23b15cb9039af6cd32aa999 100644
> > --- a/security/integrity/ima/ima_main.c
> > +++ b/security/integrity/ima/ima_main.c
> > @@ -28,6 +28,7 @@
> >  #include <linux/iversion.h>
> >  #include <linux/evm.h>
> >  #include <linux/crash_dump.h>
> > +#include <linux/time64.h>
> >  
> >  #include "ima.h"
> >  
> > @@ -199,10 +200,13 @@ static void ima_check_last_writer(struct ima_iint_cache *iint,
> >  					    &iint->atomic_flags);
> >  		if ((iint->flags & IMA_NEW_FILE) ||
> >  		    vfs_getattr_nosec(&file->f_path, &stat,
> > -				      STATX_CHANGE_COOKIE,
> > -				      AT_STATX_SYNC_AS_STAT) ||
> > -		    !(stat.result_mask & STATX_CHANGE_COOKIE) ||
> > -		    stat.change_cookie != iint->real_inode.version) {
> > +			    STATX_CHANGE_COOKIE | STATX_CTIME,
> > +			    AT_STATX_SYNC_AS_STAT) ||
> > +		    ((stat.result_mask & STATX_CHANGE_COOKIE) ?
> > +		      stat.change_cookie != iint->real_inode.version :
> > +		      (!(stat.result_mask & STATX_CTIME) ||
> > +			timespec64_to_ns(&stat.ctime) !=
> > +			(s64)iint->real_inode.version))) {
> >  			iint->flags &= ~(IMA_DONE_MASK | IMA_NEW_FILE);
> >  			iint->measured_pcrs = 0;
> >  			if (update)
> 
> The original i_version test was clear.  This code has become really hard to
> understand and needs to be cleaned up.  Defining a helper function, will also
> avoid code duplication.
> 
> Mimi

^ permalink raw reply

* Re: [PATCH net-next v2 0/4] net: uapi: Provide an UAPI definition of 'struct sockaddr'
From: Jakub Kicinski @ 2026-01-30 16:17 UTC (permalink / raw)
  To: Thomas Weißschuh
  Cc: Eric Dumazet, Kuniyuki Iwashima, Paolo Abeni, Willem de Bruijn,
	David S. Miller, Simon Horman, Shuah Khan, Matthieu Baerts,
	Mat Martineau, Geliang Tang, Mickaël Salaün,
	Günther Noack, Alexei Starovoitov, Daniel Borkmann,
	Jesper Dangaard Brouer, John Fastabend, Stanislav Fomichev,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, KP Singh, Hao Luo, Jiri Olsa, netdev, linux-kernel,
	linux-api, Arnd Bergmann, linux-kselftest, mptcp,
	linux-security-module, bpf, libc-alpha, Carlos O'Donell,
	Adhemerval Zanella, Rich Felker, klibc, Florian Weimer
In-Reply-To: <20260130112309-28f2645b-e756-4173-96da-cf5c59191520@linutronix.de>

On Fri, 30 Jan 2026 11:34:15 +0100 Thomas Weißschuh wrote:
> > Are all those selftests / samples getting broken by this patch set?  
> 
> Yes.
> 
> Some of them get broken by the new 'struct sockaddr', but some others are
> already broken just by the new transitive inclusion of libc-compat.h.
> So any header starting to use the compatibility machinery may trigger breakage
> in code including UAPI headers before libc header, even for completely new type
> definitions which themselves would not conflict with libc.

Let's split the uAPI header changes from any selftest changes.
If you're saying the the selftests no longer build after the uAPI
header changes then of course we can't apply the patches.

^ permalink raw reply

* Re: [PATCH] lsm: preserve /proc/sys/vm/mmap_min_addr when !CONFIG_SECURITY
From: Paul Moore @ 2026-01-30 16:48 UTC (permalink / raw)
  To: Kees Cook; +Cc: linux-security-module, linux-mm, lorenzo.stoakes
In-Reply-To: <202601291730.45120C1A@keescook>

On Thu, Jan 29, 2026 at 8:31 PM Kees Cook <kees@kernel.org> wrote:
> On Thu, Jan 29, 2026 at 05:51:33PM -0500, Paul Moore wrote:
> > While reworking the LSM initialization code the
> > /proc/sys/vm/mmap_min_addr handler was inadvertently caught up in the
> > change and the procfs entry wasn't setup when CONFIG_SECURITY was not
> > selected at kernel build time.  This patch restores the previous behavior
> > and ensures that the procfs entry is setup regardless of the
> > CONFIG_SECURITY state.
> >
> > Future work will improve upon this, likely by moving the procfs handler
> > into the mm subsystem, but this patch should resolve the immediate
> > regression.
> >
> > Fixes: 4ab5efcc2829 ("lsm: consolidate all of the LSM framework initcalls")
> > Reported-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
> > Signed-off-by: Paul Moore <paul@paul-moore.com>
>
> Good catch and fix!
>
> Reviewed-by: Kees Cook <kees@kernel.org>

Merged into lsm/stable-6.19, with plans to send this to Linus early
next week after a day or two in linux-next.  Thanks everyone!

-- 
paul-moore.com

^ permalink raw reply

* Re: [PATCH v4 15/17] module: Introduce hash-based integrity checking
From: Petr Pavlu @ 2026-01-30 17:06 UTC (permalink / raw)
  To: Thomas Weißschuh
  Cc: Nathan Chancellor, Arnd Bergmann, Luis Chamberlain, Sami Tolvanen,
	Daniel Gomez, Paul Moore, James Morris, Serge E. Hallyn,
	Jonathan Corbet, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Naveen N Rao, Mimi Zohar, Roberto Sassu,
	Dmitry Kasatkin, Eric Snowberg, Nicolas Schier, Daniel Gomez,
	Aaron Tomlin, Christophe Leroy (CS GROUP), Nicolas Schier,
	Nicolas Bouchinet, Xiu Jianfeng, Fabian Grünbichler,
	Arnout Engelen, Mattia Rizzolo, kpcyrd, Christian Heusel,
	Câju Mihai-Drosi, Sebastian Andrzej Siewior, linux-kbuild,
	linux-kernel, linux-arch, linux-modules, linux-security-module,
	linux-doc, linuxppc-dev, linux-integrity
In-Reply-To: <20260113-module-hashes-v4-15-0b932db9b56b@weissschuh.net>

On 1/13/26 1:28 PM, Thomas Weißschuh wrote:
> Normally the .ko module files depend on a fully built vmlinux to be
> available for modpost validation and BTF generation. With
> CONFIG_MODULE_HASHES, vmlinux now depends on the modules
> to build a merkle tree. This introduces a dependency cycle which is
> impossible to satisfy. Work around this by building the modules during
> link-vmlinux.sh, after vmlinux is complete enough for modpost and BTF
> but before the final module hashes are

I wonder if this dependency cycle could be resolved by utilizing the
split into vmlinux.unstripped and vmlinux that occurred last year.

The idea is to create the following ordering: vmlinux.unstripped ->
modules -> vmlinux, and to patch in .module_hashes only when building
the final vmlinux.

This would require the following:
* Split scripts/Makefile.vmlinux into two Makefiles, one that builds the
  current vmlinux.unstripped and the second one that builds the final
  vmlinux from it.
* Modify the top Makefile to recognize vmlinux.unstripped and update the
  BTF generation rule 'modules: vmlinux' to
  'modules: vmlinux.unstripped'.
* Add the 'vmlinux: modules' ordering in the top Makefile for
  CONFIG_MODULE_HASHES=y.
* Remove the patching of vmlinux.unstripped in scripts/link-vmlinux.sh
  and instead move it into scripts/Makefile.vmlinux when running objcopy
  to produce the final vmlinux.

I think this approach has two main advantages:
* CONFIG_MODULE_HASHES can be made orthogonal to
  CONFIG_DEBUG_INFO_BTF_MODULES.
* All dependencies are expressed at the Makefile level instead of having
  scripts/link-vmlinux.sh invoke 'make -f Makefile modules'.

Below is a rough prototype that applies on top of this series. It is a
bit verbose due to the splitting of part of scripts/Makefile.vmlinux
into scripts/Makefile.vmlinux_unstripped.

-- 
Thanks,
Petr


diff --git a/Makefile b/Makefile
index 841772a5a260..19a3beb82fa7 100644
--- a/Makefile
+++ b/Makefile
@@ -1259,7 +1259,7 @@ vmlinux_o: vmlinux.a $(KBUILD_VMLINUX_LIBS)
 vmlinux.o modules.builtin.modinfo modules.builtin: vmlinux_o
 	@:
 
-PHONY += vmlinux
+PHONY += vmlinux.unstripped vmlinux
 # LDFLAGS_vmlinux in the top Makefile defines linker flags for the top vmlinux,
 # not for decompressors. LDFLAGS_vmlinux in arch/*/boot/compressed/Makefile is
 # unrelated; the decompressors just happen to have the same base name,
@@ -1270,9 +1270,11 @@ PHONY += vmlinux
 #   https://savannah.gnu.org/bugs/?61463
 # For Make > 4.4, the following simple code will work:
 #  vmlinux: private export LDFLAGS_vmlinux := $(LDFLAGS_vmlinux)
-vmlinux: private _LDFLAGS_vmlinux := $(LDFLAGS_vmlinux)
-vmlinux: export LDFLAGS_vmlinux = $(_LDFLAGS_vmlinux)
-vmlinux: vmlinux.o $(KBUILD_LDS) modpost
+vmlinux.unstripped: private _LDFLAGS_vmlinux := $(LDFLAGS_vmlinux)
+vmlinux.unstripped: export LDFLAGS_vmlinux = $(_LDFLAGS_vmlinux)
+vmlinux.unstripped: vmlinux.o $(KBUILD_LDS) modpost
+	$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.vmlinux_unstripped
+vmlinux: vmlinux.unstripped
 	$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.vmlinux
 
 # The actual objects are generated when descending,
@@ -1541,7 +1543,7 @@ all: dtbs
 endif
 
 ifdef CONFIG_GENERIC_BUILTIN_DTB
-vmlinux: dtbs
+vmlinux.unstripped: dtbs
 endif
 
 endif
@@ -1588,9 +1590,11 @@ endif
 # is an exception.
 ifdef CONFIG_DEBUG_INFO_BTF_MODULES
 KBUILD_BUILTIN := y
-ifndef CONFIG_MODULE_HASHES
-modules: vmlinux
+modules: vmlinux.unstripped
 endif
+
+ifdef CONFIG_MODULE_HASHES
+vmlinux: modules
 endif
 
 modules: modules_prepare
@@ -1983,11 +1987,7 @@ modules.order: $(build-dir)
 # KBUILD_MODPOST_NOFINAL can be set to skip the final link of modules.
 # This is solely useful to speed up test compiles.
 modules: modpost
-ifdef CONFIG_MODULE_HASHES
-ifeq ($(MODULE_HASHES_MODPOST_FINAL), 1)
-	$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modfinal
-endif
-else ifneq ($(KBUILD_MODPOST_NOFINAL),1)
+ifneq ($(KBUILD_MODPOST_NOFINAL),1)
 	$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modfinal
 endif
 
diff --git a/scripts/Makefile.modfinal b/scripts/Makefile.modfinal
index 890724edac69..213e21ecfe0d 100644
--- a/scripts/Makefile.modfinal
+++ b/scripts/Makefile.modfinal
@@ -55,7 +55,7 @@ if_changed_except = $(if $(call newer_prereqs_except,$(2))$(cmd-check),      \
 	$(cmd);                                                              \
 	printf '%s\n' 'savedcmd_$@ := $(make-cmd)' > $(dot-target).cmd, @:)
 
-# Re-generate module BTFs if either module's .ko or vmlinux changed
+# Re-generate module BTFs if either module's .ko or vmlinux.unstripped changed
 %.ko: %.o %.mod.o .module-common.o $(objtree)/scripts/module.lds $(and $(CONFIG_DEBUG_INFO_BTF_MODULES),$(KBUILD_BUILTIN),$(objtree)/.tmp_vmlinux_btf.stamp) FORCE
 	+$(call if_changed_except,ld_ko_o,$(objtree)/.tmp_vmlinux_btf.stamp)
 ifdef CONFIG_DEBUG_INFO_BTF_MODULES
diff --git a/scripts/Makefile.vmlinux b/scripts/Makefile.vmlinux
index 4ce849f6253a..8c2a938c88ab 100644
--- a/scripts/Makefile.vmlinux
+++ b/scripts/Makefile.vmlinux
@@ -15,78 +15,24 @@ targets :=
 %.o: %.S FORCE
 	$(call if_changed_rule,as_o_S)
 
-# Built-in dtb
-# ---------------------------------------------------------------------------
-
-quiet_cmd_wrap_dtbs = WRAP    $@
-      cmd_wrap_dtbs = {							\
-	echo '\#include <asm-generic/vmlinux.lds.h>';			\
-	echo '.section .dtb.init.rodata,"a"';				\
-	while read dtb; do						\
-		symbase=__dtb_$$(basename -s .dtb "$${dtb}" | tr - _);	\
-		echo '.balign STRUCT_ALIGNMENT';			\
-		echo ".global $${symbase}_begin";			\
-		echo "$${symbase}_begin:";				\
-		echo '.incbin "'$$dtb'" ';				\
-		echo ".global $${symbase}_end";				\
-		echo "$${symbase}_end:";				\
-	done < $<;							\
-	} > $@
-
-.builtin-dtbs.S: .builtin-dtbs-list FORCE
-	$(call if_changed,wrap_dtbs)
-
-quiet_cmd_gen_dtbs_list = GEN     $@
-      cmd_gen_dtbs_list = \
-	$(if $(CONFIG_BUILTIN_DTB_NAME), echo "arch/$(SRCARCH)/boot/dts/$(CONFIG_BUILTIN_DTB_NAME).dtb",:) > $@
-
-.builtin-dtbs-list: arch/$(SRCARCH)/boot/dts/dtbs-list FORCE
-	$(call if_changed,$(if $(CONFIG_BUILTIN_DTB_ALL),copy,gen_dtbs_list))
-
-targets += .builtin-dtbs-list
-
-ifdef CONFIG_GENERIC_BUILTIN_DTB
-targets += .builtin-dtbs.S .builtin-dtbs.o
-vmlinux.unstripped: .builtin-dtbs.o
-endif
-
-# vmlinux.unstripped
+# vmlinux
 # ---------------------------------------------------------------------------
 
-ifdef CONFIG_ARCH_WANTS_PRE_LINK_VMLINUX
-vmlinux.unstripped: arch/$(SRCARCH)/tools/vmlinux.arch.o
-
-arch/$(SRCARCH)/tools/vmlinux.arch.o: vmlinux.o FORCE
-	$(Q)$(MAKE) $(build)=arch/$(SRCARCH)/tools $@
-endif
-
-ARCH_POSTLINK := $(wildcard $(srctree)/arch/$(SRCARCH)/Makefile.postlink)
-
-# Final link of vmlinux with optional arch pass after final link
-cmd_link_vmlinux =							\
-	$< "$(LD)" "$(KBUILD_LDFLAGS)" "$(LDFLAGS_vmlinux)" "$@";	\
-	$(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) $@, true)
+ifdef CONFIG_MODULE_HASHES
+targets += .tmp_module_hashes.o
+.tmp_module_hashes.o: .tmp_module_hashes.c FORCE
 
-targets += vmlinux.unstripped .vmlinux.export.o
-vmlinux.unstripped: scripts/link-vmlinux.sh vmlinux.o .vmlinux.export.o $(KBUILD_LDS) FORCE
-	+$(call if_changed_dep,link_vmlinux)
-ifdef CONFIG_DEBUG_INFO_BTF
-vmlinux.unstripped: $(RESOLVE_BTFIDS)
-endif
+quiet_cmd_module_hashes = OBJCOPY $@
+      cmd_module_hashes = $(OBJCOPY) --dump-section .module_hashes=$@ $<
 
-ifdef CONFIG_BUILDTIME_TABLE_SORT
-vmlinux.unstripped: scripts/sorttable
-endif
+targets += .tmp_module_hashes.bin
+.tmp_module_hashes.bin: .tmp_module_hashes.o FORCE
+	$(call if_changed,module_hashes)
 
-ifdef CONFIG_MODULE_HASHES
-vmlinux.unstripped: $(objtree)/scripts/modules-merkle-tree
-vmlinux.unstripped: modules.order
-vmlinux.unstripped: $(wildcard include/config/MODULE_INSTALL_STRIP)
+vmlinux: .tmp_module_hashes.bin
+patch-module-hashes := --update-section .module_hashes=.tmp_module_hashes.bin
 endif
 
-# vmlinux
-# ---------------------------------------------------------------------------
-
 remove-section-y                                   := .modinfo
 remove-section-$(CONFIG_ARCH_VMLINUX_NEEDS_RELOCS) += '.rel*' '!.rel*.dyn'
 # for compatibility with binutils < 2.32
@@ -98,70 +44,15 @@ remove-symbols := -w --strip-unneeded-symbol='__mod_device_table__*'
 # To avoid warnings: "empty loadable segment detected at ..." from GNU objcopy,
 # it is necessary to remove the PT_LOAD flag from the segment.
 quiet_cmd_strip_relocs = OBJCOPY $@
-      cmd_strip_relocs = $(OBJCOPY) $(patsubst %,--set-section-flags %=noload,$(remove-section-y)) $< $@; \
-                         $(OBJCOPY) $(addprefix --remove-section=,$(remove-section-y)) $(remove-symbols) $@
+      cmd_script_relocs = $(OBJCOPY) $(patsubst %,--set-section-flags %=noload,$(remove-section-y)) $< $@; \
+                          $(OBJCOPY) $(addprefix --remove-section=,$(remove-section-y)) \
+                                     $(remove-symbols) \
+                                     $(patch-module-hashes) $@
 
 targets += vmlinux
 vmlinux: vmlinux.unstripped FORCE
 	$(call if_changed,strip_relocs)
 
-# modules.builtin.modinfo
-# ---------------------------------------------------------------------------
-
-# .modinfo in vmlinux.unstripped is aligned to 8 bytes for compatibility with
-# tools that expect vmlinux to have sufficiently aligned sections but the
-# additional bytes used for padding .modinfo to satisfy this requirement break
-# certain versions of kmod with
-#
-#   depmod: ERROR: kmod_builtin_iter_next: unexpected string without modname prefix
-#
-# Strip the trailing padding bytes after extracting .modinfo to comply with
-# what kmod expects to parse.
-quiet_cmd_modules_builtin_modinfo = GEN     $@
-      cmd_modules_builtin_modinfo = $(cmd_objcopy); \
-                                    sed -i 's/\x00\+$$/\x00/g' $@
-
-OBJCOPYFLAGS_modules.builtin.modinfo := -j .modinfo -O binary
-
-targets += modules.builtin.modinfo
-modules.builtin.modinfo: vmlinux.unstripped FORCE
-	$(call if_changed,modules_builtin_modinfo)
-
-# modules.builtin
-# ---------------------------------------------------------------------------
-
-__default: modules.builtin
-
-# The second line aids cases where multiple modules share the same object.
-
-quiet_cmd_modules_builtin = GEN     $@
-      cmd_modules_builtin = \
-	tr '\0' '\n' < $< | \
-	sed -n 's/^[[:alnum:]:_]*\.file=//p' | \
-	tr ' ' '\n' | uniq | sed -e 's:^:kernel/:' -e 's/$$/.ko/' > $@
-
-targets += modules.builtin
-modules.builtin: modules.builtin.modinfo FORCE
-	$(call if_changed,modules_builtin)
-
-# modules.builtin.ranges
-# ---------------------------------------------------------------------------
-ifdef CONFIG_BUILTIN_MODULE_RANGES
-__default: modules.builtin.ranges
-
-quiet_cmd_modules_builtin_ranges = GEN     $@
-      cmd_modules_builtin_ranges = gawk -f $(real-prereqs) > $@
-
-targets += modules.builtin.ranges
-modules.builtin.ranges: $(srctree)/scripts/generate_builtin_ranges.awk \
-			modules.builtin vmlinux.map vmlinux.o.map FORCE
-	$(call if_changed,modules_builtin_ranges)
-
-vmlinux.map: vmlinux.unstripped
-	@:
-
-endif
-
 # Add FORCE to the prerequisites of a target to force it to be always rebuilt.
 # ---------------------------------------------------------------------------
 
diff --git a/scripts/Makefile.vmlinux_unstripped b/scripts/Makefile.vmlinux_unstripped
new file mode 100644
index 000000000000..914ee6f3b935
--- /dev/null
+++ b/scripts/Makefile.vmlinux_unstripped
@@ -0,0 +1,159 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+PHONY := __default
+__default: vmlinux.unstripped
+
+include include/config/auto.conf
+include $(srctree)/scripts/Kbuild.include
+include $(srctree)/scripts/Makefile.lib
+
+targets :=
+
+%.o: %.c FORCE
+	$(call if_changed_rule,cc_o_c)
+
+%.o: %.S FORCE
+	$(call if_changed_rule,as_o_S)
+
+# Built-in dtb
+# ---------------------------------------------------------------------------
+
+quiet_cmd_wrap_dtbs = WRAP    $@
+      cmd_wrap_dtbs = {							\
+	echo '\#include <asm-generic/vmlinux.lds.h>';			\
+	echo '.section .dtb.init.rodata,"a"';				\
+	while read dtb; do						\
+		symbase=__dtb_$$(basename -s .dtb "$${dtb}" | tr - _);	\
+		echo '.balign STRUCT_ALIGNMENT';			\
+		echo ".global $${symbase}_begin";			\
+		echo "$${symbase}_begin:";				\
+		echo '.incbin "'$$dtb'" ';				\
+		echo ".global $${symbase}_end";				\
+		echo "$${symbase}_end:";				\
+	done < $<;							\
+	} > $@
+
+.builtin-dtbs.S: .builtin-dtbs-list FORCE
+	$(call if_changed,wrap_dtbs)
+
+quiet_cmd_gen_dtbs_list = GEN     $@
+      cmd_gen_dtbs_list = \
+	$(if $(CONFIG_BUILTIN_DTB_NAME), echo "arch/$(SRCARCH)/boot/dts/$(CONFIG_BUILTIN_DTB_NAME).dtb",:) > $@
+
+.builtin-dtbs-list: arch/$(SRCARCH)/boot/dts/dtbs-list FORCE
+	$(call if_changed,$(if $(CONFIG_BUILTIN_DTB_ALL),copy,gen_dtbs_list))
+
+targets += .builtin-dtbs-list
+
+ifdef CONFIG_GENERIC_BUILTIN_DTB
+targets += .builtin-dtbs.S .builtin-dtbs.o
+vmlinux.unstripped: .builtin-dtbs.o
+endif
+
+# vmlinux.unstripped
+# ---------------------------------------------------------------------------
+
+ifdef CONFIG_ARCH_WANTS_PRE_LINK_VMLINUX
+vmlinux.unstripped: arch/$(SRCARCH)/tools/vmlinux.arch.o
+
+arch/$(SRCARCH)/tools/vmlinux.arch.o: vmlinux.o FORCE
+	$(Q)$(MAKE) $(build)=arch/$(SRCARCH)/tools $@
+endif
+
+ARCH_POSTLINK := $(wildcard $(srctree)/arch/$(SRCARCH)/Makefile.postlink)
+
+# Final link of vmlinux with optional arch pass after final link
+cmd_link_vmlinux =							\
+	$< "$(LD)" "$(KBUILD_LDFLAGS)" "$(LDFLAGS_vmlinux)" "$@";	\
+	$(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) $@, true)
+
+targets += vmlinux.unstripped .vmlinux.export.o
+vmlinux.unstripped: scripts/link-vmlinux.sh vmlinux.o .vmlinux.export.o $(KBUILD_LDS) FORCE
+	+$(call if_changed_dep,link_vmlinux)
+ifdef CONFIG_DEBUG_INFO_BTF
+vmlinux.unstripped: $(RESOLVE_BTFIDS)
+endif
+
+ifdef CONFIG_BUILDTIME_TABLE_SORT
+vmlinux.unstripped: scripts/sorttable
+endif
+
+ifdef CONFIG_MODULE_HASHES
+vmlinux.unstripped: $(objtree)/scripts/modules-merkle-tree
+vmlinux.unstripped: modules.order
+vmlinux.unstripped: $(wildcard include/config/MODULE_INSTALL_STRIP)
+endif
+
+# modules.builtin.modinfo
+# ---------------------------------------------------------------------------
+
+# .modinfo in vmlinux.unstripped is aligned to 8 bytes for compatibility with
+# tools that expect vmlinux to have sufficiently aligned sections but the
+# additional bytes used for padding .modinfo to satisfy this requirement break
+# certain versions of kmod with
+#
+#   depmod: ERROR: kmod_builtin_iter_next: unexpected string without modname prefix
+#
+# Strip the trailing padding bytes after extracting .modinfo to comply with
+# what kmod expects to parse.
+quiet_cmd_modules_builtin_modinfo = GEN     $@
+      cmd_modules_builtin_modinfo = $(cmd_objcopy); \
+                                    sed -i 's/\x00\+$$/\x00/g' $@
+
+OBJCOPYFLAGS_modules.builtin.modinfo := -j .modinfo -O binary
+
+targets += modules.builtin.modinfo
+modules.builtin.modinfo: vmlinux.unstripped FORCE
+	$(call if_changed,modules_builtin_modinfo)
+
+# modules.builtin
+# ---------------------------------------------------------------------------
+
+__default: modules.builtin
+
+# The second line aids cases where multiple modules share the same object.
+
+quiet_cmd_modules_builtin = GEN     $@
+      cmd_modules_builtin = \
+	tr '\0' '\n' < $< | \
+	sed -n 's/^[[:alnum:]:_]*\.file=//p' | \
+	tr ' ' '\n' | uniq | sed -e 's:^:kernel/:' -e 's/$$/.ko/' > $@
+
+targets += modules.builtin
+modules.builtin: modules.builtin.modinfo FORCE
+	$(call if_changed,modules_builtin)
+
+# modules.builtin.ranges
+# ---------------------------------------------------------------------------
+ifdef CONFIG_BUILTIN_MODULE_RANGES
+__default: modules.builtin.ranges
+
+quiet_cmd_modules_builtin_ranges = GEN     $@
+      cmd_modules_builtin_ranges = gawk -f $(real-prereqs) > $@
+
+targets += modules.builtin.ranges
+modules.builtin.ranges: $(srctree)/scripts/generate_builtin_ranges.awk \
+			modules.builtin vmlinux.map vmlinux.o.map FORCE
+	$(call if_changed,modules_builtin_ranges)
+
+vmlinux.map: vmlinux.unstripped
+	@:
+
+endif
+
+# Add FORCE to the prerequisites of a target to force it to be always rebuilt.
+# ---------------------------------------------------------------------------
+
+PHONY += FORCE
+FORCE:
+
+# Read all saved command lines and dependencies for the $(targets) we
+# may be building above, using $(if_changed{,_dep}). As an
+# optimization, we don't need to read them if the target does not
+# exist, we will rebuild anyway in that case.
+
+existing-targets := $(wildcard $(sort $(targets)))
+
+-include $(foreach f,$(existing-targets),$(dir $(f)).$(notdir $(f)).cmd)
+
+.PHONY: $(PHONY)
diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
index bfeff1f5753d..80cb09707426 100755
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -316,17 +316,6 @@ if is_enabled CONFIG_BUILDTIME_TABLE_SORT; then
 	fi
 fi
 
-if is_enabled CONFIG_MODULE_HASHES; then
-	info MAKE modules
-	${MAKE} -f Makefile MODULE_HASHES_MODPOST_FINAL=1 modules
-	module_hashes_o=.tmp_module_hashes.o
-	info CC ${module_hashes_o}
-	${CC} ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS} ${KBUILD_CFLAGS} \
-		${KBUILD_CFLAGS_KERNEL} -fno-lto -c -o "${module_hashes_o}" ".tmp_module_hashes.c"
-	${OBJCOPY} --dump-section .module_hashes=.tmp_module_hashes.bin ${module_hashes_o}
-	${OBJCOPY} --update-section .module_hashes=.tmp_module_hashes.bin ${VMLINUX}
-fi
-
 # step a (see comment above)
 if is_enabled CONFIG_KALLSYMS; then
 	if ! cmp -s System.map "${kallsyms_sysmap}"; then

^ permalink raw reply related

* Re: [PATCH] ipe: document AT_EXECVE_CHECK TOCTOU issue on OverlayFS
From: Fan Wu @ 2026-01-30 19:21 UTC (permalink / raw)
  To: Amir Goldstein
  Cc: wufan, linux-security-module, linux-doc, linux-kernel, corbet,
	mic, miklos, linux-unionfs
In-Reply-To: <CAOQ4uxhf6EQKcoN055xzmi-RW2GPxRzz_ExsQawGQBSmoX2WYg@mail.gmail.com>

On Fri, Jan 30, 2026 at 3:06 AM Amir Goldstein <amir73il@gmail.com> wrote:
>
> On Fri, Jan 30, 2026 at 1:14 AM <wufan@kernel.org> wrote:
> >
> > From: Fan Wu <wufan@kernel.org>
> >
> > Document a known TOCTOU (time-of-check to time-of-use) issue when using
> > AT_EXECVE_CHECK with read() on OverlayFS.
>
> Hi Fan Wu,
>
> TBH, I don't like the way that this problem is being framed.
> IIUC, the problem is using IPE on a non-read-only fs.
> Is that correct?
>
> That fact that IPE metadata is usually coupled with read-only fs
> is interesting for the understanding of the use case, but unless
> IPE feature mandates read-only fs, this is a generic problem.
>
> OverlayFS is just one private case, which happens to be common
> in Android or containers? IDK, you did not mention this.
>
> Please describe the problem as a generic problem and give
> overlayfs as an example, preferable with references to the
> real world use cases.
>
> If I misunderstood, please explain why this problem is exclusive
> to overlayfs.
>
> Thanks,
> Amir.
>

Hi Amir,

Thanks for the review. That's exactly why we CC'd you and the
overlayfs folks, we wanted to get your perspective before documenting
this.

Let me give some background. IPE enforces execution policy based on
file integrity properties, primarily dm-verity and fs-verity. These
are the trust anchors, and files without these protections won't be
trusted by IPE. Since dm-verity and fs-verity are inherently
read-only, in typical deployments the TOCTOU issue doesn't exist. To
support overlayfs, IPE uses d_real_inode() to look through the overlay
and get the real inode from the lower layer.

Recently a new feature AT_EXECVE_CHECK was introduced to allow script
interpreters to request LSM checks on script files before execution.
The idea is: interpreter opens the script, calls execveat() with
AT_EXECVE_CHECK to verify the file passes security policy, then reads
and executes the content.

What we found is that on overlayfs with a dm-verity lower layer and
writable upper layer, when a script file only exists in the lower
layer, AT_EXECVE_CHECK passes because IPE sees it's dm-verity
protected. But if another process writes to the same path after
execveat() returns, copy-up happens and subsequent read() from the
original fd returns content from the upper layer. We verified this
through testing.

Overlayfs is popular in container environments, so we want to document
this for IPE users.

We noticed the overlayfs documentation
(https://docs.kernel.org/filesystems/overlayfs.html#non-standard-behavior)
states that if a lower layer file is opened and memory mapped,
subsequent changes are not reflected in the memory mapping. We also
verified this: mmap keeps the original lower layer content after
copy-up. One reason we CC'd you is to ask: is relying on mmap to keep
the original lower file reference a reasonable choice? Or would you
recommend against depending on this behavior?

The narrative in the patch can definitely be adjusted. Would something
like this work better:

"When using AT_EXECVE_CHECK on overlayfs, if the lower layer is
integrity-protected but the upper layer is writable, a copy-up between
the check and read() may cause the interpreter to read unverified
content."

Let us know what you think.

-Fan

^ permalink raw reply

* Re: [PATCH v4 02/17] powerpc/ima: Drop unnecessary check for CONFIG_MODULE_SIG
From: Aaron Tomlin @ 2026-01-30 20:43 UTC (permalink / raw)
  To: Thomas Weißschuh
  Cc: Nathan Chancellor, Arnd Bergmann, Luis Chamberlain, Petr Pavlu,
	Sami Tolvanen, Daniel Gomez, Paul Moore, James Morris,
	Serge E. Hallyn, Jonathan Corbet, Madhavan Srinivasan,
	Michael Ellerman, Nicholas Piggin, Naveen N Rao, Mimi Zohar,
	Roberto Sassu, Dmitry Kasatkin, Eric Snowberg, Nicolas Schier,
	Daniel Gomez, Christophe Leroy (CS GROUP), Nicolas Schier,
	Nicolas Bouchinet, Xiu Jianfeng, Fabian Grünbichler,
	Arnout Engelen, Mattia Rizzolo, kpcyrd, Christian Heusel,
	Câju Mihai-Drosi, Sebastian Andrzej Siewior, linux-kbuild,
	linux-kernel, linux-arch, linux-modules, linux-security-module,
	linux-doc, linuxppc-dev, linux-integrity
In-Reply-To: <20260113-module-hashes-v4-2-0b932db9b56b@weissschuh.net>

[-- Attachment #1: Type: text/plain, Size: 1163 bytes --]

On Tue, Jan 13, 2026 at 01:28:46PM +0100, Thomas Weißschuh wrote:
> When CONFIG_MODULE_SIG is disabled set_module_sig_enforced() is defined
> as an empty stub, so the check is unnecessary.
> The specific configuration option for set_module_sig_enforced() is
> about to change and removing the check avoids some later churn.
> 
> Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
> ---
>  arch/powerpc/kernel/ima_arch.c | 3 +--
>  1 file changed, 1 insertion(+), 2 deletions(-)
> 
> diff --git a/arch/powerpc/kernel/ima_arch.c b/arch/powerpc/kernel/ima_arch.c
> index b7029beed847..690263bf4265 100644
> --- a/arch/powerpc/kernel/ima_arch.c
> +++ b/arch/powerpc/kernel/ima_arch.c
> @@ -63,8 +63,7 @@ static const char *const secure_and_trusted_rules[] = {
>  const char *const *arch_get_ima_policy(void)
>  {
>  	if (is_ppc_secureboot_enabled()) {
> -		if (IS_ENABLED(CONFIG_MODULE_SIG))
> -			set_module_sig_enforced();
> +		set_module_sig_enforced();
>  
>  		if (is_ppc_trustedboot_enabled())
>  			return secure_and_trusted_rules;
> 
> -- 
> 2.52.0
> 

Reviewed-by: Aaron Tomlin <atomlin@atomlin.com>

-- 
Aaron Tomlin

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply

* Re: [PATCH v4 03/17] ima: efi: Drop unnecessary check for CONFIG_MODULE_SIG/CONFIG_KEXEC_SIG
From: Aaron Tomlin @ 2026-01-30 20:49 UTC (permalink / raw)
  To: Thomas Weißschuh
  Cc: Nathan Chancellor, Arnd Bergmann, Luis Chamberlain, Petr Pavlu,
	Sami Tolvanen, Daniel Gomez, Paul Moore, James Morris,
	Serge E. Hallyn, Jonathan Corbet, Madhavan Srinivasan,
	Michael Ellerman, Nicholas Piggin, Naveen N Rao, Mimi Zohar,
	Roberto Sassu, Dmitry Kasatkin, Eric Snowberg, Nicolas Schier,
	Daniel Gomez, Christophe Leroy (CS GROUP), Nicolas Schier,
	Nicolas Bouchinet, Xiu Jianfeng, Fabian Grünbichler,
	Arnout Engelen, Mattia Rizzolo, kpcyrd, Christian Heusel,
	Câju Mihai-Drosi, Sebastian Andrzej Siewior, linux-kbuild,
	linux-kernel, linux-arch, linux-modules, linux-security-module,
	linux-doc, linuxppc-dev, linux-integrity
In-Reply-To: <20260113-module-hashes-v4-3-0b932db9b56b@weissschuh.net>

[-- Attachment #1: Type: text/plain, Size: 1280 bytes --]

On Tue, Jan 13, 2026 at 01:28:47PM +0100, Thomas Weißschuh wrote:
> When configuration settings are disabled the guarded functions are
> defined as empty stubs, so the check is unnecessary.
> The specific configuration option for set_module_sig_enforced() is
> about to change and removing the checks avoids some later churn.
> 
> Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
> ---
>  security/integrity/ima/ima_efi.c | 6 ++----
>  1 file changed, 2 insertions(+), 4 deletions(-)
> 
> diff --git a/security/integrity/ima/ima_efi.c b/security/integrity/ima/ima_efi.c
> index 138029bfcce1..a35dd166ad47 100644
> --- a/security/integrity/ima/ima_efi.c
> +++ b/security/integrity/ima/ima_efi.c
> @@ -68,10 +68,8 @@ static const char * const sb_arch_rules[] = {
>  const char * const *arch_get_ima_policy(void)
>  {
>  	if (IS_ENABLED(CONFIG_IMA_ARCH_POLICY) && arch_ima_get_secureboot()) {
> -		if (IS_ENABLED(CONFIG_MODULE_SIG))
> -			set_module_sig_enforced();
> -		if (IS_ENABLED(CONFIG_KEXEC_SIG))
> -			set_kexec_sig_enforced();
> +		set_module_sig_enforced();
> +		set_kexec_sig_enforced();
>  		return sb_arch_rules;
>  	}
>  	return NULL;
> 
> -- 
> 2.52.0
> 

Reviewed-by: Aaron Tomlin <atomlin@atomlin.com>

-- 
Aaron Tomlin

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply

* Re: [PATCH v4 04/17] module: Make mod_verify_sig() static
From: Aaron Tomlin @ 2026-01-30 20:53 UTC (permalink / raw)
  To: Thomas Weißschuh
  Cc: Nathan Chancellor, Arnd Bergmann, Luis Chamberlain, Petr Pavlu,
	Sami Tolvanen, Daniel Gomez, Paul Moore, James Morris,
	Serge E. Hallyn, Jonathan Corbet, Madhavan Srinivasan,
	Michael Ellerman, Nicholas Piggin, Naveen N Rao, Mimi Zohar,
	Roberto Sassu, Dmitry Kasatkin, Eric Snowberg, Nicolas Schier,
	Daniel Gomez, Christophe Leroy (CS GROUP), Nicolas Schier,
	Nicolas Bouchinet, Xiu Jianfeng, Fabian Grünbichler,
	Arnout Engelen, Mattia Rizzolo, kpcyrd, Christian Heusel,
	Câju Mihai-Drosi, Sebastian Andrzej Siewior, linux-kbuild,
	linux-kernel, linux-arch, linux-modules, linux-security-module,
	linux-doc, linuxppc-dev, linux-integrity
In-Reply-To: <20260113-module-hashes-v4-4-0b932db9b56b@weissschuh.net>

[-- Attachment #1: Type: text/plain, Size: 1444 bytes --]

On Tue, Jan 13, 2026 at 01:28:48PM +0100, Thomas Weißschuh wrote:
> It is not used outside of signing.c.
> 
> Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
> ---
>  kernel/module/internal.h | 1 -
>  kernel/module/signing.c  | 2 +-
>  2 files changed, 1 insertion(+), 2 deletions(-)
> 
> diff --git a/kernel/module/internal.h b/kernel/module/internal.h
> index 618202578b42..e68fbcd60c35 100644
> --- a/kernel/module/internal.h
> +++ b/kernel/module/internal.h
> @@ -119,7 +119,6 @@ struct module_use {
>  	struct module *source, *target;
>  };
>  
> -int mod_verify_sig(const void *mod, struct load_info *info);
>  int try_to_force_load(struct module *mod, const char *reason);
>  bool find_symbol(struct find_symbol_arg *fsa);
>  struct module *find_module_all(const char *name, size_t len, bool even_unformed);
> diff --git a/kernel/module/signing.c b/kernel/module/signing.c
> index a2ff4242e623..fe3f51ac6199 100644
> --- a/kernel/module/signing.c
> +++ b/kernel/module/signing.c
> @@ -40,7 +40,7 @@ void set_module_sig_enforced(void)
>  /*
>   * Verify the signature on a module.
>   */
> -int mod_verify_sig(const void *mod, struct load_info *info)
> +static int mod_verify_sig(const void *mod, struct load_info *info)
>  {
>  	struct module_signature ms;
>  	size_t sig_len, modlen = info->len;
> 
> -- 
> 2.52.0
> 

Reviewed-by: Aaron Tomlin <atomlin@atomlin.com>

-- 
Aaron Tomlin

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply

* Re: [PATCH] xfrm: kill xfrm_dev_{state,policy}_flush_secctx_check()
From: Paul Moore @ 2026-01-30 21:56 UTC (permalink / raw)
  To: Tetsuo Handa
  Cc: SELinux, linux-security-module, Steffen Klassert, Herbert Xu,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Network Development
In-Reply-To: <1bb453af-3ef2-4ab6-a909-0705bd07c136@I-love.SAKURA.ne.jp>

On Wed, Jan 28, 2026 at 5:28 AM Tetsuo Handa
<penguin-kernel@i-love.sakura.ne.jp> wrote:
> On 2026/01/28 6:59, Paul Moore wrote:
> > It sounds like we either need to confirm that
> > security_xfrm_{policy,state}_delete() is already present in all code
> > paths that result in SPD/SAD deletions (in a place that can safely
> > fail and return an error),
>
> Yes.

To clarify, do you mean "yes, I agree", or "yes, I've already checked
this and can confirm that the LSM hooks are already being called"?

> >                            or we need to place
> > xfrm_dev_{policy,state}_flush_secctx_check() in a location that can
> > safely fail.
>
> Did you mean xfrm_{policy,state}_flush_secctx_check() ?

They both call into the security_xfrm_policy_delete() LSM hook which
is what I care about as that hook is what authorizes the operation.

> Regarding xfrm_policy_flush() as an example, we can observe that we are
> calling LSM hooks for must-not-fail callers ...

We need to make sure the LSM hooks are being called to authorize the
removal of SPD and SAD entries.  If you are going to remove LSM hooks
from the existing code, please document how that code path you are
changing is still subject to authorization by the LSM hooks or explain
in great detail how that authorization is not necessary.

-- 
paul-moore.com

^ permalink raw reply

* [PATCH v5 0/3] ima: Detect changes to files via kstat changes rather than i_version
From: Frederick Lawler @ 2026-01-30 22:39 UTC (permalink / raw)
  To: Mimi Zohar, Roberto Sassu, Dmitry Kasatkin, Eric Snowberg,
	Paul Moore, James Morris, Serge E. Hallyn, Darrick J. Wong,
	Christian Brauner, Josef Bacik, Jeff Layton
  Cc: linux-kernel, linux-integrity, linux-security-module, kernel-team,
	Frederick Lawler

We uncovered a case in kernels >= 6.13 where XFS is no longer updating
struct kstat.change_cookie on i_op getattr() access calls. Instead, XFS is
using multigrain ctime (as well as other file systems) for
change detection in commit 1cf7e834a6fb ("xfs: switch to
multigrain timestamps").

Because file systems may implement i_version as they see fit, IMA
unnecessarily measures files in stacked file systems. This is due
to the LOWER or UPPER FS not updating kstat.change_cookie to the
recent i_version on request. Thus, for XFS, zero is being compared
against the inode's i_version directly, and is always behind.

We're proposing to compare against the kstat.change_cookie
directly to the cached version, and fall back to a ctime comparison,
if STATX_CHANGE_COOKIE is not supplied in the result mask.

EVM is largely left alone since there's no trivial way to query a file
directly in the LSM call paths to obtain kstat.change_cookie &
kstat.ctime to cache. Thus retains accessing i_version directly.

Regression tests will be added to the Linux Test Project instead of
selftest to help catch future file system changes that may impact
future evaluation of IMA.

I'd like this to be backported to at least 6.18 if possible.

Patches 1 & 2 are preparation patches. Ideally patch 2 is squashed into
3, though not strictly necessary.

Below is a simplified test that demonstrates the issue such that
there are multiple unnecessary measurements occurring for actions on
a file in a stacked TMPFS on XFS, prior to the file moved over to TMPFS:

_fragment.config_
CONFIG_XFS_FS=y
CONFIG_OVERLAY_FS=y
CONFIG_IMA=y
CONFIG_IMA_WRITE_POLICY=y
CONFIG_IMA_READ_POLICY=y

_./test.sh_

IMA_POLICY="/sys/kernel/security/ima/policy"
TEST_BIN="/bin/date"
MNT_BASE="/tmp/ima_test_root"

mkdir -p "$MNT_BASE"
mount -t tmpfs tmpfs "$MNT_BASE"
mkdir -p "$MNT_BASE"/{xfs_disk,upper,work,ovl}

dd if=/dev/zero of="$MNT_BASE/xfs.img" bs=1M count=300
mkfs.xfs -q "$MNT_BASE/xfs.img"
mount "$MNT_BASE/xfs.img" "$MNT_BASE/xfs_disk"
cp "$TEST_BIN" "$MNT_BASE/xfs_disk/test_prog"

mount -t overlay overlay -o \
"lowerdir=$MNT_BASE/xfs_disk,upperdir=$MNT_BASE/upper,workdir=$MNT_BASE/work" \
"$MNT_BASE/ovl"

echo "audit func=BPRM_CHECK uid=$(id -u nobody)" > "$IMA_POLICY"

target_prog="$MNT_BASE/ovl/test_prog"
setpriv --reuid nobody "$target_prog"
setpriv --reuid nobody "$target_prog"
setpriv --reuid nobody "$target_prog"

audit_count=$(dmesg | grep -c "file=\"$target_prog\"")

if [[ "$audit_count" -eq 1 ]]; then
        echo "PASS: Found exactly 1 audit event."
else
        echo "FAIL: Expected 1 audit event, but found $audit_count."
        exit 1
fi

Signed-off-by: Frederick Lawler <fred@cloudflare.com>
---
Changes in v5:
- Split into patch series. [Mimi]
- Link to v4: https://lore.kernel.org/r/20260129-xfs-ima-fixup-v4-1-6bb89df7b6a3@cloudflare.com

Changes in v4:
- No functional changes.
- Add Reviewed-by & Fixes tags.
- Link to v3: https://lore.kernel.org/r/20260122-xfs-ima-fixup-v3-1-20335a8aa836@cloudflare.com

Changes in v3:
- Prefer timespec64_to_ns() to leverage attr.version. [Roberto]
- s/TPMFS/TMPFS/ in description.
- Link to v2: https://lore.kernel.org/r/20260120-xfs-ima-fixup-v2-1-f332ead8b043@cloudflare.com

Changes in v2:
- Updated commit description + message to clarify the problem.
- compare struct timespec64 to avoid collision possibility [Roberto].
- Don't check inode_attr_changed() in ima_check_last_writer()
- Link to v1: https://lore.kernel.org/r/20260112-xfs-ima-fixup-v1-1-8d13b6001312@cloudflare.com

Changes since RFC:
- Remove calls to I_IS_VERSION()
- Function documentation/comments
- Abide IMA/EVM change detection fallback invariants
- Combined ctime guard into version for attributes struct
- Link to RFC: https://lore.kernel.org/r/20251229-xfs-ima-fixup-v1-1-6a717c939f7c@cloudflare.com

---
Frederick Lawler (3):
      ima: Unify vfs_getattr_nosec() stat comparisons under helper function
      ima: Make integrity_inode_attrs_changed() call into vfs
      ima: Use kstat.ctime as a fallback change detection for stacked fs

 include/linux/integrity.h         | 43 +++++++++++++++++++++++++++++++++++----
 security/integrity/evm/evm_main.c |  5 ++---
 security/integrity/ima/ima_api.c  | 11 +++++++---
 security/integrity/ima/ima_main.c | 11 +++++-----
 4 files changed, 54 insertions(+), 16 deletions(-)
---
base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
change-id: 20251212-xfs-ima-fixup-931780a62c2c

Best regards,
-- 
Frederick Lawler <fred@cloudflare.com>


^ permalink raw reply

* [PATCH v5 1/3] ima: Unify vfs_getattr_nosec() stat comparisons under helper function
From: Frederick Lawler @ 2026-01-30 22:39 UTC (permalink / raw)
  To: Mimi Zohar, Roberto Sassu, Dmitry Kasatkin, Eric Snowberg,
	Paul Moore, James Morris, Serge E. Hallyn, Darrick J. Wong,
	Christian Brauner, Josef Bacik, Jeff Layton
  Cc: linux-kernel, linux-integrity, linux-security-module, kernel-team,
	Frederick Lawler
In-Reply-To: <20260130-xfs-ima-fixup-v5-0-57e84ea91712@cloudflare.com>

The logic for comparing kstat.change_cookie against IMA version is
hard to read. Abstract comparison logic into a new function
integrity_inode_attrs_stat_changed().

No functional change intended.

Signed-off-by: Frederick Lawler <fred@cloudflare.com>
---
 include/linux/integrity.h         | 11 +++++++++++
 security/integrity/ima/ima_main.c |  4 ++--
 2 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/include/linux/integrity.h b/include/linux/integrity.h
index f5842372359be5341b6870a43b92e695e8fc78af..beb9ab19fa6257e79266b58bcb5f55b0c5445828 100644
--- a/include/linux/integrity.h
+++ b/include/linux/integrity.h
@@ -49,6 +49,17 @@ integrity_inode_attrs_store(struct integrity_inode_attributes *attrs,
 	attrs->ino = inode->i_ino;
 }
 
+/* Compares stat attributes for change detection. */
+static inline bool
+integrity_inode_attrs_stat_changed
+(const struct integrity_inode_attributes *attrs, const struct kstat *stat)
+{
+	if (stat->result_mask & STATX_CHANGE_COOKIE)
+		return stat->change_cookie != attrs->version;
+
+	return true;
+}
+
 /*
  * On stacked filesystems detect whether the inode or its content has changed.
  */
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 5770cf691912aa912fc65280c59f5baac35dd725..6570ad10887b9ea1172c78274cf62482350e87ff 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -201,8 +201,8 @@ static void ima_check_last_writer(struct ima_iint_cache *iint,
 		    vfs_getattr_nosec(&file->f_path, &stat,
 				      STATX_CHANGE_COOKIE,
 				      AT_STATX_SYNC_AS_STAT) ||
-		    !(stat.result_mask & STATX_CHANGE_COOKIE) ||
-		    stat.change_cookie != iint->real_inode.version) {
+		    integrity_inode_attrs_stat_changed(&iint->real_inode,
+						       &stat)) {
 			iint->flags &= ~(IMA_DONE_MASK | IMA_NEW_FILE);
 			iint->measured_pcrs = 0;
 			if (update)

-- 
2.43.0


^ permalink raw reply related

* [PATCH v5 2/3] ima: Make integrity_inode_attrs_changed() call into vfs
From: Frederick Lawler @ 2026-01-30 22:39 UTC (permalink / raw)
  To: Mimi Zohar, Roberto Sassu, Dmitry Kasatkin, Eric Snowberg,
	Paul Moore, James Morris, Serge E. Hallyn, Darrick J. Wong,
	Christian Brauner, Josef Bacik, Jeff Layton
  Cc: linux-kernel, linux-integrity, linux-security-module, kernel-team,
	Frederick Lawler
In-Reply-To: <20260130-xfs-ima-fixup-v5-0-57e84ea91712@cloudflare.com>

Align integrity_inode_attrs_changed() to ima_check_last_writer()'s
semantics when detecting changes.

For IMA, stacked file systems that do not set kstat.change_cookie,
integrity_inode_attrs_changed() will compare zero to zero, thus no
change detected. This is not dissimilar to what
ima_check_last_writer() does.

No logical change intended for EVM.

Signed-off-by: Frederick Lawler <fred@cloudflare.com>
---
 include/linux/integrity.h         | 28 ++++++++++++++++++++++++----
 security/integrity/evm/evm_main.c |  5 ++---
 security/integrity/ima/ima_main.c |  5 ++---
 3 files changed, 28 insertions(+), 10 deletions(-)

diff --git a/include/linux/integrity.h b/include/linux/integrity.h
index beb9ab19fa6257e79266b58bcb5f55b0c5445828..382c783f0fa3ae4a938cdf9559291ba1903a378e 100644
--- a/include/linux/integrity.h
+++ b/include/linux/integrity.h
@@ -9,6 +9,7 @@
 
 #include <linux/fs.h>
 #include <linux/iversion.h>
+#include <linux/kernel.h>
 
 enum integrity_status {
 	INTEGRITY_PASS = 0,
@@ -62,14 +63,33 @@ integrity_inode_attrs_stat_changed
 
 /*
  * On stacked filesystems detect whether the inode or its content has changed.
+ *
+ * Must be called in process context.
  */
 static inline bool
 integrity_inode_attrs_changed(const struct integrity_inode_attributes *attrs,
-			      const struct inode *inode)
+			      struct file *file, struct inode *inode)
 {
-	return (inode->i_sb->s_dev != attrs->dev ||
-		inode->i_ino != attrs->ino ||
-		!inode_eq_iversion(inode, attrs->version));
+	struct kstat stat;
+
+	might_sleep();
+
+	if (inode->i_sb->s_dev != attrs->dev || inode->i_ino != attrs->ino)
+		return true;
+
+	/*
+	 * EVM currently relies on backing inode i_version. While IS_I_VERSION
+	 * is not a good indicator of i_version support, this still retains
+	 * the logic such that a re-evaluation should still occur for EVM, and
+	 * only for IMA if vfs_getattr_nosec() fails.
+	 */
+	if (!file || vfs_getattr_nosec(&file->f_path, &stat,
+				       STATX_CHANGE_COOKIE,
+				       AT_STATX_SYNC_AS_STAT))
+		return !IS_I_VERSION(inode) ||
+		       !inode_eq_iversion(inode, attrs->version);
+
+	return integrity_inode_attrs_stat_changed(attrs, &stat);
 }
 
 
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index 73d500a375cb37a54f295b0e1e93fd6e5d9ecddc..6a4e0e246005246d5700b1db590c1759242b9cb6 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -752,9 +752,8 @@ bool evm_metadata_changed(struct inode *inode, struct inode *metadata_inode)
 	bool ret = false;
 
 	if (iint) {
-		ret = (!IS_I_VERSION(metadata_inode) ||
-		       integrity_inode_attrs_changed(&iint->metadata_inode,
-						     metadata_inode));
+		ret = integrity_inode_attrs_changed(&iint->metadata_inode,
+						    NULL, metadata_inode);
 		if (ret)
 			iint->evm_status = INTEGRITY_UNKNOWN;
 	}
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 6570ad10887b9ea1172c78274cf62482350e87ff..8cb17c9d446caaa5a98f5ec8f027c17ba7babca8 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -328,9 +328,8 @@ static int process_measurement(struct file *file, const struct cred *cred,
 	real_inode = d_real_inode(file_dentry(file));
 	if (real_inode != inode &&
 	    (action & IMA_DO_MASK) && (iint->flags & IMA_DONE_MASK)) {
-		if (!IS_I_VERSION(real_inode) ||
-		    integrity_inode_attrs_changed(&iint->real_inode,
-						  real_inode)) {
+		if (integrity_inode_attrs_changed(&iint->real_inode,
+						  file, real_inode)) {
 			iint->flags &= ~IMA_DONE_MASK;
 			iint->measured_pcrs = 0;
 		}

-- 
2.43.0


^ permalink raw reply related

* [PATCH v5 3/3] ima: Use kstat.ctime as a fallback change detection for stacked fs
From: Frederick Lawler @ 2026-01-30 22:39 UTC (permalink / raw)
  To: Mimi Zohar, Roberto Sassu, Dmitry Kasatkin, Eric Snowberg,
	Paul Moore, James Morris, Serge E. Hallyn, Darrick J. Wong,
	Christian Brauner, Josef Bacik, Jeff Layton
  Cc: linux-kernel, linux-integrity, linux-security-module, kernel-team,
	Frederick Lawler
In-Reply-To: <20260130-xfs-ima-fixup-v5-0-57e84ea91712@cloudflare.com>

IMA performs unnecessary measurements on files in stacked file systems
that do not set kstat.change_cookie to an inode's i_version.

For example: TMPFS (upper) is stacked onto XFS (lower).
Actions files result in re-measurement because commit 1cf7e834a6fb
("xfs: switch to multigrain timestamps") introduced multigrain
timestamps into XFS which changed the kstat.change_cookie semantics
to no longer supply an i_version to compare against in
integrity_inode_attributes_changed(). Once the inode is in TMPFS,
the change detection behavior operates as normal because TMPFS updates
kstat.change_cookie to the i_version.

Instead, fall back onto a ctime comparison. This also gives file systems
that do not support i_version an opportunity avoid the same behavior,
as they're more likely to have ctime support.

timespec64_to_ns() is chosen to avoid adding extra storage to
integrity_inode_attributes by leveraging the existing version field.

Link: https://lore.kernel.org/all/aTspr4_h9IU4EyrR@CMGLRV3
Fixes: 1cf7e834a6fb ("xfs: switch to multigrain timestamps")
Suggested-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Frederick Lawler <fred@cloudflare.com>
---
 include/linux/integrity.h         |  6 +++++-
 security/integrity/ima/ima_api.c  | 11 ++++++++---
 security/integrity/ima/ima_main.c |  2 +-
 3 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/include/linux/integrity.h b/include/linux/integrity.h
index 382c783f0fa3ae4a938cdf9559291ba1903a378e..ec2c94907f417c4a71ecce29ac79edac9bc2c6f8 100644
--- a/include/linux/integrity.h
+++ b/include/linux/integrity.h
@@ -10,6 +10,7 @@
 #include <linux/fs.h>
 #include <linux/iversion.h>
 #include <linux/kernel.h>
+#include <linux/time64.h>
 
 enum integrity_status {
 	INTEGRITY_PASS = 0,
@@ -58,6 +59,9 @@ integrity_inode_attrs_stat_changed
 	if (stat->result_mask & STATX_CHANGE_COOKIE)
 		return stat->change_cookie != attrs->version;
 
+	if (stat->result_mask & STATX_CTIME)
+		return timespec64_to_ns(&stat->ctime) != (s64)attrs->version;
+
 	return true;
 }
 
@@ -84,7 +88,7 @@ integrity_inode_attrs_changed(const struct integrity_inode_attributes *attrs,
 	 * only for IMA if vfs_getattr_nosec() fails.
 	 */
 	if (!file || vfs_getattr_nosec(&file->f_path, &stat,
-				       STATX_CHANGE_COOKIE,
+				       STATX_CHANGE_COOKIE | STATX_CTIME,
 				       AT_STATX_SYNC_AS_STAT))
 		return !IS_I_VERSION(inode) ||
 		       !inode_eq_iversion(inode, attrs->version);
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index c35ea613c9f8d404ba4886e3b736c3bab29d1668..e47d6281febc15a0ac1bd2ea1d28fea4d0cd5c58 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -272,10 +272,15 @@ int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file,
 	 * to an initial measurement/appraisal/audit, but was modified to
 	 * assume the file changed.
 	 */
-	result = vfs_getattr_nosec(&file->f_path, &stat, STATX_CHANGE_COOKIE,
+	result = vfs_getattr_nosec(&file->f_path, &stat,
+				   STATX_CHANGE_COOKIE | STATX_CTIME,
 				   AT_STATX_SYNC_AS_STAT);
-	if (!result && (stat.result_mask & STATX_CHANGE_COOKIE))
-		i_version = stat.change_cookie;
+	if (!result) {
+		if (stat.result_mask & STATX_CHANGE_COOKIE)
+			i_version = stat.change_cookie;
+		else if (stat.result_mask & STATX_CTIME)
+			i_version = timespec64_to_ns(&stat.ctime);
+	}
 	hash.hdr.algo = algo;
 	hash.hdr.length = hash_digest_size[algo];
 
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 8cb17c9d446caaa5a98f5ec8f027c17ba7babca8..776db158b0bd8a0d053729ac0cc15af8b6020a98 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -199,7 +199,7 @@ static void ima_check_last_writer(struct ima_iint_cache *iint,
 					    &iint->atomic_flags);
 		if ((iint->flags & IMA_NEW_FILE) ||
 		    vfs_getattr_nosec(&file->f_path, &stat,
-				      STATX_CHANGE_COOKIE,
+				      STATX_CHANGE_COOKIE | STATX_CTIME,
 				      AT_STATX_SYNC_AS_STAT) ||
 		    integrity_inode_attrs_stat_changed(&iint->real_inode,
 						       &stat)) {

-- 
2.43.0


^ permalink raw reply related

* Re: [PATCH] xfrm: kill xfrm_dev_{state,policy}_flush_secctx_check()
From: Tetsuo Handa @ 2026-01-31  6:00 UTC (permalink / raw)
  To: Paul Moore, SELinux, linux-security-module
  Cc: Steffen Klassert, Herbert Xu, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Simon Horman, Network Development
In-Reply-To: <CAHC9VhQEKfxXzFgYShojESpQn10LES5zL6Ua0YV9b8seEKFqyA@mail.gmail.com>

On 2026/01/31 6:56, Paul Moore wrote:
> On Wed, Jan 28, 2026 at 5:28 AM Tetsuo Handa
> <penguin-kernel@i-love.sakura.ne.jp> wrote:
>> On 2026/01/28 6:59, Paul Moore wrote:
>>> It sounds like we either need to confirm that
>>> security_xfrm_{policy,state}_delete() is already present in all code
>>> paths that result in SPD/SAD deletions (in a place that can safely
>>> fail and return an error),
>>
>> Yes.
> 
> To clarify, do you mean "yes, I agree", or "yes, I've already checked
> this and can confirm that the LSM hooks are already being called"?

I mean "yes, I agree".

> 
>>>                            or we need to place
>>> xfrm_dev_{policy,state}_flush_secctx_check() in a location that can
>>> safely fail.
>>
>> Did you mean xfrm_{policy,state}_flush_secctx_check() ?
> 
> They both call into the security_xfrm_policy_delete() LSM hook which
> is what I care about as that hook is what authorizes the operation.

I can't understand what your authorization is.
No authorization can be placed during must-not-fail operation.

For example, please consider the following sequence.

  mkdir /mnt/tmpfs
  unshare -m
  mount -t tmpfs none /mnt/tmpfs
  touch /mnt/tmpfs/file1
  mkdir /mnt/tmpfs/dir1
  exit

Although there are LSM hooks for deleting a file/directory and LSM hook for
unmounting, no LSM hook is called before deleting file1, deleting dir1,
and unmounting /mnt/tmpfs because operations that happen during tear-down of
a namespace must not fail.

What "[PATCH] xfrm: kill xfrm_dev_{state,policy}_flush_secctx_check()" is doing
is the same thing for a network device. NETDEV_UNREGISTER is a must-not-fail
operation that happens during tear-down of a network device. LSM hooks are not
allowed to veto must-not-fail operations.

> 
>> Regarding xfrm_policy_flush() as an example, we can observe that we are
>> calling LSM hooks for must-not-fail callers ...
> 
> We need to make sure the LSM hooks are being called to authorize the
> removal of SPD and SAD entries.  If you are going to remove LSM hooks
> from the existing code, please document how that code path you are
> changing is still subject to authorization by the LSM hooks or explain
> in great detail how that authorization is not necessary.

Again, LSM hooks are not allowed to veto operations that happen during
NETDEV_UNREGISTER event. Current XFRM code for NETDEV_UNREGISTER event is broken
because the behavior is

  while (security_xfrm_state_delete() != 0) {
    schedule_timeout_uninterruptible(10 * HZ);
    pr_emerg("unregister_netdevice: waiting for %s to become free. Usage count = %d\n",
             dev->name, netdev_refcnt_read(dev));
  }
  while (security_xfrm_policy_delete() != 0) {
    schedule_timeout_uninterruptible(10 * HZ);
    pr_emerg("unregister_netdevice: waiting for %s to become free. Usage count = %d\n",
             dev->name, netdev_refcnt_read(dev));
  }

which is a denial-of-service kernel bug.

No room for debating "authorize the removal of SPD and SAD entries".
This path is a must-not-fail operation. Removal of SPD and SAD entries has to be done
without authorization when NETDEV_UNREGISTER event fired.

Though, you could argue whether removal of SPD and SAD entries is really what they want
when NETDEV_DOWN event fired. I don't know what the authors of commit d77e38e612a0
("xfrm: Add an IPsec hardware offloading API") are expecting because deleted entries
are not automatically revived when NETDEV_UP event fires
( https://lkml.kernel.org/r/cea4b855-fe94-4b4e-9c2d-3cef7aac1be3@I-love.SAKURA.ne.jp ).

Hmm, does
https://elixir.bootlin.com/linux/v6.19-rc5/source/include/linux/netdevice.h#L3142 mean that
LSM hooks are as well not allowed to veto operations that happen during
NETDEV_UP/NETDEV_DOWN events?

^ permalink raw reply

* Re: [PATCH v4 00/17] module: Introduce hash-based integrity checking
From: Mihai-Drosi Câju @ 2026-01-31  7:36 UTC (permalink / raw)
  To: linux
  Cc: arnd, arnout, atomlin, bigeasy, chleroy, christian, corbet, coxu,
	da.gomez, da.gomez, dmitry.kasatkin, eric.snowberg,
	f.gruenbichler, jmorris, kpcyrd, linux-arch, linux-doc,
	linux-integrity, linux-kbuild, linux-kernel, linux-modules,
	linux-security-module, linuxppc-dev, lkp, maddy, mattia, mcaju95,
	mcgrof, mpe, nathan, naveen, nicolas.bouchinet, nicolas.schier,
	npiggin, nsc, paul, petr.pavlu, roberto.sassu, samitolvanen,
	serge, xiujianfeng, zohar
In-Reply-To: <20260113-module-hashes-v4-0-0b932db9b56b@weissschuh.net>

> The current signature-based module integrity checking has some drawbacks
in combination with reproducible builds. Either the module signing key
is generated at build time, which makes the build unreproducible, or a
static signing key is used, which precludes rebuilds by third parties
and makes the whole build and packaging process much more complicated.

I think there is a middle ground where the module signing key is generated
using a key derivation function that has as an input a deterministic value
on the build host, such as /etc/machine-id . The problem with this approach
is that only hosts knowing the value will be able to reproduce the build.

Maybe this is a solution to NixOS secret management? Introduce minimal
impurity as a cryptographic seed and derive the rest of the secrets using
something like Argon2(seed, key_uuid).

There might be another approach to code integrity rather than step-by-step
reproducibility. One may exploit the very cryptographic primitives that make
reproducibility hard to ensure that reproducibility is most  likely valid.

For example, the module signing issue, the build host publishes four artifacts:
* The source-code
* The compiled and signed binary
* The build environment
* Its public key

Now, we don't need to sign with the private key to know that building the source
code using the specific build environment and signing the result with the private
key will result in the claimed binary. We can just compile and verify with the
public key.

So a traditional workflow would be:
compiled_module + module_signature == module

In this case we build the module, sign it with whatever key, distribute the
builds and the private key to whoever wants to reproduce the build. Or we build
locally and the key stays with the end-user.

While the cryptographic approach would be:
verify(compiled_code, module.signature) is True

In this case we distribute the builds, source code and the public key. While
everyone can ensure that the compiled code is the result of the build
environment and source code. The signature is verified using cryptographic
means.

As long as no one cracks RSA or an algorithm of our choosing/has an absurd
amount of luck, the cryptographic approach would be just as good as the traditional
approach at ensuring that a program has stopped with a certain output.

^ permalink raw reply

* Re: [PATCH] ipe: document AT_EXECVE_CHECK TOCTOU issue on OverlayFS
From: Amir Goldstein @ 2026-01-31 10:22 UTC (permalink / raw)
  To: Fan Wu
  Cc: linux-security-module, linux-doc, linux-kernel, corbet, mic,
	miklos, linux-unionfs, linux-fsdevel
In-Reply-To: <CAKtyLkG1_evj7=yrB6nH-8fJuP3DsWyxwrhv7O_Mk=Fy8FOvVw@mail.gmail.com>

[+CC fsdevel]

On Fri, Jan 30, 2026 at 8:21 PM Fan Wu <wufan@kernel.org> wrote:
>
> On Fri, Jan 30, 2026 at 3:06 AM Amir Goldstein <amir73il@gmail.com> wrote:
> >
> > On Fri, Jan 30, 2026 at 1:14 AM <wufan@kernel.org> wrote:
> > >
> > > From: Fan Wu <wufan@kernel.org>
> > >
> > > Document a known TOCTOU (time-of-check to time-of-use) issue when using
> > > AT_EXECVE_CHECK with read() on OverlayFS.
> >
> > Hi Fan Wu,
> >
> > TBH, I don't like the way that this problem is being framed.
> > IIUC, the problem is using IPE on a non-read-only fs.
> > Is that correct?
> >
> > That fact that IPE metadata is usually coupled with read-only fs
> > is interesting for the understanding of the use case, but unless
> > IPE feature mandates read-only fs, this is a generic problem.
> >
> > OverlayFS is just one private case, which happens to be common
> > in Android or containers? IDK, you did not mention this.
> >
> > Please describe the problem as a generic problem and give
> > overlayfs as an example, preferable with references to the
> > real world use cases.
> >
> > If I misunderstood, please explain why this problem is exclusive
> > to overlayfs.
> >
> > Thanks,
> > Amir.
> >
>
> Hi Amir,
>
> Thanks for the review. That's exactly why we CC'd you and the
> overlayfs folks, we wanted to get your perspective before documenting
> this.
>
> Let me give some background. IPE enforces execution policy based on
> file integrity properties, primarily dm-verity and fs-verity. These
> are the trust anchors, and files without these protections won't be
> trusted by IPE. Since dm-verity and fs-verity are inherently
> read-only, in typical deployments the TOCTOU issue doesn't exist. To
> support overlayfs, IPE uses d_real_inode() to look through the overlay
> and get the real inode from the lower layer.
>
> Recently a new feature AT_EXECVE_CHECK was introduced to allow script
> interpreters to request LSM checks on script files before execution.
> The idea is: interpreter opens the script, calls execveat() with
> AT_EXECVE_CHECK to verify the file passes security policy, then reads
> and executes the content.
>
> What we found is that on overlayfs with a dm-verity lower layer and
> writable upper layer, when a script file only exists in the lower
> layer, AT_EXECVE_CHECK passes because IPE sees it's dm-verity
> protected. But if another process writes to the same path after
> execveat() returns, copy-up happens and subsequent read() from the
> original fd returns content from the upper layer. We verified this
> through testing.

I don't understand how this is different from any AT_EXECVE_CHECK
TOCTOU race on a writable filesystem, regardless of IPE.
It seems to me that it is the user calling AT_EXECVE_CHECK who
is responsible for verifying after reading that file has not changed and if
it has changed, then the AT_EXECVE_CHECK could be invalidated
(depending on policy).

Maybe multi-grain ctime could provide a safe cache invalidating check?
As long as the filesystem is trusted to report true MG ctime.
See below regarding overlayfs...

>
> Overlayfs is popular in container environments, so we want to document
> this for IPE users.
>
> We noticed the overlayfs documentation
> (https://docs.kernel.org/filesystems/overlayfs.html#non-standard-behavior)
> states that if a lower layer file is opened and memory mapped,
> subsequent changes are not reflected in the memory mapping. We also
> verified this: mmap keeps the original lower layer content after
> copy-up. One reason we CC'd you is to ask: is relying on mmap to keep
> the original lower file reference a reasonable choice? Or would you
> recommend against depending on this behavior?

I recommend against depending on this behavior.
Please do not document this as a solution.

It sounds like you are documenting a recipe for how to write a safe
interpreter?

The advice to mount overlayfs read only seems impractical to 90%
of the container users which use overlayfs specifically to add writability
over a read only image.

If the generic ctime check is not considered reliable enough for checking
if a file was modified and copied up, what about checking the
STATX_ATTR_VERITY flag of the file?

ovl_getattr() reports the STATX_ flags from the "upper most" inode
and then merges some specific fields from lower layers.

I think that would mean that in the use case to describe, a copy up
would result in STATX_ATTR_VERITY going away when doing
fstat() after a copy up.

If this works, better document it as a good solution.

>
> The narrative in the patch can definitely be adjusted. Would something
> like this work better:
>
> "When using AT_EXECVE_CHECK on overlayfs, if the lower layer is
> integrity-protected but the upper layer is writable, a copy-up between
> the check and read() may cause the interpreter to read unverified
> content."

Sounds fine to me, as long as it is clear that overlayfs is just
a private case of the AT_EXECVE_CHECK TOCOU race.

Thanks,
Amir.

^ permalink raw reply

* Re: [PATCH net-next v2 0/4] net: uapi: Provide an UAPI definition of 'struct sockaddr'
From: Thomas Weißschuh @ 2026-01-31 10:26 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: Eric Dumazet, Kuniyuki Iwashima, Paolo Abeni, Willem de Bruijn,
	David S. Miller, Simon Horman, Shuah Khan, Matthieu Baerts,
	Mat Martineau, Geliang Tang, Mickaël Salaün,
	Günther Noack, Alexei Starovoitov, Daniel Borkmann,
	Jesper Dangaard Brouer, John Fastabend, Stanislav Fomichev,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, KP Singh, Hao Luo, Jiri Olsa, netdev, linux-kernel,
	linux-api, Arnd Bergmann, linux-kselftest, mptcp,
	linux-security-module, bpf, libc-alpha, Carlos O'Donell,
	Adhemerval Zanella, Rich Felker, klibc, Florian Weimer
In-Reply-To: <20260130081741.425a92e0@kernel.org>

Jan 30, 2026 17:17:46 Jakub Kicinski <kuba@kernel.org>:

> On Fri, 30 Jan 2026 11:34:15 +0100 Thomas Weißschuh wrote:
>>> Are all those selftests / samples getting broken by this patch set? 
>>
>> Yes.
>>
>> Some of them get broken by the new 'struct sockaddr', but some others are
>> already broken just by the new transitive inclusion of libc-compat.h.
>> So any header starting to use the compatibility machinery may trigger breakage
>> in code including UAPI headers before libc header, even for completely new type
>> definitions which themselves would not conflict with libc.
>
> Let's split the uAPI header changes from any selftest changes.
> If you're saying the the selftests no longer build after the uAPI
> header changes then of course we can't apply the patches.

Yes, the selftests don't build anymore after the uAPI changes.

"can't apply" as in
* "can't apply separately"
* "are unacceptable in general"
* "are too late for this cycle"
?

None of this is urgent.
We can do the selftests in one cycle and the uAPI in another one.
Feel free to pick up the patches as you see fit.
(The mptcp changes already go through their tree, so need to be dropped here)
I can also resubmit the patches differently if preferred.


Thomas

^ permalink raw reply


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