Linux Security Modules development
 help / color / mirror / Atom feed
* Re: [PATCH v2 1/3] integrity: Make arch_ima_get_secureboot integrity-wide
From: Coiby Xu @ 2026-02-12  1:28 UTC (permalink / raw)
  To: Mimi Zohar
  Cc: linux-integrity, Heiko Carstens, Alexander Egorenkov,
	Ard Biesheuvel, Dave Hansen, Roberto Sassu, Madhavan Srinivasan,
	Michael Ellerman, Nicholas Piggin, Christophe Leroy (CS GROUP),
	Vasily Gorbik, Alexander Gordeev, Christian Borntraeger,
	Sven Schnelle, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, maintainer:X86 ARCHITECTURE (32-BIT AND 64-BIT),
	H. Peter Anvin, Dmitry Kasatkin, Eric Snowberg, Paul Moore,
	James Morris, Serge E. Hallyn, Jarkko Sakkinen, open list,
	open list:LINUX FOR POWERPC (32-BIT AND 64-BIT),
	open list:S390 ARCHITECTURE,
	open list:EXTENSIBLE FIRMWARE INTERFACE (EFI),
	open list:SECURITY SUBSYSTEM, open list:KEYS/KEYRINGS_INTEGRITY
In-Reply-To: <66f9d13875e81a965984e2a661e992a3fe43c516.camel@linux.ibm.com>

On Mon, Feb 09, 2026 at 03:43:08PM -0500, Mimi Zohar wrote:
>On Tue, 2026-02-03 at 12:14 +0800, Coiby Xu wrote:
>> EVM and other LSMs need the ability to query the secure boot status of
>> the system, without directly calling the IMA arch_ima_get_secureboot
>> function. Refactor the secure boot status check into a general function
>> named arch_get_secureboot.
>>
>> Reported-and-suggested-by: Mimi Zohar <zohar@linux.ibm.com>
>> Suggested-by: Roberto Sassu <roberto.sassu@huawei.com>
>> Signed-off-by: Coiby Xu <coxu@redhat.com>
>
>Thanks, Coiby.  Other than unnecessarily splitting a line, the patch set looks
>good.  As soon as the open window closes, I'll queue these patches for linux-
>next.

Hi Mimi, thanks for reviewing the patch set! Would you like me to send a
new version with the line splitting issue fixed?

