* [PATCH] cred: clarify usage of get_cred_rcu()
From: Alice Ryhl @ 2026-02-20 9:19 UTC (permalink / raw)
To: Paul Moore, Serge Hallyn; +Cc: linux-security-module, linux-kernel, Alice Ryhl
After being confused by looking at get_cred() and get_cred_rcu(), I
figured out what's going on. Thus, add some comments to clarify how
get_cred_rcu() works for the benefit of others looking in the future.
Note that in principle we could add an assertion that non_rcu is zero in
the failure path of atomic_long_inc_not_zero().
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
---
include/linux/cred.h | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/include/linux/cred.h b/include/linux/cred.h
index ed1609d78cd7..95dcf5e967c7 100644
--- a/include/linux/cred.h
+++ b/include/linux/cred.h
@@ -213,32 +213,50 @@ * get_cred_many - Get references on a set of credentials
static inline const struct cred *get_cred_many(const struct cred *cred, int nr)
{
struct cred *nonconst_cred = (struct cred *) cred;
if (!cred)
return cred;
nonconst_cred->non_rcu = 0;
atomic_long_add(nr, &nonconst_cred->usage);
return cred;
}
/*
* get_cred - Get a reference on a set of credentials
* @cred: The credentials to reference
*
* Get a reference on the specified set of credentials. The caller must
* release the reference. If %NULL is passed, it is returned with no action.
*
* This is used to deal with a committed set of credentials.
*/
static inline const struct cred *get_cred(const struct cred *cred)
{
return get_cred_many(cred, 1);
}
+/*
+ * get_cred_rcu - Get a reference on a set of credentials under rcu
+ * @cred: The credentials to reference
+ *
+ * Get a reference on the specified set of credentials, or %NULL if the last
+ * refcount has already been put.
+ *
+ * This is used to obtain a reference under an rcu read lock.
+ */
static inline const struct cred *get_cred_rcu(const struct cred *cred)
{
struct cred *nonconst_cred = (struct cred *) cred;
if (!cred)
return NULL;
if (!atomic_long_inc_not_zero(&nonconst_cred->usage))
return NULL;
+ /*
+ * If non_rcu is not already zero, then this call to get_cred_rcu() is
+ * probably wrong because if 'usage' goes to zero prior to this call,
+ * then get_cred_rcu() assumes it is freed with rcu.
+ *
+ * However, an exception to this is using get_cred_rcu() in cases where
+ * get_cred() would have been okay. To support that case, we do not
+ * check non_rcu and set it to zero regardless.
+ */
nonconst_cred->non_rcu = 0;
return cred;
}
--
2.53.0.345.g96ddfc5eaa-goog
^ permalink raw reply related
* Re: [PATCH v2 v2] evm: check return values of crypto_shash functions
From: Roberto Sassu @ 2026-02-20 9:06 UTC (permalink / raw)
To: Daniel Hodges
Cc: Daniel Hodges, zohar, roberto.sassu, dmitry.kasatkin,
eric.snowberg, paul, jmorris, serge, linux-integrity,
linux-security-module, linux-kernel
In-Reply-To: <lj2loy57pavtihqeuywpc2aev7zy3k3poop346dtmelmocp75q@lbejeufrrxwr>
On Thu, 2026-02-19 at 10:01 -0500, Daniel Hodges wrote:
> On Thu, Feb 19, 2026 at 01:36:39PM +0100, Roberto Sassu wrote:
> > On Thu, 2026-02-19 at 10:26 +0100, Roberto Sassu wrote:
> > > On Thu, 2026-02-05 at 21:42 -0500, Daniel Hodges wrote:
> > > > The crypto_shash_update() and crypto_shash_final() functions can fail
> > > > and return error codes, but their return values were not being checked
> > > > in several places in security/integrity/evm/evm_crypto.c:
> > > >
> > > > - hmac_add_misc() ignored returns from crypto_shash_update() and
> > > > crypto_shash_final()
> > > > - evm_calc_hmac_or_hash() ignored returns from crypto_shash_update()
> > > > - evm_init_hmac() ignored returns from crypto_shash_update()
> > > >
> > > > If these hash operations fail silently, the resulting HMAC could be
> > > > invalid or incomplete, which could weaken the integrity verification
> > > > security that EVM provides.
> > > >
> > > > This patch converts hmac_add_misc() from void to int return type and
> > > > adds proper error checking and propagation for all crypto_shash_*
> > > > function calls. All callers are updated to handle the new return values.
> > > > Additionally, error messages are logged when cryptographic operations
> > > > fail to provide visibility into the failure rather than silently
> > > > returning error codes.
> > > >
> > > > Fixes: 66dbc325afce ("evm: re-release")
> > > > Signed-off-by: Daniel Hodges <git@danielhodges.dev>
> > >
> > > After fixing the minor issue below:
> >
> > Already did it. The patch is here (after fixing a conflict with
> > 0496fc9cdc38 "evm: Use ordered xattrs list to calculate HMAC in
> > evm_init_hmac()"):
> >
> > https://github.com/robertosassu/linux/commit/d5aba42198b602c6de002ef02a4e6cc1d75652d7
> >
> > Roberto
>
> Nice, thanks for handling that!
Welcome!
Roberto
^ permalink raw reply
* Re: [PATCH 2/5] security: export binder symbols
From: Paul Moore @ 2026-02-20 0:00 UTC (permalink / raw)
To: Alice Ryhl
Cc: Greg Kroah-Hartman, Carlos Llamas, Alexander Viro,
Christian Brauner, Jan Kara, James Morris, Serge E. Hallyn,
Andrew Morton, Dave Chinner, Qi Zheng, Roman Gushchin,
Muchun Song, David Hildenbrand, Lorenzo Stoakes, Liam R. Howlett,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Trevor Gross, Danilo Krummrich,
kernel-team, linux-fsdevel, linux-kernel, linux-security-module,
linux-mm, rust-for-linux
In-Reply-To: <20260205-binder-tristate-v1-2-dfc947c35d35@google.com>
On Thu, Feb 5, 2026 at 5:51 AM Alice Ryhl <aliceryhl@google.com> wrote:
>
> To enable building Binder as a module, export these symbols.
>
> Signed-off-by: Alice Ryhl <aliceryhl@google.com>
> ---
> security/security.c | 4 ++++
> 1 file changed, 4 insertions(+)
Acked-by: Paul Moore <paul@paul-moore.com>
--
paul-moore.com
^ permalink raw reply
* Re: [PATCH v6] lsm: Add LSM hook security_unix_find
From: Günther Noack @ 2026-02-19 20:26 UTC (permalink / raw)
To: Justin Suess
Cc: brauner, demiobenour, fahimitahera, hi, horms, ivanov.mikhail1,
jannh, jmorris, john.johansen, konstantin.meskhidze,
linux-security-module, m, matthieu, mic, netdev, paul,
samasth.norway.ananda, serge, viro
In-Reply-To: <20260219200459.1474232-1-utilityemal77@gmail.com>
On Thu, Feb 19, 2026 at 03:04:59PM -0500, Justin Suess wrote:
> Add a LSM hook security_unix_find.
>
> This hook is called to check the path of a named unix socket before a
> connection is initiated. The peer socket may be inspected as well.
>
> Why existing hooks are unsuitable:
>
> Existing socket hooks, security_unix_stream_connect(),
> security_unix_may_send(), and security_socket_connect() don't provide
> TOCTOU-free / namespace independent access to the paths of sockets.
>
> (1) We cannot resolve the path from the struct sockaddr in existing hooks.
> This requires another path lookup. A change in the path between the
> two lookups will cause a TOCTOU bug.
>
> (2) We cannot use the struct path from the listening socket, because it
> may be bound to a path in a different namespace than the caller,
> resulting in a path that cannot be referenced at policy creation time.
>
> Cc: Günther Noack <gnoack3000@gmail.com>
> Cc: Tingmao Wang <m@maowtm.org>
> Signed-off-by: Justin Suess <utilityemal77@gmail.com>
> ---
> include/linux/lsm_hook_defs.h | 5 +++++
> include/linux/security.h | 11 +++++++++++
> net/unix/af_unix.c | 13 ++++++++++---
> security/security.c | 20 ++++++++++++++++++++
> 4 files changed, 46 insertions(+), 3 deletions(-)
>
> diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
> index 8c42b4bde09c..7a0fd3dbfa29 100644
> --- a/include/linux/lsm_hook_defs.h
> +++ b/include/linux/lsm_hook_defs.h
> @@ -317,6 +317,11 @@ LSM_HOOK(int, 0, post_notification, const struct cred *w_cred,
> LSM_HOOK(int, 0, watch_key, struct key *key)
> #endif /* CONFIG_SECURITY && CONFIG_KEY_NOTIFICATIONS */
>
> +#if defined(CONFIG_SECURITY_NETWORK) && defined(CONFIG_SECURITY_PATH)
> +LSM_HOOK(int, 0, unix_find, const struct path *path, struct sock *other,
> + int flags)
> +#endif /* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */
> +
> #ifdef CONFIG_SECURITY_NETWORK
> LSM_HOOK(int, 0, unix_stream_connect, struct sock *sock, struct sock *other,
> struct sock *newsk)
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 83a646d72f6f..99a33d8eb28d 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -1931,6 +1931,17 @@ static inline int security_mptcp_add_subflow(struct sock *sk, struct sock *ssk)
> }
> #endif /* CONFIG_SECURITY_NETWORK */
>
> +#if defined(CONFIG_SECURITY_NETWORK) && defined(CONFIG_SECURITY_PATH)
> +
> +int security_unix_find(const struct path *path, struct sock *other, int flags);
> +
> +#else /* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */
> +static inline int security_unix_find(const struct path *path, struct sock *other, int flags)
> +{
> + return 0;
> +}
> +#endif /* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */
> +
> #ifdef CONFIG_SECURITY_INFINIBAND
> int security_ib_pkey_access(void *sec, u64 subnet_prefix, u16 pkey);
> int security_ib_endport_manage_subnet(void *sec, const char *name, u8 port_num);
> diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
> index f6d56e70c7a2..41698460194b 100644
> --- a/net/unix/af_unix.c
> +++ b/net/unix/af_unix.c
> @@ -1231,10 +1231,17 @@ static struct sock *unix_find_bsd(struct sockaddr_un *sunaddr, int addr_len,
> goto path_put;
>
> err = -EPROTOTYPE;
> - if (sk->sk_type == type)
> - touch_atime(&path);
> - else
> + if (sk->sk_type != type)
> + goto sock_put;
> +
> + /*
> + * We call the hook because we know that the inode is a socket and we
> + * hold a valid reference to it via the path.
> + */
> + err = security_unix_find(&path, sk, flags);
> + if (err)
> goto sock_put;
> + touch_atime(&path);
>
> path_put(&path);
>
> diff --git a/security/security.c b/security/security.c
> index 67af9228c4e9..c73196b8db4b 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -4731,6 +4731,26 @@ int security_mptcp_add_subflow(struct sock *sk, struct sock *ssk)
>
> #endif /* CONFIG_SECURITY_NETWORK */
>
> +#if defined(CONFIG_SECURITY_NETWORK) && defined(CONFIG_SECURITY_PATH)
> +/**
> + * security_unix_find() - Check if a named AF_UNIX socket can connect
> + * @path: path of the socket being connected to
> + * @other: peer sock
> + * @flags: flags associated with the socket
> + *
> + * This hook is called to check permissions before connecting to a named
> + * AF_UNIX socket.
> + *
> + * Return: Returns 0 if permission is granted.
> + */
> +int security_unix_find(const struct path *path, struct sock *other, int flags)
> +{
> + return call_int_hook(unix_find, path, other, flags);
> +}
> +EXPORT_SYMBOL(security_unix_find);
> +
> +#endif /* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */
> +
> #ifdef CONFIG_SECURITY_INFINIBAND
> /**
> * security_ib_pkey_access() - Check if access to an IB pkey is allowed
> --
> 2.52.0
>
Reviewed-by: Günther Noack <gnoack3000@gmail.com>
Thank you, this looks good. I'll include it in the next version of the
Unix connect patch set again.
–Günther
^ permalink raw reply
* [PATCH v6] lsm: Add LSM hook security_unix_find
From: Justin Suess @ 2026-02-19 20:04 UTC (permalink / raw)
To: utilityemal77
Cc: brauner, demiobenour, fahimitahera, gnoack3000, hi, horms,
ivanov.mikhail1, jannh, jmorris, john.johansen,
konstantin.meskhidze, linux-security-module, m, matthieu, mic,
netdev, paul, samasth.norway.ananda, serge, viro
In-Reply-To: <aZcPd3OKqxwCZV-5@suesslenovo>
Add a LSM hook security_unix_find.
This hook is called to check the path of a named unix socket before a
connection is initiated. The peer socket may be inspected as well.
Why existing hooks are unsuitable:
Existing socket hooks, security_unix_stream_connect(),
security_unix_may_send(), and security_socket_connect() don't provide
TOCTOU-free / namespace independent access to the paths of sockets.
(1) We cannot resolve the path from the struct sockaddr in existing hooks.
This requires another path lookup. A change in the path between the
two lookups will cause a TOCTOU bug.
(2) We cannot use the struct path from the listening socket, because it
may be bound to a path in a different namespace than the caller,
resulting in a path that cannot be referenced at policy creation time.
Cc: Günther Noack <gnoack3000@gmail.com>
Cc: Tingmao Wang <m@maowtm.org>
Signed-off-by: Justin Suess <utilityemal77@gmail.com>
---
include/linux/lsm_hook_defs.h | 5 +++++
include/linux/security.h | 11 +++++++++++
net/unix/af_unix.c | 13 ++++++++++---
security/security.c | 20 ++++++++++++++++++++
4 files changed, 46 insertions(+), 3 deletions(-)
diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index 8c42b4bde09c..7a0fd3dbfa29 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -317,6 +317,11 @@ LSM_HOOK(int, 0, post_notification, const struct cred *w_cred,
LSM_HOOK(int, 0, watch_key, struct key *key)
#endif /* CONFIG_SECURITY && CONFIG_KEY_NOTIFICATIONS */
+#if defined(CONFIG_SECURITY_NETWORK) && defined(CONFIG_SECURITY_PATH)
+LSM_HOOK(int, 0, unix_find, const struct path *path, struct sock *other,
+ int flags)
+#endif /* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */
+
#ifdef CONFIG_SECURITY_NETWORK
LSM_HOOK(int, 0, unix_stream_connect, struct sock *sock, struct sock *other,
struct sock *newsk)
diff --git a/include/linux/security.h b/include/linux/security.h
index 83a646d72f6f..99a33d8eb28d 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1931,6 +1931,17 @@ static inline int security_mptcp_add_subflow(struct sock *sk, struct sock *ssk)
}
#endif /* CONFIG_SECURITY_NETWORK */
+#if defined(CONFIG_SECURITY_NETWORK) && defined(CONFIG_SECURITY_PATH)
+
+int security_unix_find(const struct path *path, struct sock *other, int flags);
+
+#else /* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */
+static inline int security_unix_find(const struct path *path, struct sock *other, int flags)
+{
+ return 0;
+}
+#endif /* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */
+
#ifdef CONFIG_SECURITY_INFINIBAND
int security_ib_pkey_access(void *sec, u64 subnet_prefix, u16 pkey);
int security_ib_endport_manage_subnet(void *sec, const char *name, u8 port_num);
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index f6d56e70c7a2..41698460194b 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1231,10 +1231,17 @@ static struct sock *unix_find_bsd(struct sockaddr_un *sunaddr, int addr_len,
goto path_put;
err = -EPROTOTYPE;
- if (sk->sk_type == type)
- touch_atime(&path);
- else
+ if (sk->sk_type != type)
+ goto sock_put;
+
+ /*
+ * We call the hook because we know that the inode is a socket and we
+ * hold a valid reference to it via the path.
+ */
+ err = security_unix_find(&path, sk, flags);
+ if (err)
goto sock_put;
+ touch_atime(&path);
path_put(&path);
diff --git a/security/security.c b/security/security.c
index 67af9228c4e9..c73196b8db4b 100644
--- a/security/security.c
+++ b/security/security.c
@@ -4731,6 +4731,26 @@ int security_mptcp_add_subflow(struct sock *sk, struct sock *ssk)
#endif /* CONFIG_SECURITY_NETWORK */
+#if defined(CONFIG_SECURITY_NETWORK) && defined(CONFIG_SECURITY_PATH)
+/**
+ * security_unix_find() - Check if a named AF_UNIX socket can connect
+ * @path: path of the socket being connected to
+ * @other: peer sock
+ * @flags: flags associated with the socket
+ *
+ * This hook is called to check permissions before connecting to a named
+ * AF_UNIX socket.
+ *
+ * Return: Returns 0 if permission is granted.
+ */
+int security_unix_find(const struct path *path, struct sock *other, int flags)
+{
+ return call_int_hook(unix_find, path, other, flags);
+}
+EXPORT_SYMBOL(security_unix_find);
+
+#endif /* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */
+
#ifdef CONFIG_SECURITY_INFINIBAND
/**
* security_ib_pkey_access() - Check if access to an IB pkey is allowed
--
2.52.0
^ permalink raw reply related
* Re: [PATCH v4 15/17] module: Introduce hash-based integrity checking
From: Nicolas Schier @ 2026-02-19 14:27 UTC (permalink / raw)
To: Thomas Weißschuh
Cc: Petr Pavlu, Nathan Chancellor, Arnd Bergmann, Luis Chamberlain,
Sami Tolvanen, Daniel Gomez, Paul Moore, James Morris,
Serge E. Hallyn, Jonathan Corbet, Madhavan Srinivasan,
Michael Ellerman, Nicholas Piggin, Naveen N Rao, Mimi Zohar,
Roberto Sassu, Dmitry Kasatkin, Eric Snowberg, Daniel Gomez,
Aaron Tomlin, Christophe Leroy (CS GROUP), Nicolas Bouchinet,
Xiu Jianfeng, Fabian Grünbichler, Arnout Engelen,
Mattia Rizzolo, kpcyrd, Christian Heusel, Câju Mihai-Drosi,
Sebastian Andrzej Siewior, linux-kbuild, linux-kernel, linux-arch,
linux-modules, linux-security-module, linux-doc, linuxppc-dev,
linux-integrity
In-Reply-To: <28cf8d51-7530-41d5-a47b-cad5ecabd269@t-8ch.de>
On Tue, Feb 03, 2026 at 01:55:05PM +0100, Thomas Weißschuh wrote:
> On 2026-01-30 18:06:20+0100, Petr Pavlu wrote:
> > On 1/13/26 1:28 PM, Thomas Weißschuh wrote:
> > > Normally the .ko module files depend on a fully built vmlinux to be
> > > available for modpost validation and BTF generation. With
> > > CONFIG_MODULE_HASHES, vmlinux now depends on the modules
> > > to build a merkle tree. This introduces a dependency cycle which is
> > > impossible to satisfy. Work around this by building the modules during
> > > link-vmlinux.sh, after vmlinux is complete enough for modpost and BTF
> > > but before the final module hashes are
> >
> > I wonder if this dependency cycle could be resolved by utilizing the
> > split into vmlinux.unstripped and vmlinux that occurred last year.
> >
> > The idea is to create the following ordering: vmlinux.unstripped ->
> > modules -> vmlinux, and to patch in .module_hashes only when building
> > the final vmlinux.
> >
> > This would require the following:
> > * Split scripts/Makefile.vmlinux into two Makefiles, one that builds the
> > current vmlinux.unstripped and the second one that builds the final
> > vmlinux from it.
> > * Modify the top Makefile to recognize vmlinux.unstripped and update the
> > BTF generation rule 'modules: vmlinux' to
> > 'modules: vmlinux.unstripped'.
> > * Add the 'vmlinux: modules' ordering in the top Makefile for
> > CONFIG_MODULE_HASHES=y.
> > * Remove the patching of vmlinux.unstripped in scripts/link-vmlinux.sh
> > and instead move it into scripts/Makefile.vmlinux when running objcopy
> > to produce the final vmlinux.
> >
> > I think this approach has two main advantages:
> > * CONFIG_MODULE_HASHES can be made orthogonal to
> > CONFIG_DEBUG_INFO_BTF_MODULES.
> > * All dependencies are expressed at the Makefile level instead of having
> > scripts/link-vmlinux.sh invoke 'make -f Makefile modules'.
> >
> > Below is a rough prototype that applies on top of this series. It is a
> > bit verbose due to the splitting of part of scripts/Makefile.vmlinux
> > into scripts/Makefile.vmlinux_unstripped.
>
> That looks like a feasible alternative. Before adopting it, I'd like to
> hear the preference of the kbuild folks.
>
> > diff --git a/Makefile b/Makefile
> > index 841772a5a260..19a3beb82fa7 100644
> > --- a/Makefile
> > +++ b/Makefile
> > @@ -1259,7 +1259,7 @@ vmlinux_o: vmlinux.a $(KBUILD_VMLINUX_LIBS)
> > vmlinux.o modules.builtin.modinfo modules.builtin: vmlinux_o
> > @:
> >
> > -PHONY += vmlinux
> > +PHONY += vmlinux.unstripped vmlinux
> > # LDFLAGS_vmlinux in the top Makefile defines linker flags for the top vmlinux,
> > # not for decompressors. LDFLAGS_vmlinux in arch/*/boot/compressed/Makefile is
> > # unrelated; the decompressors just happen to have the same base name,
> > @@ -1270,9 +1270,11 @@ PHONY += vmlinux
> > # https://savannah.gnu.org/bugs/?61463
> > # For Make > 4.4, the following simple code will work:
> > # vmlinux: private export LDFLAGS_vmlinux := $(LDFLAGS_vmlinux)
> > -vmlinux: private _LDFLAGS_vmlinux := $(LDFLAGS_vmlinux)
> > -vmlinux: export LDFLAGS_vmlinux = $(_LDFLAGS_vmlinux)
> > -vmlinux: vmlinux.o $(KBUILD_LDS) modpost
> > +vmlinux.unstripped: private _LDFLAGS_vmlinux := $(LDFLAGS_vmlinux)
> > +vmlinux.unstripped: export LDFLAGS_vmlinux = $(_LDFLAGS_vmlinux)
> > +vmlinux.unstripped: vmlinux.o $(KBUILD_LDS) modpost
> > + $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.vmlinux_unstripped
> > +vmlinux: vmlinux.unstripped
> > $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.vmlinux
>
> Maybe we could keep them together in a single Makefile,
> and instead have different targets in it.
>
yes, I think so, too. I like the Petr's alternative.
Kind regards,
Nicolas
^ permalink raw reply
* Re: [PATCH v2 v2] evm: check return values of crypto_shash functions
From: Daniel Hodges @ 2026-02-19 15:01 UTC (permalink / raw)
To: Roberto Sassu
Cc: Daniel Hodges, zohar, roberto.sassu, dmitry.kasatkin,
eric.snowberg, paul, jmorris, serge, linux-integrity,
linux-security-module, linux-kernel
In-Reply-To: <cfbd9e3c63e03500279198ec7a80ba009dfccc63.camel@huaweicloud.com>
On Thu, Feb 19, 2026 at 01:36:39PM +0100, Roberto Sassu wrote:
> On Thu, 2026-02-19 at 10:26 +0100, Roberto Sassu wrote:
> > On Thu, 2026-02-05 at 21:42 -0500, Daniel Hodges wrote:
> > > The crypto_shash_update() and crypto_shash_final() functions can fail
> > > and return error codes, but their return values were not being checked
> > > in several places in security/integrity/evm/evm_crypto.c:
> > >
> > > - hmac_add_misc() ignored returns from crypto_shash_update() and
> > > crypto_shash_final()
> > > - evm_calc_hmac_or_hash() ignored returns from crypto_shash_update()
> > > - evm_init_hmac() ignored returns from crypto_shash_update()
> > >
> > > If these hash operations fail silently, the resulting HMAC could be
> > > invalid or incomplete, which could weaken the integrity verification
> > > security that EVM provides.
> > >
> > > This patch converts hmac_add_misc() from void to int return type and
> > > adds proper error checking and propagation for all crypto_shash_*
> > > function calls. All callers are updated to handle the new return values.
> > > Additionally, error messages are logged when cryptographic operations
> > > fail to provide visibility into the failure rather than silently
> > > returning error codes.
> > >
> > > Fixes: 66dbc325afce ("evm: re-release")
> > > Signed-off-by: Daniel Hodges <git@danielhodges.dev>
> >
> > After fixing the minor issue below:
>
> Already did it. The patch is here (after fixing a conflict with
> 0496fc9cdc38 "evm: Use ordered xattrs list to calculate HMAC in
> evm_init_hmac()"):
>
> https://github.com/robertosassu/linux/commit/d5aba42198b602c6de002ef02a4e6cc1d75652d7
>
> Roberto
Nice, thanks for handling that!
-Daniel
^ permalink raw reply
* Re: [PATCH] task: delete task_euid()
From: Gary Guo @ 2026-02-19 14:43 UTC (permalink / raw)
To: Alice Ryhl
Cc: Paul Moore, Serge Hallyn, Jonathan Corbet, Greg Kroah-Hartman,
Shuah Khan, Alex Shi, Yanteng Si, Dongliang Mu, Miguel Ojeda,
Boqun Feng, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
Trevor Gross, Danilo Krummrich, linux-security-module, linux-doc,
linux-kernel, rust-for-linux, Jann Horn
In-Reply-To: <20260219-remove-task-euid-v1-1-904060826e07@google.com>
On 2026-02-19 12:14, Alice Ryhl wrote:
> task_euid() is a very weird operation. You can see how weird it is by
> grepping for task_euid() - binder is its only user. task_euid() obtains
> the objective effective UID - it looks at the credentials of the task
> for purposes of acting on it as an object, but then accesses the
> effective UID (which the credentials.7 man page describes as "[...]
> used
> by the kernel to determine the permissions that the process will have
> when accessing shared resources [...]").
>
> Since usage in Binder has now been removed, get rid of the resulting
> dead code.
>
> Changes to the zh_CN translation was carried out with the help of
> Gemini and Google Translate.
>
> Suggested-by: Jann Horn <jannh@google.com>
> Signed-off-by: Alice Ryhl <aliceryhl@google.com>
Reviewed-by: Gary Guo <gary@garyguo.net>
With Alex's translation suggestion applied.
Thanks,
Gary
> ---
> Depends on these two changes:
> https://lore.kernel.org/all/20260212-rust-uid-v1-1-deff4214c766@google.com/
> https://lore.kernel.org/all/20260213-binder-uid-v1-0-7b795ae05523@google.com/
> ---
> Documentation/security/credentials.rst | 6 ++----
> Documentation/translations/zh_CN/security/credentials.rst | 6 ++----
> include/linux/cred.h | 1 -
> rust/helpers/task.c | 5 -----
> rust/kernel/task.rs | 10
> ----------
> 5 files changed, 4 insertions(+), 24 deletions(-)
^ permalink raw reply
* Re: [PATCH] task: delete task_euid()
From: Alice Ryhl @ 2026-02-19 14:35 UTC (permalink / raw)
To: Alex Shi
Cc: Paul Moore, Serge Hallyn, Jonathan Corbet, Greg Kroah-Hartman,
Shuah Khan, Alex Shi, Yanteng Si, Dongliang Mu, Miguel Ojeda,
Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
Andreas Hindborg, Trevor Gross, Danilo Krummrich,
linux-security-module, linux-doc, linux-kernel, rust-for-linux,
Jann Horn
In-Reply-To: <c2b65a8f-b0cc-4bba-8ef9-7a079314d52d@gmail.com>
On Thu, Feb 19, 2026 at 10:27:01PM +0800, Alex Shi wrote:
>
>
> On 2026/2/19 20:14, Alice Ryhl wrote:
> > task_euid() is a very weird operation. You can see how weird it is by
> > grepping for task_euid() - binder is its only user. task_euid() obtains
> > the objective effective UID - it looks at the credentials of the task
> > for purposes of acting on it as an object, but then accesses the
> > effective UID (which the credentials.7 man page describes as "[...] used
> > by the kernel to determine the permissions that the process will have
> > when accessing shared resources [...]").
> >
> > Since usage in Binder has now been removed, get rid of the resulting
> > dead code.
> >
> > Changes to the zh_CN translation was carried out with the help of
> > Gemini and Google Translate.
> > diff --git a/Documentation/translations/zh_CN/security/credentials.rst b/Documentation/translations/zh_CN/security/credentials.rst
> > index 88fcd9152ffe91d79fc10bfc7b2a37d301b4938a..f0b2efec342438b81be415dc513622c961bb7e59 100644
> > --- a/Documentation/translations/zh_CN/security/credentials.rst
> > +++ b/Documentation/translations/zh_CN/security/credentials.rst
> > @@ -337,15 +337,13 @@ const指针上操作,因此不需要进行类型转换,但需要临时放弃
> > ``__task_cred()`` 的结果不应直接传递给 ``get_cred()`` ,
> > 因为这可能与 ``commit_cred()`` 发生竞争条件。
> > -还有一些方便的函数可以访问另一个任务凭据的特定部分,将RCU操作对调用方隐藏起来::
> > +有一个方便的函数可用于访问另一个任务凭据的特定部分,从而对调用方隐藏RCU机制::
>
> LGTM.
>
> > uid_t task_uid(task) Task's real UID
> > - uid_t task_euid(task) Task's effective UID
> > -如果调用方在此时已经持有RCU读锁,则应使用::
> > +如果调用方在此时已经持有RCU读锁,则应改为使用::
>
> Please keep the old version. the new one is a bit ambiguous.
Thanks for checking!
Alice
^ permalink raw reply
* Re: [PATCH] task: delete task_euid()
From: Alex Shi @ 2026-02-19 14:27 UTC (permalink / raw)
To: Alice Ryhl, Paul Moore, Serge Hallyn, Jonathan Corbet,
Greg Kroah-Hartman, Shuah Khan, Alex Shi, Yanteng Si,
Dongliang Mu
Cc: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Trevor Gross, Danilo Krummrich,
linux-security-module, linux-doc, linux-kernel, rust-for-linux,
Jann Horn
In-Reply-To: <20260219-remove-task-euid-v1-1-904060826e07@google.com>
On 2026/2/19 20:14, Alice Ryhl wrote:
> task_euid() is a very weird operation. You can see how weird it is by
> grepping for task_euid() - binder is its only user. task_euid() obtains
> the objective effective UID - it looks at the credentials of the task
> for purposes of acting on it as an object, but then accesses the
> effective UID (which the credentials.7 man page describes as "[...] used
> by the kernel to determine the permissions that the process will have
> when accessing shared resources [...]").
>
> Since usage in Binder has now been removed, get rid of the resulting
> dead code.
>
> Changes to the zh_CN translation was carried out with the help of
> Gemini and Google Translate.
>
> Suggested-by: Jann Horn<jannh@google.com>
> Signed-off-by: Alice Ryhl<aliceryhl@google.com>
> ---
> Depends on these two changes:
> https://lore.kernel.org/all/20260212-rust-uid-v1-1-deff4214c766@google.com/
> https://lore.kernel.org/all/20260213-binder-uid-
> v1-0-7b795ae05523@google.com/
> ---
> Documentation/security/credentials.rst | 6 ++----
> Documentation/translations/zh_CN/security/credentials.rst | 6 ++----
> include/linux/cred.h | 1 -
> rust/helpers/task.c | 5 -----
> rust/kernel/task.rs | 10 ----------
> 5 files changed, 4 insertions(+), 24 deletions(-)
>
> diff --git a/Documentation/security/credentials.rst b/Documentation/security/credentials.rst
> index d0191c8b8060edb7b272402c019cff941ec22743..81d3b5737d85bde9b77bff94dfb93ed8037b2302 100644
> --- a/Documentation/security/credentials.rst
> +++ b/Documentation/security/credentials.rst
> @@ -393,16 +393,14 @@ the credentials so obtained when they're finished with.
> The result of ``__task_cred()`` should not be passed directly to
> ``get_cred()`` as this may race with ``commit_cred()``.
>
> -There are a couple of convenience functions to access bits of another task's
> -credentials, hiding the RCU magic from the caller::
> +There is a convenience function to access bits of another task's credentials,
> +hiding the RCU magic from the caller::
>
> uid_t task_uid(task) Task's real UID
> - uid_t task_euid(task) Task's effective UID
>
> If the caller is holding the RCU read lock at the time anyway, then::
>
> __task_cred(task)->uid
> - __task_cred(task)->euid
>
> should be used instead. Similarly, if multiple aspects of a task's credentials
> need to be accessed, RCU read lock should be used, ``__task_cred()`` called,
> diff --git a/Documentation/translations/zh_CN/security/credentials.rst b/Documentation/translations/zh_CN/security/credentials.rst
> index 88fcd9152ffe91d79fc10bfc7b2a37d301b4938a..f0b2efec342438b81be415dc513622c961bb7e59 100644
> --- a/Documentation/translations/zh_CN/security/credentials.rst
> +++ b/Documentation/translations/zh_CN/security/credentials.rst
> @@ -337,15 +337,13 @@ const指针上操作,因此不需要进行类型转换,但需要临时放弃
> ``__task_cred()`` 的结果不应直接传递给 ``get_cred()`` ,
> 因为这可能与 ``commit_cred()`` 发生竞争条件。
>
> -还有一些方便的函数可以访问另一个任务凭据的特定部分,将RCU操作对调用方隐藏起来::
> +有一个方便的函数可用于访问另一个任务凭据的特定部分,从而对调用方隐藏RCU机制::
LGTM.
>
> uid_t task_uid(task) Task's real UID
> - uid_t task_euid(task) Task's effective UID
>
> -如果调用方在此时已经持有RCU读锁,则应使用::
> +如果调用方在此时已经持有RCU读锁,则应改为使用::
Please keep the old version. the new one is a bit ambiguous.
Thanks
Alex
^ permalink raw reply
* Re: [PATCH v5 2/9] landlock: Control pathname UNIX domain socket resolution by path
From: Günther Noack @ 2026-02-19 13:59 UTC (permalink / raw)
To: Mickaël Salaün
Cc: Günther Noack, John Johansen, Tingmao Wang, Justin Suess,
Jann Horn, linux-security-module, Samasth Norway Ananda,
Matthieu Buffet, Mikhail Ivanov, konstantin.meskhidze,
Demi Marie Obenour, Alyssa Ross, Tahera Fahimi
In-Reply-To: <20260219.IF4zee3Quo3j@digikod.net>
On Thu, Feb 19, 2026 at 10:45:44AM +0100, Mickaël Salaün wrote:
> On Wed, Feb 18, 2026 at 10:37:16AM +0100, Mickaël Salaün wrote:
> > On Sun, Feb 15, 2026 at 11:51:50AM +0100, Günther Noack wrote:
> > > * Add a new access right LANDLOCK_ACCESS_FS_RESOLVE_UNIX, which
> > > controls the look up operations for named UNIX domain sockets. The
> > > resolution happens during connect() and sendmsg() (depending on
> > > socket type).
> > > * Hook into the path lookup in unix_find_bsd() in af_unix.c, using a
> > > LSM hook. Make policy decisions based on the new access rights
> > > * Increment the Landlock ABI version.
> > > * Minor test adaptions to keep the tests working.
> > >
> > > With this access right, access is granted if either of the following
> > > conditions is met:
> > >
> > > * The target socket's filesystem path was allow-listed using a
> > > LANDLOCK_RULE_PATH_BENEATH rule, *or*:
> > > * The target socket was created in the same Landlock domain in which
> > > LANDLOCK_ACCESS_FS_RESOLVE_UNIX was restricted.
> > >
> > > In case of a denial, connect() and sendmsg() return EACCES, which is
> > > the same error as it is returned if the user does not have the write
> > > bit in the traditional Unix file system permissions of that file.
> > >
> > > This feature was created with substantial discussion and input from
> > > Justin Suess, Tingmao Wang and Mickaël Salaün.
> > >
> > > Cc: Tingmao Wang <m@maowtm.org>
> > > Cc: Justin Suess <utilityemal77@gmail.com>
> > > Cc: Mickaël Salaün <mic@digikod.net>
> > > Suggested-by: Jann Horn <jannh@google.com>
> > > Link: https://github.com/landlock-lsm/linux/issues/36
> > > Signed-off-by: Günther Noack <gnoack3000@gmail.com>
> > > ---
> > > include/uapi/linux/landlock.h | 10 ++
> > > security/landlock/access.h | 11 +-
> > > security/landlock/audit.c | 1 +
> > > security/landlock/fs.c | 102 ++++++++++++++++++-
> > > security/landlock/limits.h | 2 +-
> > > security/landlock/syscalls.c | 2 +-
> > > tools/testing/selftests/landlock/base_test.c | 2 +-
> > > tools/testing/selftests/landlock/fs_test.c | 5 +-
> > > 8 files changed, 128 insertions(+), 7 deletions(-)
>
> > > index 60ff217ab95b..8d0edf94037d 100644
> > > --- a/security/landlock/audit.c
> > > +++ b/security/landlock/audit.c
> > > @@ -37,6 +37,7 @@ static const char *const fs_access_strings[] = {
> > > [BIT_INDEX(LANDLOCK_ACCESS_FS_REFER)] = "fs.refer",
> > > [BIT_INDEX(LANDLOCK_ACCESS_FS_TRUNCATE)] = "fs.truncate",
> > > [BIT_INDEX(LANDLOCK_ACCESS_FS_IOCTL_DEV)] = "fs.ioctl_dev",
> > > + [BIT_INDEX(LANDLOCK_ACCESS_FS_RESOLVE_UNIX)] = "fs.resolve_unix",
> > > };
> > >
> > > static_assert(ARRAY_SIZE(fs_access_strings) == LANDLOCK_NUM_ACCESS_FS);
> > > diff --git a/security/landlock/fs.c b/security/landlock/fs.c
> > > index e764470f588c..76035c6f2bf1 100644
> > > --- a/security/landlock/fs.c
> > > +++ b/security/landlock/fs.c
> > > @@ -27,6 +27,7 @@
> > > #include <linux/lsm_hooks.h>
> > > #include <linux/mount.h>
> > > #include <linux/namei.h>
> > > +#include <linux/net.h>
> > > #include <linux/path.h>
> > > #include <linux/pid.h>
> > > #include <linux/rcupdate.h>
> > > @@ -314,7 +315,8 @@ static struct landlock_object *get_inode_object(struct inode *const inode)
> > > LANDLOCK_ACCESS_FS_WRITE_FILE | \
> > > LANDLOCK_ACCESS_FS_READ_FILE | \
> > > LANDLOCK_ACCESS_FS_TRUNCATE | \
> > > - LANDLOCK_ACCESS_FS_IOCTL_DEV)
> > > + LANDLOCK_ACCESS_FS_IOCTL_DEV | \
> > > + LANDLOCK_ACCESS_FS_RESOLVE_UNIX)
> > > /* clang-format on */
> > >
> > > /*
> > > @@ -1561,6 +1563,103 @@ static int hook_path_truncate(const struct path *const path)
> > > return current_check_access_path(path, LANDLOCK_ACCESS_FS_TRUNCATE);
> > > }
> > >
> > > +/**
> > > + * unmask_scoped_access - Remove access right bits in @masks in all layers
> > > + * where @client and @server have the same domain
> > > + *
> > > + * This does the same as domain_is_scoped(), but unmasks bits in @masks.
> > > + * It can not return early as domain_is_scoped() does.
>
> Why can't we use the same logic as for other scopes?
The other scopes, for which this is implemented in domain_is_scoped(),
do not need to do this layer-by-layer.
I have to admit, in my initial implementation, I was using
domain_is_scoped() directly, and the logic at the end of the hook was
roughly:
--- BUGGY CODE START ---
// ...
if (!domain_is_scoped(..., ..., LANDLOCK_ACCESS_FS_RESOLVE_UNIX))
return 0; /* permitted */
return current_check_access_path(path, LANDLOCK_ACCESS_FS_RESOLVE_UNIX)
}
--- BUGGY CODE END ---
Unfortunately, that is a logic error though -- it implements the formula
Access granted if:
(FOR-ALL l ∈ layers scoped-access-ok(l)) OR (FOR-ALL l ∈ layers path-access-ok(l)) (WRONG!)
but the formula we want is:
Access granted if:
FOR-ALL l ∈ layers (scoped-access-ok(l) OR path-access-ok(l)) (CORRECT!)
This makes a difference in the case where (pseudocode):
1. landlock_restrict_self(RESOLVE_UNIX) // d1
2. create_unix_server("./sock")
3. landlock_restrict_self(RESOLVE_UNIX, rule=Allow(".", RESOLVE_UNIX)) // d2
4. connect_unix("./sock")
,------------------------------------------------d1--,
| |
| ./sock server |
| ^ |
| | |
| ,------------------------------------------d2--, |
| | | | |
| | client | |
| | | |
| '----------------------------------------------' |
| |
'----------------------------------------------------'
(BTW, this scenario is covered in the selftests, that is why there is
a variant of these selftests where instead of applying "no domain", we
apply a domain with an exception rule like in step 3 in the pseudocode
above. Applying that domain should behave the same as applying no
domain at all.)
Intuitively, it is clear that the access should be granted:
- d1 does not restrict access to the server,
because the socket was created within d1 itself.
- d2 does not restrict access to the server,
because it has a rule to allow it
But the "buggy code" logic above comes to a different conclusion:
- the domain_is_scoped() check denies the access, because the server
is in a more privileged domain relative to the client domain.
- the current_check_access_path() check denies the access as well,
because the socket's path is not allow-listed in d1.
In the 'intuitive' reasoning above, we are checking d1 and d2
independently of each other. While Landlock is not implemented like
that internally, we need to stay consistent with it so that domains
compose correctly. The way to do that is to track is access check
results on a per-layer basis again, and that is why
unmask_scoped_access() uses a layer mask for tracking. The original
domain_is_scoped() does not use a layer mask, but that also means that
it can return early in some scenarios -- if for any of the relevant
layer depths, the client and server domains are not the same, it exits
early with failure because it's overall not fulfillable any more. In
the RESOLVE_UNIX case though, we need to remember in which layers we
failed (both high an low ones), because these layers can still be
fulfilled with a PATH_BENEATH rule later.
Summary:
Option 1: We *can* unify this if you want. It just might come at a
small performance penalty for domain_is_scoped(), which now uses the
larger layer mask data structure and can't do the same early returns
any more as before.
Option 2: Alternatively, if we move the two functions into the same
module, we can keep them separate but still test them against each
other to make sure they are in-line:
This invocation should return true...
domain_is_scoped(cli, srv, access)
...in the exactly the same situations where this invocation leaves any
bits set in layer_masks:
landlock_init_layer_masks(dom, access, &layer_masks, LL_KEY_INODE);
unmask_scoped_access(cli, srv, &layer_masks, access);
What do you prefer?
> > > + *
> > > + * @client: Client domain
> > > + * @server: Server domain
> > > + * @masks: Layer access masks to unmask
> > > + * @access: Access bit that controls scoping
> > > + */
> > > +static void unmask_scoped_access(const struct landlock_ruleset *const client,
> > > + const struct landlock_ruleset *const server,
> > > + struct layer_access_masks *const masks,
> > > + const access_mask_t access)
> >
> > This helper should be moved to task.c and factored out with
> > domain_is_scoped(). This should be a dedicated patch.
>
> Well, if domain_is_scoped() can be refactored and made generic, it would
> make more sense to move it to domain.c
>
> >
> > > +{
> > > + int client_layer, server_layer;
> > > + const struct landlock_hierarchy *client_walker, *server_walker;
> > > +
> > > + if (WARN_ON_ONCE(!client))
> > > + return; /* should not happen */
> > > +
> > > + if (!server)
> > > + return; /* server has no Landlock domain; nothing to clear */
> > > +
> > > + client_layer = client->num_layers - 1;
> > > + client_walker = client->hierarchy;
> > > + server_layer = server->num_layers - 1;
> > > + server_walker = server->hierarchy;
> > > +
> > > + /*
> > > + * Clears the access bits at all layers where the client domain is the
> > > + * same as the server domain. We start the walk at min(client_layer,
> > > + * server_layer). The layer bits until there can not be cleared because
> > > + * either the client or the server domain is missing.
> > > + */
> > > + for (; client_layer > server_layer; client_layer--)
> > > + client_walker = client_walker->parent;
> > > +
> > > + for (; server_layer > client_layer; server_layer--)
> > > + server_walker = server_walker->parent;
> > > +
> > > + for (; client_layer >= 0; client_layer--) {
> > > + if (masks->access[client_layer] & access &&
> > > + client_walker == server_walker)
> > > + masks->access[client_layer] &= ~access;
> > > +
> > > + client_walker = client_walker->parent;
> > > + server_walker = server_walker->parent;
> > > + }
> > > +}
^ permalink raw reply
* Re: [PATCH v5 1/9] lsm: Add LSM hook security_unix_find
From: Justin Suess @ 2026-02-19 13:26 UTC (permalink / raw)
To: Mickaël Salaün
Cc: Günther Noack, John Johansen, Paul Moore, James Morris,
Serge E . Hallyn, Tingmao Wang, linux-security-module,
Samasth Norway Ananda, Matthieu Buffet, Mikhail Ivanov,
konstantin.meskhidze, Demi Marie Obenour, Alyssa Ross, Jann Horn,
Tahera Fahimi, Simon Horman, netdev, Alexander Viro,
Christian Brauner
In-Reply-To: <20260217.Nei3Aeg8bo6h@digikod.net>
On Wed, Feb 18, 2026 at 10:36:37AM +0100, Mickaël Salaün wrote:
> On Sun, Feb 15, 2026 at 11:51:49AM +0100, Günther Noack wrote:
> > From: Justin Suess <utilityemal77@gmail.com>
> >
> > Add a LSM hook security_unix_find.
> >
> > This hook is called to check the path of a named unix socket before a
> > connection is initiated. The peer socket may be inspected as well.
> >
> > Why existing hooks are unsuitable:
> >
> > Existing socket hooks, security_unix_stream_connect(),
> > security_unix_may_send(), and security_socket_connect() don't provide
> > TOCTOU-free / namespace independent access to the paths of sockets.
> >
> > (1) We cannot resolve the path from the struct sockaddr in existing hooks.
> > This requires another path lookup. A change in the path between the
> > two lookups will cause a TOCTOU bug.
> >
> > (2) We cannot use the struct path from the listening socket, because it
> > may be bound to a path in a different namespace than the caller,
> > resulting in a path that cannot be referenced at policy creation time.
> >
> > Cc: Günther Noack <gnoack3000@gmail.com>
> > Cc: Tingmao Wang <m@maowtm.org>
> > Signed-off-by: Justin Suess <utilityemal77@gmail.com>
> > ---
> > include/linux/lsm_hook_defs.h | 5 +++++
> > include/linux/security.h | 11 +++++++++++
> > net/unix/af_unix.c | 8 ++++++++
> > security/security.c | 20 ++++++++++++++++++++
> > 4 files changed, 44 insertions(+)
> >
> > diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
> > index 8c42b4bde09c..7a0fd3dbfa29 100644
> > --- a/include/linux/lsm_hook_defs.h
> > +++ b/include/linux/lsm_hook_defs.h
> > @@ -317,6 +317,11 @@ LSM_HOOK(int, 0, post_notification, const struct cred *w_cred,
> > LSM_HOOK(int, 0, watch_key, struct key *key)
> > #endif /* CONFIG_SECURITY && CONFIG_KEY_NOTIFICATIONS */
> >
> > +#if defined(CONFIG_SECURITY_NETWORK) && defined(CONFIG_SECURITY_PATH)
> > +LSM_HOOK(int, 0, unix_find, const struct path *path, struct sock *other,
> > + int flags)
> > +#endif /* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */
> > +
> > #ifdef CONFIG_SECURITY_NETWORK
> > LSM_HOOK(int, 0, unix_stream_connect, struct sock *sock, struct sock *other,
> > struct sock *newsk)
> > diff --git a/include/linux/security.h b/include/linux/security.h
> > index 83a646d72f6f..99a33d8eb28d 100644
> > --- a/include/linux/security.h
> > +++ b/include/linux/security.h
> > @@ -1931,6 +1931,17 @@ static inline int security_mptcp_add_subflow(struct sock *sk, struct sock *ssk)
> > }
> > #endif /* CONFIG_SECURITY_NETWORK */
> >
> > +#if defined(CONFIG_SECURITY_NETWORK) && defined(CONFIG_SECURITY_PATH)
> > +
> > +int security_unix_find(const struct path *path, struct sock *other, int flags);
> > +
> > +#else /* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */
> > +static inline int security_unix_find(const struct path *path, struct sock *other, int flags)
> > +{
> > + return 0;
> > +}
> > +#endif /* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */
> > +
> > #ifdef CONFIG_SECURITY_INFINIBAND
> > int security_ib_pkey_access(void *sec, u64 subnet_prefix, u16 pkey);
> > int security_ib_endport_manage_subnet(void *sec, const char *name, u8 port_num);
> > diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
> > index d0511225799b..369812b79dd8 100644
> > --- a/net/unix/af_unix.c
> > +++ b/net/unix/af_unix.c
> > @@ -1230,6 +1230,14 @@ static struct sock *unix_find_bsd(struct sockaddr_un *sunaddr, int addr_len,
> > if (!sk)
> > goto path_put;
> >
> > + /*
> > + * We call the hook because we know that the inode is a socket and we
> > + * hold a valid reference to it via the path.
> > + */
> > + err = security_unix_find(&path, sk, flags);
> > + if (err)
> > + goto sock_put;
> > +
> > err = -EPROTOTYPE;
> > if (sk->sk_type == type)
>
> I think this hook call should be moved here, just before the
> touch_atime() call for consistency with the socket type check, and to
> avoid doing useless check in the hook.
>
Agreed. One less annoyance for end users of the hook is a win. I'll
resend the hook with the call moved into this if (sk->sk_type == type)
block for the next version.
> > touch_atime(&path);
> > diff --git a/security/security.c b/security/security.c
> > index 67af9228c4e9..c73196b8db4b 100644
> > --- a/security/security.c
> > +++ b/security/security.c
> > @@ -4731,6 +4731,26 @@ int security_mptcp_add_subflow(struct sock *sk, struct sock *ssk)
> >
> > #endif /* CONFIG_SECURITY_NETWORK */
> >
> > +#if defined(CONFIG_SECURITY_NETWORK) && defined(CONFIG_SECURITY_PATH)
> > +/**
> > + * security_unix_find() - Check if a named AF_UNIX socket can connect
> > + * @path: path of the socket being connected to
> > + * @other: peer sock
> > + * @flags: flags associated with the socket
> > + *
> > + * This hook is called to check permissions before connecting to a named
> > + * AF_UNIX socket.
> > + *
> > + * Return: Returns 0 if permission is granted.
> > + */
> > +int security_unix_find(const struct path *path, struct sock *other, int flags)
> > +{
> > + return call_int_hook(unix_find, path, other, flags);
> > +}
> > +EXPORT_SYMBOL(security_unix_find);
> > +
> > +#endif /* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */
> > +
> > #ifdef CONFIG_SECURITY_INFINIBAND
> > /**
> > * security_ib_pkey_access() - Check if access to an IB pkey is allowed
> > --
> > 2.52.0
> >
> >
^ permalink raw reply
* Re: [PATCH v2 v2] evm: check return values of crypto_shash functions
From: Roberto Sassu @ 2026-02-19 12:36 UTC (permalink / raw)
To: Daniel Hodges
Cc: zohar, roberto.sassu, dmitry.kasatkin, eric.snowberg, paul,
jmorris, serge, linux-integrity, linux-security-module,
linux-kernel
In-Reply-To: <6ce273a26b396232f3ee64a980575562e766c501.camel@huaweicloud.com>
On Thu, 2026-02-19 at 10:26 +0100, Roberto Sassu wrote:
> On Thu, 2026-02-05 at 21:42 -0500, Daniel Hodges wrote:
> > The crypto_shash_update() and crypto_shash_final() functions can fail
> > and return error codes, but their return values were not being checked
> > in several places in security/integrity/evm/evm_crypto.c:
> >
> > - hmac_add_misc() ignored returns from crypto_shash_update() and
> > crypto_shash_final()
> > - evm_calc_hmac_or_hash() ignored returns from crypto_shash_update()
> > - evm_init_hmac() ignored returns from crypto_shash_update()
> >
> > If these hash operations fail silently, the resulting HMAC could be
> > invalid or incomplete, which could weaken the integrity verification
> > security that EVM provides.
> >
> > This patch converts hmac_add_misc() from void to int return type and
> > adds proper error checking and propagation for all crypto_shash_*
> > function calls. All callers are updated to handle the new return values.
> > Additionally, error messages are logged when cryptographic operations
> > fail to provide visibility into the failure rather than silently
> > returning error codes.
> >
> > Fixes: 66dbc325afce ("evm: re-release")
> > Signed-off-by: Daniel Hodges <git@danielhodges.dev>
>
> After fixing the minor issue below:
Already did it. The patch is here (after fixing a conflict with
0496fc9cdc38 "evm: Use ordered xattrs list to calculate HMAC in
evm_init_hmac()"):
https://github.com/robertosassu/linux/commit/d5aba42198b602c6de002ef02a4e6cc1d75652d7
Roberto
> Reviewed-by: Roberto Sassu <roberto.sassu@huawei.com>
>
> > ---
> > security/integrity/evm/evm_crypto.c | 55 ++++++++++++++++++++++-------
> > 1 file changed, 42 insertions(+), 13 deletions(-)
> >
> > diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c
> > index a5e730ffda57..402eb1ca64ce 100644
> > --- a/security/integrity/evm/evm_crypto.c
> > +++ b/security/integrity/evm/evm_crypto.c
> > @@ -139,7 +139,7 @@ static struct shash_desc *init_desc(char type, uint8_t hash_algo)
> > * (Additional directory/file metadata needs to be added for more complete
> > * protection.)
> > */
> > -static void hmac_add_misc(struct shash_desc *desc, struct inode *inode,
> > +static int hmac_add_misc(struct shash_desc *desc, struct inode *inode,
> > char type, char *digest)
> > {
> > struct h_misc {
> > @@ -149,6 +149,7 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode,
> > gid_t gid;
> > umode_t mode;
> > } hmac_misc;
> > + int error;
> >
> > memset(&hmac_misc, 0, sizeof(hmac_misc));
> > /* Don't include the inode or generation number in portable
> > @@ -169,14 +170,28 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode,
> > hmac_misc.uid = from_kuid(&init_user_ns, inode->i_uid);
> > hmac_misc.gid = from_kgid(&init_user_ns, inode->i_gid);
> > hmac_misc.mode = inode->i_mode;
> > - crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof(hmac_misc));
> > + error = crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof(hmac_misc));
> > + if (error) {
> > + pr_err("crypto_shash_update() failed: %d\n", error);
> > + return error;
> > + }
> > if ((evm_hmac_attrs & EVM_ATTR_FSUUID) &&
> > - type != EVM_XATTR_PORTABLE_DIGSIG)
> > - crypto_shash_update(desc, (u8 *)&inode->i_sb->s_uuid, UUID_SIZE);
> > - crypto_shash_final(desc, digest);
> > + type != EVM_XATTR_PORTABLE_DIGSIG) {
> > + error = crypto_shash_update(desc, (u8 *)&inode->i_sb->s_uuid, UUID_SIZE);
> > + if (error) {
> > + pr_err("crypto_shash_update() failed: %d\n", error);
> > + return error;
> > + }
> > + }
> > + error = crypto_shash_final(desc, digest);
> > + if (error) {
> > + pr_err("crypto_shash_final() failed: %d\n", error);
> > + return error;
> > + }
> >
> > pr_debug("hmac_misc: (%zu) [%*phN]\n", sizeof(struct h_misc),
> > (int)sizeof(struct h_misc), &hmac_misc);
> > + return 0;
> > }
> >
> > /*
> > @@ -260,9 +275,12 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
> >
> > if ((req_xattr_name && req_xattr_value)
> > && !strcmp(xattr->name, req_xattr_name)) {
> > - error = 0;
> > - crypto_shash_update(desc, (const u8 *)req_xattr_value,
> > + error = crypto_shash_update(desc, (const u8 *)req_xattr_value,
> > req_xattr_value_len);
>
> Please align this.
>
> Thanks
>
> Roberto
>
> > + if (error) {
> > + pr_err("crypto_shash_update() failed: %d\n", error);
> > + goto out;
> > + }
> > if (is_ima)
> > ima_present = true;
> >
> > @@ -286,15 +304,20 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
> > pr_debug("file %s: xattr %s size mismatch (kernel: %d, user: %d)\n",
> > dentry->d_name.name, xattr->name, size,
> > user_space_size);
> > - error = 0;
> > xattr_size = size;
> > - crypto_shash_update(desc, (const u8 *)xattr_value, xattr_size);
> > + error = crypto_shash_update(desc, (const u8 *)xattr_value, xattr_size);
> > + if (error) {
> > + pr_err("crypto_shash_update() failed: %d\n", error);
> > + goto out;
> > + }
> > if (is_ima)
> > ima_present = true;
> >
> > dump_security_xattr(xattr->name, xattr_value, xattr_size);
> > }
> > - hmac_add_misc(desc, inode, type, data->digest);
> > + error = hmac_add_misc(desc, inode, type, data->digest);
> > + if (error)
> > + goto out;
> >
> > if (inode != d_backing_inode(dentry) && iint) {
> > if (IS_I_VERSION(inode))
> > @@ -401,6 +424,7 @@ int evm_init_hmac(struct inode *inode, const struct xattr *xattrs,
> > {
> > struct shash_desc *desc;
> > const struct xattr *xattr;
> > + int error;
> >
> > desc = init_desc(EVM_XATTR_HMAC, HASH_ALGO_SHA1);
> > if (IS_ERR(desc)) {
> > @@ -412,12 +436,17 @@ int evm_init_hmac(struct inode *inode, const struct xattr *xattrs,
> > if (!evm_protected_xattr(xattr->name))
> > continue;
> >
> > - crypto_shash_update(desc, xattr->value, xattr->value_len);
> > + error = crypto_shash_update(desc, xattr->value, xattr->value_len);
> > + if (error) {
> > + pr_err("crypto_shash_update() failed: %d\n", error);
> > + goto out;
> > + }
> > }
> >
> > - hmac_add_misc(desc, inode, EVM_XATTR_HMAC, hmac_val);
> > + error = hmac_add_misc(desc, inode, EVM_XATTR_HMAC, hmac_val);
> > +out:
> > kfree(desc);
> > - return 0;
> > + return error;
> > }
> >
> > /*
^ permalink raw reply
* [PATCH] task: delete task_euid()
From: Alice Ryhl @ 2026-02-19 12:14 UTC (permalink / raw)
To: Paul Moore, Serge Hallyn, Jonathan Corbet, Greg Kroah-Hartman,
Shuah Khan, Alex Shi, Yanteng Si, Dongliang Mu
Cc: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Trevor Gross, Danilo Krummrich,
linux-security-module, linux-doc, linux-kernel, rust-for-linux,
Jann Horn, Alice Ryhl
task_euid() is a very weird operation. You can see how weird it is by
grepping for task_euid() - binder is its only user. task_euid() obtains
the objective effective UID - it looks at the credentials of the task
for purposes of acting on it as an object, but then accesses the
effective UID (which the credentials.7 man page describes as "[...] used
by the kernel to determine the permissions that the process will have
when accessing shared resources [...]").
Since usage in Binder has now been removed, get rid of the resulting
dead code.
Changes to the zh_CN translation was carried out with the help of
Gemini and Google Translate.
Suggested-by: Jann Horn <jannh@google.com>
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
---
Depends on these two changes:
https://lore.kernel.org/all/20260212-rust-uid-v1-1-deff4214c766@google.com/
https://lore.kernel.org/all/20260213-binder-uid-v1-0-7b795ae05523@google.com/
---
Documentation/security/credentials.rst | 6 ++----
Documentation/translations/zh_CN/security/credentials.rst | 6 ++----
include/linux/cred.h | 1 -
rust/helpers/task.c | 5 -----
rust/kernel/task.rs | 10 ----------
5 files changed, 4 insertions(+), 24 deletions(-)
diff --git a/Documentation/security/credentials.rst b/Documentation/security/credentials.rst
index d0191c8b8060edb7b272402c019cff941ec22743..81d3b5737d85bde9b77bff94dfb93ed8037b2302 100644
--- a/Documentation/security/credentials.rst
+++ b/Documentation/security/credentials.rst
@@ -393,16 +393,14 @@ the credentials so obtained when they're finished with.
The result of ``__task_cred()`` should not be passed directly to
``get_cred()`` as this may race with ``commit_cred()``.
-There are a couple of convenience functions to access bits of another task's
-credentials, hiding the RCU magic from the caller::
+There is a convenience function to access bits of another task's credentials,
+hiding the RCU magic from the caller::
uid_t task_uid(task) Task's real UID
- uid_t task_euid(task) Task's effective UID
If the caller is holding the RCU read lock at the time anyway, then::
__task_cred(task)->uid
- __task_cred(task)->euid
should be used instead. Similarly, if multiple aspects of a task's credentials
need to be accessed, RCU read lock should be used, ``__task_cred()`` called,
diff --git a/Documentation/translations/zh_CN/security/credentials.rst b/Documentation/translations/zh_CN/security/credentials.rst
index 88fcd9152ffe91d79fc10bfc7b2a37d301b4938a..f0b2efec342438b81be415dc513622c961bb7e59 100644
--- a/Documentation/translations/zh_CN/security/credentials.rst
+++ b/Documentation/translations/zh_CN/security/credentials.rst
@@ -337,15 +337,13 @@ const指针上操作,因此不需要进行类型转换,但需要临时放弃
``__task_cred()`` 的结果不应直接传递给 ``get_cred()`` ,
因为这可能与 ``commit_cred()`` 发生竞争条件。
-还有一些方便的函数可以访问另一个任务凭据的特定部分,将RCU操作对调用方隐藏起来::
+有一个方便的函数可用于访问另一个任务凭据的特定部分,从而对调用方隐藏RCU机制::
uid_t task_uid(task) Task's real UID
- uid_t task_euid(task) Task's effective UID
-如果调用方在此时已经持有RCU读锁,则应使用::
+如果调用方在此时已经持有RCU读锁,则应改为使用::
__task_cred(task)->uid
- __task_cred(task)->euid
类似地,如果需要访问任务凭据的多个方面,应使用RCU读锁,调用 ``__task_cred()``
函数,将结果存储在临时指针中,然后从临时指针中调用凭据的各个方面,最后释放锁。
diff --git a/include/linux/cred.h b/include/linux/cred.h
index ed1609d78cd7b16ed1434c937176495a4f38cf6e..b40ec3c72ee6673c7be5210a1667e3912cba9620 100644
--- a/include/linux/cred.h
+++ b/include/linux/cred.h
@@ -367,7 +367,6 @@ DEFINE_FREE(put_cred, struct cred *, if (!IS_ERR_OR_NULL(_T)) put_cred(_T))
})
#define task_uid(task) (task_cred_xxx((task), uid))
-#define task_euid(task) (task_cred_xxx((task), euid))
#define task_ucounts(task) (task_cred_xxx((task), ucounts))
#define current_cred_xxx(xxx) \
diff --git a/rust/helpers/task.c b/rust/helpers/task.c
index c0e1a06ede78c0b0641707b52a82725543e2c02c..b46b1433a67e8eb341a7ee32ca4247b304bf675f 100644
--- a/rust/helpers/task.c
+++ b/rust/helpers/task.c
@@ -28,11 +28,6 @@ __rust_helper kuid_t rust_helper_task_uid(struct task_struct *task)
return task_uid(task);
}
-__rust_helper kuid_t rust_helper_task_euid(struct task_struct *task)
-{
- return task_euid(task);
-}
-
#ifndef CONFIG_USER_NS
__rust_helper uid_t rust_helper_from_kuid(struct user_namespace *to, kuid_t uid)
{
diff --git a/rust/kernel/task.rs b/rust/kernel/task.rs
index e07d0ddd76f6917adc91ca3d17bb7719153ee17f..169ff1dde9363afc8914b431fe31f2238b213ada 100644
--- a/rust/kernel/task.rs
+++ b/rust/kernel/task.rs
@@ -218,16 +218,6 @@ pub fn uid(&self) -> Kuid {
Kuid::from_raw(unsafe { bindings::task_uid(self.as_ptr()) })
}
- /// Returns the objective effective UID of the given task.
- ///
- /// You should probably not be using this; the effective UID is normally
- /// only relevant in subjective credentials.
- #[inline]
- pub fn euid(&self) -> Kuid {
- // SAFETY: It's always safe to call `task_euid` on a valid task.
- Kuid::from_raw(unsafe { bindings::task_euid(self.as_ptr()) })
- }
-
/// Determines whether the given task has pending signals.
#[inline]
pub fn signal_pending(&self) -> bool {
---
base-commit: 2961f841b025fb234860bac26dfb7fa7cb0fb122
change-id: 20260219-remove-task-euid-19e4b00beebe
prerequisite-change-id: 20260212-rust-uid-f1b3a45c8084:v1
prerequisite-patch-id: 7ec4933af3a7f4c6bb0403c34a6dd41306836295
prerequisite-change-id: 20260213-binder-uid-a24ede5026a8:v1
prerequisite-patch-id: 7be0128bd8902879bb271d0587ac98bf242cf612
prerequisite-patch-id: 4a9d0f595d2084b3f8982a2d0d8b3df35b9fae0e
Best regards,
--
Alice Ryhl <aliceryhl@google.com>
^ permalink raw reply related
* Re: [PATCH v5 2/9] landlock: Control pathname UNIX domain socket resolution by path
From: Mickaël Salaün @ 2026-02-19 9:45 UTC (permalink / raw)
To: Günther Noack
Cc: John Johansen, Tingmao Wang, Justin Suess, Jann Horn,
linux-security-module, Samasth Norway Ananda, Matthieu Buffet,
Mikhail Ivanov, konstantin.meskhidze, Demi Marie Obenour,
Alyssa Ross, Tahera Fahimi
In-Reply-To: <20260217.lievaS8eeng8@digikod.net>
On Wed, Feb 18, 2026 at 10:37:16AM +0100, Mickaël Salaün wrote:
> On Sun, Feb 15, 2026 at 11:51:50AM +0100, Günther Noack wrote:
> > * Add a new access right LANDLOCK_ACCESS_FS_RESOLVE_UNIX, which
> > controls the look up operations for named UNIX domain sockets. The
> > resolution happens during connect() and sendmsg() (depending on
> > socket type).
> > * Hook into the path lookup in unix_find_bsd() in af_unix.c, using a
> > LSM hook. Make policy decisions based on the new access rights
> > * Increment the Landlock ABI version.
> > * Minor test adaptions to keep the tests working.
> >
> > With this access right, access is granted if either of the following
> > conditions is met:
> >
> > * The target socket's filesystem path was allow-listed using a
> > LANDLOCK_RULE_PATH_BENEATH rule, *or*:
> > * The target socket was created in the same Landlock domain in which
> > LANDLOCK_ACCESS_FS_RESOLVE_UNIX was restricted.
> >
> > In case of a denial, connect() and sendmsg() return EACCES, which is
> > the same error as it is returned if the user does not have the write
> > bit in the traditional Unix file system permissions of that file.
> >
> > This feature was created with substantial discussion and input from
> > Justin Suess, Tingmao Wang and Mickaël Salaün.
> >
> > Cc: Tingmao Wang <m@maowtm.org>
> > Cc: Justin Suess <utilityemal77@gmail.com>
> > Cc: Mickaël Salaün <mic@digikod.net>
> > Suggested-by: Jann Horn <jannh@google.com>
> > Link: https://github.com/landlock-lsm/linux/issues/36
> > Signed-off-by: Günther Noack <gnoack3000@gmail.com>
> > ---
> > include/uapi/linux/landlock.h | 10 ++
> > security/landlock/access.h | 11 +-
> > security/landlock/audit.c | 1 +
> > security/landlock/fs.c | 102 ++++++++++++++++++-
> > security/landlock/limits.h | 2 +-
> > security/landlock/syscalls.c | 2 +-
> > tools/testing/selftests/landlock/base_test.c | 2 +-
> > tools/testing/selftests/landlock/fs_test.c | 5 +-
> > 8 files changed, 128 insertions(+), 7 deletions(-)
> > index 60ff217ab95b..8d0edf94037d 100644
> > --- a/security/landlock/audit.c
> > +++ b/security/landlock/audit.c
> > @@ -37,6 +37,7 @@ static const char *const fs_access_strings[] = {
> > [BIT_INDEX(LANDLOCK_ACCESS_FS_REFER)] = "fs.refer",
> > [BIT_INDEX(LANDLOCK_ACCESS_FS_TRUNCATE)] = "fs.truncate",
> > [BIT_INDEX(LANDLOCK_ACCESS_FS_IOCTL_DEV)] = "fs.ioctl_dev",
> > + [BIT_INDEX(LANDLOCK_ACCESS_FS_RESOLVE_UNIX)] = "fs.resolve_unix",
> > };
> >
> > static_assert(ARRAY_SIZE(fs_access_strings) == LANDLOCK_NUM_ACCESS_FS);
> > diff --git a/security/landlock/fs.c b/security/landlock/fs.c
> > index e764470f588c..76035c6f2bf1 100644
> > --- a/security/landlock/fs.c
> > +++ b/security/landlock/fs.c
> > @@ -27,6 +27,7 @@
> > #include <linux/lsm_hooks.h>
> > #include <linux/mount.h>
> > #include <linux/namei.h>
> > +#include <linux/net.h>
> > #include <linux/path.h>
> > #include <linux/pid.h>
> > #include <linux/rcupdate.h>
> > @@ -314,7 +315,8 @@ static struct landlock_object *get_inode_object(struct inode *const inode)
> > LANDLOCK_ACCESS_FS_WRITE_FILE | \
> > LANDLOCK_ACCESS_FS_READ_FILE | \
> > LANDLOCK_ACCESS_FS_TRUNCATE | \
> > - LANDLOCK_ACCESS_FS_IOCTL_DEV)
> > + LANDLOCK_ACCESS_FS_IOCTL_DEV | \
> > + LANDLOCK_ACCESS_FS_RESOLVE_UNIX)
> > /* clang-format on */
> >
> > /*
> > @@ -1561,6 +1563,103 @@ static int hook_path_truncate(const struct path *const path)
> > return current_check_access_path(path, LANDLOCK_ACCESS_FS_TRUNCATE);
> > }
> >
> > +/**
> > + * unmask_scoped_access - Remove access right bits in @masks in all layers
> > + * where @client and @server have the same domain
> > + *
> > + * This does the same as domain_is_scoped(), but unmasks bits in @masks.
> > + * It can not return early as domain_is_scoped() does.
Why can't we use the same logic as for other scopes?
> > + *
> > + * @client: Client domain
> > + * @server: Server domain
> > + * @masks: Layer access masks to unmask
> > + * @access: Access bit that controls scoping
> > + */
> > +static void unmask_scoped_access(const struct landlock_ruleset *const client,
> > + const struct landlock_ruleset *const server,
> > + struct layer_access_masks *const masks,
> > + const access_mask_t access)
>
> This helper should be moved to task.c and factored out with
> domain_is_scoped(). This should be a dedicated patch.
Well, if domain_is_scoped() can be refactored and made generic, it would
make more sense to move it to domain.c
>
> > +{
> > + int client_layer, server_layer;
> > + const struct landlock_hierarchy *client_walker, *server_walker;
> > +
> > + if (WARN_ON_ONCE(!client))
> > + return; /* should not happen */
> > +
> > + if (!server)
> > + return; /* server has no Landlock domain; nothing to clear */
> > +
> > + client_layer = client->num_layers - 1;
> > + client_walker = client->hierarchy;
> > + server_layer = server->num_layers - 1;
> > + server_walker = server->hierarchy;
> > +
> > + /*
> > + * Clears the access bits at all layers where the client domain is the
> > + * same as the server domain. We start the walk at min(client_layer,
> > + * server_layer). The layer bits until there can not be cleared because
> > + * either the client or the server domain is missing.
> > + */
> > + for (; client_layer > server_layer; client_layer--)
> > + client_walker = client_walker->parent;
> > +
> > + for (; server_layer > client_layer; server_layer--)
> > + server_walker = server_walker->parent;
> > +
> > + for (; client_layer >= 0; client_layer--) {
> > + if (masks->access[client_layer] & access &&
> > + client_walker == server_walker)
> > + masks->access[client_layer] &= ~access;
> > +
> > + client_walker = client_walker->parent;
> > + server_walker = server_walker->parent;
> > + }
> > +}
^ permalink raw reply
* Re: [PATCH v2 v2] evm: check return values of crypto_shash functions
From: Roberto Sassu @ 2026-02-19 9:26 UTC (permalink / raw)
To: Daniel Hodges
Cc: zohar, roberto.sassu, dmitry.kasatkin, eric.snowberg, paul,
jmorris, serge, linux-integrity, linux-security-module,
linux-kernel
In-Reply-To: <20260206024240.19059-1-git@danielhodges.dev>
On Thu, 2026-02-05 at 21:42 -0500, Daniel Hodges wrote:
> The crypto_shash_update() and crypto_shash_final() functions can fail
> and return error codes, but their return values were not being checked
> in several places in security/integrity/evm/evm_crypto.c:
>
> - hmac_add_misc() ignored returns from crypto_shash_update() and
> crypto_shash_final()
> - evm_calc_hmac_or_hash() ignored returns from crypto_shash_update()
> - evm_init_hmac() ignored returns from crypto_shash_update()
>
> If these hash operations fail silently, the resulting HMAC could be
> invalid or incomplete, which could weaken the integrity verification
> security that EVM provides.
>
> This patch converts hmac_add_misc() from void to int return type and
> adds proper error checking and propagation for all crypto_shash_*
> function calls. All callers are updated to handle the new return values.
> Additionally, error messages are logged when cryptographic operations
> fail to provide visibility into the failure rather than silently
> returning error codes.
>
> Fixes: 66dbc325afce ("evm: re-release")
> Signed-off-by: Daniel Hodges <git@danielhodges.dev>
After fixing the minor issue below:
Reviewed-by: Roberto Sassu <roberto.sassu@huawei.com>
> ---
> security/integrity/evm/evm_crypto.c | 55 ++++++++++++++++++++++-------
> 1 file changed, 42 insertions(+), 13 deletions(-)
>
> diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c
> index a5e730ffda57..402eb1ca64ce 100644
> --- a/security/integrity/evm/evm_crypto.c
> +++ b/security/integrity/evm/evm_crypto.c
> @@ -139,7 +139,7 @@ static struct shash_desc *init_desc(char type, uint8_t hash_algo)
> * (Additional directory/file metadata needs to be added for more complete
> * protection.)
> */
> -static void hmac_add_misc(struct shash_desc *desc, struct inode *inode,
> +static int hmac_add_misc(struct shash_desc *desc, struct inode *inode,
> char type, char *digest)
> {
> struct h_misc {
> @@ -149,6 +149,7 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode,
> gid_t gid;
> umode_t mode;
> } hmac_misc;
> + int error;
>
> memset(&hmac_misc, 0, sizeof(hmac_misc));
> /* Don't include the inode or generation number in portable
> @@ -169,14 +170,28 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode,
> hmac_misc.uid = from_kuid(&init_user_ns, inode->i_uid);
> hmac_misc.gid = from_kgid(&init_user_ns, inode->i_gid);
> hmac_misc.mode = inode->i_mode;
> - crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof(hmac_misc));
> + error = crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof(hmac_misc));
> + if (error) {
> + pr_err("crypto_shash_update() failed: %d\n", error);
> + return error;
> + }
> if ((evm_hmac_attrs & EVM_ATTR_FSUUID) &&
> - type != EVM_XATTR_PORTABLE_DIGSIG)
> - crypto_shash_update(desc, (u8 *)&inode->i_sb->s_uuid, UUID_SIZE);
> - crypto_shash_final(desc, digest);
> + type != EVM_XATTR_PORTABLE_DIGSIG) {
> + error = crypto_shash_update(desc, (u8 *)&inode->i_sb->s_uuid, UUID_SIZE);
> + if (error) {
> + pr_err("crypto_shash_update() failed: %d\n", error);
> + return error;
> + }
> + }
> + error = crypto_shash_final(desc, digest);
> + if (error) {
> + pr_err("crypto_shash_final() failed: %d\n", error);
> + return error;
> + }
>
> pr_debug("hmac_misc: (%zu) [%*phN]\n", sizeof(struct h_misc),
> (int)sizeof(struct h_misc), &hmac_misc);
> + return 0;
> }
>
> /*
> @@ -260,9 +275,12 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
>
> if ((req_xattr_name && req_xattr_value)
> && !strcmp(xattr->name, req_xattr_name)) {
> - error = 0;
> - crypto_shash_update(desc, (const u8 *)req_xattr_value,
> + error = crypto_shash_update(desc, (const u8 *)req_xattr_value,
> req_xattr_value_len);
Please align this.
Thanks
Roberto
> + if (error) {
> + pr_err("crypto_shash_update() failed: %d\n", error);
> + goto out;
> + }
> if (is_ima)
> ima_present = true;
>
> @@ -286,15 +304,20 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
> pr_debug("file %s: xattr %s size mismatch (kernel: %d, user: %d)\n",
> dentry->d_name.name, xattr->name, size,
> user_space_size);
> - error = 0;
> xattr_size = size;
> - crypto_shash_update(desc, (const u8 *)xattr_value, xattr_size);
> + error = crypto_shash_update(desc, (const u8 *)xattr_value, xattr_size);
> + if (error) {
> + pr_err("crypto_shash_update() failed: %d\n", error);
> + goto out;
> + }
> if (is_ima)
> ima_present = true;
>
> dump_security_xattr(xattr->name, xattr_value, xattr_size);
> }
> - hmac_add_misc(desc, inode, type, data->digest);
> + error = hmac_add_misc(desc, inode, type, data->digest);
> + if (error)
> + goto out;
>
> if (inode != d_backing_inode(dentry) && iint) {
> if (IS_I_VERSION(inode))
> @@ -401,6 +424,7 @@ int evm_init_hmac(struct inode *inode, const struct xattr *xattrs,
> {
> struct shash_desc *desc;
> const struct xattr *xattr;
> + int error;
>
> desc = init_desc(EVM_XATTR_HMAC, HASH_ALGO_SHA1);
> if (IS_ERR(desc)) {
> @@ -412,12 +436,17 @@ int evm_init_hmac(struct inode *inode, const struct xattr *xattrs,
> if (!evm_protected_xattr(xattr->name))
> continue;
>
> - crypto_shash_update(desc, xattr->value, xattr->value_len);
> + error = crypto_shash_update(desc, xattr->value, xattr->value_len);
> + if (error) {
> + pr_err("crypto_shash_update() failed: %d\n", error);
> + goto out;
> + }
> }
>
> - hmac_add_misc(desc, inode, EVM_XATTR_HMAC, hmac_val);
> + error = hmac_add_misc(desc, inode, EVM_XATTR_HMAC, hmac_val);
> +out:
> kfree(desc);
> - return 0;
> + return error;
> }
>
> /*
^ permalink raw reply
* Re: [PATCH v4] ima_fs: Avoid creating measurement lists for unsupported hash algos
From: Roberto Sassu @ 2026-02-19 8:54 UTC (permalink / raw)
To: dima, Mimi Zohar, Roberto Sassu, Dmitry Kasatkin, Eric Snowberg,
Paul Moore, James Morris, Serge E. Hallyn, Silvia Sisinni,
Enrico Bravi
Cc: linux-integrity, linux-security-module, linux-kernel, stable,
Dmitry Safonov
In-Reply-To: <701de3f87f0f6bde97872dd0c5bf150bfc1f2713.camel@huaweicloud.com>
On Tue, 2026-01-27 at 16:20 +0100, Roberto Sassu wrote:
> On Tue, 2026-01-27 at 15:03 +0000, Dmitry Safonov via B4 Relay wrote:
> > From: Dmitry Safonov <dima@arista.com>
> >
> > ima_init_crypto() skips initializing ima_algo_array[i] if the algorithm
> > from ima_tpm_chip->allocated_banks[i].crypto_id is not supported.
> > It seems avoid adding the unsupported algorithm to ima_algo_array will
> > break all the logic that relies on indexing by NR_BANKS(ima_tpm_chip).
>
> The patch looks good, although I didn't try yet myself.
>
> I would make the commit message slightly better, with a more fluid
> explanation.
>
> ima_tpm_chip->allocated_banks[i].crypto_id is initialized to
> HASH_ALGO__LAST if the TPM algorithm is not supported. However there
> are places relying on the algorithm to be valid because it is accessed
> by hash_algo_name[].
>
> Thus solve the problem by creating a file name that does not depend on
> the crypto algorithm to be initialized, ...
>
> Also print the template entry digest as populated by IMA.
>
> Something along these lines.
>
> Also, I have a preference for lower case instead of capital case for
> the file name, given the other names.
Hi Dmitry
do you have time to make these small changes, so that we queue the
patch for the next kernel?
Thanks
Roberto
> Could you also avoid the >, otherwise the mailer thinks it is a reply?
>
> Thanks
>
> Roberto
>
> > On 6.12.40 I observe the following read out-of-bounds in hash_algo_name:
> >
> > > ==================================================================
> > > BUG: KASAN: global-out-of-bounds in create_securityfs_measurement_lists+0x396/0x440
> > > Read of size 8 at addr ffffffff83e18138 by task swapper/0/1
> > >
> > > CPU: 4 UID: 0 PID: 1 Comm: swapper/0 Not tainted 6.12.40 #3
> > > Call Trace:
> > > <TASK>
> > > dump_stack_lvl+0x61/0x90
> > > print_report+0xc4/0x580
> > > ? kasan_addr_to_slab+0x26/0x80
> > > ? create_securityfs_measurement_lists+0x396/0x440
> > > kasan_report+0xc2/0x100
> > > ? create_securityfs_measurement_lists+0x396/0x440
> > > create_securityfs_measurement_lists+0x396/0x440
> > > ima_fs_init+0xa3/0x300
> > > ima_init+0x7d/0xd0
> > > init_ima+0x28/0x100
> > > do_one_initcall+0xa6/0x3e0
> > > kernel_init_freeable+0x455/0x740
> > > kernel_init+0x24/0x1d0
> > > ret_from_fork+0x38/0x80
> > > ret_from_fork_asm+0x11/0x20
> > > </TASK>
> > >
> > > The buggy address belongs to the variable:
> > > hash_algo_name+0xb8/0x420
> > >
> > > The buggy address belongs to the physical page:
> > > page: refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x107ce18
> > > flags: 0x8000000000002000(reserved|zone=2)
> > > raw: 8000000000002000 ffffea0041f38608 ffffea0041f38608 0000000000000000
> > > raw: 0000000000000000 0000000000000000 00000001ffffffff 0000000000000000
> > > page dumped because: kasan: bad access detected
> > >
> > > Memory state around the buggy address:
> > > ffffffff83e18000: 00 01 f9 f9 f9 f9 f9 f9 00 01 f9 f9 f9 f9 f9 f9
> > > ffffffff83e18080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
> > > > ffffffff83e18100: 00 00 00 00 00 00 00 f9 f9 f9 f9 f9 00 05 f9 f9
> > > ^
> > > ffffffff83e18180: f9 f9 f9 f9 00 00 00 00 00 00 00 04 f9 f9 f9 f9
> > > ffffffff83e18200: 00 00 00 00 00 00 00 00 04 f9 f9 f9 f9 f9 f9 f9
> > > ==================================================================
> >
> > Seems like the TPM chip supports sha3_256, which isn't yet in
> > tpm_algorithms:
> > > tpm tpm0: TPM with unsupported bank algorithm 0x0027
> >
> > Use TPM_ALG_<ID> as a postfix for file names for unsupported hashing algorithms.
> >
> > This is how it looks on the test machine I have:
> > > # ls -1 /sys/kernel/security/ima/
> > > ascii_runtime_measurements
> > > ascii_runtime_measurements_TPM_ALG_27
> > > ascii_runtime_measurements_sha1
> > > ascii_runtime_measurements_sha256
> > > binary_runtime_measurements
> > > binary_runtime_measurements_TPM_ALG_27
> > > binary_runtime_measurements_sha1
> > > binary_runtime_measurements_sha256
> > > policy
> > > runtime_measurements_count
> > > violations
> >
> > Fixes: 9fa8e7625008 ("ima: add crypto agility support for template-hash algorithm")
> > Signed-off-by: Dmitry Safonov <dima@arista.com>
> > Cc: Enrico Bravi <enrico.bravi@polito.it>
> > Cc: Silvia Sisinni <silvia.sisinni@polito.it>
> > Cc: Roberto Sassu <roberto.sassu@huawei.com>
> > Cc: Mimi Zohar <zohar@linux.ibm.com>
> > ---
> > Changes in v4:
> > - Use ima_tpm_chip->allocated_banks[algo_idx].digest_size instead of hash_digest_size[algo]
> > (Roberto Sassu)
> > - Link to v3: https://lore.kernel.org/r/20260127-ima-oob-v3-1-1dd09f4c2a6a@arista.com
> > Testing note: I test it on v6.12.40 kernel backport, which slightly differs as
> > lookup_template_data_hash_algo() was yet present.
> >
> > Changes in v3:
> > - Now fix the spelling *for real* (sorry, messed it up in v2)
> > - Link to v2: https://lore.kernel.org/r/20260127-ima-oob-v2-1-f38a18c850cf@arista.com
> >
> > Changes in v2:
> > - Instead of skipping unknown algorithms, add files under their TPM_ALG_ID (Roberto Sassu)
> > - Fix spelling (Roberto Sassu)
> > - Copy @stable on the fix
> > - Link to v1: https://lore.kernel.org/r/20260127-ima-oob-v1-1-2d42f3418e57@arista.com
> > ---
> > security/integrity/ima/ima_fs.c | 34 ++++++++++++++++++----------------
> > 1 file changed, 18 insertions(+), 16 deletions(-)
> >
> > diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
> > index 012a58959ff0..9a00a0547619 100644
> > --- a/security/integrity/ima/ima_fs.c
> > +++ b/security/integrity/ima/ima_fs.c
> > @@ -132,16 +132,12 @@ int ima_measurements_show(struct seq_file *m, void *v)
> > char *template_name;
> > u32 pcr, namelen, template_data_len; /* temporary fields */
> > bool is_ima_template = false;
> > - enum hash_algo algo;
> > int i, algo_idx;
> >
> > algo_idx = ima_sha1_idx;
> > - algo = HASH_ALGO_SHA1;
> >
> > - if (m->file != NULL) {
> > + if (m->file != NULL)
> > algo_idx = (unsigned long)file_inode(m->file)->i_private;
> > - algo = ima_algo_array[algo_idx].algo;
> > - }
> >
> > /* get entry */
> > e = qe->entry;
> > @@ -160,7 +156,8 @@ int ima_measurements_show(struct seq_file *m, void *v)
> > ima_putc(m, &pcr, sizeof(e->pcr));
> >
> > /* 2nd: template digest */
> > - ima_putc(m, e->digests[algo_idx].digest, hash_digest_size[algo]);
> > + ima_putc(m, e->digests[algo_idx].digest,
> > + ima_tpm_chip->allocated_banks[algo_idx].digest_size);
> >
> > /* 3rd: template name size */
> > namelen = !ima_canonical_fmt ? strlen(template_name) :
> > @@ -229,16 +226,12 @@ static int ima_ascii_measurements_show(struct seq_file *m, void *v)
> > struct ima_queue_entry *qe = v;
> > struct ima_template_entry *e;
> > char *template_name;
> > - enum hash_algo algo;
> > int i, algo_idx;
> >
> > algo_idx = ima_sha1_idx;
> > - algo = HASH_ALGO_SHA1;
> >
> > - if (m->file != NULL) {
> > + if (m->file != NULL)
> > algo_idx = (unsigned long)file_inode(m->file)->i_private;
> > - algo = ima_algo_array[algo_idx].algo;
> > - }
> >
> > /* get entry */
> > e = qe->entry;
> > @@ -252,7 +245,8 @@ static int ima_ascii_measurements_show(struct seq_file *m, void *v)
> > seq_printf(m, "%2d ", e->pcr);
> >
> > /* 2nd: template hash */
> > - ima_print_digest(m, e->digests[algo_idx].digest, hash_digest_size[algo]);
> > + ima_print_digest(m, e->digests[algo_idx].digest,
> > + ima_tpm_chip->allocated_banks[algo_idx].digest_size);
> >
> > /* 3th: template name */
> > seq_printf(m, " %s", template_name);
> > @@ -404,16 +398,24 @@ static int __init create_securityfs_measurement_lists(void)
> > char file_name[NAME_MAX + 1];
> > struct dentry *dentry;
> >
> > - sprintf(file_name, "ascii_runtime_measurements_%s",
> > - hash_algo_name[algo]);
> > + if (algo == HASH_ALGO__LAST)
> > + sprintf(file_name, "ascii_runtime_measurements_TPM_ALG_%x",
> > + ima_tpm_chip->allocated_banks[i].alg_id);
> > + else
> > + sprintf(file_name, "ascii_runtime_measurements_%s",
> > + hash_algo_name[algo]);
> > dentry = securityfs_create_file(file_name, S_IRUSR | S_IRGRP,
> > ima_dir, (void *)(uintptr_t)i,
> > &ima_ascii_measurements_ops);
> > if (IS_ERR(dentry))
> > return PTR_ERR(dentry);
> >
> > - sprintf(file_name, "binary_runtime_measurements_%s",
> > - hash_algo_name[algo]);
> > + if (algo == HASH_ALGO__LAST)
> > + sprintf(file_name, "binary_runtime_measurements_TPM_ALG_%x",
> > + ima_tpm_chip->allocated_banks[i].alg_id);
> > + else
> > + sprintf(file_name, "binary_runtime_measurements_%s",
> > + hash_algo_name[algo]);
> > dentry = securityfs_create_file(file_name, S_IRUSR | S_IRGRP,
> > ima_dir, (void *)(uintptr_t)i,
> > &ima_measurements_ops);
> >
> > ---
> > base-commit: 63804fed149a6750ffd28610c5c1c98cce6bd377
> > change-id: 20260127-ima-oob-9fa83a634d7b
> >
> > Best regards,
^ permalink raw reply
* Re: [PATCH] ima: check return value of crypto_shash_final() in boot aggregate
From: Roberto Sassu @ 2026-02-19 8:56 UTC (permalink / raw)
To: Daniel Hodges, Mimi Zohar, Roberto Sassu, Dmitry Kasatkin
Cc: Eric Snowberg, Paul Moore, James Morris, Serge E . Hallyn,
linux-integrity, linux-security-module, linux-kernel
In-Reply-To: <20260201024015.2862236-1-hodgesd@meta.com>
On Sat, 2026-01-31 at 18:40 -0800, Daniel Hodges wrote:
> The return value of crypto_shash_final() is not checked in
> ima_calc_boot_aggregate_tfm(). If the hash finalization fails, the
> function returns success and a corrupted boot aggregate digest could
> be used for IMA measurements.
>
> Capture the return value and propagate any error to the caller.
>
> Fixes: 76bb28f6126f ("ima: use new crypto_shash API instead of old crypto_hash")
> Signed-off-by: Daniel Hodges <hodgesd@meta.com>
Reviewed-by: Roberto Sassu <roberto.sassu@huawei.com>
Thanks
Roberto
> ---
> security/integrity/ima/ima_crypto.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c
> index 6f5696d999d0..8ae7821a65c2 100644
> --- a/security/integrity/ima/ima_crypto.c
> +++ b/security/integrity/ima/ima_crypto.c
> @@ -825,21 +825,21 @@ static int ima_calc_boot_aggregate_tfm(char *digest, u16 alg_id,
> * non-SHA1 boot_aggregate digests to avoid ambiguity.
> */
> if (alg_id != TPM_ALG_SHA1) {
> for (i = TPM_PCR8; i < TPM_PCR10; i++) {
> ima_pcrread(i, &d);
> rc = crypto_shash_update(shash, d.digest,
> crypto_shash_digestsize(tfm));
> }
> }
> if (!rc)
> - crypto_shash_final(shash, digest);
> + rc = crypto_shash_final(shash, digest);
> return rc;
> }
>
> int ima_calc_boot_aggregate(struct ima_digest_data *hash)
> {
> struct crypto_shash *tfm;
> u16 crypto_id, alg_id;
> int rc, i, bank_idx = -1;
>
> for (i = 0; i < ima_tpm_chip->nr_allocated_banks; i++) {
^ permalink raw reply
* [GIT PULL] AppArmor updates for 7.0-rc1
From: John Johansen @ 2026-02-19 0:19 UTC (permalink / raw)
To: Linus Torvalds; +Cc: LKLM, open list:SECURITY SUBSYSTEM
Hi Linus,
Below is the AppArmor update PR for 7.0
These patches have all been merge, build, and regression tested
against your tree as of yesterday. The code has been in linux-next
and the many of the patches in the Ubuntu kernels for testing.
This PR is mostly comprised of cleanups, and bug fixes, with 3 minor
features, the first being an improvement to our kunit testing, and
the other two extending the information available in audit messages.
Because this is coming so late in the window (sorry life happens),
if you would prefer I have prepared an alternate PR that contains
the set of bug fixes that apply without the features, or cleanups,
available via the tag bugfix-2026-02-18, which I can send a PR for
instead.
thanks
- john
The following changes since commit 8f0b4cce4481fb22653697cced8d0d04027cb1e8:
Linux 6.19-rc1 (2025-12-14 16:05:07 +1200)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor tags/apparmor-pr-2026-02-18
for you to fetch changes up to 08020dbe3125e936429e7966bf072e08fa964f36:
apparmor: fix signedness bug in unpack_tags() (2026-02-18 11:50:20 -0800)
----------------------------------------------------------------
+ Features
- add .kunitconfig
- audit execpath in userns mediation
- add support loading per permission tagging
+ Cleanups
- cleanup remove unused percpu critical sections in buffer management
- document the buffer hold, add an overflow guard
- split xxx_in_ns into its two separate semantic use cases
- remove apply_modes_to_perms from label_match
- refactor/cleanup cred helper fns.
- guard against free attachment/data routines being called with a NULL
- drop in_atomic flag in common_mmap, and common_file_perm, and cleanup
- make str table more generic and be able to have multiple entries
- Replace deprecated strcpy with memcpy in gen_symlink_name
- Replace deprecated strcpy in d_namespace_path
- Replace sprintf/strcpy with scnprintf/strscpy in aa_policy_init
- replace sprintf with snprintf in aa_new_learning_profile
+ Bug Fixes
- fix cast in format string DEBUG statement
- fix make aa_labelmatch return consistent
- fix fmt string type error in process_strs_entry
- fix kernel-doc comments for inview
- fix invalid deref of rawdata when export_binary is unset
- avoid per-cpu hold underflow in aa_get_buffer
- fix fast path cache check for unix sockets
- fix rlimit for posix cpu timers
- fix label and profile debug macros
- move check for aa_null file to cover all cases
- return -ENOMEM in unpack_perms_table upon alloc failure
- fix boolean argument in apparmor_mmap_file
- Fix & Optimize table creation from possibly unaligned memory
- Allow apparmor to handle unaligned dfa tables
- fix NULL deref in aa_sock_file_perm
- fix NULL pointer dereference in __unix_needs_revalidation
- fix signedness bug in unpack_tags()
----------------------------------------------------------------
Georgia Garcia (1):
apparmor: fix invalid deref of rawdata when export_binary is unset
Helge Deller (2):
AppArmor: Allow apparmor to handle unaligned dfa tables
apparmor: Fix & Optimize table creation from possibly unaligned memory
John Johansen (19):
apparmor: fix NULL sock in aa_sock_file_perm
apparmor: make str table more generic and be able to have multiple entries
apparmor: add support loading per permission tagging
apparmor: drop in_atomic flag in common_mmap, and common_file_perm
apparmor: guard against free routines being called with a NULL
apparmor: move check for aa_null file to cover all cases
apparmor: fix label and profile debug macros
apparmor: refactor/cleanup cred helper fns.
apparmor: fix rlimit for posix cpu timers
apparmor: fix fast path cache check for unix sockets
apparmor: remove apply_modes_to_perms from label_match
apparmor: make label_match return a consistent value
apparmor: split xxx_in_ns into its two separate semantic use cases
apparmor: document the buffer hold, add an overflow guard
apparmor: cleanup remove unused percpu critical sections in buffer management
apparmor: fix kernel-doc comments for inview
apparmor: fix fmt string type error in process_strs_entry
apparmor: fix aa_label to return state from compount and component match
apparmor: fix cast in format string DEBUG statement
Massimiliano Pellizzer (1):
apparmor: fix signedness bug in unpack_tags()
Maxime Bélair (1):
apparmor: userns: Add support for execpath in userns
Ryan Lee (3):
apparmor: fix boolean argument in apparmor_mmap_file
apparmor: account for in_atomic removal in common_file_perm
apparmor: return -ENOMEM in unpack_perms_table upon alloc failure
Ryota Sakamoto (1):
apparmor: add .kunitconfig
System Administrator (1):
apparmor: fix NULL pointer dereference in __unix_needs_revalidation
Thorsten Blum (4):
apparmor: replace sprintf with snprintf in aa_new_learning_profile
apparmor: Replace sprintf/strcpy with scnprintf/strscpy in aa_policy_init
apparmor: Replace deprecated strcpy in d_namespace_path
apparmor: Replace deprecated strcpy with memcpy in gen_symlink_name
Zhengmian Hu (1):
apparmor: avoid per-cpu hold underflow in aa_get_buffer
security/apparmor/.kunitconfig | 5 +
security/apparmor/af_unix.c | 2 +-
security/apparmor/apparmorfs.c | 23 ++-
security/apparmor/domain.c | 60 +++----
security/apparmor/file.c | 49 ++++--
security/apparmor/include/audit.h | 2 +
security/apparmor/include/cred.h | 100 +++++++----
security/apparmor/include/lib.h | 37 +++-
security/apparmor/include/match.h | 12 +-
security/apparmor/include/policy.h | 32 +++-
security/apparmor/label.c | 55 +++---
security/apparmor/lib.c | 29 ++--
security/apparmor/lsm.c | 66 +++++---
security/apparmor/match.c | 22 +--
security/apparmor/net.c | 6 +-
security/apparmor/path.c | 13 +-
security/apparmor/policy.c | 31 +++-
security/apparmor/policy_compat.c | 10 +-
security/apparmor/policy_unpack.c | 336 ++++++++++++++++++++++++++++++++-----
security/apparmor/resource.c | 5 +
security/apparmor/task.c | 32 ++++
21 files changed, 687 insertions(+), 240 deletions(-)
create mode 100644 security/apparmor/.kunitconfig
^ permalink raw reply
* [PATCH 2/2] landlock: Remove collect_domain_accesses
From: Justin Suess @ 2026-02-18 20:18 UTC (permalink / raw)
To: linux-security-module, Mickaël Salaün
Cc: Günther Noack, Tingmao Wang, Justin Suess
In-Reply-To: <20260218201857.1194667-1-utilityemal77@gmail.com>
Remove collect_domain_accesses and replace with inline logic using the
new path walk helper in the check_current_refer_path.
Signed-off-by: Justin Suess <utilityemal77@gmail.com>
---
security/landlock/fs.c | 128 +++++++++++++++--------------------------
1 file changed, 46 insertions(+), 82 deletions(-)
diff --git a/security/landlock/fs.c b/security/landlock/fs.c
index c6ff686c9cde..efc65dc41c0d 100644
--- a/security/landlock/fs.c
+++ b/security/landlock/fs.c
@@ -1013,77 +1013,6 @@ static access_mask_t maybe_remove(const struct dentry *const dentry)
LANDLOCK_ACCESS_FS_REMOVE_FILE;
}
-/**
- * collect_domain_accesses - Walk through a file path and collect accesses
- *
- * @domain: Domain to check against.
- * @mnt_root: Last directory to check.
- * @dir: Directory to start the walk from.
- * @layer_masks_dom: Where to store the collected accesses.
- *
- * This helper is useful to begin a path walk from the @dir directory to a
- * @mnt_root directory used as a mount point. This mount point is the common
- * ancestor between the source and the destination of a renamed and linked
- * file. While walking from @dir to @mnt_root, we record all the domain's
- * allowed accesses in @layer_masks_dom.
- *
- * Because of disconnected directories, this walk may not reach @mnt_dir. In
- * this case, the walk will continue to @mnt_dir after this call.
- *
- * This is similar to is_access_to_paths_allowed() but much simpler because it
- * only handles walking on the same mount point and only checks one set of
- * accesses.
- *
- * Returns:
- * - true if all the domain access rights are allowed for @dir;
- * - false if the walk reached @mnt_root.
- */
-static bool collect_domain_accesses(const struct landlock_ruleset *const domain,
- const struct dentry *const mnt_root,
- struct dentry *dir,
- struct layer_access_masks *layer_masks_dom)
-{
- bool ret = false;
-
- if (WARN_ON_ONCE(!domain || !mnt_root || !dir || !layer_masks_dom))
- return true;
- if (is_nouser_or_private(dir))
- return true;
-
- if (!landlock_init_layer_masks(domain, LANDLOCK_MASK_ACCESS_FS,
- layer_masks_dom, LANDLOCK_KEY_INODE))
- return true;
-
- dget(dir);
- while (true) {
- struct dentry *parent_dentry;
-
- /* Gets all layers allowing all domain accesses. */
- if (landlock_unmask_layers(find_rule(domain, dir),
- layer_masks_dom)) {
- /*
- * Stops when all handled accesses are allowed by at
- * least one rule in each layer.
- */
- ret = true;
- break;
- }
-
- /*
- * Stops at the mount point or the filesystem root for a disconnected
- * directory.
- */
- if (dir == mnt_root || unlikely(IS_ROOT(dir)))
- break;
-
- parent_dentry = dget_parent(dir);
- dput(dir);
- dir = parent_dentry;
- }
- dput(dir);
- return ret;
-}
-
/**
* current_check_refer_path - Check if a rename or link action is allowed
*
@@ -1147,7 +1076,7 @@ static int current_check_refer_path(struct dentry *const old_dentry,
bool allow_parent1, allow_parent2;
access_mask_t access_request_parent1, access_request_parent2;
struct path mnt_dir;
- struct dentry *old_parent;
+ struct path old_parent_path;
struct layer_access_masks layer_masks_parent1 = {},
layer_masks_parent2 = {};
struct landlock_request request1 = {}, request2 = {};
@@ -1202,20 +1131,55 @@ static int current_check_refer_path(struct dentry *const old_dentry,
/*
* old_dentry may be the root of the common mount point and
* !IS_ROOT(old_dentry) at the same time (e.g. with open_tree() and
- * OPEN_TREE_CLONE). We do not need to call dget(old_parent) because
+ * OPEN_TREE_CLONE). We do not need to path_get(old_parent_path) because
* we keep a reference to old_dentry.
*/
- old_parent = (old_dentry == mnt_dir.dentry) ? old_dentry :
- old_dentry->d_parent;
+ old_parent_path.mnt = mnt_dir.mnt;
+ old_parent_path.dentry = unlikely(old_dentry == mnt_dir.dentry) ?
+ old_dentry :
+ old_dentry->d_parent;
/* new_dir->dentry is equal to new_dentry->d_parent */
- allow_parent1 = collect_domain_accesses(subject->domain, mnt_dir.dentry,
- old_parent,
- &layer_masks_parent1);
- allow_parent2 = collect_domain_accesses(subject->domain, mnt_dir.dentry,
- new_dir->dentry,
- &layer_masks_parent2);
+ allow_parent1 = false;
+ allow_parent2 = false;
+ for (size_t i = 0; i < 2; i++) {
+ const struct path *const parent_path = i ? new_dir :
+ &old_parent_path;
+ struct layer_access_masks *const layer_masks =
+ i ? &layer_masks_parent2 : &layer_masks_parent1;
+ bool *const allow_parent = i ? &allow_parent2 : &allow_parent1;
+
+ if (is_nouser_or_private(parent_path->dentry) ||
+ !landlock_init_layer_masks(
+ subject->domain, LANDLOCK_MASK_ACCESS_FS,
+ layer_masks, LANDLOCK_KEY_INODE)) {
+ *allow_parent = true;
+ continue;
+ }
+ {
+ struct path walker = *parent_path;
+
+ path_get(&walker);
+ do {
+ /* Gets all layers allowing all domain accesses. */
+ if (landlock_unmask_layers(
+ find_rule(subject->domain,
+ walker.dentry),
+ layer_masks)) {
+ /*
+ * Stops when all handled accesses are
+ * allowed by at least one rule in each
+ * layer.
+ */
+ *allow_parent = true;
+ break;
+ }
+ } while (landlock_walk_path_up(&walker) ==
+ LANDLOCK_WALK_CONTINUE);
+ path_put(&walker);
+ }
+ }
if (allow_parent1 && allow_parent2)
return 0;
@@ -1233,7 +1197,7 @@ static int current_check_refer_path(struct dentry *const old_dentry,
return 0;
if (request1.access) {
- request1.audit.u.path.dentry = old_parent;
+ request1.audit.u.path.dentry = old_parent_path.dentry;
landlock_log_denial(subject, &request1);
}
if (request2.access) {
--
2.51.0
^ permalink raw reply related
* [PATCH 1/2] landlock: Add path walk helper
From: Justin Suess @ 2026-02-18 20:18 UTC (permalink / raw)
To: linux-security-module, Mickaël Salaün
Cc: Günther Noack, Tingmao Wang, Justin Suess
In-Reply-To: <20260218201857.1194667-1-utilityemal77@gmail.com>
Add a new helper function landlock_walk_path_up, which takes a pointer
to the current path in the walk, and returns an enum
landlock_walk_result corresponding to whether the current position in
the walk is a mountpoint, the real root, or neither.
Signed-off-by: Justin Suess <utilityemal77@gmail.com>
---
security/landlock/fs.c | 92 ++++++++++++++++++++++++------------------
1 file changed, 52 insertions(+), 40 deletions(-)
diff --git a/security/landlock/fs.c b/security/landlock/fs.c
index e764470f588c..c6ff686c9cde 100644
--- a/security/landlock/fs.c
+++ b/security/landlock/fs.c
@@ -317,6 +317,38 @@ static struct landlock_object *get_inode_object(struct inode *const inode)
LANDLOCK_ACCESS_FS_IOCTL_DEV)
/* clang-format on */
+/**
+ * enum landlock_walk_result - Result codes for landlock_walk_path_up()
+ * @LANDLOCK_WALK_CONTINUE: Path is now neither the real root nor an internal mount point.
+ * @LANDLOCK_WALK_STOP_REAL_ROOT: Path has reached the real VFS root.
+ * @LANDLOCK_WALK_INTERNAL: Path has reached an internal mount point.
+ */
+enum landlock_walk_result {
+ LANDLOCK_WALK_CONTINUE,
+ LANDLOCK_WALK_STOP_REAL_ROOT,
+ LANDLOCK_WALK_INTERNAL,
+};
+
+static enum landlock_walk_result landlock_walk_path_up(struct path *const path)
+{
+ struct dentry *old;
+
+ while (path->dentry == path->mnt->mnt_root) {
+ if (!follow_up(path))
+ return LANDLOCK_WALK_STOP_REAL_ROOT;
+ }
+ old = path->dentry;
+ if (unlikely(IS_ROOT(old))) {
+ if (likely(path->mnt->mnt_flags & MNT_INTERNAL))
+ return LANDLOCK_WALK_INTERNAL;
+ path->dentry = dget(path->mnt->mnt_root);
+ } else {
+ path->dentry = dget_parent(old);
+ }
+ dput(old);
+ return LANDLOCK_WALK_CONTINUE;
+}
+
/*
* @path: Should have been checked by get_path_from_fd().
*/
@@ -874,47 +906,27 @@ is_access_to_paths_allowed(const struct landlock_ruleset *const domain,
/* Stops when a rule from each layer grants access. */
if (allowed_parent1 && allowed_parent2)
break;
-
-jump_up:
- if (walker_path.dentry == walker_path.mnt->mnt_root) {
- if (follow_up(&walker_path)) {
- /* Ignores hidden mount points. */
- goto jump_up;
- } else {
- /*
- * Stops at the real root. Denies access
- * because not all layers have granted access.
- */
- break;
- }
- }
-
- if (unlikely(IS_ROOT(walker_path.dentry))) {
- if (likely(walker_path.mnt->mnt_flags & MNT_INTERNAL)) {
- /*
- * Stops and allows access when reaching disconnected root
- * directories that are part of internal filesystems (e.g. nsfs,
- * which is reachable through /proc/<pid>/ns/<namespace>).
- */
- allowed_parent1 = true;
- allowed_parent2 = true;
- break;
- }
-
- /*
- * We reached a disconnected root directory from a bind mount.
- * Let's continue the walk with the mount point we missed.
- */
- dput(walker_path.dentry);
- walker_path.dentry = walker_path.mnt->mnt_root;
- dget(walker_path.dentry);
- } else {
- struct dentry *const parent_dentry =
- dget_parent(walker_path.dentry);
-
- dput(walker_path.dentry);
- walker_path.dentry = parent_dentry;
+ /* Otherwise, keep walking up to the root. */
+ switch (landlock_walk_path_up(&walker_path)) {
+ /*
+ * Stops and allows access when reaching disconnected root
+ * directories that are part of internal filesystems (e.g. nsfs,
+ * which is reachable through /proc/<pid>/ns/<namespace>).
+ */
+ case LANDLOCK_WALK_INTERNAL:
+ allowed_parent1 = true;
+ allowed_parent2 = true;
+ break;
+ /*
+ * Stops at the real root. Denies access
+ * because not all layers have granted access
+ */
+ case LANDLOCK_WALK_STOP_REAL_ROOT:
+ break;
+ case LANDLOCK_WALK_CONTINUE:
+ continue;
}
+ break;
}
path_put(&walker_path);
--
2.51.0
^ permalink raw reply related
* [PATCH 0/2] landlock: Simplify path walk logic
From: Justin Suess @ 2026-02-18 20:18 UTC (permalink / raw)
To: linux-security-module, Mickaël Salaün
Cc: Günther Noack, Tingmao Wang, Justin Suess
Hello,
These two patches simplify the path walk logic in fs.c.
This patch was originally included in a very basic form in my
LANDLOCK_ADD_RULE_NO_INHERIT series [1], but I think that it would be better
submitted separately, as logically it doesn't have much to do with the
feature implemented in the patch.
This patch is based on the mic/next branch.
Motivation
===
Additionally, existing path walk logic is tightly bound to the
is_access_to_paths_allowed and collect_domain_accesses, and is difficult to
read and understand.
Centralizing the path logic would more easily allow other Landlock features
that may rely on path walking, such as the proposed path walk controls, or
my LANDLOCK_ADD_RULE_NO_INHERIT patch, to reuse the same logic as
currently implemented.
Background
===
The first patch in this small series introduces a helper function
landlock_walk_path_up, which takes a pointer to a struct path, and walks it
up through the VFS. The function returns an enum landlock_walk_result which
encodes whether the current path position is an internal mountpoint, the real
root, or neither.
The is_access_to_paths_allowed function is then altered to use this new helper,
cleaning up the traversal logic while retaining existing documentation comments
and improving readability.
The next patch in the series removes the collect_domain_accesses function. After
an initial re-implementation with the helper it was found that collect_domain_accesses
could be more succicently inlined into current_check_refer_path and there was little
benefit to keeping check_domain_accesses as a standalone function.
These changes overall reduce about 25 lines of code, including new documentation
for the return values of the landlock_walk_path_up function.
Results
===
These patches pass all existing selftests and kunit tests, and favorably influence
stack size.
Checkstack Results (CONFIG_AUDIT enabled)
===
Current Master Branch:
0xffffffff817d3f40 current_check_refer_path [vmlinux]: 608
0xffffffff817d2f80 is_access_to_paths_allowed [vmlinux]:352
This Patch Series:
0xffffffff817d3db0 current_check_refer_path [vmlinux]: 384
0xffffffff817d30c0 is_access_to_paths_allowed [vmlinux]:336
Thank you for your time.
Kind Regards,
Justin Suess
[1]: https://lore.kernel.org/linux-security-module/20251221194301.247484-2-utilityemal77@gmail.com/
Justin Suess (2):
landlock: Add path walk helper
landlock: Remove collect_domain_accesses
security/landlock/fs.c | 220 ++++++++++++++++++-----------------------
1 file changed, 98 insertions(+), 122 deletions(-)
--
2.51.0
^ permalink raw reply
* Re: [PATCH v5 6/9] landlock/selftests: Check that coredump sockets stay unrestricted
From: Mickaël Salaün @ 2026-02-18 20:05 UTC (permalink / raw)
To: Günther Noack
Cc: John Johansen, linux-security-module, Tingmao Wang, Justin Suess,
Samasth Norway Ananda, Matthieu Buffet, Mikhail Ivanov,
konstantin.meskhidze, Demi Marie Obenour, Alyssa Ross, Jann Horn,
Tahera Fahimi
In-Reply-To: <20260215105158.28132-7-gnoack3000@gmail.com>
On Sun, Feb 15, 2026 at 11:51:54AM +0100, Günther Noack wrote:
> Even when a process is restricted with the new
> LANDLOCK_ACCESS_FS_RESOLVE_SOCKET right, the kernel can continue
> writing its coredump to the configured coredump socket.
>
> In the test, we create a local server and rewire the system to write
> coredumps into it. We then create a child process within a Landlock
> domain where LANDLOCK_ACCESS_FS_RESOLVE_SOCKET is restricted and make
> the process crash. The test uses SO_PEERCRED to check that the
> connecting client process is the expected one.
>
> Signed-off-by: Günther Noack <gnoack3000@gmail.com>
> ---
> tools/testing/selftests/landlock/fs_test.c | 122 +++++++++++++++++++++
> 1 file changed, 122 insertions(+)
>
> diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c
> index 8fa9d7c49ac3..705d8a13d2e0 100644
> --- a/tools/testing/selftests/landlock/fs_test.c
> +++ b/tools/testing/selftests/landlock/fs_test.c
> @@ -22,6 +22,7 @@
> #include <sys/ioctl.h>
> #include <sys/mount.h>
> #include <sys/prctl.h>
> +#include <sys/resource.h>
> #include <sys/sendfile.h>
> #include <sys/socket.h>
> #include <sys/stat.h>
> @@ -4922,6 +4923,127 @@ TEST_F(scoped_domains, unix_seqpacket_connect_to_child_full)
> #undef USE_SENDTO
> #undef ENFORCE_ALL
>
> +static void read_core_pattern(struct __test_metadata *const _metadata,
> + char *buf, size_t buf_size)
> +{
> + int fd;
> + ssize_t ret;
> +
> + fd = open("/proc/sys/kernel/core_pattern", O_RDONLY | O_CLOEXEC);
> + ASSERT_LE(0, fd);
> +
> + ret = read(fd, buf, buf_size - 1);
> + ASSERT_LE(0, ret);
> + EXPECT_EQ(0, close(fd));
> +
> + buf[ret] = '\0';
> +}
> +
> +static void set_core_pattern(struct __test_metadata *const _metadata,
> + const char *pattern)
> +{
> + int fd;
> + size_t len = strlen(pattern);
> +
> + fd = open("/proc/sys/kernel/core_pattern", O_WRONLY | O_CLOEXEC);
> + ASSERT_LE(0, fd);
> +
> + ASSERT_EQ(len, write(fd, pattern, len));
> + EXPECT_EQ(0, close(fd));
> +}
I had to fix this helper to make it work with check-linux.sh:
diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c
index ae32513fb54b..64887d34079a 100644
--- a/tools/testing/selftests/landlock/fs_test.c
+++ b/tools/testing/selftests/landlock/fs_test.c
@@ -4659,11 +4659,34 @@ static void set_core_pattern(struct __test_metadata *const _metadata,
int fd;
size_t len = strlen(pattern);
+ /*
+ * Writing to /proc/sys/kernel/core_pattern requires EUID 0 because
+ * sysctl_perm() checks that, ignoring capabilities like
+ * CAP_SYS_ADMIN or CAP_DAC_OVERRIDE.
+ *
+ * Switching EUID clears the dumpable flag, which must be restored
+ * afterwards to allow coredumps.
+ */
+ set_cap(_metadata, CAP_SETUID);
+ ASSERT_EQ(0, seteuid(0));
+ clear_cap(_metadata, CAP_SETUID);
+
fd = open("/proc/sys/kernel/core_pattern", O_WRONLY | O_CLOEXEC);
- ASSERT_LE(0, fd);
+ ASSERT_LE(0, fd)
+ {
+ TH_LOG("Failed to open core_pattern for writing: %s",
+ strerror(errno));
+ }
ASSERT_EQ(len, write(fd, pattern, len));
EXPECT_EQ(0, close(fd));
+
+ set_cap(_metadata, CAP_SETUID);
+ ASSERT_EQ(0, seteuid(getuid()));
+ clear_cap(_metadata, CAP_SETUID);
+
+ /* Restore dumpable flag cleared by seteuid(). */
+ ASSERT_EQ(0, prctl(PR_SET_DUMPABLE, 1 , 0, 0, 0));
}
FIXTURE(coredump)
@@ -4680,9 +4703,7 @@ FIXTURE_SETUP(coredump)
FIXTURE_TEARDOWN_PARENT(coredump)
{
- set_cap(_metadata, CAP_SYS_ADMIN);
set_core_pattern(_metadata, self->original_core_pattern);
- clear_cap(_metadata, CAP_SYS_ADMIN);
}
/*
@@ -4705,9 +4726,7 @@ TEST_F_FORK(coredump, socket_not_restricted)
srv_fd = set_up_named_unix_server(_metadata, SOCK_STREAM, sock_path);
/* Point coredumps at our socket. */
- set_cap(_metadata, CAP_SYS_ADMIN);
set_core_pattern(_metadata, core_pattern);
- clear_cap(_metadata, CAP_SYS_ADMIN);
/* Restrict LANDLOCK_ACCESS_FS_RESOLVE_UNIX. */
enforce_fs(_metadata, LANDLOCK_ACCESS_FS_RESOLVE_UNIX, NULL);
Please run tests in this (minimal) environment.
> +
> +FIXTURE(coredump)
> +{
> + char original_core_pattern[256];
> +};
> +
> +FIXTURE_SETUP(coredump)
> +{
> + disable_caps(_metadata);
> + read_core_pattern(_metadata, self->original_core_pattern,
> + sizeof(self->original_core_pattern));
> +}
> +
> +FIXTURE_TEARDOWN_PARENT(coredump)
> +{
> + set_cap(_metadata, CAP_SYS_ADMIN);
> + set_core_pattern(_metadata, self->original_core_pattern);
> + clear_cap(_metadata, CAP_SYS_ADMIN);
> +}
> +
> +/*
> + * Test that even when a process is restricted with
> + * LANDLOCK_ACCESS_FS_RESOLVE_UNIX, the kernel can still initiate a connection
> + * to the coredump socket on the processes' behalf.
> + */
> +TEST_F_FORK(coredump, socket_not_restricted)
> +{
> + static const char core_pattern[] = "@/tmp/landlock_coredump_test.sock";
> + const char *const sock_path = core_pattern + 1;
> + int srv_fd, conn_fd, status;
> + pid_t child_pid;
> + struct ucred cred;
> + socklen_t cred_len = sizeof(cred);
> + char buf[4096];
> +
> + /* Set up the coredump server socket. */
> + unlink(sock_path);
> + srv_fd = set_up_named_unix_server(_metadata, SOCK_STREAM, sock_path);
> +
> + /* Point coredumps at our socket. */
> + set_cap(_metadata, CAP_SYS_ADMIN);
> + set_core_pattern(_metadata, core_pattern);
> + clear_cap(_metadata, CAP_SYS_ADMIN);
> +
> + /* Restrict LANDLOCK_ACCESS_FS_RESOLVE_UNIX. */
> + drop_access_rights(_metadata, &(struct landlock_ruleset_attr){
> + .handled_access_fs = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> + });
> +
> + /* Fork a child that crashes. */
> + child_pid = fork();
> + ASSERT_LE(0, child_pid);
> + if (child_pid == 0) {
> + struct rlimit rl = {
> + .rlim_cur = RLIM_INFINITY,
> + .rlim_max = RLIM_INFINITY,
> + };
> +
> + ASSERT_EQ(0, setrlimit(RLIMIT_CORE, &rl));
> +
> + /* Crash on purpose. */
> + kill(getpid(), SIGSEGV);
> + _exit(1);
> + }
> +
> + /*
> + * Accept the coredump connection. If Landlock incorrectly denies the
> + * kernel's coredump connect, accept() will block forever, so the test
> + * would time out.
> + */
> + conn_fd = accept(srv_fd, NULL, NULL);
> + ASSERT_LE(0, conn_fd);
> +
> + /* Check that the connection came from the crashing child. */
> + ASSERT_EQ(0, getsockopt(conn_fd, SOL_SOCKET, SO_PEERCRED, &cred,
> + &cred_len));
> + EXPECT_EQ(child_pid, cred.pid);
> +
> + /* Drain the coredump data so the kernel can finish. */
> + while (read(conn_fd, buf, sizeof(buf)) > 0)
> + ;
> +
> + EXPECT_EQ(0, close(conn_fd));
> +
> + /* Wait for the child and verify it coredumped. */
> + ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0));
> + ASSERT_TRUE(WIFSIGNALED(status));
> + ASSERT_TRUE(WCOREDUMP(status));
> +
> + EXPECT_EQ(0, close(srv_fd));
> + EXPECT_EQ(0, unlink(sock_path));
> +}
> +
> /* clang-format off */
> FIXTURE(layout1_bind) {};
> /* clang-format on */
> --
> 2.52.0
>
>
^ permalink raw reply related
* Re: [PATCH v5 4/9] landlock/selftests: Test LANDLOCK_ACCESS_FS_RESOLVE_UNIX
From: Mickaël Salaün @ 2026-02-18 19:11 UTC (permalink / raw)
To: Günther Noack
Cc: John Johansen, Justin Suess, Tingmao Wang, linux-security-module,
Samasth Norway Ananda, Matthieu Buffet, Mikhail Ivanov,
konstantin.meskhidze, Demi Marie Obenour, Alyssa Ross, Jann Horn,
Tahera Fahimi
In-Reply-To: <20260215105158.28132-5-gnoack3000@gmail.com>
On Sun, Feb 15, 2026 at 11:51:52AM +0100, Günther Noack wrote:
> * Extract common helpers from an existing IOCTL test that
> also uses pathname unix(7) sockets.
> * These tests use the common scoped domains fixture which is also used
> in other Landlock scoping tests and which was used in Tingmao Wang's
> earlier patch set in [1].
>
> These tests exercise the cross product of the following scenarios:
>
> * Stream connect(), Datagram connect(), Datagram sendmsg() and
> Seqpacket connect().
> * Child-to-parent and parent-to-child communication
> * The Landlock policy configuration as listed in the scoped_domains
> fixture.
> * In the default variant, Landlock domains are only placed where
> prescribed in the fixture.
> * In the "ALL_DOMAINS" variant, Landlock domains are also placed in
> the places where the fixture says to omit them, but with a
> LANDLOCK_RULE_PATH_BENEATH that allows connection.
>
> Cc: Justin Suess <utilityemal77@gmail.com>
> Cc: Tingmao Wang <m@maowtm.org>
> Cc: Mickaël Salaün <mic@digikod.net>
> Link[1]: https://lore.kernel.org/all/53b9883648225d5a08e82d2636ab0b4fda003bc9.1767115163.git.m@maowtm.org/
> Signed-off-by: Günther Noack <gnoack3000@gmail.com>
> ---
> tools/testing/selftests/landlock/fs_test.c | 384 ++++++++++++++++++++-
> 1 file changed, 368 insertions(+), 16 deletions(-)
>
> diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c
> index b318627e7561..bdeff2e0e029 100644
> --- a/tools/testing/selftests/landlock/fs_test.c
> +++ b/tools/testing/selftests/landlock/fs_test.c
> @@ -4358,30 +4358,61 @@ TEST_F_FORK(layout1, named_pipe_ioctl)
> ASSERT_EQ(child_pid, waitpid(child_pid, NULL, 0));
> }
>
> +/*
> + * set_up_named_unix_server - Create a pathname unix socket
> + *
> + * If the socket type is not SOCK_DGRAM, also invoke listen(2).
> + *
> + * Return: The listening FD - it is the caller responsibility to close it.
> + */
> +static int set_up_named_unix_server(struct __test_metadata *const _metadata,
> + int type, const char *const path)
> +{
> + int fd;
> + struct sockaddr_un addr = {
> + .sun_family = AF_UNIX,
> + };
> +
> + fd = socket(AF_UNIX, type, 0);
> + ASSERT_LE(0, fd);
> +
> + strncpy(addr.sun_path, path, sizeof(addr.sun_path));
fs_test.c: In function ‘set_up_named_unix_server’:
fs_test.c:4125:9: error: ‘strncpy’ specified bound 108 equals destination size [-Werror=stringop-truncation]
4125 | strncpy(addr.sun_path, path, sizeof(addr.sun_path));
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
We should also ASSERT the result to make sure path's length is not too big.
> + ASSERT_EQ(0, bind(fd, (struct sockaddr *)&addr, sizeof(addr)));
> +
> + if (type != SOCK_DGRAM)
> + ASSERT_EQ(0, listen(fd, 10 /* qlen */));
> + return fd;
> +}
^ permalink raw reply
* Re: [PATCH 0/2] fanotify: avid some premature LSM checks
From: Ondrej Mosnacek @ 2026-02-18 12:36 UTC (permalink / raw)
To: Jan Kara
Cc: Amir Goldstein, Matthew Bobrowski, linux-fsdevel,
linux-security-module, selinux, linux-kernel
In-Reply-To: <yk2qcux2ee7afr24xw6p7wp4t3islu64ttfsrheac2zwr6odnw@kmagnqbldb3f>
On Tue, Feb 17, 2026 at 12:09 PM Jan Kara <jack@suse.cz> wrote:
>
> On Mon 16-02-26 16:06:23, Ondrej Mosnacek wrote:
> > Restructure some of the validity and security checks in
> > fs/notify/fanotify/fanotify_user.c to avoid generating LSM access
> > denials in the audit log where hey shouldn't be.
> >
> > Ondrej Mosnacek (2):
> > fanotify: avoid/silence premature LSM capability checks
> > fanotify: call fanotify_events_supported() before path_permission()
> > and security_path_notify()
> >
> > fs/notify/fanotify/fanotify_user.c | 50 ++++++++++++++----------------
> > 1 file changed, 23 insertions(+), 27 deletions(-)
>
> The series looks good to me as well. Thanks! I'll commit the series to my
> tree once the merge window closes and fixup the comment formatting on
> commit. No need to resend.
Great, thanks!
--
Ondrej Mosnacek
Senior Software Engineer, Linux Security - SELinux kernel
Red Hat, Inc.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox