Linux Security Modules development
 help / color / mirror / Atom feed
* Re: [PATCH] ima: check return value of crypto_shash_final() in boot aggregate
From: Roberto Sassu @ 2026-02-19  8:56 UTC (permalink / raw)
  To: Daniel Hodges, Mimi Zohar, Roberto Sassu, Dmitry Kasatkin
  Cc: Eric Snowberg, Paul Moore, James Morris, Serge E . Hallyn,
	linux-integrity, linux-security-module, linux-kernel
In-Reply-To: <20260201024015.2862236-1-hodgesd@meta.com>

On Sat, 2026-01-31 at 18:40 -0800, Daniel Hodges wrote:
> The return value of crypto_shash_final() is not checked in
> ima_calc_boot_aggregate_tfm(). If the hash finalization fails, the
> function returns success and a corrupted boot aggregate digest could
> be used for IMA measurements.
> 
> Capture the return value and propagate any error to the caller.
> 
> Fixes: 76bb28f6126f ("ima: use new crypto_shash API instead of old crypto_hash")
> Signed-off-by: Daniel Hodges <hodgesd@meta.com>

Reviewed-by: Roberto Sassu <roberto.sassu@huawei.com>

Thanks

Roberto

> ---
>  security/integrity/ima/ima_crypto.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c
> index 6f5696d999d0..8ae7821a65c2 100644
> --- a/security/integrity/ima/ima_crypto.c
> +++ b/security/integrity/ima/ima_crypto.c
> @@ -825,21 +825,21 @@ static int ima_calc_boot_aggregate_tfm(char *digest, u16 alg_id,
>  	 * non-SHA1 boot_aggregate digests to avoid ambiguity.
>  	 */
>  	if (alg_id != TPM_ALG_SHA1) {
>  		for (i = TPM_PCR8; i < TPM_PCR10; i++) {
>  			ima_pcrread(i, &d);
>  			rc = crypto_shash_update(shash, d.digest,
>  						crypto_shash_digestsize(tfm));
>  		}
>  	}
>  	if (!rc)
> -		crypto_shash_final(shash, digest);
> +		rc = crypto_shash_final(shash, digest);
>  	return rc;
>  }
>  
>  int ima_calc_boot_aggregate(struct ima_digest_data *hash)
>  {
>  	struct crypto_shash *tfm;
>  	u16 crypto_id, alg_id;
>  	int rc, i, bank_idx = -1;
>  
>  	for (i = 0; i < ima_tpm_chip->nr_allocated_banks; i++) {


^ permalink raw reply

* [GIT PULL] AppArmor updates for 7.0-rc1
From: John Johansen @ 2026-02-19  0:19 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: LKLM, open list:SECURITY SUBSYSTEM

Hi Linus,

Below is the AppArmor update PR for 7.0

These patches have all been merge, build, and regression tested
against your tree as of yesterday. The code has been in linux-next
and the many of the patches in the Ubuntu kernels for testing.

This PR is mostly comprised of cleanups, and bug fixes, with 3 minor
features, the first being an improvement to our kunit testing, and
the other two extending the information available in audit messages.

Because this is coming so late in the window (sorry life happens),
if you would prefer I have prepared an alternate PR that contains
the set of bug fixes that apply without the features, or cleanups,
available via the tag bugfix-2026-02-18, which I can send a PR for
instead.


thanks
- john


The following changes since commit 8f0b4cce4481fb22653697cced8d0d04027cb1e8:

   Linux 6.19-rc1 (2025-12-14 16:05:07 +1200)

are available in the Git repository at:

   git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor tags/apparmor-pr-2026-02-18

for you to fetch changes up to 08020dbe3125e936429e7966bf072e08fa964f36:

   apparmor: fix signedness bug in unpack_tags() (2026-02-18 11:50:20 -0800)

----------------------------------------------------------------
+ Features
   - add .kunitconfig
   - audit execpath in userns mediation
   - add support loading per permission tagging

+ Cleanups
   - cleanup remove unused percpu critical sections in buffer management
   - document the buffer hold, add an overflow guard
   - split xxx_in_ns into its two separate semantic use cases
   - remove apply_modes_to_perms from label_match
   - refactor/cleanup cred helper fns.
   - guard against free attachment/data routines being called with a NULL
   - drop in_atomic flag in common_mmap, and common_file_perm, and cleanup
   - make str table more generic and be able to have multiple entries
   - Replace deprecated strcpy with memcpy in gen_symlink_name
   - Replace deprecated strcpy in d_namespace_path
   - Replace sprintf/strcpy with scnprintf/strscpy in aa_policy_init
   - replace sprintf with snprintf in aa_new_learning_profile

+ Bug Fixes
   - fix cast in format string DEBUG statement
   - fix make aa_labelmatch return consistent
   - fix fmt string type error in process_strs_entry
   - fix kernel-doc comments for inview
   - fix invalid deref of rawdata when export_binary is unset
   - avoid per-cpu hold underflow in aa_get_buffer
   - fix fast path cache check for unix sockets
   - fix rlimit for posix cpu timers
   - fix label and profile debug macros
   - move check for aa_null file to cover all cases
   - return -ENOMEM in unpack_perms_table upon alloc failure
   - fix boolean argument in apparmor_mmap_file
   - Fix & Optimize table creation from possibly unaligned memory
   - Allow apparmor to handle unaligned dfa tables
   - fix NULL deref in aa_sock_file_perm
   - fix NULL pointer dereference in __unix_needs_revalidation
   - fix signedness bug in unpack_tags()

----------------------------------------------------------------
Georgia Garcia (1):
       apparmor: fix invalid deref of rawdata when export_binary is unset

Helge Deller (2):
       AppArmor: Allow apparmor to handle unaligned dfa tables
       apparmor: Fix & Optimize table creation from possibly unaligned memory

John Johansen (19):
       apparmor: fix NULL sock in aa_sock_file_perm
       apparmor: make str table more generic and be able to have multiple entries
       apparmor: add support loading per permission tagging
       apparmor: drop in_atomic flag in common_mmap, and common_file_perm
       apparmor: guard against free routines being called with a NULL
       apparmor: move check for aa_null file to cover all cases
       apparmor: fix label and profile debug macros
       apparmor: refactor/cleanup cred helper fns.
       apparmor: fix rlimit for posix cpu timers
       apparmor: fix fast path cache check for unix sockets
       apparmor: remove apply_modes_to_perms from label_match
       apparmor: make label_match return a consistent value
       apparmor: split xxx_in_ns into its two separate semantic use cases
       apparmor: document the buffer hold, add an overflow guard
       apparmor: cleanup remove unused percpu critical sections in buffer management
       apparmor: fix kernel-doc comments for inview
       apparmor: fix fmt string type error in process_strs_entry
       apparmor: fix aa_label to return state from compount and component match
       apparmor: fix cast in format string DEBUG statement

Massimiliano Pellizzer (1):
       apparmor: fix signedness bug in unpack_tags()

Maxime Bélair (1):
       apparmor: userns: Add support for execpath in userns

Ryan Lee (3):
       apparmor: fix boolean argument in apparmor_mmap_file
       apparmor: account for in_atomic removal in common_file_perm
       apparmor: return -ENOMEM in unpack_perms_table upon alloc failure

Ryota Sakamoto (1):
       apparmor: add .kunitconfig

System Administrator (1):
       apparmor: fix NULL pointer dereference in __unix_needs_revalidation

Thorsten Blum (4):
       apparmor: replace sprintf with snprintf in aa_new_learning_profile
       apparmor: Replace sprintf/strcpy with scnprintf/strscpy in aa_policy_init
       apparmor: Replace deprecated strcpy in d_namespace_path
       apparmor: Replace deprecated strcpy with memcpy in gen_symlink_name

Zhengmian Hu (1):
       apparmor: avoid per-cpu hold underflow in aa_get_buffer

  security/apparmor/.kunitconfig     |   5 +
  security/apparmor/af_unix.c        |   2 +-
  security/apparmor/apparmorfs.c     |  23 ++-
  security/apparmor/domain.c         |  60 +++----
  security/apparmor/file.c           |  49 ++++--
  security/apparmor/include/audit.h  |   2 +
  security/apparmor/include/cred.h   | 100 +++++++----
  security/apparmor/include/lib.h    |  37 +++-
  security/apparmor/include/match.h  |  12 +-
  security/apparmor/include/policy.h |  32 +++-
  security/apparmor/label.c          |  55 +++---
  security/apparmor/lib.c            |  29 ++--
  security/apparmor/lsm.c            |  66 +++++---
  security/apparmor/match.c          |  22 +--
  security/apparmor/net.c            |   6 +-
  security/apparmor/path.c           |  13 +-
  security/apparmor/policy.c         |  31 +++-
  security/apparmor/policy_compat.c  |  10 +-
  security/apparmor/policy_unpack.c  | 336 ++++++++++++++++++++++++++++++++-----
  security/apparmor/resource.c       |   5 +
  security/apparmor/task.c           |  32 ++++
  21 files changed, 687 insertions(+), 240 deletions(-)
  create mode 100644 security/apparmor/.kunitconfig


^ permalink raw reply

* [PATCH 2/2] landlock: Remove collect_domain_accesses
From: Justin Suess @ 2026-02-18 20:18 UTC (permalink / raw)
  To: linux-security-module, Mickaël Salaün
  Cc: Günther Noack, Tingmao Wang, Justin Suess
In-Reply-To: <20260218201857.1194667-1-utilityemal77@gmail.com>

Remove collect_domain_accesses and replace with inline logic using the
new path walk helper in the check_current_refer_path.

Signed-off-by: Justin Suess <utilityemal77@gmail.com>
---
 security/landlock/fs.c | 128 +++++++++++++++--------------------------
 1 file changed, 46 insertions(+), 82 deletions(-)

diff --git a/security/landlock/fs.c b/security/landlock/fs.c
index c6ff686c9cde..efc65dc41c0d 100644
--- a/security/landlock/fs.c
+++ b/security/landlock/fs.c
@@ -1013,77 +1013,6 @@ static access_mask_t maybe_remove(const struct dentry *const dentry)
 				  LANDLOCK_ACCESS_FS_REMOVE_FILE;
 }
 
-/**
- * collect_domain_accesses - Walk through a file path and collect accesses
- *
- * @domain: Domain to check against.
- * @mnt_root: Last directory to check.
- * @dir: Directory to start the walk from.
- * @layer_masks_dom: Where to store the collected accesses.
- *
- * This helper is useful to begin a path walk from the @dir directory to a
- * @mnt_root directory used as a mount point.  This mount point is the common
- * ancestor between the source and the destination of a renamed and linked
- * file.  While walking from @dir to @mnt_root, we record all the domain's
- * allowed accesses in @layer_masks_dom.
- *
- * Because of disconnected directories, this walk may not reach @mnt_dir.  In
- * this case, the walk will continue to @mnt_dir after this call.
- *
- * This is similar to is_access_to_paths_allowed() but much simpler because it
- * only handles walking on the same mount point and only checks one set of
- * accesses.
- *
- * Returns:
- * - true if all the domain access rights are allowed for @dir;
- * - false if the walk reached @mnt_root.
- */
-static bool collect_domain_accesses(const struct landlock_ruleset *const domain,
-				    const struct dentry *const mnt_root,
-				    struct dentry *dir,
-				    struct layer_access_masks *layer_masks_dom)
-{
-	bool ret = false;
-
-	if (WARN_ON_ONCE(!domain || !mnt_root || !dir || !layer_masks_dom))
-		return true;
-	if (is_nouser_or_private(dir))
-		return true;
-
-	if (!landlock_init_layer_masks(domain, LANDLOCK_MASK_ACCESS_FS,
-				       layer_masks_dom, LANDLOCK_KEY_INODE))
-		return true;
-
-	dget(dir);
-	while (true) {
-		struct dentry *parent_dentry;
-
-		/* Gets all layers allowing all domain accesses. */
-		if (landlock_unmask_layers(find_rule(domain, dir),
-					   layer_masks_dom)) {
-			/*
-			 * Stops when all handled accesses are allowed by at
-			 * least one rule in each layer.
-			 */
-			ret = true;
-			break;
-		}
-
-		/*
-		 * Stops at the mount point or the filesystem root for a disconnected
-		 * directory.
-		 */
-		if (dir == mnt_root || unlikely(IS_ROOT(dir)))
-			break;
-
-		parent_dentry = dget_parent(dir);
-		dput(dir);
-		dir = parent_dentry;
-	}
-	dput(dir);
-	return ret;
-}
-
 /**
  * current_check_refer_path - Check if a rename or link action is allowed
  *
@@ -1147,7 +1076,7 @@ static int current_check_refer_path(struct dentry *const old_dentry,
 	bool allow_parent1, allow_parent2;
 	access_mask_t access_request_parent1, access_request_parent2;
 	struct path mnt_dir;
-	struct dentry *old_parent;
+	struct path old_parent_path;
 	struct layer_access_masks layer_masks_parent1 = {},
 				  layer_masks_parent2 = {};
 	struct landlock_request request1 = {}, request2 = {};
@@ -1202,20 +1131,55 @@ static int current_check_refer_path(struct dentry *const old_dentry,
 	/*
 	 * old_dentry may be the root of the common mount point and
 	 * !IS_ROOT(old_dentry) at the same time (e.g. with open_tree() and
-	 * OPEN_TREE_CLONE).  We do not need to call dget(old_parent) because
+	 * OPEN_TREE_CLONE).  We do not need to path_get(old_parent_path) because
 	 * we keep a reference to old_dentry.
 	 */
-	old_parent = (old_dentry == mnt_dir.dentry) ? old_dentry :
-						      old_dentry->d_parent;
+	old_parent_path.mnt = mnt_dir.mnt;
+	old_parent_path.dentry = unlikely(old_dentry == mnt_dir.dentry) ?
+					 old_dentry :
+					 old_dentry->d_parent;
 
 	/* new_dir->dentry is equal to new_dentry->d_parent */
-	allow_parent1 = collect_domain_accesses(subject->domain, mnt_dir.dentry,
-						old_parent,
-						&layer_masks_parent1);
-	allow_parent2 = collect_domain_accesses(subject->domain, mnt_dir.dentry,
-						new_dir->dentry,
-						&layer_masks_parent2);
+	allow_parent1 = false;
+	allow_parent2 = false;
+	for (size_t i = 0; i < 2; i++) {
+		const struct path *const parent_path = i ? new_dir :
+							   &old_parent_path;
+		struct layer_access_masks *const layer_masks =
+			i ? &layer_masks_parent2 : &layer_masks_parent1;
+		bool *const allow_parent = i ? &allow_parent2 : &allow_parent1;
+
+		if (is_nouser_or_private(parent_path->dentry) ||
+		    !landlock_init_layer_masks(
+			    subject->domain, LANDLOCK_MASK_ACCESS_FS,
+			    layer_masks, LANDLOCK_KEY_INODE)) {
+			*allow_parent = true;
+			continue;
+		}
 
+		{
+			struct path walker = *parent_path;
+
+			path_get(&walker);
+			do {
+				/* Gets all layers allowing all domain accesses. */
+				if (landlock_unmask_layers(
+					    find_rule(subject->domain,
+						      walker.dentry),
+					    layer_masks)) {
+					/*
+					 * Stops when all handled accesses are
+					 * allowed by at least one rule in each
+					 * layer.
+					 */
+					*allow_parent = true;
+					break;
+				}
+			} while (landlock_walk_path_up(&walker) ==
+				 LANDLOCK_WALK_CONTINUE);
+			path_put(&walker);
+		}
+	}
 	if (allow_parent1 && allow_parent2)
 		return 0;
 
@@ -1233,7 +1197,7 @@ static int current_check_refer_path(struct dentry *const old_dentry,
 		return 0;
 
 	if (request1.access) {
-		request1.audit.u.path.dentry = old_parent;
+		request1.audit.u.path.dentry = old_parent_path.dentry;
 		landlock_log_denial(subject, &request1);
 	}
 	if (request2.access) {
-- 
2.51.0


^ permalink raw reply related

* [PATCH 1/2] landlock: Add path walk helper
From: Justin Suess @ 2026-02-18 20:18 UTC (permalink / raw)
  To: linux-security-module, Mickaël Salaün
  Cc: Günther Noack, Tingmao Wang, Justin Suess
In-Reply-To: <20260218201857.1194667-1-utilityemal77@gmail.com>

Add a new helper function landlock_walk_path_up, which takes a pointer
to the current path in the walk, and returns an enum
landlock_walk_result corresponding to whether the current position in
the walk is a mountpoint, the real root, or neither.

Signed-off-by: Justin Suess <utilityemal77@gmail.com>
---
 security/landlock/fs.c | 92 ++++++++++++++++++++++++------------------
 1 file changed, 52 insertions(+), 40 deletions(-)

diff --git a/security/landlock/fs.c b/security/landlock/fs.c
index e764470f588c..c6ff686c9cde 100644
--- a/security/landlock/fs.c
+++ b/security/landlock/fs.c
@@ -317,6 +317,38 @@ static struct landlock_object *get_inode_object(struct inode *const inode)
 	LANDLOCK_ACCESS_FS_IOCTL_DEV)
 /* clang-format on */
 
+/**
+ * enum landlock_walk_result - Result codes for landlock_walk_path_up()
+ * @LANDLOCK_WALK_CONTINUE: Path is now neither the real root nor an internal mount point.
+ * @LANDLOCK_WALK_STOP_REAL_ROOT: Path has reached the real VFS root.
+ * @LANDLOCK_WALK_INTERNAL: Path has reached an internal mount point.
+ */
+enum landlock_walk_result {
+	LANDLOCK_WALK_CONTINUE,
+	LANDLOCK_WALK_STOP_REAL_ROOT,
+	LANDLOCK_WALK_INTERNAL,
+};
+
+static enum landlock_walk_result landlock_walk_path_up(struct path *const path)
+{
+	struct dentry *old;
+
+	while (path->dentry == path->mnt->mnt_root) {
+		if (!follow_up(path))
+			return LANDLOCK_WALK_STOP_REAL_ROOT;
+	}
+	old = path->dentry;
+	if (unlikely(IS_ROOT(old))) {
+		if (likely(path->mnt->mnt_flags & MNT_INTERNAL))
+			return LANDLOCK_WALK_INTERNAL;
+		path->dentry = dget(path->mnt->mnt_root);
+	} else {
+		path->dentry = dget_parent(old);
+	}
+	dput(old);
+	return LANDLOCK_WALK_CONTINUE;
+}
+
 /*
  * @path: Should have been checked by get_path_from_fd().
  */
@@ -874,47 +906,27 @@ is_access_to_paths_allowed(const struct landlock_ruleset *const domain,
 		/* Stops when a rule from each layer grants access. */
 		if (allowed_parent1 && allowed_parent2)
 			break;
-
-jump_up:
-		if (walker_path.dentry == walker_path.mnt->mnt_root) {
-			if (follow_up(&walker_path)) {
-				/* Ignores hidden mount points. */
-				goto jump_up;
-			} else {
-				/*
-				 * Stops at the real root.  Denies access
-				 * because not all layers have granted access.
-				 */
-				break;
-			}
-		}
-
-		if (unlikely(IS_ROOT(walker_path.dentry))) {
-			if (likely(walker_path.mnt->mnt_flags & MNT_INTERNAL)) {
-				/*
-				 * Stops and allows access when reaching disconnected root
-				 * directories that are part of internal filesystems (e.g. nsfs,
-				 * which is reachable through /proc/<pid>/ns/<namespace>).
-				 */
-				allowed_parent1 = true;
-				allowed_parent2 = true;
-				break;
-			}
-
-			/*
-			 * We reached a disconnected root directory from a bind mount.
-			 * Let's continue the walk with the mount point we missed.
-			 */
-			dput(walker_path.dentry);
-			walker_path.dentry = walker_path.mnt->mnt_root;
-			dget(walker_path.dentry);
-		} else {
-			struct dentry *const parent_dentry =
-				dget_parent(walker_path.dentry);
-
-			dput(walker_path.dentry);
-			walker_path.dentry = parent_dentry;
+		/* Otherwise, keep walking up to the root. */
+		switch (landlock_walk_path_up(&walker_path)) {
+		/*
+		 * Stops and allows access when reaching disconnected root
+		 * directories that are part of internal filesystems (e.g. nsfs,
+		 * which is reachable through /proc/<pid>/ns/<namespace>).
+		 */
+		case LANDLOCK_WALK_INTERNAL:
+			allowed_parent1 = true;
+			allowed_parent2 = true;
+			break;
+		/*
+		 * Stops at the real root.  Denies access
+		 * because not all layers have granted access
+		 */
+		case LANDLOCK_WALK_STOP_REAL_ROOT:
+			break;
+		case LANDLOCK_WALK_CONTINUE:
+			continue;
 		}
+		break;
 	}
 	path_put(&walker_path);
 
-- 
2.51.0


^ permalink raw reply related

* [PATCH 0/2] landlock: Simplify path walk logic
From: Justin Suess @ 2026-02-18 20:18 UTC (permalink / raw)
  To: linux-security-module, Mickaël Salaün
  Cc: Günther Noack, Tingmao Wang, Justin Suess

Hello,

These two patches simplify the path walk logic in fs.c.

This patch was originally included in a very basic form in my
LANDLOCK_ADD_RULE_NO_INHERIT series [1], but I think that it would be better
submitted separately, as logically it doesn't have much to do with the
feature implemented in the patch.

This patch is based on the mic/next branch.

Motivation
===

Additionally, existing path walk logic is tightly bound to the
is_access_to_paths_allowed and collect_domain_accesses, and is difficult to
read and understand.

Centralizing the path logic would more easily allow other Landlock features
that may rely on path walking, such as the proposed path walk controls, or
my LANDLOCK_ADD_RULE_NO_INHERIT patch, to reuse the same logic as
currently implemented.

Background
===

The first patch in this small series introduces a helper function
landlock_walk_path_up, which takes a pointer to a struct path, and walks it 
up through the VFS. The function returns an enum landlock_walk_result which
encodes whether the current path position is an internal mountpoint, the real
root, or neither.

The is_access_to_paths_allowed function is then altered to use this new helper,
cleaning up the traversal logic while retaining existing documentation comments
and improving readability.

The next patch in the series removes the collect_domain_accesses function. After
an initial re-implementation with the helper it was found that collect_domain_accesses
could be more succicently inlined into current_check_refer_path and there was little
benefit to keeping check_domain_accesses as a standalone function.

These changes overall reduce about 25 lines of code, including new documentation
for the return values of the landlock_walk_path_up function.

Results
===
These patches pass all existing selftests and kunit tests, and favorably influence
stack size.

Checkstack Results (CONFIG_AUDIT enabled)
===

Current Master Branch:
0xffffffff817d3f40 current_check_refer_path [vmlinux]:	608
0xffffffff817d2f80 is_access_to_paths_allowed [vmlinux]:352

This Patch Series:
0xffffffff817d3db0 current_check_refer_path [vmlinux]:	384
0xffffffff817d30c0 is_access_to_paths_allowed [vmlinux]:336

Thank you for your time.

Kind Regards,
Justin Suess

[1]: https://lore.kernel.org/linux-security-module/20251221194301.247484-2-utilityemal77@gmail.com/

Justin Suess (2):
  landlock: Add path walk helper
  landlock: Remove collect_domain_accesses

 security/landlock/fs.c | 220 ++++++++++++++++++-----------------------
 1 file changed, 98 insertions(+), 122 deletions(-)

-- 
2.51.0


^ permalink raw reply

* Re: [PATCH v5 6/9] landlock/selftests: Check that coredump sockets stay unrestricted
From: Mickaël Salaün @ 2026-02-18 20:05 UTC (permalink / raw)
  To: Günther Noack
  Cc: John Johansen, linux-security-module, Tingmao Wang, Justin Suess,
	Samasth Norway Ananda, Matthieu Buffet, Mikhail Ivanov,
	konstantin.meskhidze, Demi Marie Obenour, Alyssa Ross, Jann Horn,
	Tahera Fahimi
In-Reply-To: <20260215105158.28132-7-gnoack3000@gmail.com>

On Sun, Feb 15, 2026 at 11:51:54AM +0100, Günther Noack wrote:
> Even when a process is restricted with the new
> LANDLOCK_ACCESS_FS_RESOLVE_SOCKET right, the kernel can continue
> writing its coredump to the configured coredump socket.
> 
> In the test, we create a local server and rewire the system to write
> coredumps into it.  We then create a child process within a Landlock
> domain where LANDLOCK_ACCESS_FS_RESOLVE_SOCKET is restricted and make
> the process crash.  The test uses SO_PEERCRED to check that the
> connecting client process is the expected one.
> 
> Signed-off-by: Günther Noack <gnoack3000@gmail.com>
> ---
>  tools/testing/selftests/landlock/fs_test.c | 122 +++++++++++++++++++++
>  1 file changed, 122 insertions(+)
> 
> diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c
> index 8fa9d7c49ac3..705d8a13d2e0 100644
> --- a/tools/testing/selftests/landlock/fs_test.c
> +++ b/tools/testing/selftests/landlock/fs_test.c
> @@ -22,6 +22,7 @@
>  #include <sys/ioctl.h>
>  #include <sys/mount.h>
>  #include <sys/prctl.h>
> +#include <sys/resource.h>
>  #include <sys/sendfile.h>
>  #include <sys/socket.h>
>  #include <sys/stat.h>
> @@ -4922,6 +4923,127 @@ TEST_F(scoped_domains, unix_seqpacket_connect_to_child_full)
>  #undef USE_SENDTO
>  #undef ENFORCE_ALL
>  
> +static void read_core_pattern(struct __test_metadata *const _metadata,
> +			      char *buf, size_t buf_size)
> +{
> +	int fd;
> +	ssize_t ret;
> +
> +	fd = open("/proc/sys/kernel/core_pattern", O_RDONLY | O_CLOEXEC);
> +	ASSERT_LE(0, fd);
> +
> +	ret = read(fd, buf, buf_size - 1);
> +	ASSERT_LE(0, ret);
> +	EXPECT_EQ(0, close(fd));
> +
> +	buf[ret] = '\0';
> +}
> +
> +static void set_core_pattern(struct __test_metadata *const _metadata,
> +			     const char *pattern)
> +{
> +	int fd;
> +	size_t len = strlen(pattern);
> +
> +	fd = open("/proc/sys/kernel/core_pattern", O_WRONLY | O_CLOEXEC);
> +	ASSERT_LE(0, fd);
> +
> +	ASSERT_EQ(len, write(fd, pattern, len));
> +	EXPECT_EQ(0, close(fd));
> +}

I had to fix this helper to make it work with check-linux.sh:

diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c
index ae32513fb54b..64887d34079a 100644
--- a/tools/testing/selftests/landlock/fs_test.c
+++ b/tools/testing/selftests/landlock/fs_test.c
@@ -4659,11 +4659,34 @@ static void set_core_pattern(struct __test_metadata *const _metadata,
 	int fd;
 	size_t len = strlen(pattern);
 
+	/*
+	 * Writing to /proc/sys/kernel/core_pattern requires EUID 0 because
+	 * sysctl_perm() checks that, ignoring capabilities like
+	 * CAP_SYS_ADMIN or CAP_DAC_OVERRIDE.
+	 *
+	 * Switching EUID clears the dumpable flag, which must be restored
+	 * afterwards to allow coredumps.
+	 */
+	set_cap(_metadata, CAP_SETUID);
+	ASSERT_EQ(0, seteuid(0));
+	clear_cap(_metadata, CAP_SETUID);
+
 	fd = open("/proc/sys/kernel/core_pattern", O_WRONLY | O_CLOEXEC);
-	ASSERT_LE(0, fd);
+	ASSERT_LE(0, fd)
+	{
+		TH_LOG("Failed to open core_pattern for writing: %s",
+		       strerror(errno));
+	}
 
 	ASSERT_EQ(len, write(fd, pattern, len));
 	EXPECT_EQ(0, close(fd));
+
+	set_cap(_metadata, CAP_SETUID);
+	ASSERT_EQ(0, seteuid(getuid()));
+	clear_cap(_metadata, CAP_SETUID);
+
+	/* Restore dumpable flag cleared by seteuid(). */
+	ASSERT_EQ(0, prctl(PR_SET_DUMPABLE, 1 , 0, 0, 0));
 }
 
 FIXTURE(coredump)
@@ -4680,9 +4703,7 @@ FIXTURE_SETUP(coredump)
 
 FIXTURE_TEARDOWN_PARENT(coredump)
 {
-	set_cap(_metadata, CAP_SYS_ADMIN);
 	set_core_pattern(_metadata, self->original_core_pattern);
-	clear_cap(_metadata, CAP_SYS_ADMIN);
 }
 
 /*
@@ -4705,9 +4726,7 @@ TEST_F_FORK(coredump, socket_not_restricted)
 	srv_fd = set_up_named_unix_server(_metadata, SOCK_STREAM, sock_path);
 
 	/* Point coredumps at our socket. */
-	set_cap(_metadata, CAP_SYS_ADMIN);
 	set_core_pattern(_metadata, core_pattern);
-	clear_cap(_metadata, CAP_SYS_ADMIN);
 
 	/* Restrict LANDLOCK_ACCESS_FS_RESOLVE_UNIX. */
 	enforce_fs(_metadata, LANDLOCK_ACCESS_FS_RESOLVE_UNIX, NULL);


Please run tests in this (minimal) environment.

> +
> +FIXTURE(coredump)
> +{
> +	char original_core_pattern[256];
> +};
> +
> +FIXTURE_SETUP(coredump)
> +{
> +	disable_caps(_metadata);
> +	read_core_pattern(_metadata, self->original_core_pattern,
> +			  sizeof(self->original_core_pattern));
> +}
> +
> +FIXTURE_TEARDOWN_PARENT(coredump)
> +{
> +	set_cap(_metadata, CAP_SYS_ADMIN);
> +	set_core_pattern(_metadata, self->original_core_pattern);
> +	clear_cap(_metadata, CAP_SYS_ADMIN);
> +}
> +
> +/*
> + * Test that even when a process is restricted with
> + * LANDLOCK_ACCESS_FS_RESOLVE_UNIX, the kernel can still initiate a connection
> + * to the coredump socket on the processes' behalf.
> + */
> +TEST_F_FORK(coredump, socket_not_restricted)
> +{
> +	static const char core_pattern[] = "@/tmp/landlock_coredump_test.sock";
> +	const char *const sock_path = core_pattern + 1;
> +	int srv_fd, conn_fd, status;
> +	pid_t child_pid;
> +	struct ucred cred;
> +	socklen_t cred_len = sizeof(cred);
> +	char buf[4096];
> +
> +	/* Set up the coredump server socket. */
> +	unlink(sock_path);
> +	srv_fd = set_up_named_unix_server(_metadata, SOCK_STREAM, sock_path);
> +
> +	/* Point coredumps at our socket. */
> +	set_cap(_metadata, CAP_SYS_ADMIN);
> +	set_core_pattern(_metadata, core_pattern);
> +	clear_cap(_metadata, CAP_SYS_ADMIN);
> +
> +	/* Restrict LANDLOCK_ACCESS_FS_RESOLVE_UNIX. */
> +	drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
> +		.handled_access_fs = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> +	});
> +
> +	/* Fork a child that crashes. */
> +	child_pid = fork();
> +	ASSERT_LE(0, child_pid);
> +	if (child_pid == 0) {
> +		struct rlimit rl = {
> +			.rlim_cur = RLIM_INFINITY,
> +			.rlim_max = RLIM_INFINITY,
> +		};
> +
> +		ASSERT_EQ(0, setrlimit(RLIMIT_CORE, &rl));
> +
> +		/* Crash on purpose. */
> +		kill(getpid(), SIGSEGV);
> +		_exit(1);
> +	}
> +
> +	/*
> +	 * Accept the coredump connection.  If Landlock incorrectly denies the
> +	 * kernel's coredump connect, accept() will block forever, so the test
> +	 * would time out.
> +	 */
> +	conn_fd = accept(srv_fd, NULL, NULL);
> +	ASSERT_LE(0, conn_fd);
> +
> +	/* Check that the connection came from the crashing child. */
> +	ASSERT_EQ(0, getsockopt(conn_fd, SOL_SOCKET, SO_PEERCRED, &cred,
> +				&cred_len));
> +	EXPECT_EQ(child_pid, cred.pid);
> +
> +	/* Drain the coredump data so the kernel can finish. */
> +	while (read(conn_fd, buf, sizeof(buf)) > 0)
> +		;
> +
> +	EXPECT_EQ(0, close(conn_fd));
> +
> +	/* Wait for the child and verify it coredumped. */
> +	ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0));
> +	ASSERT_TRUE(WIFSIGNALED(status));
> +	ASSERT_TRUE(WCOREDUMP(status));
> +
> +	EXPECT_EQ(0, close(srv_fd));
> +	EXPECT_EQ(0, unlink(sock_path));
> +}
> +
>  /* clang-format off */
>  FIXTURE(layout1_bind) {};
>  /* clang-format on */
> -- 
> 2.52.0
> 
> 

^ permalink raw reply related

* Re: [PATCH v5 4/9] landlock/selftests: Test LANDLOCK_ACCESS_FS_RESOLVE_UNIX
From: Mickaël Salaün @ 2026-02-18 19:11 UTC (permalink / raw)
  To: Günther Noack
  Cc: John Johansen, Justin Suess, Tingmao Wang, linux-security-module,
	Samasth Norway Ananda, Matthieu Buffet, Mikhail Ivanov,
	konstantin.meskhidze, Demi Marie Obenour, Alyssa Ross, Jann Horn,
	Tahera Fahimi
In-Reply-To: <20260215105158.28132-5-gnoack3000@gmail.com>

On Sun, Feb 15, 2026 at 11:51:52AM +0100, Günther Noack wrote:
> * Extract common helpers from an existing IOCTL test that
>   also uses pathname unix(7) sockets.
> * These tests use the common scoped domains fixture which is also used
>   in other Landlock scoping tests and which was used in Tingmao Wang's
>   earlier patch set in [1].
> 
> These tests exercise the cross product of the following scenarios:
> 
> * Stream connect(), Datagram connect(), Datagram sendmsg() and
>   Seqpacket connect().
> * Child-to-parent and parent-to-child communication
> * The Landlock policy configuration as listed in the scoped_domains
>   fixture.
>   * In the default variant, Landlock domains are only placed where
>     prescribed in the fixture.
>   * In the "ALL_DOMAINS" variant, Landlock domains are also placed in
>     the places where the fixture says to omit them, but with a
>     LANDLOCK_RULE_PATH_BENEATH that allows connection.
> 
> Cc: Justin Suess <utilityemal77@gmail.com>
> Cc: Tingmao Wang <m@maowtm.org>
> Cc: Mickaël Salaün <mic@digikod.net>
> Link[1]: https://lore.kernel.org/all/53b9883648225d5a08e82d2636ab0b4fda003bc9.1767115163.git.m@maowtm.org/
> Signed-off-by: Günther Noack <gnoack3000@gmail.com>
> ---
>  tools/testing/selftests/landlock/fs_test.c | 384 ++++++++++++++++++++-
>  1 file changed, 368 insertions(+), 16 deletions(-)
> 
> diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c
> index b318627e7561..bdeff2e0e029 100644
> --- a/tools/testing/selftests/landlock/fs_test.c
> +++ b/tools/testing/selftests/landlock/fs_test.c
> @@ -4358,30 +4358,61 @@ TEST_F_FORK(layout1, named_pipe_ioctl)
>  	ASSERT_EQ(child_pid, waitpid(child_pid, NULL, 0));
>  }
>  
> +/*
> + * set_up_named_unix_server - Create a pathname unix socket
> + *
> + * If the socket type is not SOCK_DGRAM, also invoke listen(2).
> + *
> + * Return: The listening FD - it is the caller responsibility to close it.
> + */
> +static int set_up_named_unix_server(struct __test_metadata *const _metadata,
> +				    int type, const char *const path)
> +{
> +	int fd;
> +	struct sockaddr_un addr = {
> +		.sun_family = AF_UNIX,
> +	};
> +
> +	fd = socket(AF_UNIX, type, 0);
> +	ASSERT_LE(0, fd);
> +
> +	strncpy(addr.sun_path, path, sizeof(addr.sun_path));

fs_test.c: In function ‘set_up_named_unix_server’:
fs_test.c:4125:9: error: ‘strncpy’ specified bound 108 equals destination size [-Werror=stringop-truncation]
 4125 |         strncpy(addr.sun_path, path, sizeof(addr.sun_path));
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

We should also ASSERT the result to make sure path's length is not too big.

> +	ASSERT_EQ(0, bind(fd, (struct sockaddr *)&addr, sizeof(addr)));
> +
> +	if (type != SOCK_DGRAM)
> +		ASSERT_EQ(0, listen(fd, 10 /* qlen */));
> +	return fd;
> +}

