Linux Security Modules development
 help / color / mirror / Atom feed
* Re: [PATCH] apparmor: update website link
From: Ryan Lee @ 2026-07-22 16:35 UTC (permalink / raw)
  To: Baruch Siach
  Cc: John Johansen, John Johansen, Georgia Garcia, apparmor,
	linux-security-module
In-Reply-To: <2ce1d4ec18b2b47ee7ddd9c1ad7be68e185aa69c.1784632742.git.baruch@tkos.co.il>

On Tue, Jul 21, 2026 at 4:40 AM Baruch Siach <baruch@tkos.co.il> wrote:
>
> apparmor.wiki.kernel.org redirects to the current website.
>
> Signed-off-by: Baruch Siach <baruch@tkos.co.il>
> ---
>  security/apparmor/Kconfig | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/security/apparmor/Kconfig b/security/apparmor/Kconfig
> index 1e3bd44643da..472aa38254be 100644
> --- a/security/apparmor/Kconfig
> +++ b/security/apparmor/Kconfig
> @@ -11,7 +11,7 @@ config SECURITY_APPARMOR
>           This enables the AppArmor security module.
>           Required userspace tools (if they are not included in your
>           distribution) and further information may be found at
> -         http://apparmor.wiki.kernel.org
> +         https://wiki.apparmor.net
>
>           If you are unsure how to answer this question, answer N.
>
> --
> 2.53.0
>
>

Reviewed-by: Ryan Lee <ryan.lee@canonical.com>

^ permalink raw reply

* Re: unix_stream_connect and socket address resolution
From: John Ericson @ 2026-07-22 16:02 UTC (permalink / raw)
  To: Günther Noack
  Cc: David Laight, Kuniyuki Iwashima, David S . Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Cong Wang, Simon Horman,
	Christian Brauner, David Rheinsberg, Andy Lutomirski,
	Sergei Zimmerman, network dev, Mickaël Salaün,
	Günther Noack, Paul Moore, linux-security-module, LKML
In-Reply-To: <20260722.bfca37efd700@gnoack.org>

Thanks Günther!

This example makes sense to me. The behavior still feels a little odd to
me, but I can understand the practical benefit of what you describe, and
also why changing it would definitely cause breakage.

I have one addendum to ask then which is: what if before the loop we
pre-resolve the parent directory as a concrete `struct path`, and then
on each iteration of the loop resolve only the final path component to
the socket itself? (That is a single-component lookup relative to the
pre-resolved parent, to be clear.)

Per your example, a legitimate server restart recreates the socket inode
in the same directory, so this still picks up the new socket and
reconnects, while avoiding the effect where a concurrent
ancestor-directory rename causes a wildly different socket to be
resolved. Hopefully this preserves the intended use-case.

Note that this does mean recreating the parent directory itself at the
same path would no longer be followed, and a rename/unlink of the pinned
parent would cause the lookup to fail rather than resolve elsewhere.
That seems like the intended, safer direction to me, but flagging it as
a deliberate semantic change rather than an accident.

If this sounds like an acceptable middle-ground to everyone, I'd be happy to implement it.

Cheers,

John

^ permalink raw reply

* Re: [PATCH v3 0/3] keys: fix keyring assoc-array out-of-bounds read and index inconsistency
From: Jarkko Sakkinen @ 2026-07-22 15:30 UTC (permalink / raw)
  To: Michael Bommarito
  Cc: David Howells, Andrew Morton, Paul Moore, James Morris,
	Serge E . Hallyn, keyrings, linux-security-module, linux-kernel
In-Reply-To: <20260719161505.2423935-1-michael.bommarito@gmail.com>

On Sun, Jul 19, 2026 at 12:15:02PM -0400, Michael Bommarito wrote:
> An unprivileged keyring whose keys collide through the description-chunk
> path can drive assoc_array node splitting into an out-of-bounds slot write.
> Patch 1 stops the out-of-bounds read in keyring_get_key_chunk(); patch 2
> makes the chunk byte order agree with keyring_diff_objects(); patch 3 fixes
> the shortcut-walk trim so the walk cannot be steered down the wrong
> descendant.
> 
> v3 changes (patch 1 only; patches 2 and 3 are unchanged):
> Per Jarkko's review, patch 1 no longer extends the existing
> keyring_get_key_chunk() declaration line; the new offset is declared on its
> own line as unsigned int.  No functional change.
> 
> Patches 2 and 3 are unchanged from v2 and carry Jarkko's Reviewed-by.
> 
> v2: https://lore.kernel.org/keyrings/20260714115451.3773164-1-michael.bommarito@gmail.com/
> v1: https://lore.kernel.org/keyrings/20260712014500.480410-1-michael.bommarito@gmail.com/
> 
> Michael Bommarito (3):
>   keys: fix out-of-bounds read in keyring_get_key_chunk()
>   keys: make keyring key-chunk byte order agree with
>     keyring_diff_objects()
>   assoc_array: trim the final shortcut word using the current chunk end
> 
>  lib/assoc_array.c       |  3 ++-
>  security/keys/keyring.c | 14 ++++++++------
>  2 files changed, 10 insertions(+), 7 deletions(-)
> 
> 
> base-commit: 2c7c88a412aa6d09cd04b414211b4ef8553b5309
> -- 
> 2.53.0
> 

I'm setting up the testing environment now and hopefully have final
feedback within let's say "hours" (i.e. I'll do the job, and it takes what
it takes).

BR, Jarkko

^ permalink raw reply

* Re: [PATCH 1/6] ipc: Move mqueue fs magic to uapi magic header
From: Oxana Kharitonova @ 2026-07-22 15:14 UTC (permalink / raw)
  To: gnoack
  Cc: landlock, linux-kernel, linux-security-module, mic, oxana, paul,
	serge, wangyan01, webprosto
In-Reply-To: <amC69LnwcgG7xo-5@google.com>

On Wed, Jul 22, 2026 at 1:43 PM Günther Noack <gnoack@google.com> wrote:
>
> Should this live in include/linux/ipc_namespace.h instead?  Or even be
> exposed as a helper function that lets you check whether an inode is
> referring to an mqueue?
>
> —Günther

Hi Günther,

Thanks for the feedback. Agree, better to move it. I'll check how to do it
better and include in v2.


^ permalink raw reply

* [PATCH v1] selftests/landlock: Add tests for O_TMPFILE
From: Mickaël Salaün @ 2026-07-22 15:13 UTC (permalink / raw)
  To: Günther Noack
  Cc: Mickaël Salaün, linux-security-module, Takao Sato,
	Willy Tarreau, brauner, viro

open(2) with O_TMPFILE creates its unnamed inode through vfs_tmpfile(),
which, unlike normal file creation, calls neither security_path_mknod()
nor security_inode_create().  It is nonetheless mediated: vfs_tmpfile()
opens the inode through the filesystem's ->tmpfile() operation, which
reaches security_file_open() via finish_open().  The open is therefore
checked like any other, and materializing the file with linkat(2) is
checked like any other link.

Add tests for both paths so O_TMPFILE cannot bypass Landlock.

Cc: Günther Noack <gnoack@google.com>
Signed-off-by: Mickaël Salaün <mic@digikod.net>
---
 tools/testing/selftests/landlock/fs_test.c | 251 +++++++++++++++++++++
 1 file changed, 251 insertions(+)

diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c
index cdb47fc1fc0a..b826b2c6a8f0 100644
--- a/tools/testing/selftests/landlock/fs_test.c
+++ b/tools/testing/selftests/landlock/fs_test.c
@@ -450,6 +450,25 @@ static int test_open(const char *const path, const int flags)
 	return test_open_rel(AT_FDCWD, path, flags);
 }
 
+/*
+ * Opens an anonymous O_TMPFILE inode in the directory dir.  O_TMPFILE is always
+ * combined with O_WRONLY or O_RDWR, so the caller must pass one of them in
+ * flags.
+ */
+static int test_tmpfile(const char *const dir, const int flags)
+{
+	int fd;
+
+	fd = open(dir, O_TMPFILE | flags | O_CLOEXEC, 0700);
+	if (fd < 0)
+		return errno;
+
+	if (close(fd) != 0)
+		return errno;
+
+	return 0;
+}
+
 TEST_F_FORK(layout1, no_restriction)
 {
 	ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY));
@@ -2140,6 +2159,238 @@ TEST_F_FORK(layout1, link)
 	ASSERT_EQ(0, link(file1_s1d3, file2_s1d3));
 }
 
+/*
+ * O_TMPFILE does not go through the path_mknod hook: vfs_tmpfile() creates the
+ * inode without calling security_path_mknod().  These tests verify that the
+ * resulting file is still mediated, via the file_open hook, so O_TMPFILE cannot
+ * be used to bypass Landlock.
+ */
+
+/*
+ * An O_TMPFILE open requires WRITE_FILE (and READ_FILE for O_RDWR) on the
+ * directory hierarchy, exactly like any other writable open.  It does not
+ * require (nor is it granted by) MAKE_REG: the anonymous inode is not yet a
+ * named file.  O_TMPFILE always implies write access, so a read-only request is
+ * rejected by the VFS with EINVAL before Landlock is consulted; Landlock must
+ * not change that into EACCES.
+ */
+TEST_F_FORK(layout1, open_tmpfile)
+{
+	const struct rule rules[] = {
+		/* Write allowed, but neither MAKE_REG nor READ_FILE. */
+		{
+			.path = dir_s1d1,
+			.access = LANDLOCK_ACCESS_FS_WRITE_FILE,
+		},
+		/* Both read and write allowed. */
+		{
+			.path = dir_s1d2,
+			.access = LANDLOCK_ACCESS_FS_READ_FILE |
+				  LANDLOCK_ACCESS_FS_WRITE_FILE,
+		},
+		/* File-creation right without write. */
+		{
+			.path = dir_s2d1,
+			.access = LANDLOCK_ACCESS_FS_MAKE_REG,
+		},
+		{},
+	};
+
+	/* Baseline: an unsandboxed O_TMPFILE open works. */
+	EXPECT_EQ(0, test_tmpfile(dir_s1d1, O_WRONLY));
+	EXPECT_EQ(0, test_tmpfile(dir_s2d1, O_RDWR));
+	EXPECT_EQ(0, test_tmpfile(dir_s3d1, O_RDWR));
+
+	/* O_TMPFILE requires write access: read-only is EINVAL at the VFS. */
+	EXPECT_EQ(EINVAL, test_tmpfile(dir_s1d1, O_RDONLY));
+
+	enforce_fs(_metadata,
+		   LANDLOCK_ACCESS_FS_READ_FILE |
+			   LANDLOCK_ACCESS_FS_WRITE_FILE |
+			   LANDLOCK_ACCESS_FS_MAKE_REG,
+		   rules);
+
+	/* Write is enough for an O_WRONLY tmpfile; MAKE_REG is not needed. */
+	EXPECT_EQ(0, test_tmpfile(dir_s1d1, O_WRONLY));
+	/* O_RDWR additionally needs READ_FILE, which is absent here. */
+	EXPECT_EQ(EACCES, test_tmpfile(dir_s1d1, O_RDWR));
+
+	/* Read and write allowed: both open modes succeed. */
+	EXPECT_EQ(0, test_tmpfile(dir_s1d2, O_WRONLY));
+	EXPECT_EQ(0, test_tmpfile(dir_s1d2, O_RDWR));
+
+	/* MAKE_REG without WRITE_FILE does not allow the open. */
+	EXPECT_EQ(EACCES, test_tmpfile(dir_s2d1, O_WRONLY));
+	EXPECT_EQ(EACCES, test_tmpfile(dir_s2d1, O_RDWR));
+
+	/* No rule at all: the open is denied. */
+	EXPECT_EQ(EACCES, test_tmpfile(dir_s3d1, O_WRONLY));
+	EXPECT_EQ(EACCES, test_tmpfile(dir_s3d1, O_RDWR));
+
+	/*
+	 * A read-only O_TMPFILE stays EINVAL under Landlock, whether the
+	 * directory is fully allowed or has no rule: the VFS rejects the flag
+	 * combination before the file_open hook, so Landlock never turns it
+	 * into EACCES.
+	 */
+	EXPECT_EQ(EINVAL, test_tmpfile(dir_s1d2, O_RDONLY));
+	EXPECT_EQ(EINVAL, test_tmpfile(dir_s3d1, O_RDONLY));
+}
+
+/*
+ * When the ruleset handles neither file read nor write access, Landlock has no
+ * opinion on an O_TMPFILE open and must not interfere with it.
+ */
+TEST_F_FORK(layout1, open_tmpfile_unhandled)
+{
+	const struct rule rules[] = {
+		{
+			.path = dir_s1d2,
+			.access = LANDLOCK_ACCESS_FS_READ_DIR,
+		},
+		{},
+	};
+
+	enforce_fs(_metadata, LANDLOCK_ACCESS_FS_READ_DIR, rules);
+
+	EXPECT_EQ(0, test_tmpfile(dir_s1d1, O_WRONLY));
+	EXPECT_EQ(0, test_tmpfile(dir_s1d3, O_RDWR));
+	EXPECT_EQ(0, test_tmpfile(dir_s3d1, O_RDWR));
+}
+
+/*
+ * Materializing an anonymous O_TMPFILE into its creation directory with
+ * linkat(AT_EMPTY_PATH) is gated by MAKE_REG on that directory, even though
+ * obtaining the writable tmpfile only required WRITE_FILE.  This is the check
+ * that stops O_TMPFILE from creating a named file where the sandbox forbids
+ * file creation.  Linking into the same directory does not involve reparenting,
+ * so REFER is not required.
+ */
+TEST_F_FORK(layout1, link_tmpfile)
+{
+	int fd;
+	const struct rule rules[] = {
+		/* Write only: the tmpfile opens but cannot be linked. */
+		{
+			.path = dir_s1d1,
+			.access = LANDLOCK_ACCESS_FS_WRITE_FILE,
+		},
+		/* Write and MAKE_REG: the tmpfile opens and can be linked. */
+		{
+			.path = dir_s2d1,
+			.access = LANDLOCK_ACCESS_FS_WRITE_FILE |
+				  LANDLOCK_ACCESS_FS_MAKE_REG,
+		},
+		{},
+	};
+
+	/* Frees names in the two directories for the new links. */
+	ASSERT_EQ(0, unlink(file1_s1d1));
+	ASSERT_EQ(0, unlink(file1_s2d1));
+
+	enforce_fs(_metadata,
+		   LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_MAKE_REG,
+		   rules);
+
+	/*
+	 * WRITE_FILE is enough to obtain the anonymous tmpfile.  linkat(2) with
+	 * AT_EMPTY_PATH needs no capability because the fd's open-time
+	 * credentials match the caller's.  Linking into the same directory does
+	 * not require REFER (no reparenting), only MAKE_REG, which is absent
+	 * here.
+	 */
+	fd = open(dir_s1d1, O_TMPFILE | O_WRONLY | O_CLOEXEC, 0700);
+	ASSERT_LE(0, fd);
+	ASSERT_EQ(-1, linkat(fd, "", AT_FDCWD, file1_s1d1, AT_EMPTY_PATH));
+	EXPECT_EQ(EACCES, errno);
+	EXPECT_EQ(0, close(fd));
+
+	/* With MAKE_REG on the directory, the same link is allowed. */
+	fd = open(dir_s2d1, O_TMPFILE | O_WRONLY | O_CLOEXEC, 0700);
+	ASSERT_LE(0, fd);
+	EXPECT_EQ(0, linkat(fd, "", AT_FDCWD, file1_s2d1, AT_EMPTY_PATH));
+	EXPECT_EQ(0, close(fd));
+}
+
+/*
+ * Linking a tmpfile into a different directory is a reparenting operation: like
+ * any cross-directory link it requires LANDLOCK_ACCESS_FS_REFER.  Without it,
+ * materializing the tmpfile outside its creation directory is denied with
+ * EXDEV, so a tmpfile cannot escape its origin hierarchy.
+ */
+TEST_F_FORK(layout1, link_tmpfile_reparent_without_refer)
+{
+	int fd;
+	const struct rule rules[] = {
+		/* Source directory: only the tmpfile open is allowed. */
+		{
+			.path = dir_s1d1,
+			.access = LANDLOCK_ACCESS_FS_WRITE_FILE,
+		},
+		/* Destination directory: file creation is allowed. */
+		{
+			.path = dir_s2d1,
+			.access = LANDLOCK_ACCESS_FS_MAKE_REG,
+		},
+		{},
+	};
+
+	/* Frees a name in the destination directory for the new link. */
+	ASSERT_EQ(0, unlink(file1_s2d1));
+
+	enforce_fs(_metadata,
+		   LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_MAKE_REG,
+		   rules);
+
+	fd = open(dir_s1d1, O_TMPFILE | O_WRONLY | O_CLOEXEC, 0700);
+	ASSERT_LE(0, fd);
+	/* Cross-directory link without REFER is denied with EXDEV. */
+	ASSERT_EQ(-1, linkat(fd, "", AT_FDCWD, file1_s2d1, AT_EMPTY_PATH));
+	EXPECT_EQ(EXDEV, errno);
+	EXPECT_EQ(0, close(fd));
+}
+
+/*
+ * With LANDLOCK_ACCESS_FS_REFER on both directories, a tmpfile created in one
+ * directory can be linked into another.  The destination needs only MAKE_REG
+ * (plus REFER), not WRITE_FILE: the reparenting check compares file access
+ * rights, and the tmpfile gains none by moving to a directory that grants only
+ * the directory-level creation right.
+ */
+TEST_F_FORK(layout1, link_tmpfile_reparent_with_refer)
+{
+	int fd;
+	const struct rule rules[] = {
+		/* Source: tmpfile open (write) and reparenting. */
+		{
+			.path = dir_s1d1,
+			.access = LANDLOCK_ACCESS_FS_WRITE_FILE |
+				  LANDLOCK_ACCESS_FS_REFER,
+		},
+		/* Destination: file creation and reparenting, but no write. */
+		{
+			.path = dir_s2d1,
+			.access = LANDLOCK_ACCESS_FS_MAKE_REG |
+				  LANDLOCK_ACCESS_FS_REFER,
+		},
+		{},
+	};
+
+	/* Frees a name in the destination directory for the new link. */
+	ASSERT_EQ(0, unlink(file1_s2d1));
+
+	enforce_fs(_metadata,
+		   LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_MAKE_REG |
+			   LANDLOCK_ACCESS_FS_REFER,
+		   rules);
+
+	fd = open(dir_s1d1, O_TMPFILE | O_WRONLY | O_CLOEXEC, 0700);
+	ASSERT_LE(0, fd);
+	/* REFER on both sides plus MAKE_REG on the destination allows it. */
+	EXPECT_EQ(0, linkat(fd, "", AT_FDCWD, file1_s2d1, AT_EMPTY_PATH));
+	EXPECT_EQ(0, close(fd));
+}
+
 static int test_rename(const char *const oldpath, const char *const newpath)
 {
 	if (rename(oldpath, newpath))
-- 
2.54.0


^ permalink raw reply related

* Re: [PATCH 1/6] ipc: Move mqueue fs magic to uapi magic header
From: Günther Noack @ 2026-07-22 12:43 UTC (permalink / raw)
  To: Oxana Kharitonova
  Cc: mic, paul, jmorris, serge, wangyan01, linux-security-module,
	linux-kernel, landlock, webprosto
In-Reply-To: <20260722122952.42149-2-oxana@cloudflare.com>

Hello!

On Wed, Jul 22, 2026 at 01:29:37PM +0100, Oxana Kharitonova wrote:
> Move MQUEUE_MAGIC from ipc/mqueue.c to include/uapi/linux/magic.h so
> it can be shared by code outside of ipc/mqueue.c without duplicating
> the constant.
> 
> Signed-off-by: Oxana Kharitonova <oxana@cloudflare.com>
> ---
>  include/uapi/linux/magic.h | 2 ++
>  ipc/mqueue.c               | 2 +-
>  2 files changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/include/uapi/linux/magic.h b/include/uapi/linux/magic.h
> index 4f2da935a76c..8e5d33bb1453 100644
> --- a/include/uapi/linux/magic.h
> +++ b/include/uapi/linux/magic.h
> @@ -78,6 +78,8 @@
>  
>  #define V9FS_MAGIC		0x01021997
>  
> +#define MQUEUE_MAGIC		0x19800202
> +
>  #define BDEVFS_MAGIC            0x62646576
>  #define DAXFS_MAGIC             0x64646178
>  #define BINFMTFS_MAGIC          0x42494e4d
> diff --git a/ipc/mqueue.c b/ipc/mqueue.c
> index 4798b375972b..9515597d45ce 100644
> --- a/ipc/mqueue.c
> +++ b/ipc/mqueue.c
> @@ -22,6 +22,7 @@
>  #include <linux/sysctl.h>
>  #include <linux/poll.h>
>  #include <linux/mqueue.h>
> +#include <linux/magic.h>
>  #include <linux/msg.h>
>  #include <linux/skbuff.h>
>  #include <linux/vmalloc.h>
> @@ -47,7 +48,6 @@ struct mqueue_fs_context {
>  	bool			 newns;	/* Set if newly created ipc namespace */
>  };
>  
> -#define MQUEUE_MAGIC	0x19800202
>  #define DIRENT_SIZE	20
>  #define FILENT_SIZE	80
>  
> -- 
> 2.50.1 (Apple Git-155)
> 

The only reference to MQUEUE_MAGIC that I find in your patchset is from
Landlock's kernel code -- For a value that gets serialized to disk, like
for the other file systems, I think there is actually a legitimate use
case for userspace to use that value, when dealing with raw images?  But
that's not the case here, I think?

Should this live in include/linux/ipc_namespace.h instead?  Or even be
exposed as a helper function that lets you check whether an inode is
referring to an mqueue?

—Günther

^ permalink raw reply

* [PATCH 6/6] landlock: Document POSIX message queue scoping
From: Oxana Kharitonova @ 2026-07-22 12:29 UTC (permalink / raw)
  To: mic, gnoack
  Cc: paul, jmorris, serge, wangyan01, linux-security-module,
	linux-kernel, landlock, oxana, webprosto
In-Reply-To: <20260722122952.42149-1-oxana@cloudflare.com>

Document LANDLOCK_SCOPE_POSIX_MSG_QUEUE in the userspace API and UAPI
kernel-doc.

Signed-off-by: Oxana Kharitonova <oxana@cloudflare.com>
---
 Documentation/admin-guide/LSM/landlock.rst |  6 ++++--
 Documentation/userspace-api/landlock.rst   | 11 ++++++++++-
 include/uapi/linux/landlock.h              |  6 +++++-
 3 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/Documentation/admin-guide/LSM/landlock.rst b/Documentation/admin-guide/LSM/landlock.rst
index 8eb85c9381ff..1ecb2017271b 100644
--- a/Documentation/admin-guide/LSM/landlock.rst
+++ b/Documentation/admin-guide/LSM/landlock.rst
@@ -60,9 +60,11 @@ AUDIT_LANDLOCK_ACCESS
         - net.bind_udp - UDP port binding was denied
         - net.connect_send_udp - UDP connection and send was denied
 
-    **scope.*** - IPC scoping restrictions (ABI 6+):
+    **scope.*** - IPC scoping restrictions:
         - scope.abstract_unix_socket - Abstract UNIX socket connection denied
-        - scope.signal - Signal sending denied
+          (ABI 6+)
+        - scope.signal - Signal sending denied (ABI 6+)
+        - scope.posix_msg_queue - POSIX message queue opening denied (ABI 11+)
 
     Multiple blockers can appear in a single event (comma-separated) when
     multiple access rights are missing. For example, creating a regular file
diff --git a/Documentation/userspace-api/landlock.rst b/Documentation/userspace-api/landlock.rst
index 5a63d4476c1c..c4fa84e6d281 100644
--- a/Documentation/userspace-api/landlock.rst
+++ b/Documentation/userspace-api/landlock.rst
@@ -86,7 +86,8 @@ to be explicit about the denied-by-default access rights.
             LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP,
         .scoped =
             LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET |
-            LANDLOCK_SCOPE_SIGNAL,
+            LANDLOCK_SCOPE_SIGNAL |
+            LANDLOCK_SCOPE_POSIX_MSG_QUEUE,
     };
 
 Because we may not know which kernel version an application will be executed
@@ -140,6 +141,10 @@ version, and only use the available subset of access rights:
         ruleset_attr.handled_access_net &=
             ~(LANDLOCK_ACCESS_NET_BIND_UDP |
               LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP);
+        __attribute__((fallthrough));
+    case 10:
+        /* Removes LANDLOCK_SCOPE_POSIX_MSG_QUEUE for ABI < 11 */
+        ruleset_attr.scoped &= ~LANDLOCK_SCOPE_POSIX_MSG_QUEUE;
     }
 
 This enables the creation of an inclusive ruleset that will contain our rules.
@@ -420,6 +425,10 @@ The operations which can be scoped are:
     A :manpage:`sendto(2)` on a socket which was previously connected will not
     be restricted.  This works for both datagram and stream sockets.
 
+``LANDLOCK_SCOPE_POSIX_MSG_QUEUE``
+    This limits opening POSIX message queues to queues created by a process in
+    the same or a nested Landlock domain.
+
 IPC scoping does not support exceptions via :manpage:`landlock_add_rule(2)`.
 If an operation is scoped within a domain, no rules can be added to allow access
 to resources or processes outside of the scope.
diff --git a/include/uapi/linux/landlock.h b/include/uapi/linux/landlock.h
index 96d0c3b423ac..21ba31ad4d4b 100644
--- a/include/uapi/linux/landlock.h
+++ b/include/uapi/linux/landlock.h
@@ -478,7 +478,9 @@ struct landlock_net_port_attr {
  * Setting a flag for a ruleset will isolate the Landlock domain to forbid
  * connections to resources outside the domain.
  *
- * This is supported since Landlock ABI version 6.
+ * This is supported since Landlock ABI version 6.  The
+ * %LANDLOCK_SCOPE_POSIX_MSG_QUEUE scope is supported since Landlock ABI version
+ * 11.
  *
  * Scopes:
  *
@@ -487,6 +489,8 @@ struct landlock_net_port_attr {
  *   related Landlock domain (e.g., a parent domain or a non-sandboxed process).
  * - %LANDLOCK_SCOPE_SIGNAL: Restrict a sandboxed process from sending a signal
  *   to another process outside the domain.
+ * - %LANDLOCK_SCOPE_POSIX_MSG_QUEUE: Restrict a sandboxed process from opening
+ *   a POSIX message queue created outside the domain.
  */
 /* clang-format off */
 #define LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET		(1ULL << 0)
-- 
2.50.1 (Apple Git-155)


^ permalink raw reply related

* [PATCH 5/6] samples/landlock: Support POSIX message queue scoping
From: Oxana Kharitonova @ 2026-07-22 12:29 UTC (permalink / raw)
  To: mic, gnoack
  Cc: paul, jmorris, serge, wangyan01, linux-security-module,
	linux-kernel, landlock, oxana, webprosto
In-Reply-To: <20260722122952.42149-1-oxana@cloudflare.com>

Teach the sandboxer sample to request LANDLOCK_SCOPE_POSIX_MSG_QUEUE
through LL_SCOPED.

Add the "q" scope selector for POSIX message queues and document it in
the sample help text. Also allow POSIX message queue denials to be
quieted with "posix_msg_queue" through LL_QUIET_ACCESS.

Signed-off-by: Oxana Kharitonova <oxana@cloudflare.com>
---
 samples/landlock/sandboxer.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/samples/landlock/sandboxer.c b/samples/landlock/sandboxer.c
index ac71019e6212..59024ca53398 100644
--- a/samples/landlock/sandboxer.c
+++ b/samples/landlock/sandboxer.c
@@ -240,10 +240,12 @@ static bool check_ruleset_scope(const char *const env_var,
 	bool error = false;
 	bool abstract_scoping = false;
 	bool signal_scoping = false;
+	bool posix_mqueue_scoping = false;
 
 	/* Scoping is not supported by Landlock ABI */
 	if (!(ruleset_attr->scoped &
-	      (LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET | LANDLOCK_SCOPE_SIGNAL)))
+	      (LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET | LANDLOCK_SCOPE_SIGNAL |
+	       LANDLOCK_SCOPE_POSIX_MSG_QUEUE)))
 		goto out_unset;
 
 	env_type_scope = getenv(env_var);
@@ -260,6 +262,9 @@ static bool check_ruleset_scope(const char *const env_var,
 		} else if (strcmp("s", ipc_scoping_name) == 0 &&
 			   !signal_scoping) {
 			signal_scoping = true;
+		} else if (strcmp("q", ipc_scoping_name) == 0 &&
+			   !posix_mqueue_scoping) {
+			posix_mqueue_scoping = true;
 		} else {
 			fprintf(stderr, "Unknown or duplicate scope \"%s\"\n",
 				ipc_scoping_name);
@@ -276,6 +281,8 @@ static bool check_ruleset_scope(const char *const env_var,
 		ruleset_attr->scoped &= ~LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET;
 	if (!signal_scoping)
 		ruleset_attr->scoped &= ~LANDLOCK_SCOPE_SIGNAL;
+	if (!posix_mqueue_scoping)
+		ruleset_attr->scoped &= ~LANDLOCK_SCOPE_POSIX_MSG_QUEUE;
 
 	unsetenv(env_var);
 	return error;
@@ -354,6 +361,9 @@ static int add_quiet_access(const char *const env_var,
 				LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET;
 		else if (strcmp(str_access, "signal") == 0)
 			ruleset_attr->quiet_scoped |= LANDLOCK_SCOPE_SIGNAL;
+		else if (strcmp(str_access, "posix_msg_queue") == 0)
+			ruleset_attr->quiet_scoped |=
+				LANDLOCK_SCOPE_POSIX_MSG_QUEUE;
 		else {
 			fprintf(stderr, "Unknown quiet access \"%s\"\n",
 				str_access);
@@ -400,6 +410,7 @@ static const char help[] =
 	"* " ENV_SCOPED_NAME ": actions denied on the outside of the landlock domain\n"
 	"  - \"a\" to restrict opening abstract unix sockets\n"
 	"  - \"s\" to restrict sending signals\n"
+	"  - \"q\" to restrict opening POSIX message queues\n"
 	"\n"
 	"A sandboxer should not log denied access requests to avoid spamming logs, "
 	"but to test audit we can set " ENV_FORCE_LOG_NAME "=1\n"
@@ -416,6 +427,7 @@ static const char help[] =
 	"  - \"udp_connect\" to quiet udp connect / send denials\n"
 	"  - \"abstract_unix_socket\" to quiet abstract unix socket denials\n"
 	"  - \"signal\" to quiet signal denials\n"
+	"  - \"posix_msg_queue\" to quiet POSIX message queue denials\n"
 	"\n"
 	"Example:\n"
 	ENV_FS_RO_NAME "=\"${PATH}:/lib:/usr:/proc:/etc:/dev/urandom\" "
@@ -423,7 +435,7 @@ static const char help[] =
 	ENV_TCP_BIND_NAME "=\"9418\" "
 	ENV_TCP_CONNECT_NAME "=\"80:443\" "
 	ENV_UDP_CONNECT_SEND_NAME "=\"53\" "
-	ENV_SCOPED_NAME "=\"a:s\" "
+	ENV_SCOPED_NAME "=\"a:s:q\" "
 	"%1$s bash -i\n"
 	"\n"
 	"This sandboxer can use Landlock features up to ABI version "
-- 
2.50.1 (Apple Git-155)


^ permalink raw reply related

* [PATCH 4/6] selftests/landlock: Test POSIX message queue scoping
From: Oxana Kharitonova @ 2026-07-22 12:29 UTC (permalink / raw)
  To: mic, gnoack
  Cc: paul, jmorris, serge, wangyan01, linux-security-module,
	linux-kernel, landlock, oxana, webprosto
In-Reply-To: <20260722122952.42149-1-oxana@cloudflare.com>

Add tests for LANDLOCK_SCOPE_POSIX_MSG_QUEUE.

Verify that opening a queue created outside the current scoped domain is
denied, and that opening a queue created within the same domain remains
allowed.

Signed-off-by: Oxana Kharitonova <oxana@cloudflare.com>
---
 .../landlock/scoped_posix_msg_queue_test.c    | 223 ++++++++++++++++++
 .../testing/selftests/landlock/scoped_test.c  |   2 +-
 2 files changed, 224 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/landlock/scoped_posix_msg_queue_test.c

diff --git a/tools/testing/selftests/landlock/scoped_posix_msg_queue_test.c b/tools/testing/selftests/landlock/scoped_posix_msg_queue_test.c
new file mode 100644
index 000000000000..602ba5c7a83d
--- /dev/null
+++ b/tools/testing/selftests/landlock/scoped_posix_msg_queue_test.c
@@ -0,0 +1,223 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Landlock tests - POSIX message queue scoping
+ *
+ * Copyright © 2024-2026 Microsoft Corporation
+ */
+
+#define _GNU_SOURCE
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <linux/landlock.h>
+#include <mqueue.h>
+#include <stddef.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "common.h"
+#include "scoped_common.h"
+
+static void set_mq_name(char *const name, const size_t size)
+{
+	snprintf(name, size, "/selftests-landlock-mq-tid%d", sys_gettid());
+}
+
+FIXTURE(scoped_domains)
+{
+	char mq_name[NAME_MAX];
+};
+
+#include "scoped_base_variants.h"
+
+FIXTURE_SETUP(scoped_domains)
+{
+	drop_caps(_metadata);
+
+	set_mq_name(self->mq_name, sizeof(self->mq_name));
+	/* Removes a possibly stale queue from a previous run. */
+	mq_unlink(self->mq_name);
+}
+
+FIXTURE_TEARDOWN(scoped_domains)
+{
+}
+
+/*
+ * The parent creates the message queue, then the child tries
+ * to open it, with scoped domain(s) or no domain at all.
+ */
+TEST_F(scoped_domains, open_parent_queue)
+{
+	pid_t child;
+	int status;
+	int pipe_parent[2], pipe_child[2];
+	char buf;
+	mqd_t mq;
+
+	ASSERT_EQ(0, pipe2(pipe_parent, O_CLOEXEC));
+	ASSERT_EQ(0, pipe2(pipe_child, O_CLOEXEC));
+
+	if (variant->domain_both)
+		create_scoped_domain(_metadata, LANDLOCK_SCOPE_POSIX_MSG_QUEUE);
+
+	child = fork();
+	ASSERT_LE(0, child);
+	if (child == 0) {
+		mqd_t mq_child;
+
+		EXPECT_EQ(0, close(pipe_parent[1]));
+		EXPECT_EQ(0, close(pipe_child[0]));
+
+		if (variant->domain_child)
+			create_scoped_domain(_metadata,
+					     LANDLOCK_SCOPE_POSIX_MSG_QUEUE);
+
+		/* Waits for the parent to create the queue. */
+		ASSERT_EQ(1, read(pipe_parent[0], &buf, 1));
+
+		mq_child = mq_open(self->mq_name, O_RDWR);
+		if (!variant->domain_child) {
+			EXPECT_LE(0, mq_child);
+			if (mq_child >= 0)
+				EXPECT_EQ(0, mq_close(mq_child));
+		} else {
+			EXPECT_EQ(-1, mq_child);
+			EXPECT_EQ(EPERM, errno);
+		}
+
+		ASSERT_EQ(1, write(pipe_child[1], ".", 1));
+		_exit(_metadata->exit_code);
+		return;
+	}
+	EXPECT_EQ(0, close(pipe_parent[0]));
+	EXPECT_EQ(0, close(pipe_child[1]));
+
+	if (variant->domain_parent)
+		create_scoped_domain(_metadata, LANDLOCK_SCOPE_POSIX_MSG_QUEUE);
+
+	mq = mq_open(self->mq_name, O_CREAT | O_RDWR, 0600, NULL);
+	ASSERT_LE(0, mq);
+
+	ASSERT_EQ(1, write(pipe_parent[1], ".", 1));
+	ASSERT_EQ(1, read(pipe_child[0], &buf, 1));
+
+	ASSERT_EQ(child, waitpid(child, &status, 0));
+	EXPECT_EQ(0, mq_close(mq));
+	EXPECT_EQ(0, mq_unlink(self->mq_name));
+
+	if (WIFSIGNALED(status) || !WIFEXITED(status) ||
+	    WEXITSTATUS(status) != EXIT_SUCCESS)
+		_metadata->exit_code = KSFT_FAIL;
+}
+
+/*
+ * The child creates the message queue, then the parent tries
+ * to open it, with scoped domain(s) or no domain at all.
+ */
+TEST_F(scoped_domains, open_child_queue)
+{
+	pid_t child;
+	bool can_open_child_queue;
+	int status;
+	int pipe_parent[2], pipe_child[2];
+	char buf;
+	mqd_t mq;
+
+	can_open_child_queue = !variant->domain_parent;
+
+	ASSERT_EQ(0, pipe2(pipe_parent, O_CLOEXEC));
+	ASSERT_EQ(0, pipe2(pipe_child, O_CLOEXEC));
+
+	if (variant->domain_both)
+		create_scoped_domain(_metadata, LANDLOCK_SCOPE_POSIX_MSG_QUEUE);
+
+	child = fork();
+	ASSERT_LE(0, child);
+	if (child == 0) {
+		mqd_t mq_child;
+
+		EXPECT_EQ(0, close(pipe_parent[1]));
+		EXPECT_EQ(0, close(pipe_child[0]));
+
+		if (variant->domain_child)
+			create_scoped_domain(_metadata,
+					     LANDLOCK_SCOPE_POSIX_MSG_QUEUE);
+
+		/* Waits for the parent to be in a domain, if any. */
+		ASSERT_EQ(1, read(pipe_parent[0], &buf, 1));
+
+		mq_child = mq_open(self->mq_name, O_CREAT | O_RDWR, 0600, NULL);
+		ASSERT_LE(0, mq_child);
+
+		ASSERT_EQ(1, write(pipe_child[1], ".", 1));
+
+		ASSERT_EQ(1, read(pipe_parent[0], &buf, 1));
+		EXPECT_EQ(0, mq_close(mq_child));
+		EXPECT_EQ(0, mq_unlink(self->mq_name));
+		_exit(_metadata->exit_code);
+		return;
+	}
+	EXPECT_EQ(0, close(pipe_parent[0]));
+	EXPECT_EQ(0, close(pipe_child[1]));
+
+	if (variant->domain_parent)
+		create_scoped_domain(_metadata, LANDLOCK_SCOPE_POSIX_MSG_QUEUE);
+
+	/* Signals that the parent is in a domain, if any. */
+	ASSERT_EQ(1, write(pipe_parent[1], ".", 1));
+
+	/* Waits for the child to create the queue. */
+	ASSERT_EQ(1, read(pipe_child[0], &buf, 1));
+
+	mq = mq_open(self->mq_name, O_RDWR);
+	if (can_open_child_queue) {
+		EXPECT_LE(0, mq);
+		if (mq >= 0)
+			EXPECT_EQ(0, mq_close(mq));
+	} else {
+		EXPECT_EQ(-1, mq);
+		EXPECT_EQ(EPERM, errno);
+	}
+
+	/* Signals to the child that the open attempt is done. */
+	ASSERT_EQ(1, write(pipe_parent[1], ".", 1));
+
+	ASSERT_EQ(child, waitpid(child, &status, 0));
+	if (WIFSIGNALED(status) || !WIFEXITED(status) ||
+	    WEXITSTATUS(status) != EXIT_SUCCESS)
+		_metadata->exit_code = KSFT_FAIL;
+}
+
+/*
+ * A process must always be able to open a queue it created within its own
+ * domain, whatever the enforced scope is.
+ */
+TEST(create_and_open_same_domain)
+{
+	char mq_name[NAME_MAX];
+	mqd_t mq_create, mq_open_again;
+
+	drop_caps(_metadata);
+	set_mq_name(mq_name, sizeof(mq_name));
+	mq_unlink(mq_name);
+
+	create_scoped_domain(_metadata, LANDLOCK_SCOPE_POSIX_MSG_QUEUE);
+
+	mq_create = mq_open(mq_name, O_CREAT | O_RDWR, 0600, NULL);
+	ASSERT_LE(0, mq_create);
+
+	mq_open_again = mq_open(mq_name, O_RDWR);
+	EXPECT_LE(0, mq_open_again);
+	if (mq_open_again >= 0)
+		EXPECT_EQ(0, mq_close(mq_open_again));
+
+	EXPECT_EQ(0, mq_close(mq_create));
+	EXPECT_EQ(0, mq_unlink(mq_name));
+}
+
+TEST_HARNESS_MAIN
diff --git a/tools/testing/selftests/landlock/scoped_test.c b/tools/testing/selftests/landlock/scoped_test.c
index b90f76ed0d9c..c530baa50948 100644
--- a/tools/testing/selftests/landlock/scoped_test.c
+++ b/tools/testing/selftests/landlock/scoped_test.c
@@ -12,7 +12,7 @@
 
 #include "common.h"
 
-#define ACCESS_LAST LANDLOCK_SCOPE_SIGNAL
+#define ACCESS_LAST LANDLOCK_SCOPE_POSIX_MSG_QUEUE
 
 TEST(ruleset_with_unknown_scope)
 {
-- 
2.50.1 (Apple Git-155)


^ permalink raw reply related

* [PATCH 3/6] landlock: Bump ABI for LANDLOCK_SCOPE_POSIX_MSG_QUEUE
From: Oxana Kharitonova @ 2026-07-22 12:29 UTC (permalink / raw)
  To: mic, gnoack
  Cc: paul, jmorris, serge, wangyan01, linux-security-module,
	linux-kernel, landlock, oxana, webprosto
In-Reply-To: <20260722122952.42149-1-oxana@cloudflare.com>

Increase the landlock ABI version so userspace can detect support for
LANDLOCK_SCOPE_POSIX_MSG_QUEUE.

Signed-off-by: Oxana Kharitonova <oxana@cloudflare.com>
---
 security/landlock/syscalls.c                 | 2 +-
 tools/testing/selftests/landlock/base_test.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/security/landlock/syscalls.c b/security/landlock/syscalls.c
index 36b02892c62f..84521a31bf75 100644
--- a/security/landlock/syscalls.c
+++ b/security/landlock/syscalls.c
@@ -169,7 +169,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 = 10;
+const int landlock_abi_version = 11;
 
 /**
  * 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 cbd3c1669951..b8b5fa1042ba 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(10, landlock_create_ruleset(NULL, 0,
+	ASSERT_EQ(11, landlock_create_ruleset(NULL, 0,
 					      LANDLOCK_CREATE_RULESET_VERSION));
 
 	ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0,
-- 
2.50.1 (Apple Git-155)


^ permalink raw reply related

* [PATCH 2/6] landlock: Scope POSIX message queue opens
From: Oxana Kharitonova @ 2026-07-22 12:29 UTC (permalink / raw)
  To: mic, gnoack
  Cc: paul, jmorris, serge, wangyan01, linux-security-module,
	linux-kernel, landlock, oxana, webprosto
In-Reply-To: <20260722122952.42149-1-oxana@cloudflare.com>

Add support for enforcing LANDLOCK_SCOPE_POSIX_MSG_QUEUE when opening
POSIX message queues.

Tag mqueuefs inodes at instantiation time with the landlock domain of
the task that created the queue. This domain is stored in the landlock
inode security blob and kept alive until the inode security blob is
released.

On file open, detect mqueuefs regular files and compare the queue
creator's domain with the opener's scoped domain. Deny the open when
the opener is restricted by LANDLOCK_SCOPE_POSIX_MSG_QUEUE and the queue
was created outside of an allowed parent domain.

This makes POSIX message queues follow the same scoped-domain model as
the existing landlock IPC restrictions, while keeping the queue creator
domain tied to the lifetime of the queue inode.

Signed-off-by: Oxana Kharitonova <oxana@cloudflare.com>
---
 include/uapi/linux/landlock.h |  1 +
 security/landlock/audit.c     |  9 ++++++++
 security/landlock/audit.h     |  1 +
 security/landlock/fs.c        | 35 ++++++++++++++++++++++++++++
 security/landlock/fs.h        | 15 ++++++++++++
 security/landlock/limits.h    |  2 +-
 security/landlock/ruleset.c   |  1 -
 security/landlock/task.c      | 43 +++++++++++++++++++++++++++++++++++
 security/landlock/task.h      |  4 ++++
 9 files changed, 109 insertions(+), 2 deletions(-)

diff --git a/include/uapi/linux/landlock.h b/include/uapi/linux/landlock.h
index 272f047df438..96d0c3b423ac 100644
--- a/include/uapi/linux/landlock.h
+++ b/include/uapi/linux/landlock.h
@@ -491,6 +491,7 @@ struct landlock_net_port_attr {
 /* clang-format off */
 #define LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET		(1ULL << 0)
 #define LANDLOCK_SCOPE_SIGNAL		                (1ULL << 1)
+#define LANDLOCK_SCOPE_POSIX_MSG_QUEUE		        (1ULL << 2)
 /* clang-format on*/
 
 #endif /* _UAPI_LINUX_LANDLOCK_H */
diff --git a/security/landlock/audit.c b/security/landlock/audit.c
index 50536c568526..895397b5cbca 100644
--- a/security/landlock/audit.c
+++ b/security/landlock/audit.c
@@ -82,6 +82,10 @@ get_blocker(const enum landlock_request_type type,
 	case LANDLOCK_REQUEST_SCOPE_SIGNAL:
 		WARN_ON_ONCE(access_bit != -1);
 		return "scope.signal";
+
+	case LANDLOCK_REQUEST_SCOPE_POSIX_MSG_QUEUE:
+		WARN_ON_ONCE(access_bit != -1);
+		return "scope.posix_msg_queue";
 	}
 
 	WARN_ON_ONCE(1);
@@ -646,6 +650,11 @@ void landlock_log_denial(const struct landlock_cred_security *const subject,
 				!!(quiet_mask &
 				   LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);
 			break;
+		case LANDLOCK_REQUEST_SCOPE_POSIX_MSG_QUEUE:
+			quiet_applicable_to_access =
+				!!(quiet_mask &
+				   LANDLOCK_SCOPE_POSIX_MSG_QUEUE);
+			break;
 		/*
 		 * Leave LANDLOCK_REQUEST_PTRACE and
 		 * LANDLOCK_REQUEST_FS_CHANGE_TOPOLOGY unhandled for now - they
diff --git a/security/landlock/audit.h b/security/landlock/audit.h
index 620f8a24291d..ce85417548fa 100644
--- a/security/landlock/audit.h
+++ b/security/landlock/audit.h
@@ -21,6 +21,7 @@ enum landlock_request_type {
 	LANDLOCK_REQUEST_NET_ACCESS,
 	LANDLOCK_REQUEST_SCOPE_ABSTRACT_UNIX_SOCKET,
 	LANDLOCK_REQUEST_SCOPE_SIGNAL,
+	LANDLOCK_REQUEST_SCOPE_POSIX_MSG_QUEUE,
 };
 
 /*
diff --git a/security/landlock/fs.c b/security/landlock/fs.c
index f7e5e4ef9eac..c6558b448a06 100644
--- a/security/landlock/fs.c
+++ b/security/landlock/fs.c
@@ -51,6 +51,7 @@
 #include "object.h"
 #include "ruleset.h"
 #include "setup.h"
+#include "task.h"
 
 /* Underlying object management */
 
@@ -1268,6 +1269,33 @@ static void hook_inode_free_security_rcu(void *inode_security)
 	 */
 	inode_sec = inode_security + landlock_blob_sizes.lbs_inode;
 	WARN_ON_ONCE(inode_sec->object);
+
+	landlock_put_ruleset_deferred(inode_sec->mq_domain);
+}
+
+/*
+ * Tag a newly created POSIX message queue with its creator's domain.
+ *
+ * This is the earliest reachable point with both the creator's context and a
+ * fully initialized inode.
+ */
+static void hook_d_instantiate(struct dentry *const dentry,
+			       struct inode *const inode)
+{
+	struct landlock_ruleset *dom;
+
+	if (!landlock_is_posix_mqueue_inode(inode))
+		return;
+
+	dom = landlock_get_current_domain();
+	if (!dom)
+		return;
+
+	if (WARN_ON_ONCE(landlock_inode(inode)->mq_domain))
+		return;
+
+	landlock_get_ruleset(dom);
+	landlock_inode(inode)->mq_domain = dom;
 }
 
 /* Super-block hooks */
@@ -1756,6 +1784,12 @@ static int hook_file_open(struct file *const file)
 	const struct landlock_cred_security *const subject =
 		landlock_get_applicable_subject(file->f_cred, any_fs, NULL);
 	struct landlock_request request = {};
+	int err;
+
+	/* POSIX message queue scoping is independent of FS access rights. */
+	err = landlock_check_posix_mqueue_open(file);
+	if (err)
+		return err;
 
 	if (!subject)
 		return 0;
@@ -1979,6 +2013,7 @@ static void hook_file_free_security(struct file *file)
 
 static struct security_hook_list landlock_hooks[] __ro_after_init = {
 	LSM_HOOK_INIT(inode_free_security_rcu, hook_inode_free_security_rcu),
+	LSM_HOOK_INIT(d_instantiate, hook_d_instantiate),
 
 	LSM_HOOK_INIT(sb_delete, hook_sb_delete),
 	LSM_HOOK_INIT(sb_mount, hook_sb_mount),
diff --git a/security/landlock/fs.h b/security/landlock/fs.h
index b4421d9df68f..aefe078845fa 100644
--- a/security/landlock/fs.h
+++ b/security/landlock/fs.h
@@ -14,6 +14,7 @@
 #include <linux/fs.h>
 #include <linux/init.h>
 #include <linux/rcupdate.h>
+#include <uapi/linux/magic.h>
 
 #include "access.h"
 #include "cred.h"
@@ -38,6 +39,14 @@ struct landlock_inode_security {
 	 * performed by get_inode_object().
 	 */
 	struct landlock_object __rcu *object;
+	/**
+	 * @mq_domain: Domain of the task that created POSIX message queue.
+	 * Only set for mqueuefs inodes (i.e. s_magic == MQUEUE_MAGIC) at
+	 * creation time by hook_d_instantiate(), never modified afterwards.
+	 * Used to check LANDLOCK_SCOPE_POSIX_MSG_QUEUE against the
+	 * accessing task's domain.
+	 */
+	struct landlock_ruleset *mq_domain;
 };
 
 /**
@@ -141,6 +150,12 @@ landlock_inode(const struct inode *const inode)
 	return inode->i_security + landlock_blob_sizes.lbs_inode;
 }
 
+static inline bool
+landlock_is_posix_mqueue_inode(const struct inode *const inode)
+{
+	return S_ISREG(inode->i_mode) && inode->i_sb->s_magic == MQUEUE_MAGIC;
+}
+
 static inline struct landlock_superblock_security *
 landlock_superblock(const struct super_block *const superblock)
 {
diff --git a/security/landlock/limits.h b/security/landlock/limits.h
index 08d5f2f6d321..70a7c5c7af85 100644
--- a/security/landlock/limits.h
+++ b/security/landlock/limits.h
@@ -27,7 +27,7 @@
 #define LANDLOCK_MASK_ACCESS_NET	((LANDLOCK_LAST_ACCESS_NET << 1) - 1)
 #define LANDLOCK_NUM_ACCESS_NET		__const_hweight64(LANDLOCK_MASK_ACCESS_NET)
 
-#define LANDLOCK_LAST_SCOPE		LANDLOCK_SCOPE_SIGNAL
+#define LANDLOCK_LAST_SCOPE		LANDLOCK_SCOPE_POSIX_MSG_QUEUE
 #define LANDLOCK_MASK_SCOPE		((LANDLOCK_LAST_SCOPE << 1) - 1)
 #define LANDLOCK_NUM_SCOPE		__const_hweight64(LANDLOCK_MASK_SCOPE)
 
diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c
index 4dd09ea22c84..aa37d50ead87 100644
--- a/security/landlock/ruleset.c
+++ b/security/landlock/ruleset.c
@@ -520,7 +520,6 @@ static void free_ruleset_work(struct work_struct *const work)
 	free_ruleset(ruleset);
 }
 
-/* Only called by hook_cred_free(). */
 void landlock_put_ruleset_deferred(struct landlock_ruleset *const ruleset)
 {
 	if (ruleset && refcount_dec_and_test(&ruleset->usage)) {
diff --git a/security/landlock/task.c b/security/landlock/task.c
index 55522a601367..d65e43550b26 100644
--- a/security/landlock/task.c
+++ b/security/landlock/task.c
@@ -453,6 +453,49 @@ static int hook_file_send_sigiotask(struct task_struct *tsk,
 	return -EPERM;
 }
 
+static const struct access_masks posix_mqueue_scope = {
+	.scope = LANDLOCK_SCOPE_POSIX_MSG_QUEUE,
+};
+
+/**
+ * landlock_check_posix_mqueue_open - Deny opening a POSIX message queue
+ * created by a task from a different (non-ancestor) domain
+ *
+ * @file: The mqueuefs file being opened.
+ *
+ * Return: -EPERM if the open must be denied, 0 otherwise.
+ */
+int landlock_check_posix_mqueue_open(struct file *const file)
+{
+	const struct inode *const inode = file_inode(file);
+	const struct landlock_cred_security *subject;
+	size_t handle_layer;
+
+	if (!landlock_is_posix_mqueue_inode(inode))
+		return 0;
+
+	subject = landlock_get_applicable_subject(file->f_cred,
+						  posix_mqueue_scope,
+						  &handle_layer);
+	if (!subject)
+		return 0;
+
+	if (!domain_is_scoped(subject->domain,
+			      landlock_inode(inode)->mq_domain,
+			      LANDLOCK_SCOPE_POSIX_MSG_QUEUE))
+		return 0;
+
+	landlock_log_denial(subject, &(struct landlock_request) {
+		.type = LANDLOCK_REQUEST_SCOPE_POSIX_MSG_QUEUE,
+		.audit = {
+			.type = LSM_AUDIT_DATA_FILE,
+			.u.file = file,
+		},
+		.layer_plus_one = handle_layer + 1,
+	});
+	return -EPERM;
+}
+
 static struct security_hook_list landlock_hooks[] __ro_after_init = {
 	LSM_HOOK_INIT(ptrace_access_check, hook_ptrace_access_check),
 	LSM_HOOK_INIT(ptrace_traceme, hook_ptrace_traceme),
diff --git a/security/landlock/task.h b/security/landlock/task.h
index 7c00360219a2..0b031dc17bbf 100644
--- a/security/landlock/task.h
+++ b/security/landlock/task.h
@@ -9,6 +9,10 @@
 #ifndef _SECURITY_LANDLOCK_TASK_H
 #define _SECURITY_LANDLOCK_TASK_H
 
+#include <linux/fs.h>
+
 __init void landlock_add_task_hooks(void);
 
+int landlock_check_posix_mqueue_open(struct file *const file);
+
 #endif /* _SECURITY_LANDLOCK_TASK_H */
-- 
2.50.1 (Apple Git-155)


^ permalink raw reply related

* [PATCH 1/6] ipc: Move mqueue fs magic to uapi magic header
From: Oxana Kharitonova @ 2026-07-22 12:29 UTC (permalink / raw)
  To: mic, gnoack
  Cc: paul, jmorris, serge, wangyan01, linux-security-module,
	linux-kernel, landlock, oxana, webprosto
In-Reply-To: <20260722122952.42149-1-oxana@cloudflare.com>

Move MQUEUE_MAGIC from ipc/mqueue.c to include/uapi/linux/magic.h so
it can be shared by code outside of ipc/mqueue.c without duplicating
the constant.

Signed-off-by: Oxana Kharitonova <oxana@cloudflare.com>
---
 include/uapi/linux/magic.h | 2 ++
 ipc/mqueue.c               | 2 +-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/include/uapi/linux/magic.h b/include/uapi/linux/magic.h
index 4f2da935a76c..8e5d33bb1453 100644
--- a/include/uapi/linux/magic.h
+++ b/include/uapi/linux/magic.h
@@ -78,6 +78,8 @@
 
 #define V9FS_MAGIC		0x01021997
 
+#define MQUEUE_MAGIC		0x19800202
+
 #define BDEVFS_MAGIC            0x62646576
 #define DAXFS_MAGIC             0x64646178
 #define BINFMTFS_MAGIC          0x42494e4d
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 4798b375972b..9515597d45ce 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -22,6 +22,7 @@
 #include <linux/sysctl.h>
 #include <linux/poll.h>
 #include <linux/mqueue.h>
+#include <linux/magic.h>
 #include <linux/msg.h>
 #include <linux/skbuff.h>
 #include <linux/vmalloc.h>
@@ -47,7 +48,6 @@ struct mqueue_fs_context {
 	bool			 newns;	/* Set if newly created ipc namespace */
 };
 
-#define MQUEUE_MAGIC	0x19800202
 #define DIRENT_SIZE	20
 #define FILENT_SIZE	80
 
-- 
2.50.1 (Apple Git-155)


^ permalink raw reply related

* [PATCH 0/6] landlock: Add POSIX message queue scoping
From: Oxana Kharitonova @ 2026-07-22 12:29 UTC (permalink / raw)
  To: mic, gnoack
  Cc: paul, jmorris, serge, wangyan01, linux-security-module,
	linux-kernel, landlock, oxana, webprosto

Hi,

This series adds landlock support for scoping POSIX message queuesi [1].
 
Landlock already supports scoped IPC restrictions for signals and abstract
UNIX sockets. These restrictions make it possible to prevent a sandboxed
task from interacting with IPC objects outside of its Landlock domain,
while still allowing communication within the same domain or with nested
domains.
 
This series extends the same model to POSIX message queues with a new
LANDLOCK_SCOPE_POSIX_MSG_QUEUE scope. When this scope is enforced, a task
can only open POSIX message queues that were created by a task in the same
landlock domain or in a nested domain.
 
The implementation tags mqueuefs inodes at creation time with the creator's
landlock domain. This domain is kept alive for the lifetime of the inode
and is checked when the queue is opened.
 
The series also exposes the mqueuefs magic number through the shared UAPI
magic header, bumps the Landlock ABI, updates documentation, adds sandboxer
support, and adds selftests.
 
The new behavior is:
 
- a task restricted with LANDLOCK_SCOPE_POSIX_MSG_QUEUE cannot open a queue
  created outside of its Landlock scope;
- a task can still open a queue created within its own Landlock domain;
- queues created outside of any Landlock domain are treated as outside the
  scope for a scoped opener.

[1] https://man7.org/linux/man-pages/man7/mq_overview.7.html

Oxana Kharitonova (6):
  ipc: Move mqueue fs magic to uapi magic header
  landlock: Scope POSIX message queue opens
  landlock: Bump ABI for LANDLOCK_SCOPE_POSIX_MSG_QUEUE
  selftests/landlock: Test POSIX message queue scoping
  samples/landlock: Support POSIX message queue scoping
  landlock: Document POSIX message queue scoping

 Documentation/admin-guide/LSM/landlock.rst    |   6 +-
 Documentation/userspace-api/landlock.rst      |  11 +-
 include/uapi/linux/landlock.h                 |   7 +-
 include/uapi/linux/magic.h                    |   2 +
 ipc/mqueue.c                                  |   2 +-
 samples/landlock/sandboxer.c                  |  16 +-
 security/landlock/audit.c                     |   9 +
 security/landlock/audit.h                     |   1 +
 security/landlock/fs.c                        |  35 +++
 security/landlock/fs.h                        |  15 ++
 security/landlock/limits.h                    |   2 +-
 security/landlock/ruleset.c                   |   1 -
 security/landlock/syscalls.c                  |   2 +-
 security/landlock/task.c                      |  43 ++++
 security/landlock/task.h                      |   4 +
 tools/testing/selftests/landlock/base_test.c  |   2 +-
 .../landlock/scoped_posix_msg_queue_test.c    | 223 ++++++++++++++++++
 .../testing/selftests/landlock/scoped_test.c  |   2 +-
 18 files changed, 371 insertions(+), 12 deletions(-)
 create mode 100644 tools/testing/selftests/landlock/scoped_posix_msg_queue_test.c

-- 
2.50.1 (Apple Git-155)


^ permalink raw reply

* Re: unix_stream_connect and socket address resolution
From: David Laight @ 2026-07-22 10:05 UTC (permalink / raw)
  To: John Ericson
  Cc: Kuniyuki Iwashima, David S . Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Cong Wang, Simon Horman, Christian Brauner,
	David Rheinsberg, Andy Lutomirski, Sergei Zimmerman, network dev,
	Mickaël Salaün, Günther Noack, Paul Moore,
	linux-security-module, LKML
In-Reply-To: <9c437c7c-7919-41e2-9161-fc94803a9b34@app.fastmail.com>

On Tue, 21 Jul 2026 16:37:07 -0400
"John Ericson" <mail@johnericson.me> wrote:

> In case this is useful or interesting to anyone, I deep a some history
> spelunking, and the restart logic in question seems to date back to
> Import 2.2.4pre6:
> 
> https://github.com/tbodt/linux-history/commit/7d4fc34b9bbc0a14d3e5f6b2f978373422e1ca8a#diff-0553d076c243e06ae312480cb8cb52f1cebe1d80fc099d3842593e12c9e0d4f3
> 
> ---
> @@ -673,9 +703,25 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr,
>  	   we will have to recheck all again in any case.
>  	 */
>  
> +restart:
>  	/*  Find listening sock */
>  	other=unix_find_other(sunaddr, addr_len, sk->type, hash, &err);
>  
> +	if (!other)
> +		return -ECONNREFUSED;
> +
> +	while (other->ack_backlog >= other->max_ack_backlog) {
> +		unix_unlock(other);

This unlocks the socket - I doubt it makes sense to sleep with it locked.

> +		if (other->dead || other->state != TCP_LISTEN)
> +			return -ECONNREFUSED;

Those look like potential UAF.
Hopefully changed in the current code!

> +		if (flags & O_NONBLOCK)
> +			return -EAGAIN;
> +		interruptible_sleep_on(&unix_ack_wqueue);
> +		if (signal_pending(current))
> +			return -ERESTARTSYS;
> +		goto restart;

Since 'other' was unlocked the search must be repated.

	David

> +        }
> +
>  	/* create new sock for complete connection */
>  	newsk = unix_create1(NULL, 1);
>  
> @@ -704,7 +750,7 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr,
>  
>  	/* Check that listener is in valid state. */
>  	err = -ECONNREFUSED;
> -	if (other == NULL || other->dead || other->state != TCP_LISTEN)
> +	if (other->dead || other->state != TCP_LISTEN)
>  		goto out;
>  
>  	err = -ENOMEM;
> ---
> 
> My question can be basically restated: why should the `restart` label
> not go *after* the `unix_find_other` call?
> 
> Cheers,
> 
> John
> 


^ permalink raw reply

* Re: unix_stream_connect and socket address resolution
From: Günther Noack @ 2026-07-22  7:25 UTC (permalink / raw)
  To: John Ericson
  Cc: David Laight, Kuniyuki Iwashima, David S . Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Cong Wang, Simon Horman,
	Christian Brauner, David Rheinsberg, Andy Lutomirski,
	Sergei Zimmerman, network dev, Mickaël Salaün,
	Günther Noack, Paul Moore, linux-security-module, LKML
In-Reply-To: <9c437c7c-7919-41e2-9161-fc94803a9b34@app.fastmail.com>

Hello John!

On Tue, Jul 21, 2026 at 04:37:07PM -0400, John Ericson wrote:
> In case this is useful or interesting to anyone, I deep a some history
> spelunking, and the restart logic in question seems to date back to
> Import 2.2.4pre6:
> 
> https://github.com/tbodt/linux-history/commit/7d4fc34b9bbc0a14d3e5f6b2f978373422e1ca8a#diff-0553d076c243e06ae312480cb8cb52f1cebe1d80fc099d3842593e12c9e0d4f3
> 
> ---
> @@ -673,9 +703,25 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr,
>  	   we will have to recheck all again in any case.
>  	 */
>  
> +restart:
>  	/*  Find listening sock */
>  	other=unix_find_other(sunaddr, addr_len, sk->type, hash, &err);
>  
> +	if (!other)
> +		return -ECONNREFUSED;
> +
> +	while (other->ack_backlog >= other->max_ack_backlog) {
> +		unix_unlock(other);
> +		if (other->dead || other->state != TCP_LISTEN)
> +			return -ECONNREFUSED;
> +		if (flags & O_NONBLOCK)
> +			return -EAGAIN;
> +		interruptible_sleep_on(&unix_ack_wqueue);
> +		if (signal_pending(current))
> +			return -ERESTARTSYS;
> +		goto restart;
> +        }
> +
>  	/* create new sock for complete connection */
>  	newsk = unix_create1(NULL, 1);
>  
> @@ -704,7 +750,7 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr,
>  
>  	/* Check that listener is in valid state. */
>  	err = -ECONNREFUSED;
> -	if (other == NULL || other->dead || other->state != TCP_LISTEN)
> +	if (other->dead || other->state != TCP_LISTEN)
>  		goto out;
>  
>  	err = -ENOMEM;
> ---
> 
> My question can be basically restated: why should the `restart` label
> not go *after* the `unix_find_other` call?

To elaborate on David Laights answer -- the classic way of restarting
a Unix Domain socket server is that the server unlink(2)s the socket
file and then bind(2)s the address again.  In other words, when the
server restarts, the new instance offers the service on a socket file
with the same name but it's technically a *fresh* socket file.  So a
"normal" server restart is not technically that different to the
example you gave in your earlier mail (the "File system version").

Another variant of this is one where the server uses rename(2) to
switch out the socket file atomically during restart.

I was not around when that af_unix code was written, and cannot
guarantee that by interpretation is correct, but in the hope that
someone will point it out if it's totally bogus: My interpretation is
that the "goto restart" loop in af_unix.c is designed to smoothen the
server restart cases in a way so that the client doesn't have to deal
with manual system call restarts.  That loop needs to include the
repeated vfs lookup so that it actually gets the socket that belongs
to the fresh socket file.  (Otherwise it would just observe the same
SOCK_DEAD socket from the old server process again. - The new server
serves from a new struct socket.)

Example Scenario, where a client connect(2) races with the shutdown of
an old server during an "atomic" (rename(2)) server restart:

* Old server process serves on /foo/bar.sock
* New server process starts up
* New server process binds (and creates) /foo/bar.sock.tmp
* Client runs connect(2) to /foo/bar.sock,
  does the unix_find_other lookup, getting the old server's socket
* New server process renames /foo/bar.sock.tmp to /foo/bar.sock
* Old server process shuts down, socket transitions to SOCK_DEAD
  through unix_release() -> unix_release_sock() -> sock_orphan()
* Client connect(2) syscall checks the socket and discovers the
  SOCK_DEAD state, because it still holds a pointer to the old server
  socket.

To recover from this, connect(2) does the VFS lookup again, because
the already looked up dead socket isn't coming back.  The connect(2)
function pretends that it ran a tiny bit later and only observed the
new socket.

In this scenario, the userspace server is already going to great
lengths to make the switch atomic - it would be surprising IMHO if the
connect(2) operation could still return errors to userspace due to
race conditions in that case.

Again, this is just my own interpretation.  I also did not find any
better documentation on this.  If I am wrong, I am more than happy to
be corrected. :)

–Günther

^ permalink raw reply

* Re: [RFC PATCH 06/20] bpf: lsm: Add Landlock kfuncs
From: Justin Suess @ 2026-07-21 21:55 UTC (permalink / raw)
  To: Paul Moore
  Cc: Mickaël Salaün, ast, daniel, andrii, kpsingh, viro,
	brauner, kees, gnoack, jack, jmorris, serge, song, yonghong.song,
	martin.lau, m, eddyz87, john.fastabend, sdf, skhan, bpf,
	linux-security-module, linux-kernel, linux-fsdevel,
	Frederick Lawler
In-Reply-To: <CAHC9VhRp6pvQXskNU0FXBkDw=MAF8Ht1Mk7BbUeU8JnEkSk52g@mail.gmail.com>

On Wed, Jul 01, 2026 at 02:33:26PM -0400, Paul Moore wrote:
> On Wed, Jul 1, 2026 at 2:29 PM Justin Suess <utilityemal77@gmail.com> wrote:
> > On Wed, Jul 01, 2026 at 09:28:22AM -0400, Paul Moore wrote:
> > > On Wed, Jul 1, 2026 at 8:52 AM Justin Suess <utilityemal77@gmail.com> wrote:
> > > > On Wed, Jul 01, 2026 at 08:12:34AM -0400, Paul Moore wrote:
> > > > > On Wed, Jul 1, 2026 at 6:59 AM Mickaël Salaün <mic@digikod.net> wrote:
> > > > > > On Tue, Apr 07, 2026 at 04:01:28PM -0400, Justin Suess wrote:
> [..]
>
> Please keep in mind that the LSM framework API needs to be reasonably
> generic.  We've got some general guidance on adding new LSM hooks at
> the link below:
> 
> https://github.com/LinuxSecurityModule/kernel/blob/main/README.md#new-lsm-hooks
>

Howdy,

I'd like to reopen this conversation with a fresh proposal.

Apologies it's been a while.. hope this isn't too long.

I've re-read the LSM design documents linked above, plus some of the
older discussions where similar things were proposed, and this is a
redesign I'd like feedback on before wasting time prototyping.

Background
==========

Refresher (since it's been a minute):

The original RFC exposed kfuncs (non-ABI functions callable
from sleepable BPF LSM programs) straight out of security/landlock, to
apply a userspace-created Landlock ruleset to a binprm during exec.
That skipped the LSM framework entirely and was basically a direct
line into one LSM.

Paul and Casey, as I understand it your objection breaks down into
two parts:

1. LSM configuration/policy interfaces shouldn't exist outside the
   LSM framework. If every LSM grows its own kernel-internal API
   surface it gets messy and hard to refactor.

2. Anything at the framework level has to be reasonably generic. From
   the design docs:

   "Hooks should be designed to be LSM agnostic. While it is possible
   that only one LSM might implement the hook at the time of
   submission, the hook's behavior should be generic enough that
   other LSMs could provide a meaningful implementation."

The proposal here should meet this better.

Proposal
========

Broadly, I am seeking to propose an LSM framework API for kfuncs.

This would be ALL through the existing LSM hook interface.

Instead of individual LSMs exporting kfuncs, the LSM framework exports
all LSM kfuncs and dispatches them to LSMs through generic LSM hooks.

Here's an ASCII diagram (hopefully it doesn't get mangled)
of the framework:

     bpf_landlock_restrict_binprm(bprm, ruleset, flags)
                        |
                        |  strongly BTF-typed
                        |  (struct bpf_landlock_ruleset *)
                        v
   +-------------------------------------------------------------+
   |                       LSM framework                         |
   |                                                             |
   |  security/lsm_kfuncs.c            (owns all kfuncs)         |
   |     - kfunc filter: prog type / sleepable / LSM enabled?    |
   |     - type erasure: ruleset -> void *policy                 |
   |                        |                                    |
   |                        v                                    |
   |  security_kfunc_enforce_bprm_policy(LSM_ID_LANDLOCK,        |
   |                                     bprm, policy, flags)    |
   |                        |                                    |
   |     lsm_for_each_hook: | dispatch by lsm_id                 |
   |        +---------------+---------------+                    |
   |        |               |               |                    |
   +--------|---------------|---------------|--------------------+
            v               v               v
      id != lsm_id     id != lsm_id    id == LSM_ID_LANDLOCK
      (skipped)        (skipped)            |
                                            v
   +-------------------------------------------------------------+
   |  security/landlock                                          |
   |                                                             |
   |  LSM_HOOK_INIT(kfunc_enforce_bprm_policy,                   |
   |                hook_enforce_bprm_policy)                    |
   |     - applies ruleset, staged to bprm_committing_creds      |
   +-------------------------------------------------------------+

      no LSM matches / hook not implemented  ->  -EOPNOTSUPP

1. The LSM framework owns the kfuncs.

   Individual LSMs never register or export a kfunc. All kfuncs live
   under security/ (say security/lsm_kfuncs.c) and go through the LSM
   tree. LSMs only ever implement ordinary LSM hooks, via
   LSM_HOOK_INIT() like anything else. No LSM touches BPF.

   The kfuncs break down into two categories:

   a. kfuncs that talk to the LSM framework itself and no specific
      LSM. There's already userspace precedent for this category in
      the LSM syscalls (lsm_list_modules() etc). To be honest
      category (a) may not need any kfuncs at all to start with; I'm
      including it for completeness of the model :)

   b. kfuncs that carry a policy operation to one specific LSM.
      Applying a Landlock ruleset to a binprm (this series), or
      hypothetically loading an AppArmor profile. The kfunc from
      this series is one of these:

      bpf_landlock_restrict_binprm(struct linux_binprm *bprm,
                                   const struct bpf_landlock_ruleset *ruleset,
                                   u32 flags);

2. Either way, every kfunc call passes through a generic LSM hook. No
   kfunc calls directly into an individual LSM. The shim in
   security/security.c (or other lsm framework owned file) is the
   only caller of the hook.

3. Category (a) kfuncs map 1:1 onto an LSM hook. The framework
   dispatches to every LSM implementing the hook and returns the
   collective verdict, same as any hook today.

4. Category (b) kfuncs follow the existing
   security_getprocattr()/security_setprocattr() precedent: a generic
   hook dispatched by LSM id. For the Landlock case the shim would
   look something like:

      int security_kfunc_enforce_bprm_policy(int lsm_id,
                                             struct linux_binprm *bprm,
                                             void *policy,
                                             u32 flags);

   dispatched by lsm_id:

      lsm_for_each_hook(scall, kfunc_enforce_bprm_policy) {
              if (scall->hl->lsmid->id != lsm_id)
                      continue;
              return scall->hl->hook.kfunc_enforce_bprm_policy(bprm,
                                                        policy, flags);
      }
      return -EOPNOTSUPP;

   The hook is generic in that any LSM with a notion of a per-task or
   per-exec policy object can implement it. Landlock implements it
   like any other hook:

      LSM_HOOK_INIT(kfunc_enforce_bprm_policy,
                    hook_enforce_bprm_policy),

   Critically, Landlock only receives hook calls with a matching
   LSM_ID, so another LSM implementing the same hook never sees calls
   meant for a different kfunc.

5. Type safety at the kfunc boundary is preserved.

   Note the asymmetry between the kfunc signature and the hook
   signature above: the kfunc the BPF verifier sees stays strongly
   BTF-typed (struct bpf_landlock_ruleset *), so BPF programs get
   full verifier type checking and can't pass an arbitrary pointer.

   This also avoids a user facing multiplexer.

   The erasure to void * happens inside the shim, after the verifier
   has already guaranteed the pointer's type, and the receiving LSM
   (picked by lsm_id) is the only LSM that will ever see it. Think
   the relationship setprocattr has with its string payloads, just
   with stronger (BPF verifier-enforced) typing on the kfunc side.

6. The shim checks that the target LSM is actually enabled at
   runtime, and that the calling context is OK (i.e. implementing a
   kfunc filter). This is centralized to make it easier for review
   from both LSM and BPF subsystems.

BPF Side
=========

Alexei / Song / Kumar / BPF maintainers,

Even if this proposal doesn't touch kernel/bpf/, I still would
need to hear your feedback / review on this every bit as much
as I need to hear the LSM side.

I think the kfunc / kptr model with strong typing fits this well.
We can have reference counted and strongly typed policy objects
for the LSMs, and kfuncs give more flexibility for API deprecation
as they are not considered to be ABI like helpers...

Obviously any new kfunc / kptr would need to be reviewed by BPF tree
especially with regards to kptr lifetimes and the calling context.

But hopefully this centralizes the interface that would otherwise be an
ad-hoc mess of individual LSMs trying to define kfuncs willy-nilly and
causing regressions.

One particular point that I would need to know is what should happen if
an LSM is not loaded / compiled in, but the kfunc is called. Is a
verifier rejection acceptible? Or is a runtime error more appropriate
for this?

Thanks,
Justin

^ permalink raw reply

* Re: unix_stream_connect and socket address resolution
From: John Ericson @ 2026-07-21 20:37 UTC (permalink / raw)
  To: David Laight
  Cc: Kuniyuki Iwashima, David S . Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Cong Wang, Simon Horman, Christian Brauner,
	David Rheinsberg, Andy Lutomirski, Sergei Zimmerman, network dev,
	Mickaël Salaün, Günther Noack, Paul Moore,
	linux-security-module, LKML
In-Reply-To: <85991dc3-6fa5-4466-a0cb-b407291cdb44@app.fastmail.com>

In case this is useful or interesting to anyone, I deep a some history
spelunking, and the restart logic in question seems to date back to
Import 2.2.4pre6:

https://github.com/tbodt/linux-history/commit/7d4fc34b9bbc0a14d3e5f6b2f978373422e1ca8a#diff-0553d076c243e06ae312480cb8cb52f1cebe1d80fc099d3842593e12c9e0d4f3

---
@@ -673,9 +703,25 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr,
 	   we will have to recheck all again in any case.
 	 */
 
+restart:
 	/*  Find listening sock */
 	other=unix_find_other(sunaddr, addr_len, sk->type, hash, &err);
 
+	if (!other)
+		return -ECONNREFUSED;
+
+	while (other->ack_backlog >= other->max_ack_backlog) {
+		unix_unlock(other);
+		if (other->dead || other->state != TCP_LISTEN)
+			return -ECONNREFUSED;
+		if (flags & O_NONBLOCK)
+			return -EAGAIN;
+		interruptible_sleep_on(&unix_ack_wqueue);
+		if (signal_pending(current))
+			return -ERESTARTSYS;
+		goto restart;
+        }
+
 	/* create new sock for complete connection */
 	newsk = unix_create1(NULL, 1);
 
@@ -704,7 +750,7 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr,
 
 	/* Check that listener is in valid state. */
 	err = -ECONNREFUSED;
-	if (other == NULL || other->dead || other->state != TCP_LISTEN)
+	if (other->dead || other->state != TCP_LISTEN)
 		goto out;
 
 	err = -ENOMEM;
---

My question can be basically restated: why should the `restart` label
not go *after* the `unix_find_other` call?

Cheers,

John

^ permalink raw reply

* Re: [PATCH v3 1/2] treewide: Add a flag to detect the Apple T2 chip
From: Hans de Goede @ 2026-07-21 15:29 UTC (permalink / raw)
  To: Atharva Tiwari
  Cc: Bjorn Helgaas, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, x86, H. Peter Anvin, Andreas Noever, Mika Westerberg,
	Yehezkel Bernat, Ilpo Järvinen, Jarkko Sakkinen, Mimi Zohar,
	Roberto Sassu, Dmitry Kasatkin, Eric Snowberg, Paul Moore,
	James Morris, Serge E. Hallyn, linux-pci, linux-kernel, linux-usb,
	platform-driver-x86, linux-integrity, keyrings,
	linux-security-module
In-Reply-To: <20260721063412.11588-2-atharvatiwarilinuxdev@gmail.com>

Hi,

On 21-Jul-26 08:34, Atharva Tiwari wrote:
> Add a flag to detect Apple T2 chips on Intel Macs.
> Cache the result to avoid repeated checks. That will
> be used in upcoming patches.
> 
> Signed-off-by: Atharva Tiwari <atharvatiwarilinuxdev@gmail.com>
> ---
>  arch/x86/kernel/quirks.c                      | 105 ++++++++++++++++++
>  include/linux/platform_data/x86/apple.h       |   5 +
>  .../platform_certs/keyring_handler.h          |   8 --
>  security/integrity/platform_certs/load_uefi.c |  38 ++-----
>  4 files changed, 118 insertions(+), 38 deletions(-)
> 
> diff --git a/arch/x86/kernel/quirks.c b/arch/x86/kernel/quirks.c
> index a92f18db9610..300d6436060d 100644
> --- a/arch/x86/kernel/quirks.c
> +++ b/arch/x86/kernel/quirks.c
> @@ -664,8 +664,113 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x2083, quirk_intel_purley_xeon_ras
>  bool x86_apple_machine;
>  EXPORT_SYMBOL(x86_apple_machine);
>  
> +bool has_apple_t2_chip;
> +EXPORT_SYMBOL(has_apple_t2_chip);
> +
> +static const struct dmi_system_id apple_t2_devices[] __initconst = {
> +	{
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro15,1"),
> +		},
> +	},
> +	{
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro15,2"),
> +		},
> +	},
> +	{
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro15,3"),
> +		},
> +	},
> +	{
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro15,4"),
> +		},
> +	},
> +	{
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro16,1"),
> +		},
> +	},
> +	{
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro16,2"),
> +		},
> +	},
> +	{
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro16,3"),
> +		},
> +	},
> +	{
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro16,4"),
> +		},
> +	},
> +	{
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir8,1"),
> +		},
> +	},
> +	{
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir8,2"),
> +		},
> +	},
> +	{
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir9,1"),
> +		},
> +	},
> +	{
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "Macmini8,1"),
> +		},
> +	},
> +	{
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "MacPro7,1"),
> +		},
> +	},
> +	{
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "iMac20,1"),
> +		},
> +	},
> +	{
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "iMac20,2"),
> +		},
> +	},
> +	{
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "iMacPro1,1"),
> +		},
> +	},
> +	{ }
> +};
> +

This takes quite a bit of storage, struct dmi_system_id is not
very efficient.

How about making this a NULL terminated array of strings:

const char *apple_t2_devices[] __initconst = {
	"MacBookPro15,1",
	...
	"iMacPro1,1",
	NULL
};

>  void __init early_platform_quirks(void)
>  {
>  	x86_apple_machine = dmi_match(DMI_SYS_VENDOR, "Apple Inc.") ||
>  			    dmi_match(DMI_SYS_VENDOR, "Apple Computer, Inc.");
> +
> +	has_apple_t2_chip = dmi_check_system(apple_t2_devices);

and then here:

	for (int i = 0; x86_apple_machine && apple_t2_devices[i]; i++)
		if (dmi_match(DMI_PRODUCT_NAME, apple_t2_devices[i])) {
			has_apple_t2_chip = true;
			break;
		}

This should save some space and IMHO just having a compact list of
product-names is more readable too.

Regards,

Hans


>  }
> diff --git a/include/linux/platform_data/x86/apple.h b/include/linux/platform_data/x86/apple.h
> index 079e816c3c21..47b27dceab18 100644
> --- a/include/linux/platform_data/x86/apple.h
> +++ b/include/linux/platform_data/x86/apple.h
> @@ -6,8 +6,13 @@
>   * x86_apple_machine - whether the machine is an x86 Apple Macintosh
>   */
>  extern bool x86_apple_machine;
> +/**
> + * has_apple_t2_chip - whether the machine has the Apple T2 chip
> + */
> +extern bool has_apple_t2_chip;
>  #else
>  #define x86_apple_machine false
> +#define has_apple_t2_chip false
>  #endif
>  
>  #endif
> diff --git a/security/integrity/platform_certs/keyring_handler.h b/security/integrity/platform_certs/keyring_handler.h
> index f92895cc50f6..a355f4400179 100644
> --- a/security/integrity/platform_certs/keyring_handler.h
> +++ b/security/integrity/platform_certs/keyring_handler.h
> @@ -45,11 +45,3 @@ efi_element_handler_t get_handler_for_code_signing_keys(const efi_guid_t *sig_ty
>  efi_element_handler_t get_handler_for_dbx(const efi_guid_t *sig_type);
>  
>  #endif
> -
> -#ifndef UEFI_QUIRK_SKIP_CERT
> -#define UEFI_QUIRK_SKIP_CERT(vendor, product) \
> -		 .matches = { \
> -			DMI_MATCH(DMI_BOARD_VENDOR, vendor), \
> -			DMI_MATCH(DMI_PRODUCT_NAME, product), \
> -		},
> -#endif
> diff --git a/security/integrity/platform_certs/load_uefi.c b/security/integrity/platform_certs/load_uefi.c
> index c0d6948446c3..b4096d4c828d 100644
> --- a/security/integrity/platform_certs/load_uefi.c
> +++ b/security/integrity/platform_certs/load_uefi.c
> @@ -3,42 +3,16 @@
>  #include <linux/kernel.h>
>  #include <linux/sched.h>
>  #include <linux/cred.h>
> -#include <linux/dmi.h>
>  #include <linux/err.h>
>  #include <linux/efi.h>
>  #include <linux/slab.h>
>  #include <linux/ima.h>
> +#include <linux/platform_data/x86/apple.h>
>  #include <keys/asymmetric-type.h>
>  #include <keys/system_keyring.h>
>  #include "../integrity.h"
>  #include "keyring_handler.h"
>  
> -/*
> - * On T2 Macs reading the db and dbx efi variables to load UEFI Secure Boot
> - * certificates causes occurrence of a page fault in Apple's firmware and
> - * a crash disabling EFI runtime services. The following quirk skips reading
> - * these variables.
> - */
> -static const struct dmi_system_id uefi_skip_cert[] = {
> -	{ UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro15,1") },
> -	{ UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro15,2") },
> -	{ UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro15,3") },
> -	{ UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro15,4") },
> -	{ UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro16,1") },
> -	{ UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro16,2") },
> -	{ UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro16,3") },
> -	{ UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro16,4") },
> -	{ UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookAir8,1") },
> -	{ UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookAir8,2") },
> -	{ UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookAir9,1") },
> -	{ UEFI_QUIRK_SKIP_CERT("Apple Inc.", "Macmini8,1") },
> -	{ UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacPro7,1") },
> -	{ UEFI_QUIRK_SKIP_CERT("Apple Inc.", "iMac20,1") },
> -	{ UEFI_QUIRK_SKIP_CERT("Apple Inc.", "iMac20,2") },
> -	{ UEFI_QUIRK_SKIP_CERT("Apple Inc.", "iMacPro1,1") },
> -	{ }
> -};
> -
>  /*
>   * Look to see if a UEFI variable called MokIgnoreDB exists and return true if
>   * it does.
> @@ -165,10 +139,14 @@ static int __init load_uefi_certs(void)
>  	unsigned long dbsize = 0, dbxsize = 0, mokxsize = 0;
>  	efi_status_t status;
>  	int rc = 0;
> -	const struct dmi_system_id *dmi_id;
>  
> -	dmi_id = dmi_first_match(uefi_skip_cert);
> -	if (dmi_id) {
> +	/*
> +	 * On T2 Macs reading the db and dbx efi variables to load UEFI Secure Boot
> +	 * certificates causes occurrence of a page fault in Apple's firmware and
> +	 * a crash disabling EFI runtime services. The following quirk skips reading
> +	 * these variables.
> +	 */
> +	if (has_apple_t2_chip) {
>  		pr_err("Reading UEFI Secure Boot Certs is not supported on T2 Macs.\n");
>  		return false;
>  	}


^ permalink raw reply

* Re: [PATCH v4] security: Expand task_setscheduler LSM hook
From: Casey Schaufler @ 2026-07-21 14:45 UTC (permalink / raw)
  To: Aaron Tomlin, tsbogend, paul, jmorris, serge, mingo, peterz,
	juri.lelli, vincent.guittot, stephen.smalley.work, longman, tj,
	hannes, mkoutny
  Cc: chenridong, dietmar.eggemann, rostedt, bsegall, mgorman, vschneid,
	kprateek.nayak, omosnace, kees, neelx, sean, chjohnst, steve,
	mproche, nick.lange, cgroups, linux-mips, linux-fsdevel,
	linux-security-module, selinux, linux-kernel, Casey Schaufler
In-Reply-To: <20260720014156.459386-1-atomlin@atomlin.com>

On 7/19/2026 6:41 PM, Aaron Tomlin wrote:
> At present, the task_setscheduler LSM hook provides security modules
> with the opportunity to mediate changes to a task's scheduling policy by
> inspecting the requested sched_attr. However, when invoked via
> sched_setaffinity(), the hook lacks visibility into the actual CPU
> affinity mask being requested. Consequently, security modules are
> entirely blind to the target CPUs and cannot make granular access
> control decisions based on spatial isolation.
>
> In modern multi-tenant and real-time environments, CPU isolation is a
> critical boundary. The inability to audit or restrict specific CPU
> pinning requests limits the effectiveness of security policies,
> particularly when attempting to shield isolated or cryptographic cores
> from unprivileged or compromised tasks.
>
> This patch expands the security_task_setscheduler() hook signature to
> include a pointer to the requested cpumask alongside the existing
> sched_attr. Because this is a shared hook used for multiple scheduling
> attribute changes, call sites that do not modify CPU affinity are
> updated to safely pass NULL for the mask. To protect against unverified
> dereferences, the parameter is annotated with __nullable in the LSM hook
> definition, ensuring the BPF verifier mandates explicit NULL checks for
> attached eBPF programs.
>
> Historically, SELinux has governed all scheduling alterations under a
> single, monolithic PROCESS__SETSCHED access vector. However, by
> inspecting fields such as attr->sched_policy or attr->sched_priority, a
> security module can introduce granular access controls. For instance,
> differentiating between standard time-sharing policies and
> latency-sensitive real-time policies.
>
> This change updates all in-tree security modules (SELinux and Smack) to
> accommodate the new parameter mechanically, while providing LSMs with
> the necessary context to enforce strict affinity policies.
>
> Signed-off-by: Aaron Tomlin <atomlin@atomlin.com>
> ---
> Changes since v3:
>
>  - Expanded the task_setscheduler LSM hook to accept the 'sched_attr'
>    payload, enabling BPF and other LSMs to inspect scheduling attributes
>    (Peter Zijlstra)
>
>  - Updated all call sites for security_task_setscheduler() to correctly
>    pass the attr structure when available, or NULL otherwise
>    (Peter Zijlstra)
>
>  - Added the necessary forward declaration for struct sched_attr to
>    include/linux/security.h
>
>  - Linked to v3: https://lore.kernel.org/lkml/20260526142838.774711-1-atomlin@atomlin.com/
>
> Changes since v2:
>
>  - Dropped patch 1. This is to be addressed by the cgroup cpuset
>    maintainer (Waiman Long)
>
>  - Dropped patch 3. Will be submitted as a separate patch (Paul Moore)
>
>  - Linked to v2: https://lore.kernel.org/lkml/20260509213803.968464-1-atomlin@atomlin.com/
>
> Changes since v1:
>
>  - Reordered the allocation and user-copy of new_mask in the MIPS
>    architecture's mipsmt_sys_sched_setaffinity() to occur before the
>    LSM hook is invoked. This ensures the security modules evaluate a fully
>    populated mask rather than uninitialised memory, while cleanly handling
>    error unwinding
>
>  - Updated cpuset_can_fork() to pass the destination cpuset's effective CPU
>    mask instead of NULL
>
>  - Linked to v1: https://lore.kernel.org/lkml/20260509164847.939294-1-atomlin@atomlin.com/
>
> Signed-off-by: Aaron Tomlin <atomlin@atomlin.com>

For the (trivial) Smack changes:
Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>

> ---
>  arch/mips/kernel/mips-mt-fpaff.c |  2 +-
>  fs/proc/base.c                   |  2 +-
>  include/linux/lsm_hook_defs.h    |  4 +++-
>  include/linux/security.h         | 15 +++++++++++----
>  kernel/cgroup/cpuset.c           |  4 ++--
>  kernel/sched/syscalls.c          |  4 ++--
>  security/commoncap.c             |  9 +++++++--
>  security/security.c              | 14 +++++++++-----
>  security/selinux/hooks.c         |  4 +++-
>  security/smack/smack_lsm.c       | 13 +++++++++++--
>  10 files changed, 50 insertions(+), 21 deletions(-)
>
> diff --git a/arch/mips/kernel/mips-mt-fpaff.c b/arch/mips/kernel/mips-mt-fpaff.c
> index 4fead87d2f43..c7a5d55cf7ca 100644
> --- a/arch/mips/kernel/mips-mt-fpaff.c
> +++ b/arch/mips/kernel/mips-mt-fpaff.c
> @@ -110,7 +110,7 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
>  		goto out_unlock;
>  	}
>  
> -	retval = security_task_setscheduler(p);
> +	retval = security_task_setscheduler(p, NULL, new_mask);
>  	if (retval)
>  		goto out_unlock;
>  
> diff --git a/fs/proc/base.c b/fs/proc/base.c
> index 780f81259052..b14401030e5c 100644
> --- a/fs/proc/base.c
> +++ b/fs/proc/base.c
> @@ -2589,7 +2589,7 @@ static ssize_t timerslack_ns_write(struct file *file, const char __user *buf,
>  		}
>  		rcu_read_unlock();
>  
> -		err = security_task_setscheduler(p);
> +		err = security_task_setscheduler(p, NULL, NULL);
>  		if (err) {
>  			count = err;
>  			goto out;
> diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
> index 65c9609ec207..80ca02879620 100644
> --- a/include/linux/lsm_hook_defs.h
> +++ b/include/linux/lsm_hook_defs.h
> @@ -255,7 +255,9 @@ LSM_HOOK(int, 0, task_prlimit, const struct cred *cred,
>  	 const struct cred *tcred, unsigned int flags)
>  LSM_HOOK(int, 0, task_setrlimit, struct task_struct *p, unsigned int resource,
>  	 struct rlimit *new_rlim)
> -LSM_HOOK(int, 0, task_setscheduler, struct task_struct *p)
> +LSM_HOOK(int, 0, task_setscheduler, struct task_struct *p,
> +	 const struct sched_attr *attr__nullable,
> +	 const struct cpumask *in_mask__nullable)
>  LSM_HOOK(int, 0, task_getscheduler, struct task_struct *p)
>  LSM_HOOK(int, 0, task_movememory, struct task_struct *p)
>  LSM_HOOK(int, 0, task_kill, struct task_struct *p, struct kernel_siginfo *info,
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 153e9043058f..82dfe4e3f8d1 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -82,6 +82,7 @@ struct ctl_table;
>  struct audit_krule;
>  struct user_namespace;
>  struct timezone;
> +struct sched_attr;
>  
>  enum lsm_event {
>  	LSM_POLICY_CHANGE,
> @@ -196,7 +197,9 @@ extern int cap_mmap_addr(unsigned long addr);
>  extern int cap_task_fix_setuid(struct cred *new, const struct cred *old, int flags);
>  extern int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
>  			  unsigned long arg4, unsigned long arg5);
> -extern int cap_task_setscheduler(struct task_struct *p);
> +extern int cap_task_setscheduler(struct task_struct *p,
> +				 const struct sched_attr *attr,
> +				 const struct cpumask *in_mask);
>  extern int cap_task_setioprio(struct task_struct *p, int ioprio);
>  extern int cap_task_setnice(struct task_struct *p, int nice);
>  extern int cap_vm_enough_memory(struct mm_struct *mm, long pages);
> @@ -531,7 +534,9 @@ int security_task_prlimit(const struct cred *cred, const struct cred *tcred,
>  			  unsigned int flags);
>  int security_task_setrlimit(struct task_struct *p, unsigned int resource,
>  		struct rlimit *new_rlim);
> -int security_task_setscheduler(struct task_struct *p);
> +int security_task_setscheduler(struct task_struct *p,
> +			       const struct sched_attr *attr,
> +			       const struct cpumask *in_mask);
>  int security_task_getscheduler(struct task_struct *p);
>  int security_task_movememory(struct task_struct *p);
>  int security_task_kill(struct task_struct *p, struct kernel_siginfo *info,
> @@ -1393,9 +1398,11 @@ static inline int security_task_setrlimit(struct task_struct *p,
>  	return 0;
>  }
>  
> -static inline int security_task_setscheduler(struct task_struct *p)
> +static inline int security_task_setscheduler(struct task_struct *p,
> +					     const struct sched_attr *attr,
> +					     const struct cpumask *in_mask)
>  {
> -	return cap_task_setscheduler(p);
> +	return cap_task_setscheduler(p, attr, in_mask);
>  }
>  
>  static inline int security_task_getscheduler(struct task_struct *p)
> diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
> index 45944b3e31ca..6ab47cf5582b 100644
> --- a/kernel/cgroup/cpuset.c
> +++ b/kernel/cgroup/cpuset.c
> @@ -3042,7 +3042,7 @@ static int cpuset_can_attach(struct cgroup_taskset *tset)
>  			goto out_unlock;
>  
>  		if (setsched_check) {
> -			ret = security_task_setscheduler(task);
> +			ret = security_task_setscheduler(task, NULL, cs->effective_cpus);
>  			if (ret)
>  				goto out_unlock;
>  		}
> @@ -3600,7 +3600,7 @@ static int cpuset_can_fork(struct task_struct *task, struct css_set *cset)
>  	if (ret)
>  		goto out_unlock;
>  
> -	ret = security_task_setscheduler(task);
> +	ret = security_task_setscheduler(task, NULL, cs->effective_cpus);
>  	if (ret)
>  		goto out_unlock;
>  
> diff --git a/kernel/sched/syscalls.c b/kernel/sched/syscalls.c
> index b215b0ead9a6..86490035e815 100644
> --- a/kernel/sched/syscalls.c
> +++ b/kernel/sched/syscalls.c
> @@ -540,7 +540,7 @@ int __sched_setscheduler(struct task_struct *p,
>  		if (attr->sched_flags & SCHED_FLAG_SUGOV)
>  			return -EINVAL;
>  
> -		retval = security_task_setscheduler(p);
> +		retval = security_task_setscheduler(p, attr, NULL);
>  		if (retval)
>  			return retval;
>  	}
> @@ -1213,7 +1213,7 @@ long sched_setaffinity(pid_t pid, const struct cpumask *in_mask)
>  			return -EPERM;
>  	}
>  
> -	retval = security_task_setscheduler(p);
> +	retval = security_task_setscheduler(p, NULL, in_mask);
>  	if (retval)
>  		return retval;
>  
> diff --git a/security/commoncap.c b/security/commoncap.c
> index 3399535808fe..d83eee0459fe 100644
> --- a/security/commoncap.c
> +++ b/security/commoncap.c
> @@ -1222,13 +1222,18 @@ static int cap_safe_nice(struct task_struct *p)
>  /**
>   * cap_task_setscheduler - Determine if scheduler policy change is permitted
>   * @p: The task to affect
> + * @attr: Requested scheduling attributes (ignored)
> + * @in_mask: Requested CPU affinity mask (ignored)
>   *
>   * Determine if the requested scheduler policy change is permitted for the
> - * specified task.
> + * specified task. The capabilities security module does not evaluate the
> + * @attr or @in_mask parameters, relying solely on cap_safe_nice().
>   *
>   * Return: 0 if permission is granted, -ve if denied.
>   */
> -int cap_task_setscheduler(struct task_struct *p)
> +int cap_task_setscheduler(struct task_struct *p,
> +			  const struct sched_attr *attr __always_unused,
> +			  const struct cpumask *in_mask __always_unused)
>  {
>  	return cap_safe_nice(p);
>  }
> diff --git a/security/security.c b/security/security.c
> index 71aea8fdf014..a6725dddc34f 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -3240,17 +3240,21 @@ int security_task_setrlimit(struct task_struct *p, unsigned int resource,
>  }
>  
>  /**
> - * security_task_setscheduler() - Check if setting sched policy/param is allowed
> + * security_task_setscheduler() - Check if setting sched policy/param/affinity is allowed
>   * @p: target task
> + * @attr: requested scheduling attributes, or NULL if not changing parameters
> + * @in_mask: requested CPU affinity mask, or NULL if not changing affinity
>   *
> - * Check permission before setting scheduling policy and/or parameters of
> - * process @p.
> + * Check permission before setting the scheduling policy, parameters, and/or
> + * CPU affinity of process @p.
>   *
>   * Return: Returns 0 if permission is granted.
>   */
> -int security_task_setscheduler(struct task_struct *p)
> +int security_task_setscheduler(struct task_struct *p,
> +			       const struct sched_attr *attr,
> +			       const struct cpumask *in_mask)
>  {
> -	return call_int_hook(task_setscheduler, p);
> +	return call_int_hook(task_setscheduler, p, attr, in_mask);
>  }
>  
>  /**
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index 8d6945edae7a..d77a8d5c364c 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -4559,7 +4559,9 @@ static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource,
>  	return 0;
>  }
>  
> -static int selinux_task_setscheduler(struct task_struct *p)
> +static int selinux_task_setscheduler(struct task_struct *p,
> +				     const struct sched_attr *attr __always_unused,
> +				     const struct cpumask *in_mask __always_unused)
>  {
>  	return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
>  			    PROCESS__SETSCHED, NULL);
> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
> index ff115068c5c0..cf28ccc28b80 100644
> --- a/security/smack/smack_lsm.c
> +++ b/security/smack/smack_lsm.c
> @@ -2338,10 +2338,19 @@ static int smack_task_getioprio(struct task_struct *p)
>  /**
>   * smack_task_setscheduler - Smack check on setting scheduler
>   * @p: the task object
> + * @attr: Requested scheduling attributes (ignored)
> + * @in_mask: Requested CPU affinity mask (ignored)
>   *
> - * Return 0 if read access is permitted
> + * Evaluate whether the current task has write access to the target task @p
> + * to change its scheduling policy. The Smack security module relies
> + * strictly on label-based access control and does not evaluate CPU
> + * affinity masks or scheduling attributes.
> + *
> + * Return: 0 if write access is permitted
>   */
> -static int smack_task_setscheduler(struct task_struct *p)
> +static int smack_task_setscheduler(struct task_struct *p,
> +				   const struct sched_attr *attr __always_unused,
> +				   const struct cpumask *in_mask __always_unused)
>  {
>  	return smk_curacc_on_task(p, MAY_WRITE, __func__);
>  }

^ permalink raw reply

* [PATCH v2 3/3] module: Bring includes in linux/kmod.h up to date
From: Petr Pavlu @ 2026-07-21 13:11 UTC (permalink / raw)
  To: Tony Luck, Borislav Petkov, Thomas Gleixner, Ingo Molnar,
	Dave Hansen, x86, H. Peter Anvin, Philipp Reisner, Lars Ellenberg,
	Christoph Böhmwalder, Jens Axboe, Johan Hovold, Alex Elder,
	Greg Kroah-Hartman, Rafael J. Wysocki, Michal Januszewski,
	Helge Deller, Alexander Viro, Christian Brauner, Jan Kara,
	Trond Myklebust, Anna Schumaker, Chuck Lever, Jeff Layton,
	NeilBrown, Olga Kornievskaia, Dai Ngo, Tom Talpey, Mark Fasheh,
	Joel Becker, Joseph Qi, Tejun Heo, Johannes Weiner,
	Michal Koutný, Luis Chamberlain, Petr Pavlu, Daniel Gomez,
	Sami Tolvanen, Aaron Tomlin, Pavel Machek, Len Brown,
	Andrew Morton, Danilo Krummrich, Nikolay Aleksandrov,
	Ido Schimmel, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, David Howells, Jarkko Sakkinen,
	Paul Moore, James Morris, Serge E. Hallyn, Kentaro Takeda,
	Tetsuo Handa
  Cc: linux-edac, linux-kernel, drbd-dev, linux-block, greybus-dev,
	linuxppc-dev, linux-acpi, linux-fbdev, dri-devel, linux-fsdevel,
	linux-nfs, ocfs2-devel, cgroups, linux-modules, linux-pm,
	driver-core, bridge, netdev, keyrings, linux-security-module
In-Reply-To: <20260721131207.803760-1-petr.pavlu@suse.com>

Including linux/kmod.h alone results in 1.5 MB of preprocessed output, even
though it provides only a few functions and macros.

The header currently depends on:

* __printf() -> linux/compiler_attributes.h,
* ENOSYS -> linux/errno.h,
* bool -> linux/types.h.

Include only these files, reducing the preprocessed output to 10 kB.

Signed-off-by: Petr Pavlu <petr.pavlu@suse.com>
Reviewed-by: Aaron Tomlin <atomlin@atomlin.com>
---
 include/linux/kmod.h | 12 ++----------
 1 file changed, 2 insertions(+), 10 deletions(-)

diff --git a/include/linux/kmod.h b/include/linux/kmod.h
index 9a07c3215389..b9474a62a568 100644
--- a/include/linux/kmod.h
+++ b/include/linux/kmod.h
@@ -2,17 +2,9 @@
 #ifndef __LINUX_KMOD_H__
 #define __LINUX_KMOD_H__
 
-/*
- *	include/linux/kmod.h
- */
-
-#include <linux/umh.h>
-#include <linux/gfp.h>
-#include <linux/stddef.h>
+#include <linux/compiler_attributes.h>
 #include <linux/errno.h>
-#include <linux/compiler.h>
-#include <linux/workqueue.h>
-#include <linux/sysctl.h>
+#include <linux/types.h>
 
 #ifdef CONFIG_MODULES
 /* modprobe exit status on success, -ve on error.  Return value
-- 
2.54.0


^ permalink raw reply related

* [PATCH v2 2/3] time/jiffies: Include linux/sysctl.h for proc_int_u2k_conv_uop(), ...
From: Petr Pavlu @ 2026-07-21 13:11 UTC (permalink / raw)
  To: Tony Luck, Borislav Petkov, Thomas Gleixner, Ingo Molnar,
	Dave Hansen, x86, H. Peter Anvin, Philipp Reisner, Lars Ellenberg,
	Christoph Böhmwalder, Jens Axboe, Johan Hovold, Alex Elder,
	Greg Kroah-Hartman, Rafael J. Wysocki, Michal Januszewski,
	Helge Deller, Alexander Viro, Christian Brauner, Jan Kara,
	Trond Myklebust, Anna Schumaker, Chuck Lever, Jeff Layton,
	NeilBrown, Olga Kornievskaia, Dai Ngo, Tom Talpey, Mark Fasheh,
	Joel Becker, Joseph Qi, Tejun Heo, Johannes Weiner,
	Michal Koutný, Luis Chamberlain, Petr Pavlu, Daniel Gomez,
	Sami Tolvanen, Aaron Tomlin, Pavel Machek, Len Brown,
	Andrew Morton, Danilo Krummrich, Nikolay Aleksandrov,
	Ido Schimmel, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, David Howells, Jarkko Sakkinen,
	Paul Moore, James Morris, Serge E. Hallyn, Kentaro Takeda,
	Tetsuo Handa
  Cc: linux-edac, linux-kernel, drbd-dev, linux-block, greybus-dev,
	linuxppc-dev, linux-acpi, linux-fbdev, dri-devel, linux-fsdevel,
	linux-nfs, ocfs2-devel, cgroups, linux-modules, linux-pm,
	driver-core, bridge, netdev, keyrings, linux-security-module
In-Reply-To: <20260721131207.803760-1-petr.pavlu@suse.com>

The kernel/time/jiffies.c file uses proc_int_u2k_conv_uop(),
proc_int_k2u_conv_kop(), proc_int_conv(), proc_dointvec_conv() and
proc_doulongvec_minmax_conv(), which are declared in linux/sysctl.h. It
currently relies on this header being included indirectly through
linux/module.h -> linux/kmod.h. Add the missing include in preparation for
removing the linux/sysctl.h include from linux/kmod.h.

Signed-off-by: Petr Pavlu <petr.pavlu@suse.com>
---
 kernel/time/jiffies.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/kernel/time/jiffies.c b/kernel/time/jiffies.c
index d51428867a33..17cdb5ef8893 100644
--- a/kernel/time/jiffies.c
+++ b/kernel/time/jiffies.c
@@ -8,6 +8,7 @@
 #include <linux/jiffies.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/sysctl.h>
 
 #include "timekeeping.h"
 #include "tick-internal.h"
-- 
2.54.0


^ permalink raw reply related

* [PATCH v2 1/3] umh, treewide: Explicitly include linux/umh.h where needed
From: Petr Pavlu @ 2026-07-21 13:11 UTC (permalink / raw)
  To: Tony Luck, Borislav Petkov, Thomas Gleixner, Ingo Molnar,
	Dave Hansen, x86, H. Peter Anvin, Philipp Reisner, Lars Ellenberg,
	Christoph Böhmwalder, Jens Axboe, Johan Hovold, Alex Elder,
	Greg Kroah-Hartman, Rafael J. Wysocki, Michal Januszewski,
	Helge Deller, Alexander Viro, Christian Brauner, Jan Kara,
	Trond Myklebust, Anna Schumaker, Chuck Lever, Jeff Layton,
	NeilBrown, Olga Kornievskaia, Dai Ngo, Tom Talpey, Mark Fasheh,
	Joel Becker, Joseph Qi, Tejun Heo, Johannes Weiner,
	Michal Koutný, Luis Chamberlain, Petr Pavlu, Daniel Gomez,
	Sami Tolvanen, Aaron Tomlin, Pavel Machek, Len Brown,
	Andrew Morton, Danilo Krummrich, Nikolay Aleksandrov,
	Ido Schimmel, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, David Howells, Jarkko Sakkinen,
	Paul Moore, James Morris, Serge E. Hallyn, Kentaro Takeda,
	Tetsuo Handa
  Cc: linux-edac, linux-kernel, drbd-dev, linux-block, greybus-dev,
	linuxppc-dev, linux-acpi, linux-fbdev, dri-devel, linux-fsdevel,
	linux-nfs, ocfs2-devel, cgroups, linux-modules, linux-pm,
	driver-core, bridge, netdev, keyrings, linux-security-module
In-Reply-To: <20260721131207.803760-1-petr.pavlu@suse.com>

The usermode helper declarations were previously provided by linux/kmod.h
but commit c1f3fa2a4fde ("kmod: split off umh headers into its own file")
moved them to linux/umh.h in 2017. Add explicit includes of linux/umh.h to
files that use usermode helpers and remove linux/kmod.h where it is no
longer needed.

Signed-off-by: Petr Pavlu <petr.pavlu@suse.com>
---
 arch/x86/kernel/cpu/mce/dev-mcelog.c | 2 +-
 drivers/block/drbd/drbd_nl.c         | 1 +
 drivers/greybus/svc_watchdog.c       | 1 +
 drivers/macintosh/windfarm_core.c    | 1 +
 drivers/pnp/pnpbios/core.c           | 2 +-
 drivers/video/fbdev/uvesafb.c        | 1 +
 fs/coredump.c                        | 2 +-
 fs/nfs/cache_lib.c                   | 2 +-
 fs/nfsd/nfs4layouts.c                | 2 +-
 fs/nfsd/nfs4recover.c                | 1 +
 fs/ocfs2/stackglue.c                 | 1 +
 kernel/cgroup/cgroup-v1.c            | 2 +-
 kernel/module/kmod.c                 | 1 +
 kernel/power/process.c               | 2 +-
 kernel/reboot.c                      | 2 +-
 kernel/umh.c                         | 2 +-
 lib/kobject_uevent.c                 | 2 +-
 net/bridge/br_stp_if.c               | 2 +-
 security/keys/request_key.c          | 2 +-
 security/tomoyo/common.h             | 2 +-
 20 files changed, 20 insertions(+), 13 deletions(-)

diff --git a/arch/x86/kernel/cpu/mce/dev-mcelog.c b/arch/x86/kernel/cpu/mce/dev-mcelog.c
index 053555206d81..af4e76babe7a 100644
--- a/arch/x86/kernel/cpu/mce/dev-mcelog.c
+++ b/arch/x86/kernel/cpu/mce/dev-mcelog.c
@@ -11,7 +11,7 @@
 
 #include <linux/miscdevice.h>
 #include <linux/slab.h>
-#include <linux/kmod.h>
+#include <linux/umh.h>
 #include <linux/poll.h>
 
 #include "internal.h"
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
index f9ffcd67607b..de90cf4a0789 100644
--- a/drivers/block/drbd/drbd_nl.c
+++ b/drivers/block/drbd/drbd_nl.c
@@ -14,6 +14,7 @@
 #define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
 
 #include <linux/module.h>
+#include <linux/umh.h>
 #include <linux/drbd.h>
 #include <linux/in.h>
 #include <linux/fs.h>
diff --git a/drivers/greybus/svc_watchdog.c b/drivers/greybus/svc_watchdog.c
index 16e6de5e9eff..b318eb34bcca 100644
--- a/drivers/greybus/svc_watchdog.c
+++ b/drivers/greybus/svc_watchdog.c
@@ -7,6 +7,7 @@
 
 #include <linux/delay.h>
 #include <linux/suspend.h>
+#include <linux/umh.h>
 #include <linux/workqueue.h>
 #include <linux/greybus.h>
 
diff --git a/drivers/macintosh/windfarm_core.c b/drivers/macintosh/windfarm_core.c
index 5307b1e34261..e66de11c69a3 100644
--- a/drivers/macintosh/windfarm_core.c
+++ b/drivers/macintosh/windfarm_core.c
@@ -34,6 +34,7 @@
 #include <linux/platform_device.h>
 #include <linux/mutex.h>
 #include <linux/freezer.h>
+#include <linux/umh.h>
 
 #include "windfarm.h"
 
diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c
index f7e86ae9f72f..46af1f549337 100644
--- a/drivers/pnp/pnpbios/core.c
+++ b/drivers/pnp/pnpbios/core.c
@@ -47,7 +47,7 @@
 #include <linux/delay.h>
 #include <linux/acpi.h>
 #include <linux/freezer.h>
-#include <linux/kmod.h>
+#include <linux/umh.h>
 #include <linux/kthread.h>
 
 #include <asm/page.h>
diff --git a/drivers/video/fbdev/uvesafb.c b/drivers/video/fbdev/uvesafb.c
index 9d82326c744f..6c503e6914d6 100644
--- a/drivers/video/fbdev/uvesafb.c
+++ b/drivers/video/fbdev/uvesafb.c
@@ -23,6 +23,7 @@
 #include <linux/io.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
+#include <linux/umh.h>
 #include <video/edid.h>
 #include <video/uvesafb.h>
 #ifdef CONFIG_X86
diff --git a/fs/coredump.c b/fs/coredump.c
index e68a76ff92a3..4908b44f6fdc 100644
--- a/fs/coredump.c
+++ b/fs/coredump.c
@@ -32,7 +32,7 @@
 #include <linux/tsacct_kern.h>
 #include <linux/cn_proc.h>
 #include <linux/audit.h>
-#include <linux/kmod.h>
+#include <linux/umh.h>
 #include <linux/fsnotify.h>
 #include <linux/fs_struct.h>
 #include <linux/pipe_fs_i.h>
diff --git a/fs/nfs/cache_lib.c b/fs/nfs/cache_lib.c
index 9738a1ae92ca..ca4e81d4e315 100644
--- a/fs/nfs/cache_lib.c
+++ b/fs/nfs/cache_lib.c
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 2009 Trond Myklebust <Trond.Myklebust@netapp.com>
  */
-#include <linux/kmod.h>
+#include <linux/umh.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/mount.h>
diff --git a/fs/nfsd/nfs4layouts.c b/fs/nfsd/nfs4layouts.c
index f34320e4c2f4..008f0f088c3a 100644
--- a/fs/nfsd/nfs4layouts.c
+++ b/fs/nfsd/nfs4layouts.c
@@ -3,7 +3,7 @@
  * Copyright (c) 2014 Christoph Hellwig.
  */
 #include <linux/exportfs_block.h>
-#include <linux/kmod.h>
+#include <linux/umh.h>
 #include <linux/file.h>
 #include <linux/jhash.h>
 #include <linux/sched.h>
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index 6ea25a52d2f4..20b98e43f668 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -41,6 +41,7 @@
 #include <linux/fs.h>
 #include <linux/hex.h>
 #include <linux/module.h>
+#include <linux/umh.h>
 #include <net/net_namespace.h>
 #include <linux/sunrpc/rpc_pipe_fs.h>
 #include <linux/sunrpc/clnt.h>
diff --git a/fs/ocfs2/stackglue.c b/fs/ocfs2/stackglue.c
index 741d6191d871..0ccaab29426d 100644
--- a/fs/ocfs2/stackglue.c
+++ b/fs/ocfs2/stackglue.c
@@ -18,6 +18,7 @@
 #include <linux/kobject.h>
 #include <linux/sysfs.h>
 #include <linux/sysctl.h>
+#include <linux/umh.h>
 
 #include "ocfs2_fs.h"
 
diff --git a/kernel/cgroup/cgroup-v1.c b/kernel/cgroup/cgroup-v1.c
index a4337c9b5287..cbcde5c28b18 100644
--- a/kernel/cgroup/cgroup-v1.c
+++ b/kernel/cgroup/cgroup-v1.c
@@ -2,7 +2,7 @@
 #include "cgroup-internal.h"
 
 #include <linux/ctype.h>
-#include <linux/kmod.h>
+#include <linux/umh.h>
 #include <linux/sort.h>
 #include <linux/delay.h>
 #include <linux/mm.h>
diff --git a/kernel/module/kmod.c b/kernel/module/kmod.c
index a25dccdf7aa7..dcaad5d65275 100644
--- a/kernel/module/kmod.c
+++ b/kernel/module/kmod.c
@@ -28,6 +28,7 @@
 #include <linux/ptrace.h>
 #include <linux/async.h>
 #include <linux/uaccess.h>
+#include <linux/umh.h>
 
 #include <trace/events/module.h>
 #include "internal.h"
diff --git a/kernel/power/process.c b/kernel/power/process.c
index dc0dfc349f22..295904ec9a82 100644
--- a/kernel/power/process.c
+++ b/kernel/power/process.c
@@ -16,7 +16,7 @@
 #include <linux/freezer.h>
 #include <linux/delay.h>
 #include <linux/workqueue.h>
-#include <linux/kmod.h>
+#include <linux/umh.h>
 #include <trace/events/power.h>
 #include <linux/cpuset.h>
 
diff --git a/kernel/reboot.c b/kernel/reboot.c
index 695c33e75efd..3d4a262973e7 100644
--- a/kernel/reboot.c
+++ b/kernel/reboot.c
@@ -11,13 +11,13 @@
 #include <linux/ctype.h>
 #include <linux/export.h>
 #include <linux/kexec.h>
-#include <linux/kmod.h>
 #include <linux/kmsg_dump.h>
 #include <linux/reboot.h>
 #include <linux/suspend.h>
 #include <linux/syscalls.h>
 #include <linux/syscore_ops.h>
 #include <linux/uaccess.h>
+#include <linux/umh.h>
 
 /*
  * this indicates whether you can reboot with ctrl-alt-del: the default is yes
diff --git a/kernel/umh.c b/kernel/umh.c
index 48117c569e1a..72b2d9a878aa 100644
--- a/kernel/umh.c
+++ b/kernel/umh.c
@@ -8,7 +8,7 @@
 #include <linux/binfmts.h>
 #include <linux/syscalls.h>
 #include <linux/unistd.h>
-#include <linux/kmod.h>
+#include <linux/umh.h>
 #include <linux/slab.h>
 #include <linux/completion.h>
 #include <linux/cred.h>
diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c
index ddbc4d7482d2..a67129e452a3 100644
--- a/lib/kobject_uevent.c
+++ b/lib/kobject_uevent.c
@@ -17,7 +17,7 @@
 #include <linux/string.h>
 #include <linux/kobject.h>
 #include <linux/export.h>
-#include <linux/kmod.h>
+#include <linux/umh.h>
 #include <linux/slab.h>
 #include <linux/socket.h>
 #include <linux/skbuff.h>
diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c
index a7e5422eb5d1..89bc161a4b47 100644
--- a/net/bridge/br_stp_if.c
+++ b/net/bridge/br_stp_if.c
@@ -8,7 +8,7 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/kmod.h>
+#include <linux/umh.h>
 #include <linux/etherdevice.h>
 #include <linux/rtnetlink.h>
 #include <net/switchdev.h>
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index fa2bb9f2f538..e6ba2d054399 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -9,7 +9,7 @@
 
 #include <linux/export.h>
 #include <linux/sched.h>
-#include <linux/kmod.h>
+#include <linux/umh.h>
 #include <linux/err.h>
 #include <linux/keyctl.h>
 #include <linux/slab.h>
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h
index d098cf8aae61..d26034000913 100644
--- a/security/tomoyo/common.h
+++ b/security/tomoyo/common.h
@@ -16,7 +16,7 @@
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/file.h>
-#include <linux/kmod.h>
+#include <linux/umh.h>
 #include <linux/fs.h>
 #include <linux/sched.h>
 #include <linux/namei.h>
-- 
2.54.0


^ permalink raw reply related

* [PATCH v2 0/3] Bring includes in linux/kmod.h up to date
From: Petr Pavlu @ 2026-07-21 13:11 UTC (permalink / raw)
  To: Tony Luck, Borislav Petkov, Thomas Gleixner, Ingo Molnar,
	Dave Hansen, x86, H. Peter Anvin, Philipp Reisner, Lars Ellenberg,
	Christoph Böhmwalder, Jens Axboe, Johan Hovold, Alex Elder,
	Greg Kroah-Hartman, Rafael J. Wysocki, Michal Januszewski,
	Helge Deller, Alexander Viro, Christian Brauner, Jan Kara,
	Trond Myklebust, Anna Schumaker, Chuck Lever, Jeff Layton,
	NeilBrown, Olga Kornievskaia, Dai Ngo, Tom Talpey, Mark Fasheh,
	Joel Becker, Joseph Qi, Tejun Heo, Johannes Weiner,
	Michal Koutný, Luis Chamberlain, Petr Pavlu, Daniel Gomez,
	Sami Tolvanen, Aaron Tomlin, Pavel Machek, Len Brown,
	Andrew Morton, Danilo Krummrich, Nikolay Aleksandrov,
	Ido Schimmel, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, David Howells, Jarkko Sakkinen,
	Paul Moore, James Morris, Serge E. Hallyn, Kentaro Takeda,
	Tetsuo Handa
  Cc: linux-edac, linux-kernel, drbd-dev, linux-block, greybus-dev,
	linuxppc-dev, linux-acpi, linux-fbdev, dri-devel, linux-fsdevel,
	linux-nfs, ocfs2-devel, cgroups, linux-modules, linux-pm,
	driver-core, bridge, netdev, keyrings, linux-security-module

The usermode helper declarations were previously provided by linux/kmod.h
but commit c1f3fa2a4fde ("kmod: split off umh headers into its own file")
moved them to linux/umh.h in 2017. Add explicit includes of linux/umh.h to
files that use usermode helpers and remove linux/kmod.h where it is no
longer needed.

Also add a missing include of linux/sysctl.h to kernel/time/jiffies.c.

Finally, clean up linux/kmod.h so that it includes only the headers that it
actually requires, importantly removing the compat linux/umh.h include.

This cleanup is motivated by trying to reduce the preprocessed size of
linux/module.h, which includes linux/kmod.h. The linux/module.h header is
included by every *.mod.c file to provide `struct module` and other related
definitions, so it should avoid pulling in unnecessary dependencies. Note
that this series doesn't immediately improve the situation, since most of
the files included by linux/kmod.h are, for now, also included by
linux/module.h through other paths.

Apologies for the wide distribution. Acked-bys are appreciated.

Changes in v2:
- Remove the linux/kmod.h include from kernel/cgroup/cgroup-v1.c.
- Add a missing include of linux/sysctl.h to kernel/time/jiffies.c.
- Link to v1: https://lore.kernel.org/linux-modules/20260708154510.6794-1-petr.pavlu@suse.com/

Petr Pavlu (3):
  umh, treewide: Explicitly include linux/umh.h where needed
  time/jiffies: Include linux/sysctl.h for proc_int_u2k_conv_uop(), ...
  module: Bring includes in linux/kmod.h up to date

 arch/x86/kernel/cpu/mce/dev-mcelog.c |  2 +-
 drivers/block/drbd/drbd_nl.c         |  1 +
 drivers/greybus/svc_watchdog.c       |  1 +
 drivers/macintosh/windfarm_core.c    |  1 +
 drivers/pnp/pnpbios/core.c           |  2 +-
 drivers/video/fbdev/uvesafb.c        |  1 +
 fs/coredump.c                        |  2 +-
 fs/nfs/cache_lib.c                   |  2 +-
 fs/nfsd/nfs4layouts.c                |  2 +-
 fs/nfsd/nfs4recover.c                |  1 +
 fs/ocfs2/stackglue.c                 |  1 +
 include/linux/kmod.h                 | 12 ++----------
 kernel/cgroup/cgroup-v1.c            |  2 +-
 kernel/module/kmod.c                 |  1 +
 kernel/power/process.c               |  2 +-
 kernel/reboot.c                      |  2 +-
 kernel/time/jiffies.c                |  1 +
 kernel/umh.c                         |  2 +-
 lib/kobject_uevent.c                 |  2 +-
 net/bridge/br_stp_if.c               |  2 +-
 security/keys/request_key.c          |  2 +-
 security/tomoyo/common.h             |  2 +-
 22 files changed, 23 insertions(+), 23 deletions(-)

-- 
2.54.0


^ permalink raw reply

* [PATCH] apparmor: update website link
From: Baruch Siach @ 2026-07-21 11:19 UTC (permalink / raw)
  To: John Johansen, John Johansen, Georgia Garcia
  Cc: apparmor, linux-security-module, Baruch Siach

apparmor.wiki.kernel.org redirects to the current website.

Signed-off-by: Baruch Siach <baruch@tkos.co.il>
---
 security/apparmor/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/security/apparmor/Kconfig b/security/apparmor/Kconfig
index 1e3bd44643da..472aa38254be 100644
--- a/security/apparmor/Kconfig
+++ b/security/apparmor/Kconfig
@@ -11,7 +11,7 @@ config SECURITY_APPARMOR
 	  This enables the AppArmor security module.
 	  Required userspace tools (if they are not included in your
 	  distribution) and further information may be found at
-	  http://apparmor.wiki.kernel.org
+	  https://wiki.apparmor.net
 
 	  If you are unsure how to answer this question, answer N.
 
-- 
2.53.0


^ permalink raw reply related

* Re: [PATCH v3 1/2] treewide: Add a flag to detect the Apple T2 chip
From: Jarkko Sakkinen @ 2026-07-21 10:57 UTC (permalink / raw)
  To: Atharva Tiwari
  Cc: Bjorn Helgaas, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, x86, H. Peter Anvin, Andreas Noever, Mika Westerberg,
	Yehezkel Bernat, Hans de Goede, Ilpo Järvinen, Mimi Zohar,
	Roberto Sassu, Dmitry Kasatkin, Eric Snowberg, Paul Moore,
	James Morris, Serge E. Hallyn, linux-pci, linux-kernel, linux-usb,
	platform-driver-x86, linux-integrity, keyrings,
	linux-security-module
In-Reply-To: <20260721063412.11588-2-atharvatiwarilinuxdev@gmail.com>

On Tue, Jul 21, 2026 at 02:34:06AM -0400, Atharva Tiwari wrote:
> Add a flag to detect Apple T2 chips on Intel Macs.
> Cache the result to avoid repeated checks. That will
> be used in upcoming patches.
> 
> Signed-off-by: Atharva Tiwari <atharvatiwarilinuxdev@gmail.com>
> ---
>  arch/x86/kernel/quirks.c                      | 105 ++++++++++++++++++
>  include/linux/platform_data/x86/apple.h       |   5 +
>  .../platform_certs/keyring_handler.h          |   8 --
>  security/integrity/platform_certs/load_uefi.c |  38 ++-----
>  4 files changed, 118 insertions(+), 38 deletions(-)
> 
> diff --git a/arch/x86/kernel/quirks.c b/arch/x86/kernel/quirks.c
> index a92f18db9610..300d6436060d 100644
> --- a/arch/x86/kernel/quirks.c
> +++ b/arch/x86/kernel/quirks.c
> @@ -664,8 +664,113 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x2083, quirk_intel_purley_xeon_ras
>  bool x86_apple_machine;
>  EXPORT_SYMBOL(x86_apple_machine);
>  
> +bool has_apple_t2_chip;
> +EXPORT_SYMBOL(has_apple_t2_chip);
> +
> +static const struct dmi_system_id apple_t2_devices[] __initconst = {
> +	{
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro15,1"),
> +		},
> +	},
> +	{
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro15,2"),
> +		},
> +	},
> +	{
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro15,3"),
> +		},
> +	},
> +	{
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro15,4"),
> +		},
> +	},
> +	{
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro16,1"),
> +		},
> +	},
> +	{
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro16,2"),
> +		},
> +	},
> +	{
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro16,3"),
> +		},
> +	},
> +	{
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro16,4"),
> +		},
> +	},
> +	{
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir8,1"),
> +		},
> +	},
> +	{
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir8,2"),
> +		},
> +	},
> +	{
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir9,1"),
> +		},
> +	},
> +	{
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "Macmini8,1"),
> +		},
> +	},
> +	{
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "MacPro7,1"),
> +		},
> +	},
> +	{
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "iMac20,1"),
> +		},
> +	},
> +	{
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "iMac20,2"),
> +		},
> +	},
> +	{
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "iMacPro1,1"),
> +		},
> +	},
> +	{ }
> +};
> +
>  void __init early_platform_quirks(void)
>  {
>  	x86_apple_machine = dmi_match(DMI_SYS_VENDOR, "Apple Inc.") ||
>  			    dmi_match(DMI_SYS_VENDOR, "Apple Computer, Inc.");
> +
> +	has_apple_t2_chip = dmi_check_system(apple_t2_devices);
>  }
> diff --git a/include/linux/platform_data/x86/apple.h b/include/linux/platform_data/x86/apple.h
> index 079e816c3c21..47b27dceab18 100644
> --- a/include/linux/platform_data/x86/apple.h
> +++ b/include/linux/platform_data/x86/apple.h
> @@ -6,8 +6,13 @@
>   * x86_apple_machine - whether the machine is an x86 Apple Macintosh
>   */
>  extern bool x86_apple_machine;
> +/**
> + * has_apple_t2_chip - whether the machine has the Apple T2 chip
> + */
> +extern bool has_apple_t2_chip;
>  #else
>  #define x86_apple_machine false
> +#define has_apple_t2_chip false
>  #endif
>  
>  #endif
> diff --git a/security/integrity/platform_certs/keyring_handler.h b/security/integrity/platform_certs/keyring_handler.h
> index f92895cc50f6..a355f4400179 100644
> --- a/security/integrity/platform_certs/keyring_handler.h
> +++ b/security/integrity/platform_certs/keyring_handler.h
> @@ -45,11 +45,3 @@ efi_element_handler_t get_handler_for_code_signing_keys(const efi_guid_t *sig_ty
>  efi_element_handler_t get_handler_for_dbx(const efi_guid_t *sig_type);
>  
>  #endif
> -
> -#ifndef UEFI_QUIRK_SKIP_CERT
> -#define UEFI_QUIRK_SKIP_CERT(vendor, product) \
> -		 .matches = { \
> -			DMI_MATCH(DMI_BOARD_VENDOR, vendor), \
> -			DMI_MATCH(DMI_PRODUCT_NAME, product), \
> -		},
> -#endif
> diff --git a/security/integrity/platform_certs/load_uefi.c b/security/integrity/platform_certs/load_uefi.c
> index c0d6948446c3..b4096d4c828d 100644
> --- a/security/integrity/platform_certs/load_uefi.c
> +++ b/security/integrity/platform_certs/load_uefi.c
> @@ -3,42 +3,16 @@
>  #include <linux/kernel.h>
>  #include <linux/sched.h>
>  #include <linux/cred.h>
> -#include <linux/dmi.h>
>  #include <linux/err.h>
>  #include <linux/efi.h>
>  #include <linux/slab.h>
>  #include <linux/ima.h>
> +#include <linux/platform_data/x86/apple.h>
>  #include <keys/asymmetric-type.h>
>  #include <keys/system_keyring.h>
>  #include "../integrity.h"
>  #include "keyring_handler.h"
>  
> -/*
> - * On T2 Macs reading the db and dbx efi variables to load UEFI Secure Boot
> - * certificates causes occurrence of a page fault in Apple's firmware and
> - * a crash disabling EFI runtime services. The following quirk skips reading
> - * these variables.
> - */
> -static const struct dmi_system_id uefi_skip_cert[] = {
> -	{ UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro15,1") },
> -	{ UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro15,2") },
> -	{ UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro15,3") },
> -	{ UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro15,4") },
> -	{ UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro16,1") },
> -	{ UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro16,2") },
> -	{ UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro16,3") },
> -	{ UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro16,4") },
> -	{ UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookAir8,1") },
> -	{ UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookAir8,2") },
> -	{ UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookAir9,1") },
> -	{ UEFI_QUIRK_SKIP_CERT("Apple Inc.", "Macmini8,1") },
> -	{ UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacPro7,1") },
> -	{ UEFI_QUIRK_SKIP_CERT("Apple Inc.", "iMac20,1") },
> -	{ UEFI_QUIRK_SKIP_CERT("Apple Inc.", "iMac20,2") },
> -	{ UEFI_QUIRK_SKIP_CERT("Apple Inc.", "iMacPro1,1") },
> -	{ }
> -};
> -
>  /*
>   * Look to see if a UEFI variable called MokIgnoreDB exists and return true if
>   * it does.
> @@ -165,10 +139,14 @@ static int __init load_uefi_certs(void)
>  	unsigned long dbsize = 0, dbxsize = 0, mokxsize = 0;
>  	efi_status_t status;
>  	int rc = 0;
> -	const struct dmi_system_id *dmi_id;
>  
> -	dmi_id = dmi_first_match(uefi_skip_cert);
> -	if (dmi_id) {
> +	/*
> +	 * On T2 Macs reading the db and dbx efi variables to load UEFI Secure Boot
> +	 * certificates causes occurrence of a page fault in Apple's firmware and
> +	 * a crash disabling EFI runtime services. The following quirk skips reading
> +	 * these variables.
> +	 */
> +	if (has_apple_t2_chip) {
>  		pr_err("Reading UEFI Secure Boot Certs is not supported on T2 Macs.\n");
>  		return false;
>  	}
> -- 
> 2.43.0
> 


Acked-by: Jarkko Sakkinen <jarkko@kernel.org>

BR, Jarkko

^ 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