>
>> diff --git a/security/integrity/ima/ima_efi.c b/security/integrity/ima/ima_efi.c
>> index 138029bfcce1..27521d665d33 100644
>> --- a/security/integrity/ima/ima_efi.c
>> +++ b/security/integrity/ima/ima_efi.c
[...]
>>  {
>> -	if (IS_ENABLED(CONFIG_IMA_ARCH_POLICY) && arch_ima_get_secureboot()) {
>> +	if (IS_ENABLED(CONFIG_IMA_ARCH_POLICY) &&
>> +	    arch_get_secureboot()) {
>
>No need to split the line here or below.
>
>
>>  		if (IS_ENABLED(CONFIG_MODULE_SIG))
>>  			set_module_sig_enforced();
>>  		if (IS_ENABLED(CONFIG_KEXEC_SIG))
>> diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
>> index 5770cf691912..6d093ac82a45 100644
>> --- a/security/integrity/ima/ima_main.c
>> +++ b/security/integrity/ima/ima_main.c
>> @@ -949,8 +949,8 @@ static int ima_load_data(enum kernel_load_data_id id, bool contents)
>>
>>  	switch (id) {
>>  	case LOADING_KEXEC_IMAGE:
>> -		if (IS_ENABLED(CONFIG_KEXEC_SIG)
>> -		    && arch_ima_get_secureboot()) {
>> +		if (IS_ENABLED(CONFIG_KEXEC_SIG) &&
>> +		    arch_get_secureboot()) {
>
>===>
>
>Mimi
>
>>  			pr_err("impossible to appraise a kernel image without a file descriptor; try using kexec_file_load syscall.\n");
>>  			return -EACCES;
>>  		}
>

-- 
Best regards,
Coiby


^ permalink raw reply

* Re: [GIT PULL] Landlock update for v7.0-rc1
From: pr-tracker-bot @ 2026-02-12  0:04 UTC (permalink / raw)
  To: Mickaël Salaün
  Cc: Linus Torvalds, Mickaël Salaün, Günther Noack,
	Matthieu Buffet, Samasth Norway Ananda, linux-kernel,
	linux-security-module
In-Reply-To: <20260211141302.1134092-1-mic@digikod.net>

The pull request you sent on Wed, 11 Feb 2026 15:13:02 +0100:

> https://lore.kernel.org/keys/20260206.waiCh9iex3ai@digikod.net/ --

has been merged into torvalds/linux.git:
https://git.kernel.org/torvalds/c/c22e26bd0906e9c8325462993f01adb16b8ea2c0

Thank you!

-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/prtracker.html

^ permalink raw reply

* Re: [GIT PULL] Smack patches for 7.0
From: pr-tracker-bot @ 2026-02-12  0:04 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: Linus Torvalds, LSM List, Linux kernel mailing list,
	Konstantin Andreev, Taimoor Zaeem, Casey Schaufler
In-Reply-To: <28dea16f-18c3-4a2f-821c-e85b660125ed@schaufler-ca.com>

The pull request you sent on Mon, 9 Feb 2026 13:15:00 -0800:

> https://github.com/cschaufler/smack-next tags/Smack-for-7.0

has been merged into torvalds/linux.git:
https://git.kernel.org/torvalds/c/146fa666d89f233b87f1cdc7b9bce34c61b45cbd

Thank you!

-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/prtracker.html

^ permalink raw reply

* Re: [RFC PATCH] fs/pidfs: Add permission check to pidfd_info()
From: Daniel Durning @ 2026-02-11 19:43 UTC (permalink / raw)
  To: Christian Brauner
  Cc: linux-fsdevel, linux-security-module, selinux, viro, jack, paul,
	stephen.smalley.work, omosnace, Oleg Nesterov
In-Reply-To: <20260209-spanplatten-zerrt-73851db30f18@brauner>

On Mon, Feb 9, 2026 at 9:01 AM Christian Brauner <brauner@kernel.org> wrote:
>
> On Fri, Feb 06, 2026 at 06:02:48PM +0000, danieldurning.work@gmail.com wrote:
> > From: Daniel Durning <danieldurning.work@gmail.com>
> >
> > Added a permission check to pidfd_info(). Originally, process info
> > could be retrieved with a pidfd even if proc was mounted with hidepid
> > enabled, allowing pidfds to be used to bypass those protections. We
> > now call ptrace_may_access() to perform some DAC checking as well
> > as call the appropriate LSM hook.
> >
> > The downside to this approach is that there are now more restrictions
> > on accessing this info from a pidfd than when just using proc (without
> > hidepid). I am open to suggestions if anyone can think of a better way
> > to handle this.
>
> This isn't really workable since this would regress userspace quite a
> bit. I think we need a different approach. I've given it some thought
> and everything's kinda ugly but this might work.
>
> In struct pid_namespace record whether anyone ever mounted a procfs
> with hidepid turned on for this pidns. In pidfd_info() we check whether
> hidepid was ever turned on. If it wasn't we're done and can just return
> the info. This will be the common case. If hidepid was ever turned on
> use kern_path("/proc") to lookup procfs. If not found check
> ptrace_may_access() to decide whether to return the info or not. If
> /proc is found check it's hidepid settings and make a decision based on
> that.
>
> You can probably reorder this to call ptrace_may_access() first and then
> do the procfs lookup dance. Thoughts?

Thanks for the feedback. I think your solution makes sense.

Unfortunately, it seems like systemd mounts procfs with hidepid enabled on
boot for services with the ProtectProc option enabled. This means that
procfs will always have been mounted with hidepid in the init pid namespace.
Do you think it would be viable to record whether or not procfs was mounted
with hidepid enabled in the mount namespace instead?

> > I have also noticed that it is possible to use pidfds to poll on any
> > process regardless of whether the process is a child of the caller,
> > has a different UID, or has a different security context. Is this
> > also worth addressing? If so, what exactly should the DAC checks be?
>
> Oleg and I had discusses this and decided that such polling isn't
> sensitive information so by default this should just work and it's
> relied upon in Android and in a bunch of other workloads. An LSM can of
> course restrict access via security_file_ioctl().
>
> Fwiw, pidfds now support persistent trusted extended attributes so if
> the LSM folks wanted we can add security.* extended attribute support
> and they can mark pidfds with persistent security labels - persistent as
> in for the lifetime of the task.
>
> > Signed-off-by: Daniel Durning <danieldurning.work@gmail.com>
> > ---
> >  fs/pidfs.c | 7 +++++++
> >  1 file changed, 7 insertions(+)
> >
> > diff --git a/fs/pidfs.c b/fs/pidfs.c
> > index dba703d4ce4a..058a7d798bca 100644
> > --- a/fs/pidfs.c
> > +++ b/fs/pidfs.c
> > @@ -365,6 +365,13 @@ static long pidfd_info(struct file *file, unsigned int cmd, unsigned long arg)
> >               goto copy_out;
> >       }
> >
> > +     /*
> > +      * Do a filesystem cred ptrace check to verify access
> > +      * to the task's info.
> > +      */
> > +     if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS))
> > +             return -EACCES;
> > +
> >       c = get_task_cred(task);
> >       if (!c)
> >               return -ESRCH;
> > --
> > 2.52.0
> >

^ permalink raw reply

* Re: [PATCH v3 0/3] Landlock multithreaded enforcement
From: Mickaël Salaün @ 2026-02-11 14:55 UTC (permalink / raw)
  To: Günther Noack
  Cc: linux-security-module, Jann Horn, Serge Hallyn,
	Konstantin Meskhidze, Tingmao Wang, Matthieu Buffet
In-Reply-To: <20260205.phu7Bo2ieMih@digikod.net>

FYI, syzkaller now supports this new flag, and it has been fuzzed for a
few months (before being merged):
https://github.com/google/syzkaller/commit/e5e258750ba4cad4408ac45a26c0aafff51d45b1

On Thu, Feb 05, 2026 at 07:53:47PM +0100, Mickaël Salaün wrote:
> Good job for writing this complex mechanic (and the related doc), this
> patch series is great!  It's been in linux-next for a few weeks and I'll
> take it for Linux 7.0
> 
> I did some cosmetic changes though, you'll find them in my commits.
> Some more tests are needed but I'll take this series for now.
> 
> Thanks!
> 
> On Thu, Nov 27, 2025 at 12:51:33PM +0100, Günther Noack wrote:
> > This patch set adds the LANDLOCK_RESTRICT_SELF_TSYNC flag to
> > landlock_restrict_self().  With this flag, the passed Landlock ruleset
> > will not only be applied to the calling thread, but to all threads
> > which belong to the same process.
> > 
> > Motivation
> > ==========
> > 
> > TL;DR: The libpsx/nptl(7) signal hack which we use in user space for
> > multi-threaded Landlock enforcement is incompatible with Landlock's
> > signal scoping support.  Landlock can restrict the use of signals
> > across Landlock domains, but we need signals ourselves in user space
> > in ways that are not permitted any more under these restrictions.
> > 
> > Enabling Landlock proves to be difficult in processes that are already
> > multi-threaded at the time of enforcement:
> > 
> > * Enforcement in only one thread is usually a mistake because threads
> >   do not normally have proper security boundaries between them.
> > 
> > * Also, multithreading is unavoidable in some circumstances, such as
> >   when using Landlock from a Go program.  Go programs are already
> >   multithreaded by the time that they enter the "func main()".
> > 
> > So far, the approach in Go[1] was to use libpsx[2].  This library
> > implements the mechanism described in nptl(7) [3]: It keeps track of
> > all threads with a linker hack and then makes all threads do the same
> > syscall by registering a signal handler for them and invoking it.
> > 
> > With commit 54a6e6bbf3be ("landlock: Add signal scoping"), Landlock
> > gained the ability to restrict the use of signals across different
> > Landlock domains.
> > 
> > Landlock's signal scoping support is incompatible with the libpsx
> > approach of enabling Landlock:
> > 
> > (1) With libpsx, although all threads enforce the same ruleset object,
> >     they technically do the operation separately and end up in
> >     distinct Landlock domains.  This breaks signaling across threads
> >     when using LANDLOCK_SCOPE_SIGNAL.
> > 
> > (2) Cross-thread Signals are themselves needed to enforce further
> >     nested Landlock domains across multiple threads.  So nested
> >     Landlock policies become impossible there.
> > 
> > In addition to Landlock itself, cross-thread signals are also needed
> > for other seemingly-harmless API calls like the setuid(2) [4] and for
> > the use of libcap (co-developed with libpsx), which have the same
> > problem where the underlying syscall only applies to the calling
> > thread.
> > 
> > Implementation details
> > ======================
> > 
> > Enforcement prerequisites
> > -------------------------
> > 
> > Normally, the prerequisite for enforcing a Landlock policy is to
> > either have CAP_SYS_ADMIN or the no_new_privs flag.  With
> > LANDLOCK_RESTRICT_SELF_TSYNC, the no_new_privs flag will automatically
> > be applied for sibling threads if the caller had it.
> > 
> > These prerequisites and the "TSYNC" behavior work the same as for
> > Seccomp and its SECCOMP_FILTER_FLAG_TSYNC flag.
> > 
> > Pseudo-signals
> > --------------
> > 
> > Landlock domains are stored in struct cred, and a task's struct cred
> > can only be modified by the task itself [6].
> > 
> > To make that work, we use task_work_add() to register a pseudo-signal
> > for each of the affected threads.  At signal execution time, these
> > tasks will coordinate to switch out their Landlock policy in lockstep
> > with each other, guaranteeing all-or-nothing semantics.
> > 
> > This implementation can be thought of as a kernel-side implementation
> > of the userspace hack that glibc/NPTL use for setuid(2) [3] [4], and
> > which libpsx implements for libcap [2].
> > 
> > Finding all sibling threads
> > ---------------------------
> > 
> > In order to avoid grabbing the global task_list_lock, we employ the
> > scheme proposed by Jann Horn in [7]:
> > 
> > 1. Loop through the list of sibling threads
> > 2. Schedule a pseudo-signal for each and make each thread wait in the
> >    pseudo-signal
> > 3. Go back to 1. and look for more sibling thread that we have not
> >    seen yet
> > 
> > Do this until no more new threads are found.  As all threads were
> > waiting in their pseudo-signals, they can not spawn additional threads
> > and we found them all.
> > 
> > Coordination between tasks
> > --------------------------
> > 
> > As tasks run their pseudo-signal task work, they coordinate through
> > the following completions:
> > 
> >  - all_prepared (with counter num_preparing)
> >  
> >    When done, all new sibling threads in the inner loop(!) of finding
> >    new threads are now in their pseudo-signal handlers and have
> >    prepared the struct cred object to commit (or written an error into
> >    the shared "preparation_error").
> > 
> >    The lifetime of all_prepared is only the inner loop of finding new
> >    threads.
> > 
> >  - ready_to_commit
> > 
> >    When done, the outer loop of finding new threads is done and all
> >    sibling threads have prepared their struct cred object.  Marked
> >    completed by the calling thread.
> > 
> >  - all_finished
> > 
> >    When done, all sibling threads are done executing their
> >    pseudo-signal handlers.
> > 
> > Use of credentials API
> > ----------------------
> > 
> > Under normal circumstances, sibling threads share the same struct cred
> > object.  To avoid unnecessary duplication, if we find that a thread
> > uses the same struct cred as the calling thread, we side-step the
> > normal use of the credentials API [6] and place a pointer to that
> > existing struct cred instead of creating a new one using
> > prepare_creds() in the sibling thread.
> > 
> > Noteworthy discussion points
> > ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> > 
> > * We are side-stepping the normal credentials API [6], by re-wiring an
> >   existing struct cred object instead of calling prepare_creds().
> > 
> >   We can technically avoid it, but it would create unnecessary
> >   duplicate struct cred objects in multithreaded scenarios.
> > 
> > Change Log
> > ==========
> > 
> > v3:
> >  - bigger organizational changes
> >    - move tsync logic into own file
> >    - tsync: extract count_additional_threads() and
> >      schedule_task_work()
> >  - code style
> >    - restrict_one_thread, syscalls.c: use err instead of res (mic)
> >    - restrict_one_thread: inline current_cred variable
> >    - restrict_one_thread: add comment to shortcut logic (mic)
> >    - rsync_works helpers: use size_t i for loop vars
> >    - landlock_cred_copy: skip redundant NULL checks
> >    - function name: s,tsync_works_free,tsync_works_release, (mic)
> >    - tsync_works_grow_by: kzalloc into a temporary variable for
> >      clarity (mic)
> >    - tsync_works_contains_task: make struct task_works const
> >  - bugs
> >    - handle kmalloc family failures correctly (jannh)
> >    - tsync_works_release: check task NULL ptr before put
> >    - s/put_task_struct_rcu_user/put_task_struct/ (jannh)
> >  - concurrency bugs
> >    - schedule_task_work: do not return error when encountering exiting
> >      tasks This can happen during normal operation, we should not
> >      error due to it (jannh)
> >    - landlock_restrict_sibling_threads: make current hold the
> >      num_unfinished/all_finished barrier (more robust, jannh)
> >    - un-wedge the deadlock using wait_for_completion_interruptible
> >      (jannh) See "testing" below and discussion in
> >      https://lore.kernel.org/all/CAG48ez1oS9kANZBq1bt+D76MX03DPHAFp76GJt7z5yx-Na1VLQ@mail.gmail.com/
> >  - logic
> >    - tsync_works_grow_by(): grow to size+n, not capacity+n
> >    - tsync_works_grow_by(): add overflow check for capacity increase
> >    - landlock_restrict_self(): make TSYNC and LOG flags work together
> >    - set no_new_privs in the same way as seccomp,
> >      whenever the calling thread had it
> >  - testing
> >    - add test where multiple threads call landlock_restrict_self()
> >      concurrently
> >    - test that no_new_privs is implicitly enabled for sibling threads
> >  - bump ABI version to v8
> >  - documentation improvements
> >    - document ABI v8
> >    - move flag documentation into the landlock.h header
> >    - comment: Explain why we do not need sighand->siglock or
> >      cred_guard_mutex
> >    - various comment improvements
> >    - reminder above struct landlock_cred_security about updating
> >      landlock_cred_copy on changes
> > 
> > v2:
> >  - https://lore.kernel.org/all/20250221184417.27954-2-gnoack3000@gmail.com/
> >  - Semantics:
> >    - Threads implicitly set NO_NEW_PRIVS unless they have
> >      CAP_SYS_ADMIN, to fulfill Landlock policy enforcement
> >      prerequisites
> >    - Landlock policy gets unconditionally overridden even if the
> >      previously established Landlock domains in sibling threads were
> >      diverging.
> >  - Restructure discovery of all sibling threads, with the algorithm
> >    proposed by Jann Horn [7]: Loop through threads multiple times, and
> >    get them all stuck in the pseudo signal (task work), until no new
> >    sibling threads show up.
> >  - Use RCU lock when iterating over sibling threads.
> >  - Override existing Landlock domains of other threads,
> >    instead of applying a new Landlock policy on top
> >  - Directly re-wire the struct cred for sibling threads,
> >    instread of creating a new one with prepare_creds().
> >  - Tests:
> >    - Remove multi_threaded_failure test
> >      (The only remaining failure case is ENOMEM,
> >      there is no good way to provoke that in a selftest)
> >    - Add test for success despite diverging Landlock domains.
> > 
> > [1] https://github.com/landlock-lsm/go-landlock
> > [2] https://sites.google.com/site/fullycapable/who-ordered-libpsx
> > [3] https://man.gnoack.org/7/nptl
> > [4] https://man.gnoack.org/2/setuid#VERSIONS
> > [5] https://lore.kernel.org/all/20240805-remove-cred-transfer-v2-0-a2aa1d45e6b8@google.com/
> > [6] https://www.kernel.org/doc/html/latest/security/credentials.html
> > [7] https://lore.kernel.org/all/CAG48ez0pWg3OTABfCKRk5sWrURM-HdJhQMcWedEppc_z1rrVJw@mail.gmail.com/
> > 
> > Günther Noack (3):
> >   landlock: Multithreading support for landlock_restrict_self()
> >   landlock: selftests for LANDLOCK_RESTRICT_SELF_TSYNC
> >   landlock: Document LANDLOCK_RESTRICT_SELF_TSYNC
> > 
> >  Documentation/userspace-api/landlock.rst      |   8 +
> >  include/uapi/linux/landlock.h                 |  13 +
> >  security/landlock/Makefile                    |   2 +-
> >  security/landlock/cred.h                      |  12 +
> >  security/landlock/limits.h                    |   2 +-
> >  security/landlock/syscalls.c                  |  66 ++-
> >  security/landlock/tsync.c                     | 555 ++++++++++++++++++
> >  security/landlock/tsync.h                     |  16 +
> >  tools/testing/selftests/landlock/base_test.c  |   8 +-
> >  tools/testing/selftests/landlock/tsync_test.c | 161 +++++
> >  10 files changed, 810 insertions(+), 33 deletions(-)
> >  create mode 100644 security/landlock/tsync.c
> >  create mode 100644 security/landlock/tsync.h
> >  create mode 100644 tools/testing/selftests/landlock/tsync_test.c
> > 
> > -- 
> > 2.52.0.177.g9f829587af-goog
> > 
> > 

^ permalink raw reply

* [GIT PULL] Landlock update for v7.0-rc1
From: Mickaël Salaün @ 2026-02-11 14:13 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Mickaël Salaün, Günther Noack, Matthieu Buffet,
	Samasth Norway Ananda, linux-kernel, linux-security-module

Hi,

These changes extend Landlock to enforce restrictions on a whole
process, similarly to the seccomp's TSYNC flag.  Data structure
refactoring simplifies code and improves performance.  Documentation is
extended to cover missing parts.

Please pull these changes for v7.0-rc1 .  These commits merge cleanly
with your master branch.  The kernel changes have been tested in the
latest linux-next releases for some weeks, but I rebased the last
commits to fix a kselftest build issue on old distros, and to add a
review tag.

Test coverage for security/landlock is 91.4% of 2093 lines according to
LLVM 21, and it was 91.9% of 1933 lines before this PR.

Regards,
 Mickaël


PS: I recently updated my PGP key:
    https://lore.kernel.org/keys/20260206.waiCh9iex3ai@digikod.net/

--
The following changes since commit 24d479d26b25bce5faea3ddd9fa8f3a6c3129ea7:

  Linux 6.19-rc6 (2026-01-18 15:42:45 -0800)

are available in the Git repository at:

  https://git.kernel.org/pub/scm/linux/kernel/git/mic/linux.git tags/landlock-7.0-rc1

for you to fetch changes up to e265b330b93e3a3f9ff5256451d4f09b5f89b239:

  mailmap: Add entry for Mickaël Salaün (2026-02-11 12:03:44 +0100)

----------------------------------------------------------------
Landlock update for v7.0-rc1

----------------------------------------------------------------
Günther Noack (6):
      landlock: Multithreading support for landlock_restrict_self()
      selftests/landlock: Add LANDLOCK_RESTRICT_SELF_TSYNC tests
      landlock: Document LANDLOCK_RESTRICT_SELF_TSYNC
      selftests/landlock: Add filesystem access benchmark
      landlock: Add access_mask_subset() helper
      landlock: Transpose the layer masks data structure

Matthieu Buffet (2):
      landlock: Minor reword of docs for TCP access rights
      landlock: Refactor TCP socket type check

Mickaël Salaün (1):
      mailmap: Add entry for Mickaël Salaün

Samasth Norway Ananda (3):
      landlock: Add backwards compatibility for restrict flags
      landlock: Add errata documentation section
      landlock: Document audit blocker field format

 .mailmap                                      |   1 +
 Documentation/admin-guide/LSM/landlock.rst    |  35 +-
 Documentation/userspace-api/landlock.rst      | 105 ++++-
 include/uapi/linux/landlock.h                 |  30 +-
 security/landlock/Makefile                    |  11 +-
 security/landlock/access.h                    |  35 +-
 security/landlock/audit.c                     |  81 ++--
 security/landlock/audit.h                     |   3 +-
 security/landlock/cred.h                      |  12 +
 security/landlock/domain.c                    |  44 +-
 security/landlock/domain.h                    |   3 +-
 security/landlock/errata/abi-1.h              |   8 +
 security/landlock/errata/abi-4.h              |   7 +
 security/landlock/errata/abi-6.h              |  10 +
 security/landlock/fs.c                        | 352 ++++++++--------
 security/landlock/limits.h                    |   2 +-
 security/landlock/net.c                       |  30 +-
 security/landlock/ruleset.c                   |  91 ++---
 security/landlock/ruleset.h                   |   6 +-
 security/landlock/syscalls.c                  |  65 +--
 security/landlock/tsync.c                     | 561 ++++++++++++++++++++++++++
 security/landlock/tsync.h                     |  16 +
 tools/testing/selftests/landlock/.gitignore   |   1 +
 tools/testing/selftests/landlock/Makefile     |   1 +
 tools/testing/selftests/landlock/base_test.c  |   8 +-
 tools/testing/selftests/landlock/fs_bench.c   | 214 ++++++++++
 tools/testing/selftests/landlock/tsync_test.c | 161 ++++++++
 27 files changed, 1490 insertions(+), 403 deletions(-)
 create mode 100644 security/landlock/tsync.c
 create mode 100644 security/landlock/tsync.h
 create mode 100644 tools/testing/selftests/landlock/fs_bench.c
 create mode 100644 tools/testing/selftests/landlock/tsync_test.c

^ permalink raw reply

* Re: [PATCH] selftests/landlock: Remove duplicate include of stdio.h
From: Mickaël Salaün @ 2026-02-11 11:16 UTC (permalink / raw)
  To: Chen Ni; +Cc: gnoack, shuah, linux-security-module, linux-kselftest,
	linux-kernel
In-Reply-To: <20260211062122.2975127-1-nichen@iscas.ac.cn>

On Wed, Feb 11, 2026 at 02:21:22PM +0800, Chen Ni wrote:
> Remove duplicate inclusion of stdio.h in fs_bench.c to clean up
> redundant code.

Thanks!  I also detected this issue while running `sort -u` on the
includes, so this is already taken into account in my next branch (with
other small fixes).

> 
> Signed-off-by: Chen Ni <nichen@iscas.ac.cn>
> ---
>  tools/testing/selftests/landlock/fs_bench.c | 1 -
>  1 file changed, 1 deletion(-)
> 
> diff --git a/tools/testing/selftests/landlock/fs_bench.c b/tools/testing/selftests/landlock/fs_bench.c
> index 733c1264e5fd..551cb615ad93 100644
> --- a/tools/testing/selftests/landlock/fs_bench.c
> +++ b/tools/testing/selftests/landlock/fs_bench.c
> @@ -26,7 +26,6 @@
>  #include <linux/prctl.h>
>  #include <stdbool.h>
>  #include <stdio.h>
> -#include <stdio.h>
>  #include <errno.h>
>  #include <stdlib.h>
>  #include <string.h>
> -- 
> 2.25.1
> 
> 

^ permalink raw reply

* Re: [PATCH v1] mailmap: Add entry for Mickaël Salaün
From: Paul Moore @ 2026-02-11  9:45 UTC (permalink / raw)
  To: Mickaël Salaün
  Cc: linux-kernel, linux-security-module, Günther Noack,
	James Morris
In-Reply-To: <20260207111136.577249-1-mic@digikod.net>

On Sat, Feb 7, 2026 at 6:28 AM Mickaël Salaün <mic@digikod.net> wrote:
>
> My Microsoft address is no longer used.  Add a mailmap entry to reflect
> that.
>
> Cc: Günther Noack <gnoack@google.com>
> Cc: James Morris <jamorris@linux.microsoft.com>
> Signed-off-by: Mickaël Salaün <mic@digikod.net>
> ---
>  .mailmap | 1 +
>  1 file changed, 1 insertion(+)

Reviewed-by: Paul Moore <paul@paul-moore.com>

-- 
paul-moore.com

^ permalink raw reply

* Re: [PATCH] selftests/landlock: Remove duplicate include of stdio.h
From: Günther Noack @ 2026-02-11  8:27 UTC (permalink / raw)
  To: Chen Ni
  Cc: mic, gnoack, shuah, linux-security-module, linux-kselftest,
	linux-kernel
In-Reply-To: <20260211062122.2975127-1-nichen@iscas.ac.cn>

On Wed, Feb 11, 2026 at 02:21:22PM +0800, Chen Ni wrote:
> Remove duplicate inclusion of stdio.h in fs_bench.c to clean up
> redundant code.

Thanks, well spotted!

Reviewed-by: Günther Noack <gnoack3000@gmail.com>

^ permalink raw reply

* [PATCH] selftests/landlock: Remove duplicate include of stdio.h
From: Chen Ni @ 2026-02-11  6:21 UTC (permalink / raw)
  To: mic
  Cc: gnoack, shuah, linux-security-module, linux-kselftest,
	linux-kernel, Chen Ni

Remove duplicate inclusion of stdio.h in fs_bench.c to clean up
redundant code.

Signed-off-by: Chen Ni <nichen@iscas.ac.cn>
---
 tools/testing/selftests/landlock/fs_bench.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/tools/testing/selftests/landlock/fs_bench.c b/tools/testing/selftests/landlock/fs_bench.c
index 733c1264e5fd..551cb615ad93 100644
--- a/tools/testing/selftests/landlock/fs_bench.c
+++ b/tools/testing/selftests/landlock/fs_bench.c
@@ -26,7 +26,6 @@
 #include <linux/prctl.h>
 #include <stdbool.h>
 #include <stdio.h>
-#include <stdio.h>
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
-- 
2.25.1


^ permalink raw reply related

* Re: [RFC][PATCH v2] ima: Add support for staging measurements for deletion and trimming
From: steven chen @ 2026-02-11  0:09 UTC (permalink / raw)
  To: Roberto Sassu, corbet, zohar, dmitry.kasatkin, eric.snowberg,
	paul, jmorris, serge
  Cc: linux-doc, linux-kernel, linux-integrity, linux-security-module,
	gregorylumen, nramas, Roberto Sassu, steven chen
In-Reply-To: <52069703-98fc-4667-8c29-446ea73249cb@huaweicloud.com>

On 1/29/2026 12:20 AM, Roberto Sassu wrote:
> On 1/28/2026 10:30 PM, steven chen wrote:
>> On 12/12/2025 9:19 AM, Roberto Sassu wrote:
>>> From: Roberto Sassu <roberto.sassu@huawei.com>
>>>
>>> Introduce the ability of staging the entire (or a portion of the) IMA
>>> measurement list for deletion. Staging means moving the current 
>>> content of
>>> the measurement list to a separate location, and allowing users to 
>>> read and
>>> delete it. This causes the measurement list to be atomically truncated
>>> before new measurements can be added. Staging can be done only once 
>>> at a
>>> time. In the event of kexec(), staging is reverted and staged 
>>> entries will
>>> be carried over to the new kernel.
>>>
>>> User space is responsible to concatenate the staged IMA measurements 
>>> list
>>> portions following the temporal order in which the operations were 
>>> done,
>>> together with the current measurement list. Then, it can send the 
>>> collected
>>> data to the remote verifiers.
>>>
>>> Also introduce the ability of trimming N measurements entries from 
>>> the IMA
>>> measurements list, provided that user space has already read them. 
>>> Trimming
>>> combines staging and deletion in one operation.
>>>
>>> The benefit of these solutions is the ability to free precious kernel
>>> memory, in exchange of delegating user space to reconstruct the full
>>> measurement list from the chunks. No trust needs to be given to user 
>>> space,
>>> since the integrity of the measurement list is protected by the TPM.
>>>
>>> By default, staging/trimming the measurements list does not alter 
>>> the hash
>>> table. When staging/trimming are done, IMA is still able to detect
>>> collisions on the staged and later deleted measurement entries, by 
>>> keeping
>>> the entry digests (only template data are freed).
>>>
>>> However, since during the measurements list serialization only the SHA1
>>> digest is passed, and since there are no template data to 
>>> recalculate the
>>> other digests from, the hash table is currently not populated with 
>>> digests
>>> from staged/deleted entries after kexec().
>>>
>>> Introduce the new kernel option ima_flush_htable to decide whether 
>>> or not
>>> the digests of staged measurement entries are flushed from the hash 
>>> table.
>>>
>>> Then, introduce ascii_runtime_measurements_staged_<algo> and
>>> binary_runtime_measurement_staged_<algo> interfaces to 
>>> stage/trim/delete
>>> the measurements. Use 'echo A > <IMA interface>' and
>>> 'echo D > <IMA interface>' to respectively stage and delete the entire
>>> measurements list. Use 'echo N > <IMA interface>', with N between 1 and
>>> LONG_MAX, to stage the selected portion of the measurements list, and
>>> 'echo -N > <IMA interface>' to trim N measurements entries.
>>>
>>> The ima_measure_users counter (protected by the ima_measure_lock 
>>> mutex) has
>>> been introduced to protect access to the measurements list and the 
>>> staged
>>> part. The open method of all the measurement interfaces has been 
>>> extended
>>> to allow only one writer at a time or, in alternative, multiple 
>>> readers.
>>> The write permission is used to stage/trim/delete the measurements, the
>>> read permission to read them. Write requires also the CAP_SYS_ADMIN
>>> capability.
>>>
>>> Finally, introduce and maintain dedicate counters for the number of
>>> measurement entries and binary size, for the current measurements list
>>> (BINARY_SIZE), for the current measurements list plus staged entries
>>> (BINARY_SIZE_STAGED) useful for kexec() segment allocation, and for the
>>> entire measurement list without staging/trimming (BINARY_SIZE_FULL) 
>>> useful
>>> for the kexec-related critical data records.
>> Is the following possible race condition for staged list:
>>
>> Agent A: create staged list            Staged list A1
>>           new measurement added    Measurement list M1
>>           Two lists in kernel: A1 and M1
>>
>> Agent B: read staged list (A1) to do verification
>>           new measurement added    Measurement list M2
>>           Two lists in kernel: A1 and M2
>>
>> Agent A: verified and remove staged list (A1)
>>           new measurement added    Measurement list M3
>>           One list in kernel: M3
>>
>> Agent C: create staged list            Staged list C1
>>           new measurement added    Measurement list M4
>>           Two lists in kernel: C1 and M4
>>
>> Agent B: remove staged list (?), C1 removed ---this will cause problem
>>           new measurement added    Measurement list M5
>>           One list in kernel: M5
>>
>> Agent C: try to remove staged list(?)
>
> If you remember the patch, we added a read-write protection to the 
> measurements interfaces. As long as you keep the interface open for 
> write no one else can make change on the staging. Sure, you can drop 
> the write, and reopen for read, but then you should expect someone 
> else to operate on the interface.
>
> If you want to be sure no one else changes the staged measurements, 
> just keep the interface open for write, read the staged measurements 
> and delete them.
>
> Roberto
>
For different use cases, we can compare lock time for both staged method 
and trim N method:

t1: user space measurement list lock time
t2: kernel measurement list lock time

     Stage approach use case 1:
               1. read PCR quote
               2. read list
               3. attestation
               4. get N from attestation response
---          5. hold the list in the user space
  ^   ---    6. hold the measurement list
        ^     7. stage the list
t1    t2   8. trim N
        v     9. put the rest of stage back to measurement list
  v   ---    10. release the measurement list
---          11. release the list in the user space
  For this case, agent race condition may happen

   Stage approach use case 2:
               1. read PCR quote
---          2. hold the list in the user space
  ^           3. stage the list
               4. read list
               5. attestation
t1    ---  6. hold the measurement list
          ^   7. get N from attestation response
          t2  8. trim N
          v    9. put the rest of stage back to measurement list
  v    ---   10. release the measurement list
---          11. release the list in the user space
  For this case, no agent race condition happen

the following use case for trim N method

    Trim N approach use case:
              1. read total trimmed T
              2. read PCR quote
              3. read list,
              4. attestation
              5. get N from attestation response
---         6. hold the list in the user space
  ^   ---   7. hold the measurement list
        ^
t1   t2   8. trim with format T:N, update T
        v
  v   ---    9 . release the measurement list
---          10. release the list in the user space
     no agent race condition happen

For all use cases, I think for both t1 and t2, trim N method has better 
result.

Steven

>> Possible solution?
>>    Save the total number trimmed T or tag
>>
>>    Trim request sync this parameter to trim the staged list
>>
>> Regards,
>>
>> Steven
>>
>>> Note: This code derives from the Alt-IMA Huawei project, and is being
>>>        released under the dual license model (GPL-2.0 OR MIT).
>>>
>>> Link: https://github.com/linux-integrity/linux/issues/1
>>> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
>>> --- 


^ permalink raw reply

* Re: [PATCH v4 2/6] landlock: Control pathname UNIX domain socket resolution by path
From: Günther Noack @ 2026-02-10 23:09 UTC (permalink / raw)
  To: Mickaël Salaün
  Cc: Günther Noack, John Johansen, Tingmao Wang, Justin Suess,
	Jann Horn, linux-security-module, Samasth Norway Ananda,
	Matthieu Buffet, Mikhail Ivanov, konstantin.meskhidze,
	Demi Marie Obenour, Alyssa Ross, Tahera Fahimi
In-Reply-To: <20260209.IWeigh1theik@digikod.net>

On Mon, Feb 09, 2026 at 06:28:24PM +0100, Mickaël Salaün wrote:
> On Mon, Feb 09, 2026 at 11:21:57AM +0100, Günther Noack wrote:
> > On Mon, Feb 09, 2026 at 12:10:12AM +0100, Günther Noack wrote:
> > > +static int hook_unix_find(const struct path *const path, struct sock *other,
> > > +			  int flags)
> > > +{
> > > +	const struct landlock_ruleset *dom_other;
> > > +	const struct landlock_cred_security *subject;
> > > +	struct layer_access_masks layer_masks;
> > > +	struct landlock_request request = {};
> > > +	static const struct access_masks fs_resolve_unix = {
> > > +		.fs = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> > > +	};
> > > +	int type = other->sk_type;
> > > +
> > > +	/* Lookup for the purpose of saving coredumps is OK. */
> > > +	if (flags & SOCK_COREDUMP)
> > > +		return 0;
> > > +
> > > +	/* Only stream, dgram and seqpacket sockets are restricted. */
> > > +	if (type != SOCK_STREAM && type != SOCK_DGRAM && type != SOCK_SEQPACKET)
> > > +		return 0;
> >
> > [...]
>
> You can remove these type checks.  We're building Landlock access
> control wrt to the (moving) current state of Linux, and the goal is to
> cover most/useful access types that currently make sense.  Once access
> type is implemented, it should handle (by default) future features
> related to the kernel object to make sure a sandbox is well covered.
> This LANDLOCK_ACCESS_FS_RESOLVE_UNIX right is really about UNIX sockets
> that can be resolved through the filesystem, so this should handle
> current and potential future UNIX sockets as well.
> 
> If a new named UNIX socket type is created, Landlock should handle that
> with this access right, unless there is a specific semantic (e.g.
> coredump), in which case we'll update the access right, and potentially
> add a new one if it makes sense.
> 
> I was thinking about calling WARN_ON_ONCE() but this is not worth it.

Sounds good, removed the check for the next version.

The possibility of a new UNIX socket type seems anyway pretty
theoretical, and even if an additional type were added, it's not
entirely unthinkable that we would actually want to have it covered
under the same access right.

–Günther

^ permalink raw reply

* Re: [PATCH v4 2/6] landlock: Control pathname UNIX domain socket resolution by path
From: Günther Noack @ 2026-02-10 23:04 UTC (permalink / raw)
  To: Justin Suess
  Cc: Günther Noack, Mickaël Salaün, John Johansen,
	Tingmao Wang, Jann Horn, linux-security-module,
	Samasth Norway Ananda, Matthieu Buffet, Mikhail Ivanov,
	konstantin.meskhidze, Demi Marie Obenour, Alyssa Ross,
	Tahera Fahimi
In-Reply-To: <c060c613-146e-49eb-b9d8-da28cbb680f7@gmail.com>

On Mon, Feb 09, 2026 at 08:11:18AM -0500, Justin Suess wrote:
> On 2/9/26 05:21, Günther Noack wrote:
> > On Mon, Feb 09, 2026 at 12:10:12AM +0100, Günther Noack wrote:
> >> +	/* Lookup for the purpose of saving coredumps is OK. */
> >> +	if (flags & SOCK_COREDUMP)
> >> +		return 0;
> if (unlikely(flags & SOCK_COREDUMP))
>     return 0;

Done.


> >> +
> >> +	/* Only stream, dgram and seqpacket sockets are restricted. */
> >> +	if (type != SOCK_STREAM && type != SOCK_DGRAM && type != SOCK_SEQPACKET)
> >> +		return 0;
> if (unlikely(type != SOCK_STREAM && type != SOCK_DGRAM && type != SOCK_SEQPACKET))
>     return 0;

Not applicable any more, as I dropped the check per Mickaël's review
in the adjacent mail (I do not think it makes a big difference either
way, TBH.)

–Günther

^ permalink raw reply

* Re: [PATCH] man/man7/kernel_lockdown.7: remove Secure Boot untruth
From: Alejandro Colomar @ 2026-02-10 22:06 UTC (permalink / raw)
  To: Nicolas Bouchinet
  Cc: Xiu Jianfeng, Alyssa Ross, Heinrich Schuchardt, David Howells,
	linux-security-module, linux-man
In-Reply-To: <aYYP23WUyydsMGyx@archlinux>

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

Hi all,

On 2026-02-06T17:08:35+0100, Nicolas Bouchinet wrote:
> On Thu, Feb 05, 2026 at 07:48:02PM +0800, Xiu Jianfeng wrote:
> > On 2/4/2026 3:50 AM, Alyssa Ross wrote:
> > > This is true for Fedora, where this page was sourced from, but I don't
> > > believe it has ever been true for the mainline kernel, because Linus
> > > rejected it.
> > 
> > Yeah, I also found this issue not long ago, but I haven't had time to submit
> > a fix patch yet.
> > 
> > > 
> > > Link: https://bbs.archlinux.org/viewtopic.php?pid=2088704#p2088704
> > > Link: https://lore.kernel.org/lkml/CA+55aFzYbpRAdma0PvqE+9ygySuKzNKByqOzzMufBoovXVnfPw@mail.gmail.com/
> > > Fixes: bb509e6fc ("kernel_lockdown.7: New page documenting the Kernel Lockdown feature")
> > > Signed-off-by: Alyssa Ross <hi@alyssa.is>
> > 
> > I am not sure if appropriate to add my ACK here, if needed, feel free to
> > add:
> > 
> > Acked-by: Xiu Jianfeng <xiujianfeng@huawei.com>
> > 
> 
> You can also add mine too :
> 
> Acked-by: Nicolas Bouchinet <nicolas.bouchinet@oss.cyber.gouv.fr>

Thanks!  I've applied the patch.

    Link: <https://bbs.archlinux.org/viewtopic.php?pid=2088704#p2088704>
    Link: <https://lore.kernel.org/lkml/CA+55aFzYbpRAdma0PvqE+9ygySuKzNKByqOzzMufBoovXVnfPw@mail.gmail.com/>
    Fixes: bb509e6fcbae (2020-10-16; "kernel_lockdown.7: New page documenting the Kernel Lockdown feature")
    Signed-off-by: Alyssa Ross <hi@alyssa.is>
    Message-ID: <20260203195001.20131-1-hi@alyssa.is>
    Acked-by: Xiu Jianfeng <xiujianfeng@huawei.com>
    Message-ID: <aa62e24c-537e-4141-9507-37cd0af19dfc@huawei.com>
    Acked-by: Nicolas Bouchinet <nicolas.bouchinet@oss.cyber.gouv.fr>
    Message-ID: <aYYP23WUyydsMGyx@archlinux>
    Cc: Heinrich Schuchardt <xypron.glpk@gmx.de>
    Cc: David Howells <dhowells@redhat.com>
    Cc: <linux-security-module@vger.kernel.org>
    Signed-off-by: Alejandro Colomar <alx@kernel.org>


Have a lovely night!
Alex

> 
> Thank you in advance,
> 
> Nicolas
> 
> > > ---
> > >   man/man7/kernel_lockdown.7 | 3 ---
> > >   1 file changed, 3 deletions(-)
> > > 
> > > diff --git a/man/man7/kernel_lockdown.7 b/man/man7/kernel_lockdown.7
> > > index 5090484ea..5986c8f01 100644
> > > --- a/man/man7/kernel_lockdown.7
> > > +++ b/man/man7/kernel_lockdown.7
> > > @@ -23,9 +23,6 @@ Lockdown: X: Y is restricted, see man kernel_lockdown.7
> > >   .in
> > >   .P
> > >   where X indicates the process name and Y indicates what is restricted.
> > > -.P
> > > -On an EFI-enabled x86 or arm64 machine, lockdown will be automatically enabled
> > > -if the system boots in EFI Secure Boot mode.
> > >   .\"
> > >   .SS Coverage
> > >   When lockdown is in effect, a number of features are disabled or have their
> > 

-- 
<https://www.alejandro-colomar.es>

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

^ permalink raw reply

* Re: [PATCH] man/man7/kernel_lockdown.7: remove Secure Boot untruth
From: Alejandro Colomar @ 2026-02-10 22:03 UTC (permalink / raw)
  To: Heinrich Schuchardt
  Cc: Alyssa Ross, David Howells, Nicolas Bouchinet, Xiu Jianfeng,
	linux-security-module, linux-man
In-Reply-To: <252F93CE-E2C6-4D5A-9B2B-1B4907EEE0BA@gmx.de>

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

Hi Heinrich,

On 2026-02-03T21:47:57+0100, Heinrich Schuchardt wrote:
> Am 3. Februar 2026 21:27:44 MEZ schrieb Alejandro Colomar <alx@kernel.org>:
> >Hi Alyssa,
> >
> >On 2026-02-03T20:53:33+0100, Alyssa Ross wrote:
> >> On Tue, Feb 03, 2026 at 08:50:01PM +0100, Alyssa Ross wrote:
> >> > This is true for Fedora, where this page was sourced from, but I don't
> >> > believe it has ever been true for the mainline kernel, because Linus
> >> > rejected it.
> >> >
> >> > Link: https://bbs.archlinux.org/viewtopic.php?pid=2088704#p2088704
> >> > Link: https://lore.kernel.org/lkml/CA+55aFzYbpRAdma0PvqE+9ygySuKzNKByqOzzMufBoovXVnfPw@mail.gmail.com/
> >> > Fixes: bb509e6fc ("kernel_lockdown.7: New page documenting the Kernel Lockdown feature")
> >
> >I've now CCed you in an email documenting the format we use for these.
> >It should be:
> >
> >Fixes: bb509e6fcbae (2020-10-16; "kernel_lockdown.7: New page documenting the Kernel Lockdown feature")
> >
> >I'll amend that myself.
> >
> >> > Signed-off-by: Alyssa Ross <hi@alyssa.is>
> >> 
> >> Just noticed there's a long-open bug for this as well, so additionally:
> >> 
> >> Closes: https://bugzilla.kernel.org/show_bug.cgi?id=213577
> >
> >Thanks!  I'll keep the patch for a few days, in case anyone wants to
> >comment.
> >
> >
> >Have a lovely night!
> >Alex
> >
> 
> Can we move the information from the Notes section to replace the
> removed statement? What causes lockdown is central for users.

We can do that, yes.  Although, I prefer doing it in a separate patch.


Have a lovely night!
Alex

> 
> Best regards
> 
> Heinrich
> 

-- 
<https://www.alejandro-colomar.es>

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

^ permalink raw reply

* Re: [PATCH v2 11/13] tools/testing/vma: separate VMA userland tests into separate files
From: Lorenzo Stoakes @ 2026-02-10 17:44 UTC (permalink / raw)
  To: Liam R. Howlett, Andrew Morton, Jarkko Sakkinen, Dave Hansen,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, x86,
	H . Peter Anvin, Arnd Bergmann, Greg Kroah-Hartman, Dan Williams,
	Vishal Verma, Dave Jiang, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Jani Nikula,
	Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig,
	Huang Rui, Matthew Auld, Matthew Brost, Alexander Viro,
	Christian Brauner, Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu,
	Yue Hu, Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
	Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
	David Hildenbrand, Konstantin Komarov, Mike Marshall,
	Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
	James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
	Naohiro Aota, Johannes Thumshirn, Matthew Wilcox, Vlastimil Babka,
	Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Hugh Dickins,
	Baolin Wang, Zi Yan, Nico Pache, Ryan Roberts, Dev Jain,
	Barry Song, Lance Yang, Jann Horn, Pedro Falcato, David Howells,
	Paul Moore, James Morris, Serge E . Hallyn, Yury Norov,
	Rasmus Villemoes, linux-sgx, linux-kernel, nvdimm, linux-cxl,
	dri-devel, intel-gfx, linux-fsdevel, linux-aio, linux-erofs,
	linux-ext4, linux-mm, ntfs3, devel, linux-xfs, keyrings,
	linux-security-module, Jason Gunthorpe
In-Reply-To: <opopo4rlyxz7upi2bzrx7e6cyji2nmaynvlhvr2nzvtvb5pfxu@4fekgb5faybz>

On Mon, Feb 09, 2026 at 07:58:22PM +0000, Liam R. Howlett wrote:
> * Lorenzo Stoakes <lorenzo.stoakes@oracle.com> [260122 16:06]:
> > So far the userland VMA tests have been established as a rough expression
> > of what's been possible.
> >
> > qAdapt it into a more usable form by separating out tests and shared helper
> ^^^^ Typo

Oops, Andrew - can you fix that up? Thanks! :)

>
>
> > functions.
> >
> > Since we test functions that are declared statically in mm/vma.c, we make
> > use of the trick of #include'ing kernel C files directly.
> >
> > In order for the tests to continue to function, we must therefore also
> > this way into the tests/ directory.
> >
> > We try to keep as much shared logic actually modularised into a separate
> > compilation unit in shared.c, however the merge_existing() and attach_vma()
> > helpers rely on statically declared mm/vma.c functions so these must be
> > declared in main.c.
> >
> > Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
>
> Besides that typo, it looks good.
>
> Reviewed-by: Liam R. Howlett <Liam.Howlett@oracle.com>

Thanks :)

Cheers, Lorenzo

>
> > ---
> >  tools/testing/vma/Makefile                 |   4 +-
> >  tools/testing/vma/main.c                   |  55 ++++
> >  tools/testing/vma/shared.c                 | 131 ++++++++
> >  tools/testing/vma/shared.h                 | 114 +++++++
> >  tools/testing/vma/{vma.c => tests/merge.c} | 332 +--------------------
> >  tools/testing/vma/tests/mmap.c             |  57 ++++
> >  tools/testing/vma/tests/vma.c              |  39 +++
> >  tools/testing/vma/vma_internal.h           |   9 -
> >  8 files changed, 406 insertions(+), 335 deletions(-)
> >  create mode 100644 tools/testing/vma/main.c
> >  create mode 100644 tools/testing/vma/shared.c
> >  create mode 100644 tools/testing/vma/shared.h
> >  rename tools/testing/vma/{vma.c => tests/merge.c} (82%)
> >  create mode 100644 tools/testing/vma/tests/mmap.c
> >  create mode 100644 tools/testing/vma/tests/vma.c
> >
> > diff --git a/tools/testing/vma/Makefile b/tools/testing/vma/Makefile
> > index 66f3831a668f..94133d9d3955 100644
> > --- a/tools/testing/vma/Makefile
> > +++ b/tools/testing/vma/Makefile
> > @@ -6,10 +6,10 @@ default: vma
> >
> >  include ../shared/shared.mk
> >
> > -OFILES = $(SHARED_OFILES) vma.o maple-shim.o
> > +OFILES = $(SHARED_OFILES) main.o shared.o maple-shim.o
> >  TARGETS = vma
> >
> > -vma.o: vma.c vma_internal.h ../../../mm/vma.c ../../../mm/vma_init.c ../../../mm/vma_exec.c ../../../mm/vma.h
> > +main.o: main.c shared.c shared.h vma_internal.h tests/merge.c tests/mmap.c tests/vma.c ../../../mm/vma.c ../../../mm/vma_init.c ../../../mm/vma_exec.c ../../../mm/vma.h
> >
> >  vma:	$(OFILES)
> >  	$(CC) $(CFLAGS) -o $@ $(OFILES) $(LDLIBS)
> > diff --git a/tools/testing/vma/main.c b/tools/testing/vma/main.c
> > new file mode 100644
> > index 000000000000..49b09e97a51f
> > --- /dev/null
> > +++ b/tools/testing/vma/main.c
> > @@ -0,0 +1,55 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +
> > +#include "shared.h"
> > +/*
> > + * Directly import the VMA implementation here. Our vma_internal.h wrapper
> > + * provides userland-equivalent functionality for everything vma.c uses.
> > + */
> > +#include "../../../mm/vma_init.c"
> > +#include "../../../mm/vma_exec.c"
> > +#include "../../../mm/vma.c"
> > +
> > +/* Tests are included directly so they can test static functions in mm/vma.c. */
> > +#include "tests/merge.c"
> > +#include "tests/mmap.c"
> > +#include "tests/vma.c"
> > +
> > +/* Helper functions which utilise static kernel functions. */
> > +
> > +struct vm_area_struct *merge_existing(struct vma_merge_struct *vmg)
> > +{
> > +	struct vm_area_struct *vma;
> > +
> > +	vma = vma_merge_existing_range(vmg);
> > +	if (vma)
> > +		vma_assert_attached(vma);
> > +	return vma;
> > +}
> > +
> > +int attach_vma(struct mm_struct *mm, struct vm_area_struct *vma)
> > +{
> > +	int res;
> > +
> > +	res = vma_link(mm, vma);
> > +	if (!res)
> > +		vma_assert_attached(vma);
> > +	return res;
> > +}
> > +
> > +/* Main test running which invokes tests/ *.c runners. */
> > +int main(void)
> > +{
> > +	int num_tests = 0, num_fail = 0;
> > +
> > +	maple_tree_init();
> > +	vma_state_init();
> > +
> > +	run_merge_tests(&num_tests, &num_fail);
> > +	run_mmap_tests(&num_tests, &num_fail);
> > +	run_vma_tests(&num_tests, &num_fail);
> > +
> > +	printf("%d tests run, %d passed, %d failed.\n",
> > +	       num_tests, num_tests - num_fail, num_fail);
> > +
> > +	return num_fail == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
> > +}
> > diff --git a/tools/testing/vma/shared.c b/tools/testing/vma/shared.c
> > new file mode 100644
> > index 000000000000..bda578cc3304
> > --- /dev/null
> > +++ b/tools/testing/vma/shared.c
> > @@ -0,0 +1,131 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +
> > +#include "shared.h"
> > +
> > +
> > +bool fail_prealloc;
> > +unsigned long mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR;
> > +unsigned long dac_mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR;
> > +unsigned long stack_guard_gap = 256UL<<PAGE_SHIFT;
> > +
> > +const struct vm_operations_struct vma_dummy_vm_ops;
> > +struct anon_vma dummy_anon_vma;
> > +struct task_struct __current;
> > +
> > +struct vm_area_struct *alloc_vma(struct mm_struct *mm,
> > +		unsigned long start, unsigned long end,
> > +		pgoff_t pgoff, vm_flags_t vm_flags)
> > +{
> > +	struct vm_area_struct *vma = vm_area_alloc(mm);
> > +
> > +	if (vma == NULL)
> > +		return NULL;
> > +
> > +	vma->vm_start = start;
> > +	vma->vm_end = end;
> > +	vma->vm_pgoff = pgoff;
> > +	vm_flags_reset(vma, vm_flags);
> > +	vma_assert_detached(vma);
> > +
> > +	return vma;
> > +}
> > +
> > +void detach_free_vma(struct vm_area_struct *vma)
> > +{
> > +	vma_mark_detached(vma);
> > +	vm_area_free(vma);
> > +}
> > +
> > +struct vm_area_struct *alloc_and_link_vma(struct mm_struct *mm,
> > +		unsigned long start, unsigned long end,
> > +		pgoff_t pgoff, vm_flags_t vm_flags)
> > +{
> > +	struct vm_area_struct *vma = alloc_vma(mm, start, end, pgoff, vm_flags);
> > +
> > +	if (vma == NULL)
> > +		return NULL;
> > +
> > +	if (attach_vma(mm, vma)) {
> > +		detach_free_vma(vma);
> > +		return NULL;
> > +	}
> > +
> > +	/*
> > +	 * Reset this counter which we use to track whether writes have
> > +	 * begun. Linking to the tree will have caused this to be incremented,
> > +	 * which means we will get a false positive otherwise.
> > +	 */
> > +	vma->vm_lock_seq = UINT_MAX;
> > +
> > +	return vma;
> > +}
> > +
> > +void reset_dummy_anon_vma(void)
> > +{
> > +	dummy_anon_vma.was_cloned = false;
> > +	dummy_anon_vma.was_unlinked = false;
> > +}
> > +
> > +int cleanup_mm(struct mm_struct *mm, struct vma_iterator *vmi)
> > +{
> > +	struct vm_area_struct *vma;
> > +	int count = 0;
> > +
> > +	fail_prealloc = false;
> > +	reset_dummy_anon_vma();
> > +
> > +	vma_iter_set(vmi, 0);
> > +	for_each_vma(*vmi, vma) {
> > +		detach_free_vma(vma);
> > +		count++;
> > +	}
> > +
> > +	mtree_destroy(&mm->mm_mt);
> > +	mm->map_count = 0;
> > +	return count;
> > +}
> > +
> > +bool vma_write_started(struct vm_area_struct *vma)
> > +{
> > +	int seq = vma->vm_lock_seq;
> > +
> > +	/* We reset after each check. */
> > +	vma->vm_lock_seq = UINT_MAX;
> > +
> > +	/* The vma_start_write() stub simply increments this value. */
> > +	return seq > -1;
> > +}
> > +
> > +void __vma_set_dummy_anon_vma(struct vm_area_struct *vma,
> > +		struct anon_vma_chain *avc, struct anon_vma *anon_vma)
> > +{
> > +	vma->anon_vma = anon_vma;
> > +	INIT_LIST_HEAD(&vma->anon_vma_chain);
> > +	list_add(&avc->same_vma, &vma->anon_vma_chain);
> > +	avc->anon_vma = vma->anon_vma;
> > +}
> > +
> > +void vma_set_dummy_anon_vma(struct vm_area_struct *vma,
> > +		struct anon_vma_chain *avc)
> > +{
> > +	__vma_set_dummy_anon_vma(vma, avc, &dummy_anon_vma);
> > +}
> > +
> > +struct task_struct *get_current(void)
> > +{
> > +	return &__current;
> > +}
> > +
> > +unsigned long rlimit(unsigned int limit)
> > +{
> > +	return (unsigned long)-1;
> > +}
> > +
> > +void vma_set_range(struct vm_area_struct *vma,
> > +		   unsigned long start, unsigned long end,
> > +		   pgoff_t pgoff)
> > +{
> > +	vma->vm_start = start;
> > +	vma->vm_end = end;
> > +	vma->vm_pgoff = pgoff;
> > +}
> > diff --git a/tools/testing/vma/shared.h b/tools/testing/vma/shared.h
> > new file mode 100644
> > index 000000000000..6c64211cfa22
> > --- /dev/null
> > +++ b/tools/testing/vma/shared.h
> > @@ -0,0 +1,114 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +
> > +#pragma once
> > +
> > +#include <stdbool.h>
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +
> > +#include "generated/bit-length.h"
> > +#include "maple-shared.h"
> > +#include "vma_internal.h"
> > +#include "../../../mm/vma.h"
> > +
> > +/* Simple test runner. Assumes local num_[fail, tests] counters. */
> > +#define TEST(name)							\
> > +	do {								\
> > +		(*num_tests)++;						\
> > +		if (!test_##name()) {					\
> > +			(*num_fail)++;					\
> > +			fprintf(stderr, "Test " #name " FAILED\n");	\
> > +		}							\
> > +	} while (0)
> > +
> > +#define ASSERT_TRUE(_expr)						\
> > +	do {								\
> > +		if (!(_expr)) {						\
> > +			fprintf(stderr,					\
> > +				"Assert FAILED at %s:%d:%s(): %s is FALSE.\n", \
> > +				__FILE__, __LINE__, __FUNCTION__, #_expr); \
> > +			return false;					\
> > +		}							\
> > +	} while (0)
> > +
> > +#define ASSERT_FALSE(_expr) ASSERT_TRUE(!(_expr))
> > +#define ASSERT_EQ(_val1, _val2) ASSERT_TRUE((_val1) == (_val2))
> > +#define ASSERT_NE(_val1, _val2) ASSERT_TRUE((_val1) != (_val2))
> > +
> > +#define IS_SET(_val, _flags) ((_val & _flags) == _flags)
> > +
> > +extern bool fail_prealloc;
> > +
> > +/* Override vma_iter_prealloc() so we can choose to fail it. */
> > +#define vma_iter_prealloc(vmi, vma)					\
> > +	(fail_prealloc ? -ENOMEM : mas_preallocate(&(vmi)->mas, (vma), GFP_KERNEL))
> > +
> > +#define CONFIG_DEFAULT_MMAP_MIN_ADDR 65536
> > +
> > +extern unsigned long mmap_min_addr;
> > +extern unsigned long dac_mmap_min_addr;
> > +extern unsigned long stack_guard_gap;
> > +
> > +extern const struct vm_operations_struct vma_dummy_vm_ops;
> > +extern struct anon_vma dummy_anon_vma;
> > +extern struct task_struct __current;
> > +
> > +/*
> > + * Helper function which provides a wrapper around a merge existing VMA
> > + * operation.
> > + *
> > + * Declared in main.c as uses static VMA function.
> > + */
> > +struct vm_area_struct *merge_existing(struct vma_merge_struct *vmg);
> > +
> > +/*
> > + * Helper function to allocate a VMA and link it to the tree.
> > + *
> > + * Declared in main.c as uses static VMA function.
> > + */
> > +int attach_vma(struct mm_struct *mm, struct vm_area_struct *vma);
> > +
> > +/* Helper function providing a dummy vm_ops->close() method.*/
> > +static inline void dummy_close(struct vm_area_struct *)
> > +{
> > +}
> > +
> > +/* Helper function to simply allocate a VMA. */
> > +struct vm_area_struct *alloc_vma(struct mm_struct *mm,
> > +		unsigned long start, unsigned long end,
> > +		pgoff_t pgoff, vm_flags_t vm_flags);
> > +
> > +/* Helper function to detach and free a VMA. */
> > +void detach_free_vma(struct vm_area_struct *vma);
> > +
> > +/* Helper function to allocate a VMA and link it to the tree. */
> > +struct vm_area_struct *alloc_and_link_vma(struct mm_struct *mm,
> > +		unsigned long start, unsigned long end,
> > +		pgoff_t pgoff, vm_flags_t vm_flags);
> > +
> > +/*
> > + * Helper function to reset the dummy anon_vma to indicate it has not been
> > + * duplicated.
> > + */
> > +void reset_dummy_anon_vma(void);
> > +
> > +/*
> > + * Helper function to remove all VMAs and destroy the maple tree associated with
> > + * a virtual address space. Returns a count of VMAs in the tree.
> > + */
> > +int cleanup_mm(struct mm_struct *mm, struct vma_iterator *vmi);
> > +
> > +/* Helper function to determine if VMA has had vma_start_write() performed. */
> > +bool vma_write_started(struct vm_area_struct *vma);
> > +
> > +void __vma_set_dummy_anon_vma(struct vm_area_struct *vma,
> > +		struct anon_vma_chain *avc, struct anon_vma *anon_vma);
> > +
> > +/* Provide a simple dummy VMA/anon_vma dummy setup for testing. */
> > +void vma_set_dummy_anon_vma(struct vm_area_struct *vma,
> > +			    struct anon_vma_chain *avc);
> > +
> > +/* Helper function to specify a VMA's range. */
> > +void vma_set_range(struct vm_area_struct *vma,
> > +		   unsigned long start, unsigned long end,
> > +		   pgoff_t pgoff);
> > diff --git a/tools/testing/vma/vma.c b/tools/testing/vma/tests/merge.c
> > similarity index 82%
> > rename from tools/testing/vma/vma.c
> > rename to tools/testing/vma/tests/merge.c
> > index 93d21bc7e112..3708dc6945b0 100644
> > --- a/tools/testing/vma/vma.c
> > +++ b/tools/testing/vma/tests/merge.c
> > @@ -1,132 +1,5 @@
> >  // SPDX-License-Identifier: GPL-2.0-or-later
> >
> > -#include <stdbool.h>
> > -#include <stdio.h>
> > -#include <stdlib.h>
> > -
> > -#include "generated/bit-length.h"
> > -
> > -#include "maple-shared.h"
> > -#include "vma_internal.h"
> > -
> > -/* Include so header guard set. */
> > -#include "../../../mm/vma.h"
> > -
> > -static bool fail_prealloc;
> > -
> > -/* Then override vma_iter_prealloc() so we can choose to fail it. */
> > -#define vma_iter_prealloc(vmi, vma)					\
> > -	(fail_prealloc ? -ENOMEM : mas_preallocate(&(vmi)->mas, (vma), GFP_KERNEL))
> > -
> > -#define CONFIG_DEFAULT_MMAP_MIN_ADDR 65536
> > -
> > -unsigned long mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR;
> > -unsigned long dac_mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR;
> > -unsigned long stack_guard_gap = 256UL<<PAGE_SHIFT;
> > -
> > -/*
> > - * Directly import the VMA implementation here. Our vma_internal.h wrapper
> > - * provides userland-equivalent functionality for everything vma.c uses.
> > - */
> > -#include "../../../mm/vma_init.c"
> > -#include "../../../mm/vma_exec.c"
> > -#include "../../../mm/vma.c"
> > -
> > -const struct vm_operations_struct vma_dummy_vm_ops;
> > -static struct anon_vma dummy_anon_vma;
> > -
> > -#define ASSERT_TRUE(_expr)						\
> > -	do {								\
> > -		if (!(_expr)) {						\
> > -			fprintf(stderr,					\
> > -				"Assert FAILED at %s:%d:%s(): %s is FALSE.\n", \
> > -				__FILE__, __LINE__, __FUNCTION__, #_expr); \
> > -			return false;					\
> > -		}							\
> > -	} while (0)
> > -#define ASSERT_FALSE(_expr) ASSERT_TRUE(!(_expr))
> > -#define ASSERT_EQ(_val1, _val2) ASSERT_TRUE((_val1) == (_val2))
> > -#define ASSERT_NE(_val1, _val2) ASSERT_TRUE((_val1) != (_val2))
> > -
> > -#define IS_SET(_val, _flags) ((_val & _flags) == _flags)
> > -
> > -static struct task_struct __current;
> > -
> > -struct task_struct *get_current(void)
> > -{
> > -	return &__current;
> > -}
> > -
> > -unsigned long rlimit(unsigned int limit)
> > -{
> > -	return (unsigned long)-1;
> > -}
> > -
> > -/* Helper function to simply allocate a VMA. */
> > -static struct vm_area_struct *alloc_vma(struct mm_struct *mm,
> > -					unsigned long start,
> > -					unsigned long end,
> > -					pgoff_t pgoff,
> > -					vm_flags_t vm_flags)
> > -{
> > -	struct vm_area_struct *vma = vm_area_alloc(mm);
> > -
> > -	if (vma == NULL)
> > -		return NULL;
> > -
> > -	vma->vm_start = start;
> > -	vma->vm_end = end;
> > -	vma->vm_pgoff = pgoff;
> > -	vm_flags_reset(vma, vm_flags);
> > -	vma_assert_detached(vma);
> > -
> > -	return vma;
> > -}
> > -
> > -/* Helper function to allocate a VMA and link it to the tree. */
> > -static int attach_vma(struct mm_struct *mm, struct vm_area_struct *vma)
> > -{
> > -	int res;
> > -
> > -	res = vma_link(mm, vma);
> > -	if (!res)
> > -		vma_assert_attached(vma);
> > -	return res;
> > -}
> > -
> > -static void detach_free_vma(struct vm_area_struct *vma)
> > -{
> > -	vma_mark_detached(vma);
> > -	vm_area_free(vma);
> > -}
> > -
> > -/* Helper function to allocate a VMA and link it to the tree. */
> > -static struct vm_area_struct *alloc_and_link_vma(struct mm_struct *mm,
> > -						 unsigned long start,
> > -						 unsigned long end,
> > -						 pgoff_t pgoff,
> > -						 vm_flags_t vm_flags)
> > -{
> > -	struct vm_area_struct *vma = alloc_vma(mm, start, end, pgoff, vm_flags);
> > -
> > -	if (vma == NULL)
> > -		return NULL;
> > -
> > -	if (attach_vma(mm, vma)) {
> > -		detach_free_vma(vma);
> > -		return NULL;
> > -	}
> > -
> > -	/*
> > -	 * Reset this counter which we use to track whether writes have
> > -	 * begun. Linking to the tree will have caused this to be incremented,
> > -	 * which means we will get a false positive otherwise.
> > -	 */
> > -	vma->vm_lock_seq = UINT_MAX;
> > -
> > -	return vma;
> > -}
> > -
> >  /* Helper function which provides a wrapper around a merge new VMA operation. */
> >  static struct vm_area_struct *merge_new(struct vma_merge_struct *vmg)
> >  {
> > @@ -146,20 +19,6 @@ static struct vm_area_struct *merge_new(struct vma_merge_struct *vmg)
> >  	return vma;
> >  }
> >
> > -/*
> > - * Helper function which provides a wrapper around a merge existing VMA
> > - * operation.
> > - */
> > -static struct vm_area_struct *merge_existing(struct vma_merge_struct *vmg)
> > -{
> > -	struct vm_area_struct *vma;
> > -
> > -	vma = vma_merge_existing_range(vmg);
> > -	if (vma)
> > -		vma_assert_attached(vma);
> > -	return vma;
> > -}
> > -
> >  /*
> >   * Helper function which provides a wrapper around the expansion of an existing
> >   * VMA.
> > @@ -173,8 +32,8 @@ static int expand_existing(struct vma_merge_struct *vmg)
> >   * Helper function to reset merge state the associated VMA iterator to a
> >   * specified new range.
> >   */
> > -static void vmg_set_range(struct vma_merge_struct *vmg, unsigned long start,
> > -			  unsigned long end, pgoff_t pgoff, vm_flags_t vm_flags)
> > +void vmg_set_range(struct vma_merge_struct *vmg, unsigned long start,
> > +		   unsigned long end, pgoff_t pgoff, vm_flags_t vm_flags)
> >  {
> >  	vma_iter_set(vmg->vmi, start);
> >
> > @@ -197,8 +56,8 @@ static void vmg_set_range(struct vma_merge_struct *vmg, unsigned long start,
> >
> >  /* Helper function to set both the VMG range and its anon_vma. */
> >  static void vmg_set_range_anon_vma(struct vma_merge_struct *vmg, unsigned long start,
> > -				   unsigned long end, pgoff_t pgoff, vm_flags_t vm_flags,
> > -				   struct anon_vma *anon_vma)
> > +		unsigned long end, pgoff_t pgoff, vm_flags_t vm_flags,
> > +		struct anon_vma *anon_vma)
> >  {
> >  	vmg_set_range(vmg, start, end, pgoff, vm_flags);
> >  	vmg->anon_vma = anon_vma;
> > @@ -211,10 +70,9 @@ static void vmg_set_range_anon_vma(struct vma_merge_struct *vmg, unsigned long s
> >   * VMA, link it to the maple tree and return it.
> >   */
> >  static struct vm_area_struct *try_merge_new_vma(struct mm_struct *mm,
> > -						struct vma_merge_struct *vmg,
> > -						unsigned long start, unsigned long end,
> > -						pgoff_t pgoff, vm_flags_t vm_flags,
> > -						bool *was_merged)
> > +		struct vma_merge_struct *vmg, unsigned long start,
> > +		unsigned long end, pgoff_t pgoff, vm_flags_t vm_flags,
> > +		bool *was_merged)
> >  {
> >  	struct vm_area_struct *merged;
> >
> > @@ -234,72 +92,6 @@ static struct vm_area_struct *try_merge_new_vma(struct mm_struct *mm,
> >  	return alloc_and_link_vma(mm, start, end, pgoff, vm_flags);
> >  }
> >
> > -/*
> > - * Helper function to reset the dummy anon_vma to indicate it has not been
> > - * duplicated.
> > - */
> > -static void reset_dummy_anon_vma(void)
> > -{
> > -	dummy_anon_vma.was_cloned = false;
> > -	dummy_anon_vma.was_unlinked = false;
> > -}
> > -
> > -/*
> > - * Helper function to remove all VMAs and destroy the maple tree associated with
> > - * a virtual address space. Returns a count of VMAs in the tree.
> > - */
> > -static int cleanup_mm(struct mm_struct *mm, struct vma_iterator *vmi)
> > -{
> > -	struct vm_area_struct *vma;
> > -	int count = 0;
> > -
> > -	fail_prealloc = false;
> > -	reset_dummy_anon_vma();
> > -
> > -	vma_iter_set(vmi, 0);
> > -	for_each_vma(*vmi, vma) {
> > -		detach_free_vma(vma);
> > -		count++;
> > -	}
> > -
> > -	mtree_destroy(&mm->mm_mt);
> > -	mm->map_count = 0;
> > -	return count;
> > -}
> > -
> > -/* Helper function to determine if VMA has had vma_start_write() performed. */
> > -static bool vma_write_started(struct vm_area_struct *vma)
> > -{
> > -	int seq = vma->vm_lock_seq;
> > -
> > -	/* We reset after each check. */
> > -	vma->vm_lock_seq = UINT_MAX;
> > -
> > -	/* The vma_start_write() stub simply increments this value. */
> > -	return seq > -1;
> > -}
> > -
> > -/* Helper function providing a dummy vm_ops->close() method.*/
> > -static void dummy_close(struct vm_area_struct *)
> > -{
> > -}
> > -
> > -static void __vma_set_dummy_anon_vma(struct vm_area_struct *vma,
> > -				     struct anon_vma_chain *avc,
> > -				     struct anon_vma *anon_vma)
> > -{
> > -	vma->anon_vma = anon_vma;
> > -	INIT_LIST_HEAD(&vma->anon_vma_chain);
> > -	list_add(&avc->same_vma, &vma->anon_vma_chain);
> > -	avc->anon_vma = vma->anon_vma;
> > -}
> > -
> > -static void vma_set_dummy_anon_vma(struct vm_area_struct *vma,
> > -				   struct anon_vma_chain *avc)
> > -{
> > -	__vma_set_dummy_anon_vma(vma, avc, &dummy_anon_vma);
> > -}
> > -
> >  static bool test_simple_merge(void)
> >  {
> >  	struct vm_area_struct *vma;
> > @@ -1616,39 +1408,6 @@ static bool test_merge_extend(void)
> >  	return true;
> >  }
> >
> > -static bool test_copy_vma(void)
> > -{
> > -	vm_flags_t vm_flags = VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE;
> > -	struct mm_struct mm = {};
> > -	bool need_locks = false;
> > -	VMA_ITERATOR(vmi, &mm, 0);
> > -	struct vm_area_struct *vma, *vma_new, *vma_next;
> > -
> > -	/* Move backwards and do not merge. */
> > -
> > -	vma = alloc_and_link_vma(&mm, 0x3000, 0x5000, 3, vm_flags);
> > -	vma_new = copy_vma(&vma, 0, 0x2000, 0, &need_locks);
> > -	ASSERT_NE(vma_new, vma);
> > -	ASSERT_EQ(vma_new->vm_start, 0);
> > -	ASSERT_EQ(vma_new->vm_end, 0x2000);
> > -	ASSERT_EQ(vma_new->vm_pgoff, 0);
> > -	vma_assert_attached(vma_new);
> > -
> > -	cleanup_mm(&mm, &vmi);
> > -
> > -	/* Move a VMA into position next to another and merge the two. */
> > -
> > -	vma = alloc_and_link_vma(&mm, 0, 0x2000, 0, vm_flags);
> > -	vma_next = alloc_and_link_vma(&mm, 0x6000, 0x8000, 6, vm_flags);
> > -	vma_new = copy_vma(&vma, 0x4000, 0x2000, 4, &need_locks);
> > -	vma_assert_attached(vma_new);
> > -
> > -	ASSERT_EQ(vma_new, vma_next);
> > -
> > -	cleanup_mm(&mm, &vmi);
> > -	return true;
> > -}
> > -
> >  static bool test_expand_only_mode(void)
> >  {
> >  	vm_flags_t vm_flags = VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE;
> > @@ -1689,73 +1448,8 @@ static bool test_expand_only_mode(void)
> >  	return true;
> >  }
> >
> > -static bool test_mmap_region_basic(void)
> > -{
> > -	struct mm_struct mm = {};
> > -	unsigned long addr;
> > -	struct vm_area_struct *vma;
> > -	VMA_ITERATOR(vmi, &mm, 0);
> > -
> > -	current->mm = &mm;
> > -
> > -	/* Map at 0x300000, length 0x3000. */
> > -	addr = __mmap_region(NULL, 0x300000, 0x3000,
> > -			     VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE,
> > -			     0x300, NULL);
> > -	ASSERT_EQ(addr, 0x300000);
> > -
> > -	/* Map at 0x250000, length 0x3000. */
> > -	addr = __mmap_region(NULL, 0x250000, 0x3000,
> > -			     VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE,
> > -			     0x250, NULL);
> > -	ASSERT_EQ(addr, 0x250000);
> > -
> > -	/* Map at 0x303000, merging to 0x300000 of length 0x6000. */
> > -	addr = __mmap_region(NULL, 0x303000, 0x3000,
> > -			     VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE,
> > -			     0x303, NULL);
> > -	ASSERT_EQ(addr, 0x303000);
> > -
> > -	/* Map at 0x24d000, merging to 0x250000 of length 0x6000. */
> > -	addr = __mmap_region(NULL, 0x24d000, 0x3000,
> > -			     VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE,
> > -			     0x24d, NULL);
> > -	ASSERT_EQ(addr, 0x24d000);
> > -
> > -	ASSERT_EQ(mm.map_count, 2);
> > -
> > -	for_each_vma(vmi, vma) {
> > -		if (vma->vm_start == 0x300000) {
> > -			ASSERT_EQ(vma->vm_end, 0x306000);
> > -			ASSERT_EQ(vma->vm_pgoff, 0x300);
> > -		} else if (vma->vm_start == 0x24d000) {
> > -			ASSERT_EQ(vma->vm_end, 0x253000);
> > -			ASSERT_EQ(vma->vm_pgoff, 0x24d);
> > -		} else {
> > -			ASSERT_FALSE(true);
> > -		}
> > -	}
> > -
> > -	cleanup_mm(&mm, &vmi);
> > -	return true;
> > -}
> > -
> > -int main(void)
> > +static void run_merge_tests(int *num_tests, int *num_fail)
> >  {
> > -	int num_tests = 0, num_fail = 0;
> > -
> > -	maple_tree_init();
> > -	vma_state_init();
> > -
> > -#define TEST(name)							\
> > -	do {								\
> > -		num_tests++;						\
> > -		if (!test_##name()) {					\
> > -			num_fail++;					\
> > -			fprintf(stderr, "Test " #name " FAILED\n");	\
> > -		}							\
> > -	} while (0)
> > -
> >  	/* Very simple tests to kick the tyres. */
> >  	TEST(simple_merge);
> >  	TEST(simple_modify);
> > @@ -1771,15 +1465,5 @@ int main(void)
> >  	TEST(dup_anon_vma);
> >  	TEST(vmi_prealloc_fail);
> >  	TEST(merge_extend);
> > -	TEST(copy_vma);
> >  	TEST(expand_only_mode);
> > -
> > -	TEST(mmap_region_basic);
> > -
> > -#undef TEST
> > -
> > -	printf("%d tests run, %d passed, %d failed.\n",
> > -	       num_tests, num_tests - num_fail, num_fail);
> > -
> > -	return num_fail == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
> >  }
> > diff --git a/tools/testing/vma/tests/mmap.c b/tools/testing/vma/tests/mmap.c
> > new file mode 100644
> > index 000000000000..bded4ecbe5db
> > --- /dev/null
> > +++ b/tools/testing/vma/tests/mmap.c
> > @@ -0,0 +1,57 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +
> > +static bool test_mmap_region_basic(void)
> > +{
> > +	struct mm_struct mm = {};
> > +	unsigned long addr;
> > +	struct vm_area_struct *vma;
> > +	VMA_ITERATOR(vmi, &mm, 0);
> > +
> > +	current->mm = &mm;
> > +
> > +	/* Map at 0x300000, length 0x3000. */
> > +	addr = __mmap_region(NULL, 0x300000, 0x3000,
> > +			     VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE,
> > +			     0x300, NULL);
> > +	ASSERT_EQ(addr, 0x300000);
> > +
> > +	/* Map at 0x250000, length 0x3000. */
> > +	addr = __mmap_region(NULL, 0x250000, 0x3000,
> > +			     VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE,
> > +			     0x250, NULL);
> > +	ASSERT_EQ(addr, 0x250000);
> > +
> > +	/* Map at 0x303000, merging to 0x300000 of length 0x6000. */
> > +	addr = __mmap_region(NULL, 0x303000, 0x3000,
> > +			     VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE,
> > +			     0x303, NULL);
> > +	ASSERT_EQ(addr, 0x303000);
> > +
> > +	/* Map at 0x24d000, merging to 0x250000 of length 0x6000. */
> > +	addr = __mmap_region(NULL, 0x24d000, 0x3000,
> > +			     VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE,
> > +			     0x24d, NULL);
> > +	ASSERT_EQ(addr, 0x24d000);
> > +
> > +	ASSERT_EQ(mm.map_count, 2);
> > +
> > +	for_each_vma(vmi, vma) {
> > +		if (vma->vm_start == 0x300000) {
> > +			ASSERT_EQ(vma->vm_end, 0x306000);
> > +			ASSERT_EQ(vma->vm_pgoff, 0x300);
> > +		} else if (vma->vm_start == 0x24d000) {
> > +			ASSERT_EQ(vma->vm_end, 0x253000);
> > +			ASSERT_EQ(vma->vm_pgoff, 0x24d);
> > +		} else {
> > +			ASSERT_FALSE(true);
> > +		}
> > +	}
> > +
> > +	cleanup_mm(&mm, &vmi);
> > +	return true;
> > +}
> > +
> > +static void run_mmap_tests(int *num_tests, int *num_fail)
> > +{
> > +	TEST(mmap_region_basic);
> > +}
> > diff --git a/tools/testing/vma/tests/vma.c b/tools/testing/vma/tests/vma.c
> > new file mode 100644
> > index 000000000000..6d9775aee243
> > --- /dev/null
> > +++ b/tools/testing/vma/tests/vma.c
> > @@ -0,0 +1,39 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +
> > +static bool test_copy_vma(void)
> > +{
> > +	vm_flags_t vm_flags = VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE;
> > +	struct mm_struct mm = {};
> > +	bool need_locks = false;
> > +	VMA_ITERATOR(vmi, &mm, 0);
> > +	struct vm_area_struct *vma, *vma_new, *vma_next;
> > +
> > +	/* Move backwards and do not merge. */
> > +
> > +	vma = alloc_and_link_vma(&mm, 0x3000, 0x5000, 3, vm_flags);
> > +	vma_new = copy_vma(&vma, 0, 0x2000, 0, &need_locks);
> > +	ASSERT_NE(vma_new, vma);
> > +	ASSERT_EQ(vma_new->vm_start, 0);
> > +	ASSERT_EQ(vma_new->vm_end, 0x2000);
> > +	ASSERT_EQ(vma_new->vm_pgoff, 0);
> > +	vma_assert_attached(vma_new);
> > +
> > +	cleanup_mm(&mm, &vmi);
> > +
> > +	/* Move a VMA into position next to another and merge the two. */
> > +
> > +	vma = alloc_and_link_vma(&mm, 0, 0x2000, 0, vm_flags);
> > +	vma_next = alloc_and_link_vma(&mm, 0x6000, 0x8000, 6, vm_flags);
> > +	vma_new = copy_vma(&vma, 0x4000, 0x2000, 4, &need_locks);
> > +	vma_assert_attached(vma_new);
> > +
> > +	ASSERT_EQ(vma_new, vma_next);
> > +
> > +	cleanup_mm(&mm, &vmi);
> > +	return true;
> > +}
> > +
> > +static void run_vma_tests(int *num_tests, int *num_fail)
> > +{
> > +	TEST(copy_vma);
> > +}
> > diff --git a/tools/testing/vma/vma_internal.h b/tools/testing/vma/vma_internal.h
> > index 2743f12ecf32..b48ebae3927d 100644
> > --- a/tools/testing/vma/vma_internal.h
> > +++ b/tools/testing/vma/vma_internal.h
> > @@ -1127,15 +1127,6 @@ static inline void mapping_allow_writable(struct address_space *mapping)
> >  	atomic_inc(&mapping->i_mmap_writable);
> >  }
> >
> > -static inline void vma_set_range(struct vm_area_struct *vma,
> > -				 unsigned long start, unsigned long end,
> > -				 pgoff_t pgoff)
> > -{
> > -	vma->vm_start = start;
> > -	vma->vm_end = end;
> > -	vma->vm_pgoff = pgoff;
> > -}
> > -
> >  static inline
> >  struct vm_area_struct *vma_find(struct vma_iterator *vmi, unsigned long max)
> >  {
> > --
> > 2.52.0
> >

^ permalink raw reply

* [apparmor][PATCH] apparmor: fix incorrect success return value in unpack_tag_headers()
From: Massimiliano Pellizzer @ 2026-02-10 17:21 UTC (permalink / raw)
  To: john.johansen
  Cc: apparmor, linux-security-module, linux-kernel,
	Massimiliano Pellizzer

unpack_tag_headers() returns `true` (1) on success instead of 0.
Since it's caller unpack_tags() checks the return value with
`if (error)`, a non-zero success value is incorrectly treated as
a failure, causing tag header unpacking to always even if the data
is well-formed.

Change the success return in unpack_tag_headers() from `true` to 0.

Fixes: 3d28e2397af7 ("apparmor: add support loading per permission tagging")
Signed-off-by: Massimiliano Pellizzer <mpellizzer.dev@gmail.com>
---
 security/apparmor/policy_unpack.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
index dc908e1f5a88..221208788025 100644
--- a/security/apparmor/policy_unpack.c
+++ b/security/apparmor/policy_unpack.c
@@ -825,7 +825,7 @@ static int unpack_tag_headers(struct aa_ext *e, struct aa_tags_struct *tags)
 	tags->hdrs.size = size;
 	tags->hdrs.table = hdrs;
 	AA_DEBUG(DEBUG_UNPACK, "headers %ld size %d", (long) hdrs, size);
-	return true;
+	return 0;
 
 fail:
 	kfree_sensitive(hdrs);
-- 
2.51.0


^ permalink raw reply related

* [apparmor][PATCH] apparmor: fix signedness bug in unpack_tags()
From: Massimiliano Pellizzer @ 2026-02-10 17:15 UTC (permalink / raw)
  To: john.johansen
  Cc: apparmor, linux-security-module, linux-kernel, dan.carpenter,
	Massimiliano Pellizzer
In-Reply-To: <aYmsYRgv3VClpkjX@stanley.mountain>

Smatch static checker warning:
    security/apparmor/policy_unpack.c:966 unpack_pdb()
    warn: unsigned 'unpack_tags(e, &pdb->tags, info)' is never less than zero.

unpack_tags() is declared with return type size_t (unsigned) but returns
negative errno values on failure. The caller in unpack_pdb() tests the
return with `< 0`, which is always false for an unsigned type, making
error handling dead code. Malformed tag data would be silently accepted
instead of causing a load failure.

Change return type of unpack_tags() from size_t to int to match the
functions's actual semantic.

Fixes: 3d28e2397af7 ("apparmor: add support loading per permission tagging")
Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
Signed-off-by: Massimiliano Pellizzer <mpellizzer.dev@gmail.com>
---
 security/apparmor/policy_unpack.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
index e68adf39771f..dc908e1f5a88 100644
--- a/security/apparmor/policy_unpack.c
+++ b/security/apparmor/policy_unpack.c
@@ -835,7 +835,7 @@ static int unpack_tag_headers(struct aa_ext *e, struct aa_tags_struct *tags)
 }
 
 
-static size_t unpack_tags(struct aa_ext *e, struct aa_tags_struct *tags,
+static int unpack_tags(struct aa_ext *e, struct aa_tags_struct *tags,
 	const char **info)
 {
 	int error = -EPROTO;
-- 
2.51.0


^ permalink raw reply related

* Re: [PATCH v3 1/3] selftests/landlock: Add filesystem access benchmark
From: Mickaël Salaün @ 2026-02-10 15:42 UTC (permalink / raw)
  To: Günther Noack
  Cc: linux-security-module, Tingmao Wang, Justin Suess,
	Samasth Norway Ananda, Matthieu Buffet, Mikhail Ivanov,
	konstantin.meskhidze, Randy Dunlap
In-Reply-To: <20260206151154.97915-3-gnoack3000@gmail.com>

On Fri, Feb 06, 2026 at 04:11:53PM +0100, Günther Noack wrote:
> fs_bench benchmarks the performance of Landlock's path walk
> by exercising it in a scenario that amplifies Landlock's overhead:
> 
> * Create a large number of nested directories
> * Enforce a Landlock policy in which a rule is associated with each of
>   these subdirectories
> * Benchmark openat() applied to the deepest directory,
>   forcing Landlock to walk the entire path.
> 
> Signed-off-by: Günther Noack <gnoack3000@gmail.com>
> ---
>  tools/testing/selftests/landlock/.gitignore |   1 +
>  tools/testing/selftests/landlock/Makefile   |   1 +
>  tools/testing/selftests/landlock/fs_bench.c | 214 ++++++++++++++++++++
>  3 files changed, 216 insertions(+)
>  create mode 100644 tools/testing/selftests/landlock/fs_bench.c
> 
> diff --git a/tools/testing/selftests/landlock/.gitignore b/tools/testing/selftests/landlock/.gitignore
> index a820329cae0d..1974e17a2611 100644
> --- a/tools/testing/selftests/landlock/.gitignore
> +++ b/tools/testing/selftests/landlock/.gitignore
> @@ -1,4 +1,5 @@
>  /*_test
> +/fs_bench
>  /sandbox-and-launch
>  /true
>  /wait-pipe
> diff --git a/tools/testing/selftests/landlock/Makefile b/tools/testing/selftests/landlock/Makefile
> index 044b83bde16e..fc43225d319a 100644
> --- a/tools/testing/selftests/landlock/Makefile
> +++ b/tools/testing/selftests/landlock/Makefile

> +int main(int argc, char *argv[])
> +{
> +	bool use_landlock = true;
> +	size_t num_iterations = 100000;
> +	size_t num_subdirs = 10000;
> +	int c, curr, fd;
> +	struct tms start_time, end_time;
> +
> +	setbuf(stdout, NULL);
> +	while ((c = getopt(argc, argv, "hLd:n:")) != -1) {
> +		switch (c) {
> +		case 'h':
> +			usage(argv[0]);
> +			return EXIT_SUCCESS;
> +		case 'L':
> +			use_landlock = false;
> +			break;
> +		case 'd':
> +			num_subdirs = atoi(optarg);
> +			break;
> +		case 'n':
> +			num_iterations = atoi(optarg);
> +			break;
> +		default:
> +			usage(argv[0]);
> +			return EXIT_FAILURE;
> +		}
> +	}
> +
> +	printf("*** Benchmark ***\n");
> +	printf("%zu dirs, %zu iterations, %s landlock\n", num_subdirs,
> +	       num_iterations, use_landlock ? "with" : "without");
> +
> +	if (times(&start_time) == -1)
> +		err(1, "times");
> +
> +	curr = build_directory(num_subdirs, use_landlock);
> +
> +	for (int i = 0; i < num_iterations; i++) {
> +		fd = openat(curr, "file.txt", O_CREAT | O_TRUNC | O_WRONLY);

Some build environments complain that O_CREAT requires the fourth
openat argument to be set.  I set the mode to 0600.

> +		if (use_landlock) {
> +			if (fd == 0)
> +				errx(1, "openat succeeded, expected EACCES");
> +			if (errno != EACCES)
> +				err(1, "openat expected EACCES, but got");
> +		}
> +		if (fd != -1)
> +			close(fd);
> +	}
> +
> +	if (times(&end_time) == -1)
> +		err(1, "times");
> +
> +	printf("*** Benchmark concluded ***\n");
> +	printf("System: %ld clocks\n",
> +	       end_time.tms_stime - start_time.tms_stime);
> +	printf("User  : %ld clocks\n",
> +	       end_time.tms_utime - start_time.tms_utime);
> +	printf("Clocks per second: %ld\n", CLOCKS_PER_SEC);
> +
> +	close(curr);
> +
> +	remove_recursively(num_subdirs);
> +}
> -- 
> 2.52.0
> 
> 

^ permalink raw reply

* Re: [PATCH v4 1/6] lsm: Add LSM hook security_unix_find
From: Justin Suess @ 2026-02-10 13:02 UTC (permalink / raw)
  To: mic
  Cc: brauner, demiobenour, fahimitahera, gnoack3000, hi, horms,
	ivanov.mikhail1, jannh, jmorris, john.johansen,
	konstantin.meskhidze, linux-security-module, m, matthieu, netdev,
	paul, samasth.norway.ananda, serge, utilityemal77, viro
In-Reply-To: <20260209.yeeh3ieDuz9u@digikod.net>

> On Mon, Feb 09, 2026 at 12:10:11AM +0100, Günther Noack wrote:
> > From: Justin Suess <utilityemal77@gmail.com>
> > 
> > Add a LSM hook security_unix_find.
> > 
> > This hook is called to check the path of a named unix socket before a
> > connection is initiated. The peer socket may be inspected as well.
> > 
> > Why existing hooks are unsuitable:
> > 
> > Existing socket hooks, security_unix_stream_connect(),
> > security_unix_may_send(), and security_socket_connect() don't provide
> > TOCTOU-free / namespace independent access to the paths of sockets.
> > 
> > (1) We cannot resolve the path from the struct sockaddr in existing hooks.
> > This requires another path lookup. A change in the path between the
> > two lookups will cause a TOCTOU bug.
> > 
> > (2) We cannot use the struct path from the listening socket, because it
> > may be bound to a path in a different namespace than the caller,
> > resulting in a path that cannot be referenced at policy creation time.
> > 
> > Cc: Günther Noack <gnoack3000@gmail.com>
> > Cc: Tingmao Wang <m@maowtm.org>
> > Signed-off-by: Justin Suess <utilityemal77@gmail.com>
> > ---
> >  include/linux/lsm_hook_defs.h |  5 +++++
> >  include/linux/security.h      | 11 +++++++++++
> >  net/unix/af_unix.c            |  9 +++++++++
> >  security/security.c           | 20 ++++++++++++++++++++
> >  4 files changed, 45 insertions(+)
> > 
> > diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
> > index 8c42b4bde09c..7a0fd3dbfa29 100644
> > --- a/include/linux/lsm_hook_defs.h
> > +++ b/include/linux/lsm_hook_defs.h
> > @@ -317,6 +317,11 @@ LSM_HOOK(int, 0, post_notification, const struct cred *w_cred,
> >  LSM_HOOK(int, 0, watch_key, struct key *key)
> >  #endif /* CONFIG_SECURITY && CONFIG_KEY_NOTIFICATIONS */
> >  
> > +#if defined(CONFIG_SECURITY_NETWORK) && defined(CONFIG_SECURITY_PATH)
> > +LSM_HOOK(int, 0, unix_find, const struct path *path, struct sock *other,
> > +	 int flags)
> > +#endif /* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */
> > +
> >  #ifdef CONFIG_SECURITY_NETWORK
> >  LSM_HOOK(int, 0, unix_stream_connect, struct sock *sock, struct sock *other,
> >  	 struct sock *newsk)
> > diff --git a/include/linux/security.h b/include/linux/security.h
> > index 83a646d72f6f..99a33d8eb28d 100644
> > --- a/include/linux/security.h
> > +++ b/include/linux/security.h
> > @@ -1931,6 +1931,17 @@ static inline int security_mptcp_add_subflow(struct sock *sk, struct sock *ssk)
> >  }
> >  #endif	/* CONFIG_SECURITY_NETWORK */
> >  
> > +#if defined(CONFIG_SECURITY_NETWORK) && defined(CONFIG_SECURITY_PATH)
> > +
> > +int security_unix_find(const struct path *path, struct sock *other, int flags);
> > +
> > +#else /* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */
> > +static inline int security_unix_find(const struct path *path, struct sock *other, int flags)
> > +{
> > +	return 0;
> > +}
> > +#endif /* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */
> > +
> >  #ifdef CONFIG_SECURITY_INFINIBAND
> >  int security_ib_pkey_access(void *sec, u64 subnet_prefix, u16 pkey);
> >  int security_ib_endport_manage_subnet(void *sec, const char *name, u8 port_num);
> > diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
> > index d0511225799b..db9d279b3883 100644
> > --- a/net/unix/af_unix.c
> > +++ b/net/unix/af_unix.c
> > @@ -1226,10 +1226,19 @@ static struct sock *unix_find_bsd(struct sockaddr_un *sunaddr, int addr_len,
> >  	if (!S_ISSOCK(inode->i_mode))
> >  		goto path_put;
> >  
> > +	err = -ECONNREFUSED;
> 
> We don't see it in this patch but err is already set to -ECONNREFUSED.
> This line might be confusing, and unrelated to the goal of this patch,
> so we should remove it.

Done. I debated keeping it, but it seems more appropriate to follow the
convention. Thanks for the catch.

> 
> 
> >  	sk = unix_find_socket_byinode(inode);
> >  	if (!sk)
> >  		goto path_put;
> >  
> > +	/*
> > +	 * We call the hook because we know that the inode is a socket
> > +	 * and we hold a valid reference to it via the path.
> 
> This comment can be alligned with 80 columns.

Done.

> > +	 */
> > +	err = security_unix_find(&path, sk, flags);
> 
> This hook makes sense and is quite generic.

Indeed, I suspect it will be useful for other path-based LSM.

> > +	if (err)
> > +		goto sock_put;
> > +
> >  	err = -EPROTOTYPE;
> >  	if (sk->sk_type == type)
> >  		touch_atime(&path);
> > diff --git a/security/security.c b/security/security.c
> > index 31a688650601..9e9515955098 100644
> > --- a/security/security.c
> > +++ b/security/security.c
> > @@ -4731,6 +4731,26 @@ int security_mptcp_add_subflow(struct sock *sk, struct sock *ssk)
> >  
> >  #endif	/* CONFIG_SECURITY_NETWORK */
> >  
> > +#if defined(CONFIG_SECURITY_NETWORK) && defined(CONFIG_SECURITY_PATH)
> > +/*
> 
> This should be a docstring like other hooks: /**

Done.

> 
> > + * security_unix_find() - Check if a named AF_UNIX socket can connect
> > + * @path: path of the socket being connected to
> > + * @other: peer sock
> > + * @flags: flags associated with the socket
> > + *
> > + * This hook is called to check permissions before connecting to a named
> > + * AF_UNIX socket.
> > + *
> > + * Return: Returns 0 if permission is granted.
> > + */
> > +int security_unix_find(const struct path *path, struct sock *other, int flags)
> > +{
> > +	return call_int_hook(unix_find, path, other, flags);
> > +}
> > +EXPORT_SYMBOL(security_unix_find);
> > +
> > +#endif	/* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */
> > +
> >  #ifdef CONFIG_SECURITY_INFINIBAND
> >  /**
> >   * security_ib_pkey_access() - Check if access to an IB pkey is allowed
> > -- 
> > 2.52.0
> > 
> > 
>

Below follows revised lsm hook patch based on feedback.

diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index 8c42b4bde09c..7a0fd3dbfa29 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -317,6 +317,11 @@ LSM_HOOK(int, 0, post_notification, const struct cred *w_cred,
 LSM_HOOK(int, 0, watch_key, struct key *key)
 #endif /* CONFIG_SECURITY && CONFIG_KEY_NOTIFICATIONS */
 
+#if defined(CONFIG_SECURITY_NETWORK) && defined(CONFIG_SECURITY_PATH)
+LSM_HOOK(int, 0, unix_find, const struct path *path, struct sock *other,
+	 int flags)
+#endif /* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */
+
 #ifdef CONFIG_SECURITY_NETWORK
 LSM_HOOK(int, 0, unix_stream_connect, struct sock *sock, struct sock *other,
 	 struct sock *newsk)
diff --git a/include/linux/security.h b/include/linux/security.h
index 83a646d72f6f..99a33d8eb28d 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1931,6 +1931,17 @@ static inline int security_mptcp_add_subflow(struct sock *sk, struct sock *ssk)
 }
 #endif	/* CONFIG_SECURITY_NETWORK */
 
+#if defined(CONFIG_SECURITY_NETWORK) && defined(CONFIG_SECURITY_PATH)
+
+int security_unix_find(const struct path *path, struct sock *other, int flags);
+
+#else /* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */
+static inline int security_unix_find(const struct path *path, struct sock *other, int flags)
+{
+	return 0;
+}
+#endif /* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */
+
 #ifdef CONFIG_SECURITY_INFINIBAND
 int security_ib_pkey_access(void *sec, u64 subnet_prefix, u16 pkey);
 int security_ib_endport_manage_subnet(void *sec, const char *name, u8 port_num);
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index d0511225799b..369812b79dd8 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1230,6 +1230,14 @@ static struct sock *unix_find_bsd(struct sockaddr_un *sunaddr, int addr_len,
 	if (!sk)
 		goto path_put;
 
+	/*
+	 * We call the hook because we know that the inode is a socket and we
+	 * hold a valid reference to it via the path.
+	 */
+	err = security_unix_find(&path, sk, flags);
+	if (err)
+		goto sock_put;
+
 	err = -EPROTOTYPE;
 	if (sk->sk_type == type)
 		touch_atime(&path);
diff --git a/security/security.c b/security/security.c
index 31a688650601..eaf8f8fdf0c2 100644
--- a/security/security.c
+++ b/security/security.c
@@ -4731,6 +4731,26 @@ int security_mptcp_add_subflow(struct sock *sk, struct sock *ssk)
 
 #endif	/* CONFIG_SECURITY_NETWORK */
 
+#if defined(CONFIG_SECURITY_NETWORK) && defined(CONFIG_SECURITY_PATH)
+/**
+ * security_unix_find() - Check if a named AF_UNIX socket can connect
+ * @path: path of the socket being connected to
+ * @other: peer sock
+ * @flags: flags associated with the socket
+ *
+ * This hook is called to check permissions before connecting to a named
+ * AF_UNIX socket.
+ *
+ * Return: Returns 0 if permission is granted.
+ */
+int security_unix_find(const struct path *path, struct sock *other, int flags)
+{
+	return call_int_hook(unix_find, path, other, flags);
+}
+EXPORT_SYMBOL(security_unix_find);
+
+#endif	/* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */
+
 #ifdef CONFIG_SECURITY_INFINIBAND
 /**
  * security_ib_pkey_access() - Check if access to an IB pkey is allowed

^ permalink raw reply related

* Re: [PATCH 1/5] export file_close_fd and task_work_add
From: Alice Ryhl @ 2026-02-10  8:47 UTC (permalink / raw)
  To: Lorenzo Stoakes
  Cc: Greg Kroah-Hartman, Carlos Llamas, Alexander Viro,
	Christian Brauner, Jan Kara, Paul Moore, James Morris,
	Serge E. Hallyn, Andrew Morton, Dave Chinner, Qi Zheng,
	Roman Gushchin, Muchun Song, David Hildenbrand, Liam R. Howlett,
	Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
	Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Trevor Gross, Danilo Krummrich,
	kernel-team, linux-fsdevel, linux-kernel, linux-security-module,
	linux-mm, rust-for-linux
In-Reply-To: <df876a6e-013c-4566-890d-7c1d662fced3@lucifer.local>

On Mon, Feb 09, 2026 at 03:21:58PM +0000, Lorenzo Stoakes wrote:
> On Thu, Feb 05, 2026 at 01:45:40PM +0000, Alice Ryhl wrote:
> > +/**
> > + * close_fd_safe - close the given fd
> > + * @fd: file descriptor to close
> > + * @flags: gfp flags for allocation of task work
> > + *
> > + * This closes an fd. Unlike close_fd(), this may be used even if the fd is
> > + * currently held with fdget().
> > + *
> > + * Returns: 0 or an error code
> > + */
> > +int close_fd_safe(unsigned int fd, gfp_t flags)
> > +{
> > +	struct close_fd_safe_task_work *twcb;
> > +
> > +	twcb = kzalloc(sizeof(*twcb), flags);
> > +	if (!twcb)
> > +		return -ENOMEM;
> > +	init_task_work(&twcb->twork, close_fd_safe_callback);
> > +	twcb->file = file_close_fd(fd);
> > +	if (!twcb->file) {
> > +		kfree(twcb);
> > +		return -EBADF;
> > +	}
> > +
> > +	get_file(twcb->file);
> > +	filp_close(twcb->file, current->files);
> > +	task_work_add(current, &twcb->twork, TWA_RESUME);
> > +	return 0;
> > +}
> 
> Would need an EXPORT_SYMBOL_FOR_MODULES(...) here right?

Ah yeah, for Binder to become a module it would need to be exported.
(Though maybe it's worth moving this logic even if Binder is not made
into a module?)

> > diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h
> > index c45306a9f007..1c99a56c0cdf 100644
> > --- a/include/linux/fdtable.h
> > +++ b/include/linux/fdtable.h
> > @@ -111,6 +111,7 @@ int iterate_fd(struct files_struct *, unsigned,
> >  		const void *);
> >
> >  extern int close_fd(unsigned int fd);
> > +extern int close_fd_safe(unsigned int fd, gfp_t flags);
> 
> One nit, generally well in mm anyway we avoid the 'extern' and remove them as we
> go. Not sure about vfs actually though?

Right. Not sure about this.

> >  extern struct file *file_close_fd(unsigned int fd);
> >
> >  extern struct kmem_cache *files_cachep;
> 
> I mean this is essentially taking what's in binder and making it a general
> thing, so needs Christian's input on whether this is sensible I think :)

Yeah.

Alice

^ permalink raw reply

* Re: [GIT PULL] lsm/lsm-pr-20260203
From: pr-tracker-bot @ 2026-02-10  0:50 UTC (permalink / raw)
  To: Paul Moore; +Cc: Linus Torvalds, linux-security-module, linux-kernel
In-Reply-To: <d6f1f788f25b30ddc05703b97146f6ad@paul-moore.com>

The pull request you sent on Tue, 03 Feb 2026 23:10:44 -0500:

> https://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/lsm.git tags/lsm-pr-20260203

has been merged into torvalds/linux.git:
https://git.kernel.org/torvalds/c/bcc8fd3e1573c502edc0cb61abea0e113a761799

Thank you!

-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/prtracker.html

^ permalink raw reply

* Re: [GIT PULL] selinux/selinux-pr-20260203
From: pr-tracker-bot @ 2026-02-10  0:50 UTC (permalink / raw)
  To: Paul Moore; +Cc: Linus Torvalds, selinux, linux-security-module, linux-kernel
In-Reply-To: <74f395ba13926ab0391bd8714abc6036@paul-moore.com>

The pull request you sent on Tue, 03 Feb 2026 23:10:38 -0500:

> https://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux.git tags/selinux-pr-20260203

has been merged into torvalds/linux.git:
https://git.kernel.org/torvalds/c/6252e917b9006dfa2f3d884fe0dbaf3e676c4108

Thank you!

-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/prtracker.html

^ permalink raw reply

* [GIT PULL] Smack patches for 7.0
From: Casey Schaufler @ 2026-02-09 21:15 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: LSM List, Linux kernel mailing list, Konstantin Andreev,
	Taimoor Zaeem, Casey Schaufler
In-Reply-To: <28dea16f-18c3-4a2f-821c-e85b660125ed.ref@schaufler-ca.com>

Hello Linus,

Here is the Smack pull request for v7.0.

There's nothing exciting. Two improvements to the code for setting
the CIPSO Domain Of Interpretation (DOI), a seldom used feature,
and a formatting change. All tested and included in next for some time.

The following changes since commit f8f9c1f4d0c7a64600e2ca312dec824a0bc2f1da:

  Linux 6.19-rc3 (2025-12-28 13:24:26 -0800)

are available in the Git repository at:

  https://github.com/cschaufler/smack-next tags/Smack-for-7.0

for you to fetch changes up to 33d589ed60ae433b483761987b85e0d24e54584e:

  smack: /smack/doi: accept previously used values (2025-12-30 12:17:15 -0800)

----------------------------------------------------------------
Smack fixes for DOI specification.

----------------------------------------------------------------
Konstantin Andreev (2):
      smack: /smack/doi must be > 0
      smack: /smack/doi: accept previously used values

Taimoor Zaeem (1):
      security: smack: fix indentation in smack_access.c

 security/smack/smack_access.c |  2 +-
 security/smack/smackfs.c      | 79 +++++++++++++++++++++++++++----------------
 2 files changed, 51 insertions(+), 30 deletions(-)


^ permalink raw reply

* [PATCH v6 3/3] ima: Use kstat.ctime as a fallback for change detection
From: Frederick Lawler @ 2026-02-09 21:21 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: <20260209-xfs-ima-fixup-v6-0-72f576f90e67@cloudflare.com>

IMA performs unnecessary measurements on files in file systems
that do not set STATX_CHANGE_COOKIE in the vfs_getattr_nosec()'s
result mask.

Commit 1cf7e834a6fb ("xfs: switch to multigrain timestamps") introduced
multigrain timestamps to XFS, and this made XFS no longer report an
inode's i_version used by ima_collect_measurement() for change detection.

Additionally, ima_check_last_writer() & integrity_inode_attributes_change()
think there's a change for a file, when there may have not been.

Most file systems already use ctime for change detection, therefore, make
IMA fall back to compare against ctime when a file system does not report
an i_version to the kstat.change_cookie.

If neither fields are reported by vfs_getattr_nosec(), assume the file
changed.

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

XFS is just one example. There may be more file systems that adopt
multigrain timestamps in the future.

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


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