^ permalink raw reply

* Re: [PATCH 0/2] fanotify: avid some premature LSM checks
From: Ondrej Mosnacek @ 2026-02-18 12:36 UTC (permalink / raw)
  To: Jan Kara
  Cc: Amir Goldstein, Matthew Bobrowski, linux-fsdevel,
	linux-security-module, selinux, linux-kernel
In-Reply-To: <yk2qcux2ee7afr24xw6p7wp4t3islu64ttfsrheac2zwr6odnw@kmagnqbldb3f>

On Tue, Feb 17, 2026 at 12:09 PM Jan Kara <jack@suse.cz> wrote:
>
> On Mon 16-02-26 16:06:23, Ondrej Mosnacek wrote:
> > Restructure some of the validity and security checks in
> > fs/notify/fanotify/fanotify_user.c to avoid generating LSM access
> > denials in the audit log where hey shouldn't be.
> >
> > Ondrej Mosnacek (2):
> >   fanotify: avoid/silence premature LSM capability checks
> >   fanotify: call fanotify_events_supported() before path_permission()
> >     and security_path_notify()
> >
> >  fs/notify/fanotify/fanotify_user.c | 50 ++++++++++++++----------------
> >  1 file changed, 23 insertions(+), 27 deletions(-)
>
> The series looks good to me as well. Thanks! I'll commit the series to my
> tree once the merge window closes and fixup the comment formatting on
> commit. No need to resend.

Great, thanks!

-- 
Ondrej Mosnacek
Senior Software Engineer, Linux Security - SELinux kernel
Red Hat, Inc.


^ permalink raw reply

* Re: [PATCH RFC] security: add LSM blob and hooks for namespaces
From: Dr. Greg @ 2026-02-18 11:15 UTC (permalink / raw)
  To: Christian Brauner
  Cc: Casey Schaufler, Paul Moore, James Morris, linux-security-module,
	linux-kernel
In-Reply-To: <20260217-glasur-hinnimmt-ac72b3e67661@brauner>

On Tue, Feb 17, 2026 at 10:38:33AM +0100, Christian Brauner wrote:

Good morning, I hope the week is going well for everyone.

> On Mon, Feb 16, 2026 at 09:34:57AM -0800, Casey Schaufler wrote:
> > On 2/16/2026 5:52 AM, Christian Brauner wrote:
> > > All namespace types now share the same ns_common infrastructure. Extend
> > > this to include a security blob so LSMs can start managing namespaces
> > > uniformly without having to add one-off hooks or security fields to
> > > every individual namespace type.
> > 
> > The implementation appears sound.
> > 
> > I have to question whether having LSM controls on namespaces is reasonable.

> This is already in active use today but only in a very limited capacity.
> This generalizes it.

This seems to be a tacid indication of the need for namespace specific
LSM policies and/or controls, and further acknowledgement, that such
controls are in active use out in the wild.

More below on the implications of this.

> > I suppose that you could have a system where (for example) SELinux runs
> > in permissive mode except within a specific user namespace, where it would
> > enforce policy. Do you have a use case in mind?

> We will use it in systemd services and containers to monitor and
> supervise namespaces.

Christian, you are no doubt not familiar with our work, but over the
last six years our team has developed and have in production the most
sophisticated implementation of LSM namespacing that has been done.
With the caveat, of course, of implementations that have been made
public.

That work has been driven by what is the clear and apparent need to
have namespace specific and orthogonal security controls and policies,
something your patch and comments seems to clearly acknowledge.  This
need is particularily important with respect to the advancements that
are needed for AI based security modeling and interdiction.

So our comments are driven by having done a bit of this before.

There has been some dialogue and debate as to whether and how LSM
namespacing should be implemented.  The essential ingredient is the
need to have a task specific context of data, which can be inherited
by subordinate processes, that can be used to evaluate the LSM
security events/hooks that are executed by tasks having access to
that context of data.

Unless we misinterpret the implementation, your patch provides such
context for any process that wishes to unshare any namespace that it
is participating in.

This in turn implies that your patch is a fundamental step forward in
LSM namespacing.  This isn't a criticism, just an observation.

The reason we can feel pretty strongly about this is that we initially
used the same strategy that you are using in a very early
implementation of TSEM.  We abandoned that approach, since the
dynamics/politics of Linux kernel development, particularily in
security, tends to disfavor having to touch core kernel
infrastructure, so we implemented the equivalent of your approach
entirely in the context of our LSM.

To widen the scope of the impact of this, your patch also lays the
framework for implementing LSM specific security policy with kernel
modules.  Again, not a criticism, just an observation, because we
implement the same capability with TSEM.

For those reading along at home.  The reason that this is safe with a
classic namespace approach and not with previous 'loadable LSM'
strategies is that a process can verify that a policy module is loaded
and prepared to handle requests to interpret the events, before the
namespace installation/activation that would drive use of the module
actually takes effect.

Your approach is quite generic, which is positive. The open question
is whether or not the strategy is generic enough to handle LSM's that
may have very dynamic and varied requirements with respect to how to
configure the policy that will be implemented for the namespace.

Hopefully all of this will enable further discussions on this issue.

Best wishes for a productive remainder of the week.

As always,
Dr. Greg

The Quixote Project - Flailing at the Travails of Cybersecurity
              https://github.com/Quixote-Project


^ permalink raw reply

* Re: [PATCH v5 3/9] samples/landlock: Add support for named UNIX domain socket restrictions
From: Mickaël Salaün @ 2026-02-18  9:37 UTC (permalink / raw)
  To: Günther Noack
  Cc: John Johansen, Justin Suess, linux-security-module, Tingmao Wang,
	Samasth Norway Ananda, Matthieu Buffet, Mikhail Ivanov,
	konstantin.meskhidze, Demi Marie Obenour, Alyssa Ross, Jann Horn,
	Tahera Fahimi
In-Reply-To: <20260215105158.28132-4-gnoack3000@gmail.com>

On Sun, Feb 15, 2026 at 11:51:51AM +0100, Günther Noack wrote:
> The access right for UNIX domain socket lookups is grouped with the
> read-write rights in the sample tool.  Rationale: In the general case,
> any operations are possible through a UNIX domain socket, including
> data-mutating operations.
> 
> Cc: Justin Suess <utilityemal77@gmail.com>
> Cc: Mickaël Salaün <mic@digikod.net>
> Signed-off-by: Günther Noack <gnoack3000@gmail.com>
> ---
>  samples/landlock/sandboxer.c | 15 ++++++++++++---
>  1 file changed, 12 insertions(+), 3 deletions(-)
> 
> diff --git a/samples/landlock/sandboxer.c b/samples/landlock/sandboxer.c
> index e7af02f98208..0bbbc5c9ead6 100644
> --- a/samples/landlock/sandboxer.c
> +++ b/samples/landlock/sandboxer.c
> @@ -111,7 +111,8 @@ static int parse_path(char *env_path, const char ***const path_list)
>  	LANDLOCK_ACCESS_FS_WRITE_FILE | \
>  	LANDLOCK_ACCESS_FS_READ_FILE | \
>  	LANDLOCK_ACCESS_FS_TRUNCATE | \
> -	LANDLOCK_ACCESS_FS_IOCTL_DEV)
> +	LANDLOCK_ACCESS_FS_IOCTL_DEV | \
> +	LANDLOCK_ACCESS_FS_RESOLVE_UNIX)
>  
>  /* clang-format on */
>  
> @@ -295,11 +296,12 @@ static bool check_ruleset_scope(const char *const env_var,
>  	LANDLOCK_ACCESS_FS_MAKE_SYM | \
>  	LANDLOCK_ACCESS_FS_REFER | \
>  	LANDLOCK_ACCESS_FS_TRUNCATE | \
> -	LANDLOCK_ACCESS_FS_IOCTL_DEV)
> +	LANDLOCK_ACCESS_FS_IOCTL_DEV | \
> +	LANDLOCK_ACCESS_FS_RESOLVE_UNIX)
>  
>  /* clang-format on */
>  
> -#define LANDLOCK_ABI_LAST 7
> +#define LANDLOCK_ABI_LAST 9
>  
>  #define XSTR(s) #s
>  #define STR(s) XSTR(s)
> @@ -444,6 +446,13 @@ int main(const int argc, char *const argv[], char *const *const envp)
>  			"provided by ABI version %d (instead of %d).\n",
>  			LANDLOCK_ABI_LAST, abi);
>  		__attribute__((fallthrough));
> +	case 7:
> +		__attribute__((fallthrough));

The current code should print the hint when ABI <= 7.  Please send a
dedicated patch to fix the TSYNC-related changes.

> +	case 8:
> +		/* Removes LANDLOCK_ACCESS_FS_RESOLVE_UNIX for ABI < 9 */
> +		ruleset_attr.handled_access_fs &=
> +			~LANDLOCK_ACCESS_FS_RESOLVE_UNIX;
> +		__attribute__((fallthrough));
>  	case LANDLOCK_ABI_LAST:
>  		break;
>  	default:
> -- 
> 2.52.0
> 
> 

^ permalink raw reply

* Re: [PATCH v5 1/9] lsm: Add LSM hook security_unix_find
From: Mickaël Salaün @ 2026-02-18  9:36 UTC (permalink / raw)
  To: Günther Noack
  Cc: John Johansen, Paul Moore, James Morris, Serge E . Hallyn,
	Tingmao Wang, Justin Suess, linux-security-module,
	Samasth Norway Ananda, Matthieu Buffet, Mikhail Ivanov,
	konstantin.meskhidze, Demi Marie Obenour, Alyssa Ross, Jann Horn,
	Tahera Fahimi, Simon Horman, netdev, Alexander Viro,
	Christian Brauner
In-Reply-To: <20260215105158.28132-2-gnoack3000@gmail.com>

On Sun, Feb 15, 2026 at 11:51:49AM +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            |  8 ++++++++
>  security/security.c           | 20 ++++++++++++++++++++
>  4 files changed, 44 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..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)

I think this hook call should be moved here, just before the
touch_atime() call for consistency with the socket type check, and to
avoid doing useless check in the hook.

>  		touch_atime(&path);
> diff --git a/security/security.c b/security/security.c
> index 67af9228c4e9..c73196b8db4b 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
> -- 
> 2.52.0
> 
> 

^ permalink raw reply

* Re: [PATCH v5 8/9] landlock: Document FS access right for pathname UNIX sockets
From: Mickaël Salaün @ 2026-02-18  9:39 UTC (permalink / raw)
  To: Günther Noack
  Cc: John Johansen, Justin Suess, linux-security-module, Tingmao Wang,
	Samasth Norway Ananda, Matthieu Buffet, Mikhail Ivanov,
	konstantin.meskhidze, Demi Marie Obenour, Alyssa Ross, Jann Horn,
	Tahera Fahimi
In-Reply-To: <20260215105158.28132-9-gnoack3000@gmail.com>

On Sun, Feb 15, 2026 at 11:51:56AM +0100, Günther Noack wrote:
> Cc: Justin Suess <utilityemal77@gmail.com>
> Cc: Mickaël Salaün <mic@digikod.net>
> Signed-off-by: Günther Noack <gnoack3000@gmail.com>
> ---
>  Documentation/userspace-api/landlock.rst | 16 +++++++++++++++-
>  1 file changed, 15 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/userspace-api/landlock.rst b/Documentation/userspace-api/landlock.rst
> index 13134bccdd39..3ba73afcbc4b 100644
> --- a/Documentation/userspace-api/landlock.rst
> +++ b/Documentation/userspace-api/landlock.rst
> @@ -77,7 +77,8 @@ to be explicit about the denied-by-default access rights.
>              LANDLOCK_ACCESS_FS_MAKE_SYM |
>              LANDLOCK_ACCESS_FS_REFER |
>              LANDLOCK_ACCESS_FS_TRUNCATE |
> -            LANDLOCK_ACCESS_FS_IOCTL_DEV,
> +            LANDLOCK_ACCESS_FS_IOCTL_DEV |
> +            LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
>          .handled_access_net =
>              LANDLOCK_ACCESS_NET_BIND_TCP |
>              LANDLOCK_ACCESS_NET_CONNECT_TCP,
> @@ -127,6 +128,12 @@ version, and only use the available subset of access rights:
>          /* Removes LANDLOCK_SCOPE_* for ABI < 6 */
>          ruleset_attr.scoped &= ~(LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET |
>                                   LANDLOCK_SCOPE_SIGNAL);
> +        __attribute__((fallthrough));
> +    case 7:
> +        __attribute__((fallthrough));

I don't think the fallthrough attribute is needed here.  Same for the
sample.

> +    case 8:
> +        /* Removes LANDLOCK_ACCESS_FS_RESOLVE_UNIX for ABI < 8 */

ABI < 9

> +        ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_RESOLVE_UNIX;
>      }
>  
>  This enables the creation of an inclusive ruleset that will contain our rules.
> @@ -685,6 +692,13 @@ enforce Landlock rulesets across all threads of the calling process
>  using the ``LANDLOCK_RESTRICT_SELF_TSYNC`` flag passed to
>  sys_landlock_restrict_self().
>  
> +Pathname UNIX sockets (ABI < 9)
> +-------------------------------
> +
> +Starting with the Landlock ABI version 9, it is possible to restrict
> +connections to pathname UNIX domain sockets (:manpage:`unix(7)`) using
> +the new ``LANDLOCK_ACCESS_FS_RESOLVE_UNIX`` right.
> +
>  .. _kernel_support:
>  
>  Kernel support
> -- 
> 2.52.0
> 
> 

^ permalink raw reply

* Re: [PATCH v5 2/9] landlock: Control pathname UNIX domain socket resolution by path
From: Mickaël Salaün @ 2026-02-18  9:37 UTC (permalink / raw)
  To: Günther Noack
  Cc: 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: <20260215105158.28132-3-gnoack3000@gmail.com>

On Sun, Feb 15, 2026 at 11:51:50AM +0100, Günther Noack wrote:
> * Add a new access right LANDLOCK_ACCESS_FS_RESOLVE_UNIX, which
>   controls the look up operations for named UNIX domain sockets.  The
>   resolution happens during connect() and sendmsg() (depending on
>   socket type).
> * Hook into the path lookup in unix_find_bsd() in af_unix.c, using a
>   LSM hook.  Make policy decisions based on the new access rights
> * Increment the Landlock ABI version.
> * Minor test adaptions to keep the tests working.
> 
> With this access right, access is granted if either of the following
> conditions is met:
> 
> * The target socket's filesystem path was allow-listed using a
>   LANDLOCK_RULE_PATH_BENEATH rule, *or*:
> * The target socket was created in the same Landlock domain in which
>   LANDLOCK_ACCESS_FS_RESOLVE_UNIX was restricted.
> 
> In case of a denial, connect() and sendmsg() return EACCES, which is
> the same error as it is returned if the user does not have the write
> bit in the traditional Unix file system permissions of that file.
> 
> This feature was created with substantial discussion and input from
> Justin Suess, Tingmao Wang and Mickaël Salaün.
> 
> Cc: Tingmao Wang <m@maowtm.org>
> Cc: Justin Suess <utilityemal77@gmail.com>
> Cc: Mickaël Salaün <mic@digikod.net>
> Suggested-by: Jann Horn <jannh@google.com>
> Link: https://github.com/landlock-lsm/linux/issues/36
> Signed-off-by: Günther Noack <gnoack3000@gmail.com>
> ---
>  include/uapi/linux/landlock.h                |  10 ++
>  security/landlock/access.h                   |  11 +-
>  security/landlock/audit.c                    |   1 +
>  security/landlock/fs.c                       | 102 ++++++++++++++++++-
>  security/landlock/limits.h                   |   2 +-
>  security/landlock/syscalls.c                 |   2 +-
>  tools/testing/selftests/landlock/base_test.c |   2 +-
>  tools/testing/selftests/landlock/fs_test.c   |   5 +-
>  8 files changed, 128 insertions(+), 7 deletions(-)
> 
> diff --git a/include/uapi/linux/landlock.h b/include/uapi/linux/landlock.h
> index f88fa1f68b77..3a8fc3af0d64 100644
> --- a/include/uapi/linux/landlock.h
> +++ b/include/uapi/linux/landlock.h
> @@ -248,6 +248,15 @@ struct landlock_net_port_attr {
>   *
>   *   This access right is available since the fifth version of the Landlock
>   *   ABI.
> + * - %LANDLOCK_ACCESS_FS_RESOLVE_UNIX: Look up pathname UNIX domain sockets
> + *   (:manpage:`unix(7)`).  On UNIX domain sockets, this restricts both calls to
> + *   :manpage:`connect(2)` as well as calls to :manpage:`sendmsg(2)` with an
> + *   explicit recipient address.
> + *
> + *   This access right only applies to connections to UNIX server sockets which
> + *   were created outside of the newly created Landlock domain (e.g. from within
> + *   a parent domain or from an unrestricted process).  Newly created UNIX
> + *   servers within the same Landlock domain continue to be accessible.

It might help to add a reference to the explicit scope mechanism.

Please squash patch 9/9 into this one and also add a reference here to
the rationale described in security/landlock.rst

>   *
>   * Whether an opened file can be truncated with :manpage:`ftruncate(2)` or used
>   * with `ioctl(2)` is determined during :manpage:`open(2)`, in the same way as
> @@ -333,6 +342,7 @@ struct landlock_net_port_attr {
>  #define LANDLOCK_ACCESS_FS_REFER			(1ULL << 13)
>  #define LANDLOCK_ACCESS_FS_TRUNCATE			(1ULL << 14)
>  #define LANDLOCK_ACCESS_FS_IOCTL_DEV			(1ULL << 15)
> +#define LANDLOCK_ACCESS_FS_RESOLVE_UNIX			(1ULL << 16)
>  /* clang-format on */
>  
>  /**
> diff --git a/security/landlock/access.h b/security/landlock/access.h
> index 42c95747d7bd..9a2991688835 100644
> --- a/security/landlock/access.h
> +++ b/security/landlock/access.h
> @@ -34,7 +34,7 @@
>  	LANDLOCK_ACCESS_FS_IOCTL_DEV)
>  /* clang-format on */
>  
> -typedef u16 access_mask_t;
> +typedef u32 access_mask_t;
>  
>  /* Makes sure all filesystem access rights can be stored. */
>  static_assert(BITS_PER_TYPE(access_mask_t) >= LANDLOCK_NUM_ACCESS_FS);
> @@ -76,6 +76,15 @@ struct layer_access_masks {
>  	access_mask_t access[LANDLOCK_MAX_NUM_LAYERS];
>  };
>  
> +static inline bool
> +layer_access_masks_empty(const struct layer_access_masks *masks)
> +{
> +	for (size_t i = 0; i < ARRAY_SIZE(masks->access); i++)
> +		if (masks->access[i])
> +			return false;
> +	return true;
> +}
> +
>  /*
>   * Tracks domains responsible of a denied access.  This avoids storing in each
>   * object the full matrix of per-layer unfulfilled access rights, which is
> diff --git a/security/landlock/audit.c b/security/landlock/audit.c
> index 60ff217ab95b..8d0edf94037d 100644
> --- a/security/landlock/audit.c
> +++ b/security/landlock/audit.c
> @@ -37,6 +37,7 @@ static const char *const fs_access_strings[] = {
>  	[BIT_INDEX(LANDLOCK_ACCESS_FS_REFER)] = "fs.refer",
>  	[BIT_INDEX(LANDLOCK_ACCESS_FS_TRUNCATE)] = "fs.truncate",
>  	[BIT_INDEX(LANDLOCK_ACCESS_FS_IOCTL_DEV)] = "fs.ioctl_dev",
> +	[BIT_INDEX(LANDLOCK_ACCESS_FS_RESOLVE_UNIX)] = "fs.resolve_unix",
>  };
>  
>  static_assert(ARRAY_SIZE(fs_access_strings) == LANDLOCK_NUM_ACCESS_FS);
> diff --git a/security/landlock/fs.c b/security/landlock/fs.c
> index e764470f588c..76035c6f2bf1 100644
> --- a/security/landlock/fs.c
> +++ b/security/landlock/fs.c
> @@ -27,6 +27,7 @@
>  #include <linux/lsm_hooks.h>
>  #include <linux/mount.h>
>  #include <linux/namei.h>
> +#include <linux/net.h>
>  #include <linux/path.h>
>  #include <linux/pid.h>
>  #include <linux/rcupdate.h>
> @@ -314,7 +315,8 @@ static struct landlock_object *get_inode_object(struct inode *const inode)
>  	LANDLOCK_ACCESS_FS_WRITE_FILE | \
>  	LANDLOCK_ACCESS_FS_READ_FILE | \
>  	LANDLOCK_ACCESS_FS_TRUNCATE | \
> -	LANDLOCK_ACCESS_FS_IOCTL_DEV)
> +	LANDLOCK_ACCESS_FS_IOCTL_DEV | \
> +	LANDLOCK_ACCESS_FS_RESOLVE_UNIX)
>  /* clang-format on */
>  
>  /*
> @@ -1561,6 +1563,103 @@ static int hook_path_truncate(const struct path *const path)
>  	return current_check_access_path(path, LANDLOCK_ACCESS_FS_TRUNCATE);
>  }
>  
> +/**
> + * unmask_scoped_access - Remove access right bits in @masks in all layers
> + *                        where @client and @server have the same domain
> + *
> + * This does the same as domain_is_scoped(), but unmasks bits in @masks.
> + * It can not return early as domain_is_scoped() does.
> + *
> + * @client: Client domain
> + * @server: Server domain
> + * @masks: Layer access masks to unmask
> + * @access: Access bit that controls scoping
> + */
> +static void unmask_scoped_access(const struct landlock_ruleset *const client,
> +				 const struct landlock_ruleset *const server,
> +				 struct layer_access_masks *const masks,
> +				 const access_mask_t access)

This helper should be moved to task.c and factored out with
domain_is_scoped().  This should be a dedicated patch.

> +{
> +	int client_layer, server_layer;
> +	const struct landlock_hierarchy *client_walker, *server_walker;
> +
> +	if (WARN_ON_ONCE(!client))
> +		return; /* should not happen */
> +
> +	if (!server)
> +		return; /* server has no Landlock domain; nothing to clear */
> +
> +	client_layer = client->num_layers - 1;
> +	client_walker = client->hierarchy;
> +	server_layer = server->num_layers - 1;
> +	server_walker = server->hierarchy;
> +
> +	/*
> +	 * Clears the access bits at all layers where the client domain is the
> +	 * same as the server domain.  We start the walk at min(client_layer,
> +	 * server_layer).  The layer bits until there can not be cleared because
> +	 * either the client or the server domain is missing.
> +	 */
> +	for (; client_layer > server_layer; client_layer--)
> +		client_walker = client_walker->parent;
> +
> +	for (; server_layer > client_layer; server_layer--)
> +		server_walker = server_walker->parent;
> +
> +	for (; client_layer >= 0; client_layer--) {
> +		if (masks->access[client_layer] & access &&
> +		    client_walker == server_walker)
> +			masks->access[client_layer] &= ~access;
> +
> +		client_walker = client_walker->parent;
> +		server_walker = server_walker->parent;
> +	}
> +}
> +
> +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,
> +	};
> +
> +	/* Lookup for the purpose of saving coredumps is OK. */
> +	if (unlikely(flags & SOCK_COREDUMP))
> +		return 0;
> +
> +	/* Access to the same (or a lower) domain is always allowed. */
> +	subject = landlock_get_applicable_subject(current_cred(),
> +						  fs_resolve_unix, NULL);
> +
> +	if (!subject)
> +		return 0;
> +
> +	if (!landlock_init_layer_masks(subject->domain, fs_resolve_unix.fs,
> +				       &layer_masks, LANDLOCK_KEY_INODE))
> +		return 0;
> +
> +	/* Checks the layers in which we are connecting within the same domain. */
> +	dom_other = landlock_cred(other->sk_socket->file->f_cred)->domain;

We need to call unix_state_lock(other) before reading it, and check for
SOCK_DEAD, and check sk_socket before dereferencing it.  Indeed,
the socket can be make orphan (see unix_dgram_sendmsg and
unix_stream_connect).  I *think* a socket cannot be "resurrected" or
recycled once dead, so we may assume there is no race condition wrt
dom_other, but please double check.  This lockless call should be made
clear in the LSM hook.  It's OK to not lock the socket before
security_unix_find() (1) because no LSM might implement and (2) they
might not need to lock the socket (e.g. if the caller is not sandboxed).

The updated code should look something like this:

unix_state_unlock(other);
if (unlikely(sock_flag(other, SOCK_DEAD) || !other->sk_socket)) {
	unix_state_unlock(other);
	return 0;
}

dom_other = landlock_cred(other->sk_socket->file->f_cred)->domain;
unix_state_unlock(other);


> +	unmask_scoped_access(subject->domain, dom_other, &layer_masks,
> +			     fs_resolve_unix.fs);
> +
> +	if (layer_access_masks_empty(&layer_masks))
> +		return 0;
> +
> +	/* Checks the connections to allow-listed paths. */
> +	if (is_access_to_paths_allowed(subject->domain, path,
> +				       fs_resolve_unix.fs, &layer_masks,
> +				       &request, NULL, 0, NULL, NULL, NULL))
> +		return 0;
> +
> +	landlock_log_denial(subject, &request);
> +	return -EACCES;
> +}
> +
>  /* File hooks */
>  
>  /**
> @@ -1838,6 +1937,7 @@ static struct security_hook_list landlock_hooks[] __ro_after_init = {
>  	LSM_HOOK_INIT(path_unlink, hook_path_unlink),
>  	LSM_HOOK_INIT(path_rmdir, hook_path_rmdir),
>  	LSM_HOOK_INIT(path_truncate, hook_path_truncate),
> +	LSM_HOOK_INIT(unix_find, hook_unix_find),
>  
>  	LSM_HOOK_INIT(file_alloc_security, hook_file_alloc_security),
>  	LSM_HOOK_INIT(file_open, hook_file_open),
> diff --git a/security/landlock/limits.h b/security/landlock/limits.h
> index eb584f47288d..b454ad73b15e 100644
> --- a/security/landlock/limits.h
> +++ b/security/landlock/limits.h
> @@ -19,7 +19,7 @@
>  #define LANDLOCK_MAX_NUM_LAYERS		16
>  #define LANDLOCK_MAX_NUM_RULES		U32_MAX
>  
> -#define LANDLOCK_LAST_ACCESS_FS		LANDLOCK_ACCESS_FS_IOCTL_DEV
> +#define LANDLOCK_LAST_ACCESS_FS		LANDLOCK_ACCESS_FS_RESOLVE_UNIX
>  #define LANDLOCK_MASK_ACCESS_FS		((LANDLOCK_LAST_ACCESS_FS << 1) - 1)
>  #define LANDLOCK_NUM_ACCESS_FS		__const_hweight64(LANDLOCK_MASK_ACCESS_FS)
>  
> diff --git a/security/landlock/syscalls.c b/security/landlock/syscalls.c
> index 0d66a68677b7..933902d43241 100644
> --- a/security/landlock/syscalls.c
> +++ b/security/landlock/syscalls.c
> @@ -164,7 +164,7 @@ static const struct file_operations ruleset_fops = {
>   * If the change involves a fix that requires userspace awareness, also update
>   * the errata documentation in Documentation/userspace-api/landlock.rst .
>   */
> -const int landlock_abi_version = 8;
> +const int landlock_abi_version = 9;
>  
>  /**
>   * sys_landlock_create_ruleset - Create a new ruleset
> diff --git a/tools/testing/selftests/landlock/base_test.c b/tools/testing/selftests/landlock/base_test.c
> index 0fea236ef4bd..30d37234086c 100644
> --- a/tools/testing/selftests/landlock/base_test.c
> +++ b/tools/testing/selftests/landlock/base_test.c
> @@ -76,7 +76,7 @@ TEST(abi_version)
>  	const struct landlock_ruleset_attr ruleset_attr = {
>  		.handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE,
>  	};
> -	ASSERT_EQ(8, landlock_create_ruleset(NULL, 0,
> +	ASSERT_EQ(9, landlock_create_ruleset(NULL, 0,
>  					     LANDLOCK_CREATE_RULESET_VERSION));
>  
>  	ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0,
> diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c
> index 968a91c927a4..b318627e7561 100644
> --- a/tools/testing/selftests/landlock/fs_test.c
> +++ b/tools/testing/selftests/landlock/fs_test.c
> @@ -575,9 +575,10 @@ TEST_F_FORK(layout1, inval)
>  	LANDLOCK_ACCESS_FS_WRITE_FILE | \
>  	LANDLOCK_ACCESS_FS_READ_FILE | \
>  	LANDLOCK_ACCESS_FS_TRUNCATE | \
> -	LANDLOCK_ACCESS_FS_IOCTL_DEV)
> +	LANDLOCK_ACCESS_FS_IOCTL_DEV | \
> +	LANDLOCK_ACCESS_FS_RESOLVE_UNIX)
>  
> -#define ACCESS_LAST LANDLOCK_ACCESS_FS_IOCTL_DEV
> +#define ACCESS_LAST LANDLOCK_ACCESS_FS_RESOLVE_UNIX
>  
>  #define ACCESS_ALL ( \
>  	ACCESS_FILE | \
> -- 
> 2.52.0
> 
> 

^ permalink raw reply

* Re: [PATCH] xfrm: kill xfrm_dev_{state,policy}_flush_secctx_check()
From: Steffen Klassert @ 2026-02-18  9:22 UTC (permalink / raw)
  To: Tetsuo Handa
  Cc: Paul Moore, SELinux, linux-security-module, Herbert Xu,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Network Development
In-Reply-To: <d20f1b63-714f-48ba-9bee-cd074205404f@I-love.SAKURA.ne.jp>

On Fri, Feb 13, 2026 at 10:59:15PM +0900, Tetsuo Handa wrote:
> On 2026/02/13 19:19, Steffen Klassert wrote:
> On 2026/02/13 19:19, Steffen Klassert wrote:
> >> The NETDEV_UNREGISTER path can be triggered by just doing "unshare -n ip addr show"
> >> (i.e. implicit cleanup of a network namespace due to termination of init process in
> >> that namespace). We are not allowed to reject the cleanup_net() route.
> > 
> > And here we come to the other problem I mentioned. When a LSM policy
> > rejects to flush the xfrm states and policies on network namespace
> > exit, we leak all the xfrm states and policies in that namespace.
> > Here we have no other option, we must flush the xfrm states and
> > policies regardless of any LSM policy. This can be fixed with
> > something like that:
> 
> This something is what I explained at
> https://lkml.kernel.org/r/1bb453af-3ef2-4ab6-a909-0705bd07c136@I-love.SAKURA.ne.jp .
> The "task_valid" argument does not always reflect whether LSM policy can reject or not.

That was to fix the memleak on network namespace exit.
The task_valid check should be ok for xfrm_policy_flush()
and xfrm_state_flush().

> 
> Anyway, the patch to add xfrm_dev_unregister(dev) seems OK if we do like
> https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit?h=next-20260123&id=fc0f090e41e652d158f946c616cdd82baed3c8f4 ?

That would be OK as a first fix. Later we should
just unlink policies and states from the device,
as explained in my last mail.

^ permalink raw reply

* Re: [PATCH RFC] security: add LSM blob and hooks for namespaces
From: Casey Schaufler @ 2026-02-17 17:29 UTC (permalink / raw)
  To: Christian Brauner
  Cc: Paul Moore, James Morris, linux-security-module, linux-kernel,
	Casey Schaufler
In-Reply-To: <20260217-glasur-hinnimmt-ac72b3e67661@brauner>

On 2/17/2026 1:38 AM, Christian Brauner wrote:
> On Mon, Feb 16, 2026 at 09:34:57AM -0800, Casey Schaufler wrote:
>> On 2/16/2026 5:52 AM, Christian Brauner wrote:
>>> All namespace types now share the same ns_common infrastructure. Extend
>>> this to include a security blob so LSMs can start managing namespaces
>>> uniformly without having to add one-off hooks or security fields to
>>> every individual namespace type.
>> The implementation appears sound.
>>
>> I have to question whether having LSM controls on namespaces is reasonable.
> This is already in active use today but only in a very limited capacity.
> This generalizes it.
>
>> I suppose that you could have a system where (for example) SELinux runs
>> in permissive mode except within a specific user namespace, where it would
>> enforce policy. Do you have a use case in mind?
> We will use it in systemd services and containers to monitor and
> supervise namespaces.

While I am not among them, many people have objected strongly to making
containers an identified entity in the kernel. If these hooks were available
implementing a container scheme completely within the kernel would be
reasonably strait forward. I might consider tackling it myself.

I am also reminded of the kdbus effort of a decade ago:

	https://www.linuxfoundation.org/blog/blog/kdbus-details

Are we ready for ksystemd? UNIX systems of the 1980's suffered greatly from
an excessive enthusiasm for pushing user space functionality (e.g. STREAMS)
into the kernel. Systemd is a fine scheme, but so was inittab, in a very
different way. Adding kernel facilities to support particular application
schemes is very tempting, but often leads to dead code and interfaces that
require maintenance long after the user space scheme has moved on.


^ permalink raw reply

* Re: [PATCH v2 1/2] landlock: Fully release unused TSYNC work entries
From: Günther Noack @ 2026-02-17 16:35 UTC (permalink / raw)
  To: Mickaël Salaün; +Cc: linux-security-module, Jann Horn
In-Reply-To: <20260217.cheoghae8Ahh@digikod.net>

On Tue, Feb 17, 2026 at 02:52:46PM +0100, Mickaël Salaün wrote:
> On Tue, Feb 17, 2026 at 01:41:11PM +0100, Günther Noack wrote:
> > On Tue, Feb 17, 2026 at 01:23:39PM +0100, Mickaël Salaün wrote:
> > > +	memset(ctx, 0, sizeof(*ctx));
> > 
> > Minor (and highly optional) remark, this is the same as
> > 
> >   *ctx = (struct tsync_work){};
> 
> What about:
> 
> *ctx = (typeof(*ctx)){};

I find that harder to read, because it is less commonly seen and the typeof() is
an indirection that makes me think as a reader.  But at this point, this is only
a vague opinion and I don't feel strongly about it.  Please submit either one of
these three options :)

—Günther

^ permalink raw reply

* Re: [PATCH v2 1/2] landlock: Fully release unused TSYNC work entries
From: Mickaël Salaün @ 2026-02-17 13:52 UTC (permalink / raw)
  To: Günther Noack; +Cc: linux-security-module, Jann Horn
In-Reply-To: <aZRh52TIPAmMPJxc@google.com>

On Tue, Feb 17, 2026 at 01:41:11PM +0100, Günther Noack wrote:
> On Tue, Feb 17, 2026 at 01:23:39PM +0100, Mickaël Salaün wrote:
> > If task_work_add() failed, ctx->task is put but the tsync_works struct
> > is not reset to its previous state.  The first consequence is that the
> > kernel allocates memory for dying threads, which could lead to
> > user-accounted memory exhaustion (not very useful nor specific to this
> > case).  The second consequence is that task_work_cancel(), called by
> > cancel_tsync_works(), can dereference a NULL task pointer.
> > 
> > Fix this issues by keeping a consistent works->size wrt the added task
> > work.  This is done in a new tsync_works_trim() helper which also cleans
> > up the shared_ctx and work fields.
> > 
> > As a safeguard, add a pointer check to cancel_tsync_works() and update
> > tsync_works_release() accordingly.
> > 
> > Cc: Günther Noack <gnoack@google.com>
> > Cc: Jann Horn <jannh@google.com>
> > Signed-off-by: Mickaël Salaün <mic@digikod.net>
> > ---
> > 
> > Changes since v1:
> > https://lore.kernel.org/all/20260216142641.2100407-1-mic@digikod.net/
> > - Move the return/release logic into a new tsync_works_trim() helper
> >   (suggested by Günther).
> > - Reset the whole ctx with memset().
> > - Add an unlinkely(err).
> > ---
> >  security/landlock/tsync.c | 47 ++++++++++++++++++++++++++++++++++-----
> >  1 file changed, 41 insertions(+), 6 deletions(-)
> > 
> > diff --git a/security/landlock/tsync.c b/security/landlock/tsync.c
> > index 0d2b9c646030..42cc0ef0c704 100644
> > --- a/security/landlock/tsync.c
> > +++ b/security/landlock/tsync.c
> > @@ -203,6 +203,40 @@ static struct tsync_work *tsync_works_provide(struct tsync_works *s,
> >  	return ctx;
> >  }
> >  
> > +/**
> > + * tsync_works_trim - Put the last tsync_work element
> > + *
> > + * @s: TSYNC works to trim.
> > + *
> > + * Put the last task and decrement the size of @s.
> > + *
> > + * This helper does not cancel a running task, but just reset the last element
> > + * to zero.
> > + */
> > +static void tsync_works_trim(struct tsync_works *s)
> > +{
> > +	struct tsync_work *ctx;
> > +
> > +	if (WARN_ON_ONCE(s->size <= 0))
> > +		return;
> > +
> > +	ctx = s->works[s->size - 1];
> > +
> > +	/*
> > +	 * For consistency, remove the task from ctx so that it does not look like
> > +	 * we handed it a task_work.
> > +	 */
> > +	put_task_struct(ctx->task);
> > +	memset(ctx, 0, sizeof(*ctx));
> 
> Minor (and highly optional) remark, this is the same as
> 
>   *ctx = (struct tsync_work){};

What about:

*ctx = (typeof(*ctx)){};

> 
> which I find slightly easier to read when resetting a struct value.
> Both is fine though.
> 
> > +
> > +	/*
> > +	 * Cancel the tsync_works_provide() change to recycle the reserved memory
> > +	 * for the next thread, if any.  This also ensures that cancel_tsync_works()
> > +	 * and tsync_works_release() do not see any NULL task pointers.
> > +	 */
> > +	s->size--;
> > +}
> > +
> >  /*
> >   * tsync_works_grow_by - preallocates space for n more contexts in s
> >   *
> > @@ -276,7 +310,7 @@ static void tsync_works_release(struct tsync_works *s)
> >  	size_t i;
> >  
> >  	for (i = 0; i < s->size; i++) {
> > -		if (!s->works[i]->task)
> > +		if (WARN_ON_ONCE(!s->works[i]->task))
> >  			continue;
> >  
> >  		put_task_struct(s->works[i]->task);
> > @@ -379,16 +413,14 @@ static bool schedule_task_work(struct tsync_works *works,
> >  
> >  		init_task_work(&ctx->work, restrict_one_thread_callback);
> >  		err = task_work_add(thread, &ctx->work, TWA_SIGNAL);
> > -		if (err) {
> > +		if (unlikely(err)) {
> >  			/*
> >  			 * task_work_add() only fails if the task is about to exit.  We
> >  			 * checked that earlier, but it can happen as a race.  Resume
> >  			 * without setting an error, as the task is probably gone in the
> > -			 * next loop iteration.  For consistency, remove the task from ctx
> > -			 * so that it does not look like we handed it a task_work.
> > +			 * next loop iteration.
> >  			 */
> > -			put_task_struct(ctx->task);
> > -			ctx->task = NULL;
> > +			tsync_works_trim(works);
> >  
> >  			atomic_dec(&shared_ctx->num_preparing);
> >  			atomic_dec(&shared_ctx->num_unfinished);
> > @@ -412,6 +444,9 @@ static void cancel_tsync_works(struct tsync_works *works,
> >  	int i;
> >  
> >  	for (i = 0; i < works->size; i++) {
> > +		if (WARN_ON_ONCE(!works->works[i]->task))
> > +			continue;
> > +
> >  		if (!task_work_cancel(works->works[i]->task,
> >  				      &works->works[i]->work))
> >  			continue;
> > -- 
> > 2.53.0
> > 
> 
> Reviewed-by: Günther Noack <gnoack@google.com>
> 
> Thanks for spotting and fixing this!
> —Günther
> 

^ permalink raw reply

* Re: [PATCH v2 1/2] landlock: Fully release unused TSYNC work entries
From: Günther Noack @ 2026-02-17 12:41 UTC (permalink / raw)
  To: Mickaël Salaün; +Cc: linux-security-module, Jann Horn
In-Reply-To: <20260217122341.2359582-1-mic@digikod.net>

On Tue, Feb 17, 2026 at 01:23:39PM +0100, Mickaël Salaün wrote:
> If task_work_add() failed, ctx->task is put but the tsync_works struct
> is not reset to its previous state.  The first consequence is that the
> kernel allocates memory for dying threads, which could lead to
> user-accounted memory exhaustion (not very useful nor specific to this
> case).  The second consequence is that task_work_cancel(), called by
> cancel_tsync_works(), can dereference a NULL task pointer.
> 
> Fix this issues by keeping a consistent works->size wrt the added task
> work.  This is done in a new tsync_works_trim() helper which also cleans
> up the shared_ctx and work fields.
> 
> As a safeguard, add a pointer check to cancel_tsync_works() and update
> tsync_works_release() accordingly.
> 
> Cc: Günther Noack <gnoack@google.com>
> Cc: Jann Horn <jannh@google.com>
> Signed-off-by: Mickaël Salaün <mic@digikod.net>
> ---
> 
> Changes since v1:
> https://lore.kernel.org/all/20260216142641.2100407-1-mic@digikod.net/
> - Move the return/release logic into a new tsync_works_trim() helper
>   (suggested by Günther).
> - Reset the whole ctx with memset().
> - Add an unlinkely(err).
> ---
>  security/landlock/tsync.c | 47 ++++++++++++++++++++++++++++++++++-----
>  1 file changed, 41 insertions(+), 6 deletions(-)
> 
> diff --git a/security/landlock/tsync.c b/security/landlock/tsync.c
> index 0d2b9c646030..42cc0ef0c704 100644
> --- a/security/landlock/tsync.c
> +++ b/security/landlock/tsync.c
> @@ -203,6 +203,40 @@ static struct tsync_work *tsync_works_provide(struct tsync_works *s,
>  	return ctx;
>  }
>  
> +/**
> + * tsync_works_trim - Put the last tsync_work element
> + *
> + * @s: TSYNC works to trim.
> + *
> + * Put the last task and decrement the size of @s.
> + *
> + * This helper does not cancel a running task, but just reset the last element
> + * to zero.
> + */
> +static void tsync_works_trim(struct tsync_works *s)
> +{
> +	struct tsync_work *ctx;
> +
> +	if (WARN_ON_ONCE(s->size <= 0))
> +		return;
> +
> +	ctx = s->works[s->size - 1];
> +
> +	/*
> +	 * For consistency, remove the task from ctx so that it does not look like
> +	 * we handed it a task_work.
> +	 */
> +	put_task_struct(ctx->task);
> +	memset(ctx, 0, sizeof(*ctx));

Minor (and highly optional) remark, this is the same as

  *ctx = (struct tsync_work){};

which I find slightly easier to read when resetting a struct value.
Both is fine though.

> +
> +	/*
> +	 * Cancel the tsync_works_provide() change to recycle the reserved memory
> +	 * for the next thread, if any.  This also ensures that cancel_tsync_works()
> +	 * and tsync_works_release() do not see any NULL task pointers.
> +	 */
> +	s->size--;
> +}
> +
>  /*
>   * tsync_works_grow_by - preallocates space for n more contexts in s
>   *
> @@ -276,7 +310,7 @@ static void tsync_works_release(struct tsync_works *s)
>  	size_t i;
>  
>  	for (i = 0; i < s->size; i++) {
> -		if (!s->works[i]->task)
> +		if (WARN_ON_ONCE(!s->works[i]->task))
>  			continue;
>  
>  		put_task_struct(s->works[i]->task);
> @@ -379,16 +413,14 @@ static bool schedule_task_work(struct tsync_works *works,
>  
>  		init_task_work(&ctx->work, restrict_one_thread_callback);
>  		err = task_work_add(thread, &ctx->work, TWA_SIGNAL);
> -		if (err) {
> +		if (unlikely(err)) {
>  			/*
>  			 * task_work_add() only fails if the task is about to exit.  We
>  			 * checked that earlier, but it can happen as a race.  Resume
>  			 * without setting an error, as the task is probably gone in the
> -			 * next loop iteration.  For consistency, remove the task from ctx
> -			 * so that it does not look like we handed it a task_work.
> +			 * next loop iteration.
>  			 */
> -			put_task_struct(ctx->task);
> -			ctx->task = NULL;
> +			tsync_works_trim(works);
>  
>  			atomic_dec(&shared_ctx->num_preparing);
>  			atomic_dec(&shared_ctx->num_unfinished);
> @@ -412,6 +444,9 @@ static void cancel_tsync_works(struct tsync_works *works,
>  	int i;
>  
>  	for (i = 0; i < works->size; i++) {
> +		if (WARN_ON_ONCE(!works->works[i]->task))
> +			continue;
> +
>  		if (!task_work_cancel(works->works[i]->task,
>  				      &works->works[i]->work))
>  			continue;
> -- 
> 2.53.0
> 

Reviewed-by: Günther Noack <gnoack@google.com>

Thanks for spotting and fixing this!
—Günther

^ permalink raw reply

* [PATCH v2 1/2] landlock: Fully release unused TSYNC work entries
From: Mickaël Salaün @ 2026-02-17 12:23 UTC (permalink / raw)
  To: Günther Noack
  Cc: Mickaël Salaün, linux-security-module, Jann Horn

If task_work_add() failed, ctx->task is put but the tsync_works struct
is not reset to its previous state.  The first consequence is that the
kernel allocates memory for dying threads, which could lead to
user-accounted memory exhaustion (not very useful nor specific to this
case).  The second consequence is that task_work_cancel(), called by
cancel_tsync_works(), can dereference a NULL task pointer.

Fix this issues by keeping a consistent works->size wrt the added task
work.  This is done in a new tsync_works_trim() helper which also cleans
up the shared_ctx and work fields.

As a safeguard, add a pointer check to cancel_tsync_works() and update
tsync_works_release() accordingly.

Cc: Günther Noack <gnoack@google.com>
Cc: Jann Horn <jannh@google.com>
Signed-off-by: Mickaël Salaün <mic@digikod.net>
---

Changes since v1:
https://lore.kernel.org/all/20260216142641.2100407-1-mic@digikod.net/
- Move the return/release logic into a new tsync_works_trim() helper
  (suggested by Günther).
- Reset the whole ctx with memset().
- Add an unlinkely(err).
---
 security/landlock/tsync.c | 47 ++++++++++++++++++++++++++++++++++-----
 1 file changed, 41 insertions(+), 6 deletions(-)

diff --git a/security/landlock/tsync.c b/security/landlock/tsync.c
index 0d2b9c646030..42cc0ef0c704 100644
--- a/security/landlock/tsync.c
+++ b/security/landlock/tsync.c
@@ -203,6 +203,40 @@ static struct tsync_work *tsync_works_provide(struct tsync_works *s,
 	return ctx;
 }
 
+/**
+ * tsync_works_trim - Put the last tsync_work element
+ *
+ * @s: TSYNC works to trim.
+ *
+ * Put the last task and decrement the size of @s.
+ *
+ * This helper does not cancel a running task, but just reset the last element
+ * to zero.
+ */
+static void tsync_works_trim(struct tsync_works *s)
+{
+	struct tsync_work *ctx;
+
+	if (WARN_ON_ONCE(s->size <= 0))
+		return;
+
+	ctx = s->works[s->size - 1];
+
+	/*
+	 * For consistency, remove the task from ctx so that it does not look like
+	 * we handed it a task_work.
+	 */
+	put_task_struct(ctx->task);
+	memset(ctx, 0, sizeof(*ctx));
+
+	/*
+	 * Cancel the tsync_works_provide() change to recycle the reserved memory
+	 * for the next thread, if any.  This also ensures that cancel_tsync_works()
+	 * and tsync_works_release() do not see any NULL task pointers.
+	 */
+	s->size--;
+}
+
 /*
  * tsync_works_grow_by - preallocates space for n more contexts in s
  *
@@ -276,7 +310,7 @@ static void tsync_works_release(struct tsync_works *s)
 	size_t i;
 
 	for (i = 0; i < s->size; i++) {
-		if (!s->works[i]->task)
+		if (WARN_ON_ONCE(!s->works[i]->task))
 			continue;
 
 		put_task_struct(s->works[i]->task);
@@ -379,16 +413,14 @@ static bool schedule_task_work(struct tsync_works *works,
 
 		init_task_work(&ctx->work, restrict_one_thread_callback);
 		err = task_work_add(thread, &ctx->work, TWA_SIGNAL);
-		if (err) {
+		if (unlikely(err)) {
 			/*
 			 * task_work_add() only fails if the task is about to exit.  We
 			 * checked that earlier, but it can happen as a race.  Resume
 			 * without setting an error, as the task is probably gone in the
-			 * next loop iteration.  For consistency, remove the task from ctx
-			 * so that it does not look like we handed it a task_work.
+			 * next loop iteration.
 			 */
-			put_task_struct(ctx->task);
-			ctx->task = NULL;
+			tsync_works_trim(works);
 
 			atomic_dec(&shared_ctx->num_preparing);
 			atomic_dec(&shared_ctx->num_unfinished);
@@ -412,6 +444,9 @@ static void cancel_tsync_works(struct tsync_works *works,
 	int i;
 
 	for (i = 0; i < works->size; i++) {
+		if (WARN_ON_ONCE(!works->works[i]->task))
+			continue;
+
 		if (!task_work_cancel(works->works[i]->task,
 				      &works->works[i]->work))
 			continue;
-- 
2.53.0


^ permalink raw reply related

* [PATCH v2 2/2] landlock: Improve TSYNC types
From: Mickaël Salaün @ 2026-02-17 12:23 UTC (permalink / raw)
  To: Günther Noack
  Cc: Mickaël Salaün, linux-security-module, Jann Horn
In-Reply-To: <20260217122341.2359582-1-mic@digikod.net>

Constify pointers when it makes sense.

Consistently use size_t for loops, especially to match works->size type.

Add new lines to improve readability.

Cc: Jann Horn <jannh@google.com>
Reviewed-by: Günther Noack <gnoack@google.com>
Signed-off-by: Mickaël Salaün <mic@digikod.net>
---

Changes since v1:
- Added Reviewed-by Günther.
---
 security/landlock/tsync.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/security/landlock/tsync.c b/security/landlock/tsync.c
index 42cc0ef0c704..c588cdd111d3 100644
--- a/security/landlock/tsync.c
+++ b/security/landlock/tsync.c
@@ -290,13 +290,14 @@ static int tsync_works_grow_by(struct tsync_works *s, size_t n, gfp_t flags)
  * tsync_works_contains - checks for presence of task in s
  */
 static bool tsync_works_contains_task(const struct tsync_works *s,
-				      struct task_struct *task)
+				      const struct task_struct *task)
 {
 	size_t i;
 
 	for (i = 0; i < s->size; i++)
 		if (s->works[i]->task == task)
 			return true;
+
 	return false;
 }
 
@@ -318,6 +319,7 @@ static void tsync_works_release(struct tsync_works *s)
 
 	for (i = 0; i < s->capacity; i++)
 		kfree(s->works[i]);
+
 	kfree(s->works);
 	s->works = NULL;
 	s->size = 0;
@@ -329,7 +331,7 @@ static void tsync_works_release(struct tsync_works *s)
  */
 static size_t count_additional_threads(const struct tsync_works *works)
 {
-	struct task_struct *thread, *caller;
+	const struct task_struct *caller, *thread;
 	size_t n = 0;
 
 	caller = current;
@@ -368,7 +370,8 @@ static bool schedule_task_work(struct tsync_works *works,
 			       struct tsync_shared_context *shared_ctx)
 {
 	int err;
-	struct task_struct *thread, *caller;
+	const struct task_struct *caller;
+	struct task_struct *thread;
 	struct tsync_work *ctx;
 	bool found_more_threads = false;
 
@@ -438,10 +441,10 @@ static bool schedule_task_work(struct tsync_works *works,
  * shared_ctx->num_preparing and shared_ctx->num_unfished and mark the two
  * completions if needed, as if the task was never scheduled.
  */
-static void cancel_tsync_works(struct tsync_works *works,
+static void cancel_tsync_works(const struct tsync_works *works,
 			       struct tsync_shared_context *shared_ctx)
 {
-	int i;
+	size_t i;
 
 	for (i = 0; i < works->size; i++) {
 		if (WARN_ON_ONCE(!works->works[i]->task))
-- 
2.53.0


^ permalink raw reply related

* Re: [RFC PATCH] fs/pidfs: Add permission check to pidfd_info()
From: Christian Brauner @ 2026-02-17 12:01 UTC (permalink / raw)
  To: Daniel Durning
  Cc: linux-fsdevel, linux-security-module, selinux, viro, jack, paul,
	stephen.smalley.work, omosnace, Oleg Nesterov
In-Reply-To: <CAKrb_fEXR0uQnX5iK-ACH=amKMQ8qBSPGXmJb=1PgvEq8qsDEQ@mail.gmail.com>

On Wed, Feb 11, 2026 at 02:43:21PM -0500, Daniel Durning wrote:
> 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 guess we can see what it looks like.

^ permalink raw reply

* Re: [PATCH RFC] security: add LSM blob and hooks for namespaces
From: Paul Moore @ 2026-02-17 11:33 UTC (permalink / raw)
  To: Christian Brauner; +Cc: James Morris, linux-security-module, linux-kernel
In-Reply-To: <20260217-armer-wegfielen-ffb2cdc60283@brauner>

On February 17, 2026 9:54:42 AM Christian Brauner <brauner@kernel.org> wrote:
> On Mon, Feb 16, 2026 at 07:53:11PM +0100, Paul Moore wrote:
>> On February 16, 2026 2:52:34 PM Christian Brauner <brauner@kernel.org> wrote:
>>> All namespace types now share the same ns_common infrastructure. Extend
>>> this to include a security blob so LSMs can start managing namespaces
>>> uniformly without having to add one-off hooks or security fields to
>>> every individual namespace type.
>>>
>>> Add a ns_security pointer to ns_common and the corresponding lbs_ns
>>> blob size to lsm_blob_sizes. Allocation and freeing hooks are called
>>> from the common __ns_common_init() and __ns_common_free() paths so
>>> every namespace type gets covered in one go. All information about the
>>> namespace type and the appropriate casting helpers to get at the
>>> containing namespace are available via ns_common making it
>>> straightforward for LSMs to differentiate when they need to.
>>>
>>> A namespace_install hook is called from validate_ns() during setns(2)
>>> giving LSMs a chance to enforce policy on namespace transitions.
>>>
>>> Individual namespace types can still have their own specialized security
>>> hooks when needed. This is just the common baseline that makes it easy
>>> to track and manage namespaces from the security side without requiring
>>> every namespace type to reinvent the wheel.
>>>
>>> Signed-off-by: Christian Brauner <brauner@kernel.org>
>>> ---
>>> include/linux/lsm_hook_defs.h      |  3 ++
>>> include/linux/lsm_hooks.h          |  1 +
>>> include/linux/ns/ns_common_types.h |  3 ++
>>> include/linux/security.h           | 20 ++++++++++
>>> kernel/nscommon.c                  | 12 ++++++
>>> kernel/nsproxy.c                   |  8 +++-
>>> security/lsm_init.c                |  2 +
>>> security/security.c                | 76 ++++++++++++++++++++++++++++++++++++++
>>> 8 files changed, 124 insertions(+), 1 deletion(-)
>>
>> I still have limited network access for a few more days, but a couple of
>> quick comments in no particular order ...
>>
>> Generally speaking we don't add things to the LSM interface without a user,
>> and I can't think of a good reason why we would want to do things
>> differently here.  This means that when you propose something like this you
>> should also propose an addition to one of the in-tree LSMs to make use of
>> it. While the guidance doc linked below (also linked in the LSM MAINTAINERS
>> entry) doesn't have any guidance for the LSM blobs as they are generally a
>> byproduct of the hooks, if you are looking for some general info I think the
>> bits on adding a new LSM hook would be very close to what we would expect
>> for blob additions.
>>
>> https://github.com/LinuxSecurityModule/kernel/blob/main/README.md
>>
>> Getting to the specifics of namespace related APIs, we've had a lot of
>> discussions about namespacing and my current opinion is that we need to sort
>> out if we want a userspace API at the LSM framework layer, or if we want to
>> do that at the individual LSM layer; there is a lot of nuance there and
>> while one option may seem like an obvious choice, we need some more
>> discussion and I need a chance to get caught up on the threads. Once we have
>> an API decision then we can start sorting out the implementation details
>> like the LSM blobs.
>
> I might be misunderstanding you but what you are talking about seems
> namespacing the LSM layer itself.
>
> But I cannot stress enough this is not at all what this patchset is
> doing. :)

Likely also a misunderstanding on my end as I triage email/patches via phone.

Regardless, the guidance in the doc I linked regarding the addition of new 
LSM hooks would appear to apply here.

--
paul-moore.com



^ permalink raw reply

* Re: [PATCH 0/2] fanotify: avid some premature LSM checks
From: Jan Kara @ 2026-02-17 11:09 UTC (permalink / raw)
  To: Ondrej Mosnacek
  Cc: Jan Kara, Amir Goldstein, Matthew Bobrowski, linux-fsdevel,
	linux-security-module, selinux, linux-kernel
In-Reply-To: <20260216150625.793013-1-omosnace@redhat.com>

On Mon 16-02-26 16:06:23, Ondrej Mosnacek wrote:
> Restructure some of the validity and security checks in
> fs/notify/fanotify/fanotify_user.c to avoid generating LSM access
> denials in the audit log where hey shouldn't be.
> 
> Ondrej Mosnacek (2):
>   fanotify: avoid/silence premature LSM capability checks
>   fanotify: call fanotify_events_supported() before path_permission()
>     and security_path_notify()
> 
>  fs/notify/fanotify/fanotify_user.c | 50 ++++++++++++++----------------
>  1 file changed, 23 insertions(+), 27 deletions(-)

The series looks good to me as well. Thanks! I'll commit the series to my
tree once the merge window closes and fixup the comment formatting on
commit. No need to resend.

								Honza
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply

* Re: [PATCH RFC] security: add LSM blob and hooks for namespaces
From: Christian Brauner @ 2026-02-17  9:38 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: Paul Moore, James Morris, linux-security-module, linux-kernel
In-Reply-To: <fb40e938-f6b2-45cf-b8ab-246cd6939582@schaufler-ca.com>

On Mon, Feb 16, 2026 at 09:34:57AM -0800, Casey Schaufler wrote:
> On 2/16/2026 5:52 AM, Christian Brauner wrote:
> > All namespace types now share the same ns_common infrastructure. Extend
> > this to include a security blob so LSMs can start managing namespaces
> > uniformly without having to add one-off hooks or security fields to
> > every individual namespace type.
> 
> The implementation appears sound.
> 
> I have to question whether having LSM controls on namespaces is reasonable.

This is already in active use today but only in a very limited capacity.
This generalizes it.

> I suppose that you could have a system where (for example) SELinux runs
> in permissive mode except within a specific user namespace, where it would
> enforce policy. Do you have a use case in mind?

We will use it in systemd services and containers to monitor and
supervise namespaces.

^ permalink raw reply

* Re: [PATCH RFC] security: add LSM blob and hooks for namespaces
From: Christian Brauner @ 2026-02-17  8:54 UTC (permalink / raw)
  To: Paul Moore; +Cc: James Morris, linux-security-module, linux-kernel
In-Reply-To: <19c67cca5d8.2843.85c95baa4474aabc7814e68940a78392@paul-moore.com>

On Mon, Feb 16, 2026 at 07:53:11PM +0100, Paul Moore wrote:
> On February 16, 2026 2:52:34 PM Christian Brauner <brauner@kernel.org> wrote:
> > All namespace types now share the same ns_common infrastructure. Extend
> > this to include a security blob so LSMs can start managing namespaces
> > uniformly without having to add one-off hooks or security fields to
> > every individual namespace type.
> > 
> > Add a ns_security pointer to ns_common and the corresponding lbs_ns
> > blob size to lsm_blob_sizes. Allocation and freeing hooks are called
> > from the common __ns_common_init() and __ns_common_free() paths so
> > every namespace type gets covered in one go. All information about the
> > namespace type and the appropriate casting helpers to get at the
> > containing namespace are available via ns_common making it
> > straightforward for LSMs to differentiate when they need to.
> > 
> > A namespace_install hook is called from validate_ns() during setns(2)
> > giving LSMs a chance to enforce policy on namespace transitions.
> > 
> > Individual namespace types can still have their own specialized security
> > hooks when needed. This is just the common baseline that makes it easy
> > to track and manage namespaces from the security side without requiring
> > every namespace type to reinvent the wheel.
> > 
> > Signed-off-by: Christian Brauner <brauner@kernel.org>
> > ---
> > include/linux/lsm_hook_defs.h      |  3 ++
> > include/linux/lsm_hooks.h          |  1 +
> > include/linux/ns/ns_common_types.h |  3 ++
> > include/linux/security.h           | 20 ++++++++++
> > kernel/nscommon.c                  | 12 ++++++
> > kernel/nsproxy.c                   |  8 +++-
> > security/lsm_init.c                |  2 +
> > security/security.c                | 76 ++++++++++++++++++++++++++++++++++++++
> > 8 files changed, 124 insertions(+), 1 deletion(-)
> 
> I still have limited network access for a few more days, but a couple of
> quick comments in no particular order ...
> 
> Generally speaking we don't add things to the LSM interface without a user,
> and I can't think of a good reason why we would want to do things
> differently here.  This means that when you propose something like this you
> should also propose an addition to one of the in-tree LSMs to make use of
> it. While the guidance doc linked below (also linked in the LSM MAINTAINERS
> entry) doesn't have any guidance for the LSM blobs as they are generally a
> byproduct of the hooks, if you are looking for some general info I think the
> bits on adding a new LSM hook would be very close to what we would expect
> for blob additions.
> 
> https://github.com/LinuxSecurityModule/kernel/blob/main/README.md
> 
> Getting to the specifics of namespace related APIs, we've had a lot of
> discussions about namespacing and my current opinion is that we need to sort
> out if we want a userspace API at the LSM framework layer, or if we want to
> do that at the individual LSM layer; there is a lot of nuance there and
> while one option may seem like an obvious choice, we need some more
> discussion and I need a chance to get caught up on the threads. Once we have
> an API decision then we can start sorting out the implementation details
> like the LSM blobs.

I might be misunderstanding you but what you are talking about seems
namespacing the LSM layer itself.

But I cannot stress enough this is not at all what this patchset is
doing. :)

All that this patchset does is add new security hooks that get called
whenever a new pid, net, mount, ipc, ... namespace is created, freed, or
when someone wants to change into another namespace. We plan on using
this in systemd to supervise and track services.

^ permalink raw reply


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