Linux Security Modules development
 help / color / mirror / Atom feed
* Re: [PATCH v3] security: Expand task_setscheduler LSM hook to include CPU affinity mask
From: Aaron Tomlin @ 2026-06-15 15:22 UTC (permalink / raw)
  To: paul
  Cc: tsbogend, paul, jmorris, serge, mingo, juri.lelli,
	vincent.guittot, stephen.smalley.work, casey, longman, tj, hannes,
	mkoutny, chenridong, dietmar.eggemann, rostedt, bsegall, mgorman,
	vschneid, kprateek.nayak, omosnace, kees, neelx, sean, chjohnst,
	steve, mproche, nick.lange, cgroups, linux-mips, linux-fsdevel,
	linux-security-module, selinux, linux-kernel
In-Reply-To: <6hqq5oxvlcpmjvyns42dy2vtfvvixy7q4xyyjrrn46jrvsx5ar@gkmjsteqlpzd>

On Wed, May 27, 2026 at 09:19:11PM -0400, Aaron Tomlin wrote:
> On Wed, May 27, 2026 at 09:58:58PM +0200, Peter Zijlstra wrote:
> > On Wed, May 27, 2026 at 01:41:52PM -0400, Aaron Tomlin wrote:
> > 
> > > > > The actual use case here is multi-tenant workload isolation and visibility.
> > > > > Passing the evaluated cpumask to the BPF LSM allows operators to write a
> > > > > simple eBPF program to detect spatial boundary overlaps (e.g., logging an
> > > > > event if a requested mask intersects with platform-reserved cores).
> > 
> > Why isn't cgroups good enough to enforce this? If you create a cgroup
> > hierarchy per tenant, and constrain them using the cpuset controller,
> > they should not be able to escape, rendering this event impossible.
> 
> Hi Peter,
> 
> You raise a very fair point. The cpuset cgroup controller is indeed the
> kernel's primary vehicle for spatial enforcement, and under normal
> circumstances, it successfully prevents a tenant from escaping their
> designated cores.
> 
> The cpuset controller does govern resource limits, but does not audit
> intent. When __sched_setaffinity() is invoked, the kernel compares the
> requested in_mask against the task's allowed cpuset. If there is only a
> partial intersection, the kernel silently truncates the requested mask to
> fit the cpuset, without raising any alarm.
> 
> The BPF LSM hook, conversely, receives the raw, untruncated in_mask,
> affording operators the visibility to detect, audit, and even reject these
> violations of intent before the kernel silently sanitises the input.
> 
> This patch does not seek to replace the cpuset controller, but rather to
> complement it by providing auditing capabilities.
> 
> > > We are not creating a bespoke BPF hook here; rather, we are rectifying a
> > > historical blind spot within the API. The existing LSM hook is invoked
> > > during sched_setaffinity(), yet it presently receives only the task_struct
> > > pointer. Consequently, the security module is essentially asked, "Should
> > > Process A be permitted to alter Process B's affinity?" without being
> > > informed of the proposed affinity itself. Providing in_mask simply
> > > furnishes the existing hook with the requisite payload to make an informed
> > > decision.
> > 
> > It occurs to me that this same argument would require to also pass in
> > the new sched_attr, no? That way the LSM can inspect the new policy
> > before it becomes effective.
> 
> I agree, the underlying logic does indeed extend perfectly to sched_attr.
> 
> Presently, the LSM is equally oblivious as to whether a process is
> requesting a benign transition to SCHED_BATCH, or attempting to escalate
> its privileges by requesting a real-time policy such as SCHED_FIFO with
> maximum priority. Just as with the CPU mask, providing the sched_attr
> payload would rectify this parallel blind spot, allowing BPF policies to
> inspect and mediate scheduling attributes before they become effective.
> 
> If you are amenable, I should be more than happy to expand the scope of the
> forthcoming patch to include this. Alternatively, we could address the
> sched_attr expansion in a separate, subsequent patch. Personally, I would
> favour the latter approach, but please do let me know your preference.
> 
> I very much look forward to hearing Paul's thoughts on whether this aligns
> with the broader LSM vision.

Hi Paul,

I am writing to politely follow up on the discussion above regarding the
proposed enhancement to the sched_setaffinity LSM hook.

As you will see from the thread, Peter Zijlstra and I have discussed the
architectural justification for this change. While the cpuset cgroup
controller effectively handles spatial enforcement, it silently truncates
requested affinity masks. Passing the raw in_mask to the LSM hook enables
security modules (such as the BPF LSM) to audit and mediate the actual
intent of the request before the kernel sanitises the input, a capability
that cgroups inherently lack.

Furthermore, Peter rightly observed that this reasoning extends naturally
to sched_attr. Presently, the LSM cannot inspect whether a process is
requesting a benign scheduling policy or attempting to escalate to a
real-time priority. I am entirely amenable to addressing this parallel
blind spot, preferably in a subsequent patch.

Before I proceed any further, I would be most grateful for your perspective
as the Security sub-system maintainer. Do you feel this expansion is
acceptable?

As a brief administrative aside, please note that Thomas Bogendoerfer has
already queued the MIPS-specific changes related to this work into the
mips-next tree [1][2].

I look forward to hearing your thoughts.

[1]: https://lore.kernel.org/lkml/psb6pxogv2dlknps4p3sh6rt2h7xuuxkoif6ock5vxfz2jimec@txa6iy65crtb/
[2]: https://git.kernel.org/pub/scm/linux/kernel/git/mips/linux.git/commit/?id=98e37db4a34d3af3fb2f4648295c25b5e40b20e3


Kind regards,
-- 
Aaron Tomlin

^ permalink raw reply

* Re: [PATCH 2/2] keys: keyctl_pkey: replace BUG with return -EOPNOTSUPP
From: Jarkko Sakkinen @ 2026-06-15 12:06 UTC (permalink / raw)
  To: Mohammed EL Kadiri
  Cc: dhowells, paul, jmorris, serge, kees, keyrings,
	linux-security-module, linux-kernel, linux-hardening
In-Reply-To: <20260613130408.13709-3-med08elkadiri@gmail.com>

On Sat, Jun 13, 2026 at 02:04:08PM +0100, Mohammed EL Kadiri wrote:
> Replace two BUG() calls in keyctl_pkey_params_get_2() and
> keyctl_pkey_e_d_s() default cases with -EOPNOTSUPP, matching
> the error style already used in these functions.
> 
> Signed-off-by: Mohammed EL Kadiri <med08elkadiri@gmail.com>
> ---
>  security/keys/keyctl_pkey.c | 5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)
> 
> diff --git a/security/keys/keyctl_pkey.c b/security/keys/keyctl_pkey.c
> index 97bc27bbf079..6b2821ffeb6c 100644
> --- a/security/keys/keyctl_pkey.c
> +++ b/security/keys/keyctl_pkey.c
> @@ -155,7 +155,7 @@ static int keyctl_pkey_params_get_2(const struct keyctl_pkey_params __user *_par
>  			return -EINVAL;
>  		break;
>  	default:
> -		BUG();
> +		return -EOPNOTSUPP;
>  	}
>  
>  	params->in_len  = uparams.in_len;
> @@ -238,7 +238,8 @@ long keyctl_pkey_e_d_s(int op,
>  		params.op = kernel_pkey_sign;
>  		break;
>  	default:
> -		BUG();
> +		ret = -EOPNOTSUPP;
> +		goto error_params;
>  	}
>  
>  	in = memdup_user(_in, params.in_len);
> -- 
> 2.43.0
> 

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

Thank you.

BR, Jarkko


^ permalink raw reply

* Re: [PATCH 1/2] keys: request_key: replace BUG with return -EINVAL
From: Jarkko Sakkinen @ 2026-06-15 12:06 UTC (permalink / raw)
  To: Mohammed EL Kadiri
  Cc: dhowells, paul, jmorris, serge, kees, keyrings,
	linux-security-module, linux-kernel, linux-hardening
In-Reply-To: <20260613130408.13709-2-med08elkadiri@gmail.com>

On Sat, Jun 13, 2026 at 02:04:07PM +0100, Mohammed EL Kadiri wrote:
> Replace BUG() in construct_get_dest_keyring() default case
> with return -EINVAL to handle the unimplemented group keyring
> destination gracefully.
> 
> Signed-off-by: Mohammed EL Kadiri <med08elkadiri@gmail.com>
> ---
>  security/keys/request_key.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/security/keys/request_key.c b/security/keys/request_key.c
> index a7673ad86d18..fa2bb9f2f538 100644
> --- a/security/keys/request_key.c
> +++ b/security/keys/request_key.c
> @@ -332,7 +332,7 @@ static int construct_get_dest_keyring(struct key **_dest_keyring)
>  
>  		case KEY_REQKEY_DEFL_GROUP_KEYRING:
>  		default:
> -			BUG();
> +			return -EINVAL;
>  		}
>  
>  		/*
> -- 
> 2.43.0
> 

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

BR, Jarkko

^ permalink raw reply

* Re: [PATCH] keys: Pin request_key_auth payload in instantiate paths
From: Jarkko Sakkinen @ 2026-06-15 11:53 UTC (permalink / raw)
  To: eee sss
  Cc: keyrings, linux-security-module, linux-kernel, David Howells,
	Paul Moore, James Morris, Serge E. Hallyn
In-Reply-To: <CA+TOyfjifw5yiZwUmd3y7t227cTMpXxT_JNe0FSO-NYzhqE75Q@mail.gmail.com>

Awesome, no worries, great to hear, and thank you for responding.

And great collaboration :-)

BR, Jarkko

On Wed, Jun 10, 2026 at 10:21:13AM -0500, eee sss wrote:
> Thanks, Jarkko. Sorry for the delayed response.
> 
> I checked the commit in for-next-keys. The updated commit message and the
> cleanup look good to me.
> 
> Best,
> Shaomin
> 
> On Wed, 10 Jun 2026 13:16:01 +0300, Jarkko Sakkinen <jarkko@kernel.org> wrote:
> > On Mon, Jun 08, 2026 at 08:42:21AM +0300, Jarkko Sakkinen wrote:
> > > On Mon, Jun 08, 2026 at 08:29:11AM +0300, Jarkko Sakkinen wrote:
> > > > On Mon, Jun 08, 2026 at 06:10:23AM +0300, Jarkko Sakkinen wrote:
> > > > > On Mon, Jun 08, 2026 at 06:06:21AM +0300, Jarkko Sakkinen wrote:
> > > > > > On Tue, May 26, 2026 at 10:48:38AM +0800, Shaomin Chen wrote:
> > > > > > > keyctl_instantiate_key_common() reads request_key_auth from the assumed
> > > > > > > auth key before copying an instantiation payload from userspace. The copy
> > > > > > > can fault and sleep. If the request completes and revokes the auth key in
> > > > > > > that window, the auth payload can be detached and freed before the
> > > > > > > instantiate path uses it again.
> > > > > > >
> > > > > > > A request-key helper reproducer can trigger this race. One helper child
> > > > > > > blocks in KEYCTL_INSTANTIATE_IOV while the original helper instantiates the
> > > > > > > requested key and returns. KASAN then reports a use-after-free from the
> > > > > > > stale request_key_auth payload in keyctl_instantiate_key_common().
> > > > > > >
> > > > > > > Give request_key_auth payloads a refcount. Take a payload reference while
> > > > > >
> > > > > > Please, name concrete things accurately. I.e. 'usage' in this case. If
> > > > > > you have a name, use it instead of obfuscating generalizations.
> > > > > >
> > > > > > > authkey->sem stabilizes the payload and revocation state. Hold that
> > > > > > > reference across the instantiate and reject paths. Drop the auth key
> > > > > > > owning reference from revoke and destroy.
> > > > > > >
> > > > > > > Reported-by: Shaomin Chen <eeesssooo020@gmail.com>
> > > > > > > Closes: https://lore.kernel.org/r/20260519144403.436694-1-eeesssooo020@gmail.com
> > > > > > > Signed-off-by: Shaomin Chen <eeesssooo020@gmail.com>
> > > > > > > ---
> > > > > > > include/keys/request_key_auth-type.h | 2 ++
> > > > > > > security/keys/internal.h | 2 ++
> > > > > > > security/keys/keyctl.c | 24 +++++++++++++++-----
> > > > > > > security/keys/request_key_auth.c | 33 ++++++++++++++++++++++++++--
> > > > > > > 4 files changed, 53 insertions(+), 8 deletions(-)
> > > > > >
> > > > > > So first, couple of things.
> > > > > >
> > > > > > I'm not going to test not that well documented involving OOT driver.
> > > > >
> > > > > Oops, sorry typo. "not that well documented reproducer" :-)
> > > > >
> > > > > But it is cool we just then need to draw the picture.
> > > >
> > > > I think I got this:
> > > >
> > > > A: request_key() B: KEYCTL_INSTANTIATE_IOV
> > > > ---------------- -------------------------
> > > > create auth key
> > > > store rka in auth key
> > > > wait for helper
> > > > get auth key
> > > > load rka from auth key
> > > > copy user payload
> > > > sleep on #PF
> > > > helper completed
> > > > detach and free rka
> > > > destroy auth key
> > > > wake up
> > > > use rka->target_key
> > > > **USE-AFTER-FREE**
> > > >
> > > > So nothing really complicated here, is there?
> > >
> > > Send v2 with the code changes that I proposed as we want to the change
> > > as ergonomic as possible.
> > >
> > > Use this as the commit message:
> > >
> > > keys: Pin request_key_auth payload in instantiate paths
> > >
> > > A: request_key() B: KEYCTL_INSTANTIATE_IOV
> > > ---------------- -------------------------
> > > create auth key
> > > store rka in auth key
> > > wait for helper
> > > get auth key
> > > load rka from auth key
> > > copy user payload
> > > sleep on #PF
> > >
> > > helper completed
> > > detach and free rka
> > > destroy auth key
> > > wake up
> > > use rka->target_key
> > > **USE-AFTER-FREE**
> > >
> > > Give request_key_auth payloads a refcount. Take a payload reference while
> > > authkey->sem stabilizes the payload and revocation state. Hold that
> > > reference across the instantiate and reject paths. Drop the auth key
> > > owning reference from revoke and destroy.
> > >
> > > [jarkko: Replaced the first two paragraphs of text with a concurrency scenario.]
> > >
> > > And it includes also the remark at the end.
> > >
> > > BR, Jarkko
> >
> > Nothing heard so I pushed:
> >
> > https://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd.git/commit/?h=for-next-keys&id=9feb0bb3468e863b2b82a2eabfaeec4c7c44b90c
> >
> > It has the commit message change.
> >
> > BR, Jarkko

^ permalink raw reply

* Re: [PATCH] keys: allow request-key path to be configured via Kconfig
From: Jarkko Sakkinen @ 2026-06-15 11:49 UTC (permalink / raw)
  To: Gary Guo
  Cc: David Howells, Paul Moore, James Morris, Serge E. Hallyn,
	keyrings, linux-security-module, linux-kernel
In-Reply-To: <DJ5ES5DZ15W8.2KLL7VS1JMQOE@garyguo.net>

On Wed, Jun 10, 2026 at 02:37:41PM +0100, Gary Guo wrote:
> On Wed Jun 10, 2026 at 1:57 PM BST, Jarkko Sakkinen wrote:
> > On Mon, Jun 08, 2026 at 11:30:06AM +0100, Gary Guo wrote:
> >> 
> >> This is really just for distros to be able to configure where /sbin is located.
> >> Given usr merge and (some distros) bin/sbin merge, the canonical path of
> >> request-key binary is very likely not /sbin/request-key anymore, so it seems to
> >> make sense to me to allow this to be changed rather than always go through
> >> compatibility symlinks.
> >
> > I doubt there's a huge demand other than NixOS. Just basing this on that
> > no other noise have been made so far.
> 
> Just to add on this, both Fedora and openSUSE for example changes their
> CONFIG_MODPROBE_PATH to be /usr/sbin/modprobe after /usr merge. They still have
> the /sbin -> /usr/sbin symlink available, so it's not like they cannot work with
> /sbin/request-key, but I would think that if the option is available then they
> might switch to use /usr/sbin/request-key, too.
> 
> After all, why would one perform a symlink walk for no reason?
> 
> Best,
> Gary

It's not who is right or who is wrong. "The representation
of the argument" is not working here.

Back to the drawing board...

BR, Jarkko

^ permalink raw reply

* Re: [PATCH v2 v2] evm: check return values of crypto_shash functions
From: Roberto Sassu @ 2026-06-15  7:25 UTC (permalink / raw)
  To: Mimi Zohar, Daniel Hodges
  Cc: roberto.sassu, dmitry.kasatkin, eric.snowberg, paul, jmorris,
	serge, linux-integrity, linux-security-module, linux-kernel
In-Reply-To: <c1d570271884159e6c14617fa7dcd39bc2103e45.camel@linux.ibm.com>

On 3/9/2026 4:03 PM, Mimi Zohar 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:
>>
>> Reviewed-by: Roberto Sassu <roberto.sassu@huawei.com>
> 
> Thanks Daniel, Roberto.  Daniel there are a couple of places where the line
> length is greater than 80.  To see them, add "--max-line-length=80" to
> scripts/checkpatch.pl.  I'd appreciate your fixing them.  Otherwise, the patch
> looks good.

Daniel, do you have time to fix the style issues, so that we upstream 
your patch?

Thanks

Roberto


^ permalink raw reply

* Re: [PATCH] lsm: hold cred_guard_mutex for lsm_set_self_attr()
From: Paul Moore @ 2026-06-14 20:25 UTC (permalink / raw)
  To: John Johansen
  Cc: Stephen Smalley, selinux, omosnace, casey, serge,
	linux-security-module
In-Reply-To: <1c87912e-7d7c-49a9-b964-3568e63e74a0@canonical.com>

On Sat, Jun 13, 2026 at 7:29 PM John Johansen
<john.johansen@canonical.com> wrote:
> On 5/14/26 13:47, Paul Moore wrote:
> > On May 13, 2026 Stephen Smalley <stephen.smalley.work@gmail.com> wrote:
> >>
> >> Just as proc_pid_attr_write() already does before calling the LSM
> >> hook. This only matters for SELinux and AppArmor which check
> >> whether the process is being ptraced and if so, whether to
> >> allow the transition.
> >>
> >> Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
> >> Acked-by: Casey Schaufler <casey@schaufler-ca.com>
> >> ---
> >>   security/lsm_syscalls.c | 9 ++++++++-
> >>   1 file changed, 8 insertions(+), 1 deletion(-)
> >
> > Thanks Stephen.  I'm going to merge this into lsm/stable-7.1 now, but
> > hold on to it until next week before sending it to Linus.  While I
> > can't see why John would have any objections to this, the extra time
> > should give him a chance to respond.
> >
> you would think?
> well finally getting this far back the backlog (sorry)
>
> no objections

A review is almost always better late than never ;)  Thanks for taking a look.

-- 
paul-moore.com

^ permalink raw reply

* [PATCH] KEYS: avoid filesystem reclaim while holding keyring->sem
From: Mohammed EL Kadiri @ 2026-06-14 15:00 UTC (permalink / raw)
  To: dhowells, jarkko, paul
  Cc: jmorris, serge, ebiggers, keyrings, linux-security-module,
	linux-kernel, stable, syzkaller-bugs, Mohammed EL Kadiri,
	syzbot+f55b043dacf43776b50c

__key_link_begin() runs with keyring->sem held and calls
assoc_array_insert(), which does GFP_KERNEL allocations.  Those
allocations may enter filesystem reclaim, evict an fscrypt-protected
inode, and reach keyring_clear() via fscrypt_put_master_key() --
taking a keyring semaphore of the same lockdep class and closing a
keyring->sem -> fs_reclaim -> keyring->sem cycle reported by syzbot.

Wrap the assoc_array_insert() call with memalloc_nofs_save() /
memalloc_nofs_restore() so reclaim cannot recurse into the keys
subsystem while keyring->sem is held.

Reported-by: syzbot+f55b043dacf43776b50c@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=f55b043dacf43776b50c
Fixes: d7e7b9af104c ("fscrypt: stop using keyrings subsystem for fscrypt_master_key")
Cc: stable@vger.kernel.org
Signed-off-by: Mohammed EL Kadiri <med08elkadiri@gmail.com>
---
 security/keys/keyring.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index 5a9887d6b7be..21bb2e7e7cca 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -12,6 +12,7 @@
 #include <linux/security.h>
 #include <linux/seq_file.h>
 #include <linux/err.h>
+#include <linux/sched/mm.h>
 #include <linux/user_namespace.h>
 #include <linux/nsproxy.h>
 #include <keys/keyring-type.h>
@@ -1298,6 +1299,7 @@ int __key_link_begin(struct key *keyring,
 		     struct assoc_array_edit **_edit)
 {
 	struct assoc_array_edit *edit;
+	unsigned int nofs_flags;
 	int ret;
 
 	kenter("%d,%s,%s,",
@@ -1315,10 +1317,12 @@ int __key_link_begin(struct key *keyring,
 	/* Create an edit script that will insert/replace the key in the
 	 * keyring tree.
 	 */
+	nofs_flags = memalloc_nofs_save();
 	edit = assoc_array_insert(&keyring->keys,
 				  &keyring_assoc_array_ops,
 				  index_key,
 				  NULL);
+	memalloc_nofs_restore(nofs_flags);
 	if (IS_ERR(edit)) {
 		ret = PTR_ERR(edit);
 		goto error;
-- 
2.43.0


^ permalink raw reply related

* Re: [PATCH] lsm: hold cred_guard_mutex for lsm_set_self_attr()
From: John Johansen @ 2026-06-13 23:29 UTC (permalink / raw)
  To: Paul Moore, Stephen Smalley, selinux
  Cc: omosnace, casey, serge, linux-security-module
In-Reply-To: <b99c011e6d988fb98ad017265115b323@paul-moore.com>

On 5/14/26 13:47, Paul Moore wrote:
> On May 13, 2026 Stephen Smalley <stephen.smalley.work@gmail.com> wrote:
>>
>> Just as proc_pid_attr_write() already does before calling the LSM
>> hook. This only matters for SELinux and AppArmor which check
>> whether the process is being ptraced and if so, whether to
>> allow the transition.
>>
>> Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
>> Acked-by: Casey Schaufler <casey@schaufler-ca.com>
>> ---
>>   security/lsm_syscalls.c | 9 ++++++++-
>>   1 file changed, 8 insertions(+), 1 deletion(-)
> 
> Thanks Stephen.  I'm going to merge this into lsm/stable-7.1 now, but
> hold on to it until next week before sending it to Linus.  While I
> can't see why John would have any objections to this, the extra time
> should give him a chance to respond.
> 
you would think?
well finally getting this far back the backlog (sorry)

no objections


^ permalink raw reply

* Re: [PATCH v5 2/6] landlock: Add UDP send+connect access control
From: Mickaël Salaün @ 2026-06-13 20:55 UTC (permalink / raw)
  To: Matthieu Buffet
  Cc: Günther Noack, linux-security-module, Mikhail Ivanov,
	konstantin.meskhidze, Tingmao Wang, netdev
In-Reply-To: <20260611162107.49278-3-matthieu@buffet.re>

A few issues were identified by Sashiko:
https://sashiko.dev/#/patchset/20260611162107.49278-1-matthieu%40buffet.re

I squashed this patch:

diff --git a/security/landlock/net.c b/security/landlock/net.c
index 9273cdbbf844..b12568666a9e 100644
--- a/security/landlock/net.c
+++ b/security/landlock/net.c
@@ -261,10 +261,17 @@ static int current_check_access_socket(struct socket *const sock,
 
 static int current_check_autobind_udp_socket(struct socket *const sock)
 {
+	const struct access_masks bind_udp = {
+		.net = LANDLOCK_ACCESS_NET_BIND_UDP,
+	};
 	struct sockaddr_storage port0 = {};
 	unsigned short num;
 	bool slow;
 
+	/* Quick return for non-Landlocked tasks. */
+	if (!landlock_get_applicable_subject(current_cred(), bind_udp, NULL))
+		return 0;
+
 	/*
 	 * On UDP sockets, if a local port has not already been bound, calling
 	 * connect() or sending a first datagram has the side effect of
@@ -287,8 +294,7 @@ static int current_check_autobind_udp_socket(struct socket *const sock)
 	port0.ss_family = READ_ONCE(sock->sk->sk_family);
 
 	return current_check_access_socket(sock, (struct sockaddr *)&port0,
-					   sizeof(port0),
-					   LANDLOCK_ACCESS_NET_BIND_UDP, false);
+					   sizeof(port0), bind_udp.net, false);
 }
 
 static int hook_socket_bind(struct socket *const sock,
@@ -328,7 +334,9 @@ static int hook_socket_connect(struct socket *const sock,
 	 * connect()ing to an AF_UNSPEC address does not trigger an autobind and
 	 * should never be restricted.
 	 */
-	if (ret == 0 && sk_is_udp(sock->sk) && address->sa_family != AF_UNSPEC)
+	if (ret == 0 && sk_is_udp(sock->sk) &&
+	    addrlen >= offsetofend(typeof(*address), sa_family) &&
+	    address->sa_family != AF_UNSPEC)
 		ret = current_check_autobind_udp_socket(sock);
 
 	return ret;


We might want to factor out some code, but that should be good for now.


On Thu, Jun 11, 2026 at 06:21:02PM +0200, Matthieu Buffet wrote:
> Add support for a second fine-grained UDP access right.
> LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP controls the ability to set the
> remote port of a socket (via connect()) and to specify an explicit
> destination when sending a datagram, to override any remote peer set on
> a UDP socket (e.g. in sendto() or sendmsg()).
> It will be useful for applications that send datagrams, and for some
> servers too (those creating per-client sockets, which want to receive
> traffic only from a specific address).
> 
> Similarly as for bind(), this access control is performed when
> configuring sockets, not in hot code paths.
> 
> Add detection of when autobind is about to be required, and deny the
> operation if the process would not be allowed to call bind(0)
> explicitly. Autobind can only be performed in udp_lib_get_port() from
> code paths already controlled by LSM hooks: when connect()ing,
> sending a first datagram, and in some splice() EOF edge case which,
> afaiu, can only happen after a remote peer has been set. This invariant
> needs to be preserved to keep bind policies actually enforced.
> 
> Signed-off-by: Matthieu Buffet <matthieu@buffet.re>
> ---
>  include/uapi/linux/landlock.h               |  23 ++++
>  security/landlock/audit.c                   |   2 +
>  security/landlock/limits.h                  |   2 +-
>  security/landlock/net.c                     | 137 +++++++++++++++++---
>  tools/testing/selftests/landlock/net_test.c |   5 +-
>  5 files changed, 151 insertions(+), 18 deletions(-)
> 
> diff --git a/include/uapi/linux/landlock.h b/include/uapi/linux/landlock.h
> index 045b251ff1b4..b147223efc97 100644
> --- a/include/uapi/linux/landlock.h
> +++ b/include/uapi/linux/landlock.h
> @@ -378,11 +378,34 @@ struct landlock_net_port_attr {
>   *
>   * - %LANDLOCK_ACCESS_NET_BIND_UDP: Bind UDP sockets to the given local
>   *   port. Support added in Landlock ABI version 10.
> + * - %LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP: Set the remote port of UDP
> + *   sockets to the given port, or send datagrams to the given remote port
> + *   ignoring any destination pre-set on a socket. Support added in
> + *   Landlock ABI version 10.
> + *
> + * .. note:: Setting a remote address or sending a first datagram
> + *   auto-binds UDP sockets to an ephemeral local source port if not
> + *   already bound. To allow this if both %LANDLOCK_ACCESS_NET_BIND_UDP
> + *   and %LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP are handled, you need to
> + *   either:
> + *
> + *   - use a socket already bound to a port before the ruleset started
> + *     being enforced;
> + *   - or grant %LANDLOCK_ACCESS_NET_BIND_UDP on port 0, meaning "any
> + *     port in the ephemeral port range";
> + *   - or grant %LANDLOCK_ACCESS_NET_BIND_UDP on a specific port, and
> + *     call :manpage:`bind(2)` on that port before trying to
> + *     :manpage:`connect(2)` or send datagrams.
> + *
> + * .. note:: Sending datagrams to an ``AF_UNSPEC`` destination address
> + *   family is not supported for IPv6 UDP sockets: you will need to use a
> + *   ``NULL`` address instead.
>   */
>  /* clang-format off */
>  #define LANDLOCK_ACCESS_NET_BIND_TCP			(1ULL << 0)
>  #define LANDLOCK_ACCESS_NET_CONNECT_TCP			(1ULL << 1)
>  #define LANDLOCK_ACCESS_NET_BIND_UDP			(1ULL << 2)
> +#define LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP		(1ULL << 3)
>  /* clang-format on */
>  
>  /**
> diff --git a/security/landlock/audit.c b/security/landlock/audit.c
> index e676ebffeebe..851647197a01 100644
> --- a/security/landlock/audit.c
> +++ b/security/landlock/audit.c
> @@ -46,6 +46,8 @@ static const char *const net_access_strings[] = {
>  	[BIT_INDEX(LANDLOCK_ACCESS_NET_BIND_TCP)] = "net.bind_tcp",
>  	[BIT_INDEX(LANDLOCK_ACCESS_NET_CONNECT_TCP)] = "net.connect_tcp",
>  	[BIT_INDEX(LANDLOCK_ACCESS_NET_BIND_UDP)] = "net.bind_udp",
> +	[BIT_INDEX(LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP)] =
> +		"net.connect_send_udp",
>  };
>  
>  static_assert(ARRAY_SIZE(net_access_strings) == LANDLOCK_NUM_ACCESS_NET);
> diff --git a/security/landlock/limits.h b/security/landlock/limits.h
> index c0f30a4591b8..a4d908b240a2 100644
> --- a/security/landlock/limits.h
> +++ b/security/landlock/limits.h
> @@ -23,7 +23,7 @@
>  #define LANDLOCK_MASK_ACCESS_FS		((LANDLOCK_LAST_ACCESS_FS << 1) - 1)
>  #define LANDLOCK_NUM_ACCESS_FS		__const_hweight64(LANDLOCK_MASK_ACCESS_FS)
>  
> -#define LANDLOCK_LAST_ACCESS_NET	LANDLOCK_ACCESS_NET_BIND_UDP
> +#define LANDLOCK_LAST_ACCESS_NET	LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP
>  #define LANDLOCK_MASK_ACCESS_NET	((LANDLOCK_LAST_ACCESS_NET << 1) - 1)
>  #define LANDLOCK_NUM_ACCESS_NET		__const_hweight64(LANDLOCK_MASK_ACCESS_NET)
>  
> diff --git a/security/landlock/net.c b/security/landlock/net.c
> index 8da40614c452..0e697403eca9 100644
> --- a/security/landlock/net.c
> +++ b/security/landlock/net.c
> @@ -44,7 +44,8 @@ int landlock_append_net_rule(struct landlock_ruleset *const ruleset,
>  static int current_check_access_socket(struct socket *const sock,
>  				       struct sockaddr *const address,
>  				       const int addrlen,
> -				       access_mask_t access_request)
> +				       access_mask_t access_request,
> +				       bool connecting)
>  {
>  	unsigned short sock_family;
>  	__be16 port;
> @@ -75,19 +76,51 @@ static int current_check_access_socket(struct socket *const sock,
>  
>  	switch (address->sa_family) {
>  	case AF_UNSPEC:
> -		if (access_request == LANDLOCK_ACCESS_NET_CONNECT_TCP) {
> +		if (access_request == LANDLOCK_ACCESS_NET_CONNECT_TCP ||
> +		    (access_request == LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP &&
> +		     connecting)) {
>  			/*
>  			 * Connecting to an address with AF_UNSPEC dissolves
> -			 * the TCP association, which have the same effect as
> -			 * closing the connection while retaining the socket
> -			 * object (i.e., the file descriptor).  As for dropping
> -			 * privileges, closing connections is always allowed.
> -			 *
> -			 * For a TCP access control system, this request is
> -			 * legitimate. Let the network stack handle potential
> +			 * the remote association while retaining the socket
> +			 * object (i.e., the file descriptor). For TCP, it has
> +			 * the same effect as closing the connection. For UDP,
> +			 * it removes any preset remote address. As for
> +			 * dropping privileges, these actions are always
> +			 * allowed.
> +			 * Let the network stack handle potential
>  			 * inconsistencies and return -EINVAL if needed.
>  			 */
>  			return 0;
> +		} else if (access_request ==
> +			   LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP) {
> +			if (sock_family == AF_INET6) {
> +				/*
> +				 * We cannot allow sending UDP datagrams to an
> +				 * explicit AF_UNSPEC address on IPv6 sockets,
> +				 * even if AF_UNSPEC is treated as "no address"
> +				 * on such sockets (so it should always be allowed).
> +				 * That's because the socket's family can change under
> +				 * our feet (if another thread calls setsockopt(IPV6_ADDRFORM))
> +				 * to IPv4, which would then treat AF_UNSPEC as
> +				 * AF_INET.
> +				 */
> +				audit_net.family = AF_UNSPEC;
> +				audit_net.sk = sock->sk;
> +				landlock_init_layer_masks(
> +					subject->domain, access_request,
> +					&layer_masks, LANDLOCK_KEY_NET_PORT);
> +				landlock_log_denial(
> +					subject,
> +					&(struct landlock_request){
> +						.type = LANDLOCK_REQUEST_NET_ACCESS,
> +						.audit.type =
> +							LSM_AUDIT_DATA_NET,
> +						.audit.u.net = &audit_net,
> +						.access = access_request,
> +						.layer_masks = &layer_masks,
> +					});
> +				return -EACCES;
> +			}
>  		} else if (access_request == LANDLOCK_ACCESS_NET_BIND_TCP ||
>  			   access_request == LANDLOCK_ACCESS_NET_BIND_UDP) {
>  			/*
> @@ -130,7 +163,11 @@ static int current_check_access_socket(struct socket *const sock,
>  		} else {
>  			WARN_ON_ONCE(1);
>  		}
> -		/* Only for bind(AF_UNSPEC+INADDR_ANY) on IPv4 socket. */
> +		/*
> +		 * AF_UNSPEC is treated as AF_INET only in
> +		 * bind(AF_UNSPEC+INADDR_ANY) on IPv4 sockets and
> +		 * when sending to AF_UNSPEC addresses on IPv4 sockets.
> +		 */
>  		fallthrough;
>  	case AF_INET: {
>  		const struct sockaddr_in *addr4;
> @@ -141,7 +178,8 @@ static int current_check_access_socket(struct socket *const sock,
>  		addr4 = (struct sockaddr_in *)address;
>  		port = addr4->sin_port;
>  
> -		if (access_request == LANDLOCK_ACCESS_NET_CONNECT_TCP) {
> +		if (access_request == LANDLOCK_ACCESS_NET_CONNECT_TCP ||
> +		    access_request == LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP) {
>  			audit_net.dport = port;
>  			audit_net.v4info.daddr = addr4->sin_addr.s_addr;
>  		} else if (access_request == LANDLOCK_ACCESS_NET_BIND_TCP ||
> @@ -164,7 +202,8 @@ static int current_check_access_socket(struct socket *const sock,
>  		addr6 = (struct sockaddr_in6 *)address;
>  		port = addr6->sin6_port;
>  
> -		if (access_request == LANDLOCK_ACCESS_NET_CONNECT_TCP) {
> +		if (access_request == LANDLOCK_ACCESS_NET_CONNECT_TCP ||
> +		    access_request == LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP) {
>  			audit_net.dport = port;
>  			audit_net.v6info.daddr = addr6->sin6_addr;
>  		} else if (access_request == LANDLOCK_ACCESS_NET_BIND_TCP ||
> @@ -221,6 +260,38 @@ static int current_check_access_socket(struct socket *const sock,
>  	return -EACCES;
>  }
>  
> +static int current_check_autobind_udp_socket(struct socket *const sock)
> +{
> +	struct sockaddr_storage port0 = {};
> +	unsigned short num;
> +	bool slow;
> +
> +	/*
> +	 * On UDP sockets, if a local port has not already been bound,
> +	 * calling connect() or sending a first datagram has the side
> +	 * effect of autobinding an ephemeral port: we also have to check
> +	 * that the process would have had the right to bind(0) explicitly.
> +	 * Hold the socket lock around the inet_num read to exclude
> +	 * udp_lib_get_port()'s transient inet_num = snum write that is
> +	 * reverted to 0 on a failing reuseport bind.
> +	 */
> +	slow = lock_sock_fast(sock->sk);
> +	num = inet_sk(sock->sk)->inet_num;
> +	unlock_sock_fast(sock->sk, slow);
> +	if (num != 0)
> +		return 0;
> +
> +	/*
> +	 * Construct a struct sockaddr* with port 0 to pretend the
> +	 * process tried to bind() on that address.
> +	 */
> +	port0.ss_family = READ_ONCE(sock->sk->sk_family);
> +
> +	return current_check_access_socket(sock, (struct sockaddr *)&port0,
> +					   sizeof(port0),
> +					   LANDLOCK_ACCESS_NET_BIND_UDP, false);
> +}
> +
>  static int hook_socket_bind(struct socket *const sock,
>  			    struct sockaddr *const address, const int addrlen)
>  {
> @@ -234,7 +305,7 @@ static int hook_socket_bind(struct socket *const sock,
>  		return 0;
>  
>  	return current_check_access_socket(sock, address, addrlen,
> -					   access_request);
> +					   access_request, false);
>  }
>  
>  static int hook_socket_connect(struct socket *const sock,
> @@ -242,19 +313,55 @@ static int hook_socket_connect(struct socket *const sock,
>  			       const int addrlen)
>  {
>  	access_mask_t access_request;
> +	int ret = 0;
>  
>  	if (sk_is_tcp(sock->sk))
>  		access_request = LANDLOCK_ACCESS_NET_CONNECT_TCP;
> +	else if (sk_is_udp(sock->sk))
> +		access_request = LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP;
>  	else
>  		return 0;
>  
> -	return current_check_access_socket(sock, address, addrlen,
> -					   access_request);
> +	ret = current_check_access_socket(sock, address, addrlen,
> +					  access_request, true);
> +
> +	/*
> +	 * connect()ing to an AF_UNSPEC address does not trigger an
> +	 * autobind and should never be restricted.
> +	 */
> +	if (ret == 0 && sk_is_udp(sock->sk) && address->sa_family != AF_UNSPEC)
> +		ret = current_check_autobind_udp_socket(sock);
> +
> +	return ret;
> +}
> +
> +static int hook_socket_sendmsg(struct socket *const sock,
> +			       struct msghdr *const msg, const int size)
> +{
> +	struct sockaddr *const address = msg->msg_name;
> +	const int addrlen = msg->msg_namelen;
> +	access_mask_t access_request;
> +	int ret = 0;
> +
> +	if (sk_is_udp(sock->sk))
> +		access_request = LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP;
> +	else
> +		return 0;
> +
> +	if (address != NULL)
> +		ret = current_check_access_socket(sock, address, addrlen,
> +						  access_request, false);
> +
> +	if (ret == 0)
> +		ret = current_check_autobind_udp_socket(sock);
> +
> +	return ret;
>  }
>  
>  static struct security_hook_list landlock_hooks[] __ro_after_init = {
>  	LSM_HOOK_INIT(socket_bind, hook_socket_bind),
>  	LSM_HOOK_INIT(socket_connect, hook_socket_connect),
> +	LSM_HOOK_INIT(socket_sendmsg, hook_socket_sendmsg),
>  };
>  
>  __init void landlock_add_net_hooks(void)
> diff --git a/tools/testing/selftests/landlock/net_test.c b/tools/testing/selftests/landlock/net_test.c
> index ec392d971ea3..016c7277e370 100644
> --- a/tools/testing/selftests/landlock/net_test.c
> +++ b/tools/testing/selftests/landlock/net_test.c
> @@ -1326,12 +1326,13 @@ FIXTURE_TEARDOWN(mini)
>  
>  /* clang-format off */
>  
> -#define ACCESS_LAST LANDLOCK_ACCESS_NET_BIND_UDP
> +#define ACCESS_LAST LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP
>  
>  #define ACCESS_ALL ( \
>  	LANDLOCK_ACCESS_NET_BIND_TCP | \
>  	LANDLOCK_ACCESS_NET_CONNECT_TCP | \
> -	LANDLOCK_ACCESS_NET_BIND_UDP)
> +	LANDLOCK_ACCESS_NET_BIND_UDP | \
> +	LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP)
>  
>  /* clang-format on */
>  
> -- 
> 2.47.3
> 
> 

^ permalink raw reply related

* Re: [PATCH] Add LoadPin support for eBPF program loading
From: Alex Roberts @ 2026-06-13 18:59 UTC (permalink / raw)
  To: Alexei Starovoitov, David Windsor
  Cc: Kees Cook, Paul Moore, James Morris, Serge E . Hallyn, LKML,
	LSM List, bpf, Alexei Starovoitov, KP Singh
In-Reply-To: <CAADnVQL9CJMY9h8haj5+99x-0GmiaHv3wDWuZ_YCYETKTznBbw@mail.gmail.com>

>This patch is pointless.
This was supposed to an RFC, but b4 complained when adding presubject "[RFC]".

Sorry about the bot build errors, tested against WSL config. Is there a standard config to build against for patches?

>- [High] The LoadPin eBPF trust mechanism can be trivially bypassed
>using standard system interpreters like the dynamic linker (`ld.so`).
>- [High] The LoadPin eBPF trust mechanism can be bypassed by a
>privileged attacker using prctl(PR_SET_MM_EXE_FILE).

As the intent was an RFC, is there any value in pursuing LoadPin for eBPF or is it so trivially bypassable its not worth it?

________________________________________
From: Alexei Starovoitov <alexei.starovoitov@gmail.com>
Sent: Friday, June 12, 2026 10:20 AM
To: David Windsor <dwindsor@gmail.com>
Cc: alex.roberts109@outlook.com <alex.roberts109@outlook.com>; Kees Cook <kees@kernel.org>; Paul Moore <paul@paul-moore.com>; James Morris <jmorris@namei.org>; Serge E . Hallyn <serge@hallyn.com>; LKML <linux-kernel@vger.kernel.org>; LSM List <linux-security-module@vger.kernel.org>; bpf <bpf@vger.kernel.org>; Alexei Starovoitov <ast@kernel.org>; KP Singh <kpsingh@kernel.org>
Subject: Re: [PATCH] Add LoadPin support for eBPF program loading
 
On Thu, Jun 11, 2026 at 5:08 PM David Windsor <dwindsor@gmail.com> wrote:
>
> On Thu, Jun 11, 2026 at 01:59:10PM -0500, Alex Roberts wrote:
> > +static int loadpin_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr,
> > +                               struct bpf_token *token, bool is_kernel)
> > +{
> > +     int res = 0;
> > +     struct file *exe_file = NULL;
> > +     struct mm_struct *mm = current->mm;
> > +
> > +     if (is_kernel || !mm)
> > +             return 0;
> > +
> > +     exe_file = get_mm_exe_file(mm);
> > +     if (!exe_file)
> > +             return 0;
> > +
> > +     res = loadpin_check(exe_file, READING_EBPF);
>
> Why are we checking current here? IIUC this will be whoever calls
> bpf(2), which would be the loader, which would then be able to load bpf
> programs from an untrusted source.
>
> In the kmod case loadpin_check() sees the .ko itself.

See sashiko comments:
- [High] The LoadPin eBPF trust mechanism can be trivially bypassed
using standard system interpreters like the dynamic linker (`ld.so`).
- [High] The LoadPin eBPF trust mechanism can be bypassed by a
privileged attacker using prctl(PR_SET_MM_EXE_FILE).

and the bot is correct.
This patch is pointless.

^ permalink raw reply

* Re: [PATCH] Add LoadPin support for eBPF program loading
From: Alex Roberts @ 2026-06-13 18:54 UTC (permalink / raw)
  To: Alexei Starovoitov, David Windsor
  Cc: Kees Cook, Paul Moore, James Morris, Serge E . Hallyn, LKML,
	LSM List, bpf, Alexei Starovoitov, KP Singh
In-Reply-To: <CAADnVQL9CJMY9h8haj5+99x-0GmiaHv3wDWuZ_YCYETKTznBbw@mail.gmail.com>

>Why are we checking current here? IIUC this will be whoever calls
bpf(2), which would be the loader, which would then be able to load bpf
programs from an untrusted source.

The loader's filesystem would be pinned. If the filesystem is trusted, e.g., dm-verity with signed root hash, the loader is implicitly trusted. Would this not be similar unsigned kmodules from a load-pinned dm-verity filesystem?

Obviously, this would have to exclude the usecase of dynamically generated BPF programs from bpftrace.

________________________________________
From: Alexei Starovoitov <alexei.starovoitov@gmail.com>
Sent: Friday, June 12, 2026 10:20 AM
To: David Windsor <dwindsor@gmail.com>
Cc: alex.roberts109@outlook.com <alex.roberts109@outlook.com>; Kees Cook <kees@kernel.org>; Paul Moore <paul@paul-moore.com>; James Morris <jmorris@namei.org>; Serge E . Hallyn <serge@hallyn.com>; LKML <linux-kernel@vger.kernel.org>; LSM List <linux-security-module@vger.kernel.org>; bpf <bpf@vger.kernel.org>; Alexei Starovoitov <ast@kernel.org>; KP Singh <kpsingh@kernel.org>
Subject: Re: [PATCH] Add LoadPin support for eBPF program loading
 
On Thu, Jun 11, 2026 at 5:08 PM David Windsor <dwindsor@gmail.com> wrote:
>
> On Thu, Jun 11, 2026 at 01:59:10PM -0500, Alex Roberts wrote:
> > +static int loadpin_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr,
> > +                               struct bpf_token *token, bool is_kernel)
> > +{
> > +     int res = 0;
> > +     struct file *exe_file = NULL;
> > +     struct mm_struct *mm = current->mm;
> > +
> > +     if (is_kernel || !mm)
> > +             return 0;
> > +
> > +     exe_file = get_mm_exe_file(mm);
> > +     if (!exe_file)
> > +             return 0;
> > +
> > +     res = loadpin_check(exe_file, READING_EBPF);
>
> Why are we checking current here? IIUC this will be whoever calls
> bpf(2), which would be the loader, which would then be able to load bpf
> programs from an untrusted source.
>
> In the kmod case loadpin_check() sees the .ko itself.

See sashiko comments:
- [High] The LoadPin eBPF trust mechanism can be trivially bypassed
using standard system interpreters like the dynamic linker (`ld.so`).
- [High] The LoadPin eBPF trust mechanism can be bypassed by a
privileged attacker using prctl(PR_SET_MM_EXE_FILE).

and the bot is correct.
This patch is pointless.

^ permalink raw reply

* Re: [PATCH 09/10] docs/zh_CN: add LSM/ipe Chinese translation
From: Yan Zhu @ 2026-06-13 15:08 UTC (permalink / raw)
  To: Fan Wu
  Cc: alexs, si.yanteng, corbet, mic, dzm91, skhan, gnoack, linux-doc,
	linux-security-module
In-Reply-To: <CAKtyLkE3unhxMsH1LpqvjHQoKVgz1tcTsZWUxNHs+R6v2amf6w@mail.gmail.com>

On 6/13/2026 10:54 AM, Fan Wu wrote:
> On Fri, Jun 12, 2026 at 8:59 AM Yan Zhu <zhuyan2015@qq.com> wrote:
>>
>> Translate Documentation/admin-guide/LSM/ipe.rst into Chinese.
>>
>> Update the translation through commit d7ba853c0e47
>> ("ipe: Update documentation for script enforcement")
>>
>> Assisted-by: Claude:deepseek-4-pro
>> Signed-off-by: Yan Zhu <zhuyan2015@qq.com>
>> ---
> 
> Have you tried to refine the AI translation? IMO some are really bad translated.

I have double-checked it several times and manually corrected the 
formatting and the accuracy of the translation.

> 
> Also how does the doc translation project work? I do notice there is
> another IPE design doc translation,
> https://docs.kernel.org/next/translations/zh_CN/security/ipe.html
> which has a wrong "original link".>
> -Fan

The documents in the "admin-guide" directory are intended for both 
administrators and users, focusing on usage; the documents in the 
"security" directory are targeted at developers, emphasizing design and 
development.

-- 
Thanks
Yan Zhu


^ permalink raw reply

* [PATCH 2/2] keys: keyctl_pkey: replace BUG with return -EOPNOTSUPP
From: Mohammed EL Kadiri @ 2026-06-13 13:04 UTC (permalink / raw)
  To: jarkko, dhowells
  Cc: paul, jmorris, serge, kees, keyrings, linux-security-module,
	linux-kernel, linux-hardening, Mohammed EL Kadiri
In-Reply-To: <20260613130408.13709-1-med08elkadiri@gmail.com>

Replace two BUG() calls in keyctl_pkey_params_get_2() and
keyctl_pkey_e_d_s() default cases with -EOPNOTSUPP, matching
the error style already used in these functions.

Signed-off-by: Mohammed EL Kadiri <med08elkadiri@gmail.com>
---
 security/keys/keyctl_pkey.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/security/keys/keyctl_pkey.c b/security/keys/keyctl_pkey.c
index 97bc27bbf079..6b2821ffeb6c 100644
--- a/security/keys/keyctl_pkey.c
+++ b/security/keys/keyctl_pkey.c
@@ -155,7 +155,7 @@ static int keyctl_pkey_params_get_2(const struct keyctl_pkey_params __user *_par
 			return -EINVAL;
 		break;
 	default:
-		BUG();
+		return -EOPNOTSUPP;
 	}
 
 	params->in_len  = uparams.in_len;
@@ -238,7 +238,8 @@ long keyctl_pkey_e_d_s(int op,
 		params.op = kernel_pkey_sign;
 		break;
 	default:
-		BUG();
+		ret = -EOPNOTSUPP;
+		goto error_params;
 	}
 
 	in = memdup_user(_in, params.in_len);
-- 
2.43.0


^ permalink raw reply related

* [PATCH 1/2] keys: request_key: replace BUG with return -EINVAL
From: Mohammed EL Kadiri @ 2026-06-13 13:04 UTC (permalink / raw)
  To: jarkko, dhowells
  Cc: paul, jmorris, serge, kees, keyrings, linux-security-module,
	linux-kernel, linux-hardening, Mohammed EL Kadiri
In-Reply-To: <20260613130408.13709-1-med08elkadiri@gmail.com>

Replace BUG() in construct_get_dest_keyring() default case
with return -EINVAL to handle the unimplemented group keyring
destination gracefully.

Signed-off-by: Mohammed EL Kadiri <med08elkadiri@gmail.com>
---
 security/keys/request_key.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index a7673ad86d18..fa2bb9f2f538 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -332,7 +332,7 @@ static int construct_get_dest_keyring(struct key **_dest_keyring)
 
 		case KEY_REQKEY_DEFL_GROUP_KEYRING:
 		default:
-			BUG();
+			return -EINVAL;
 		}
 
 		/*
-- 
2.43.0


^ permalink raw reply related

* [PATCH 0/2] security/keys: replace BUG() in unreachable default cases
From: Mohammed EL Kadiri @ 2026-06-13 13:04 UTC (permalink / raw)
  To: jarkko, dhowells
  Cc: paul, jmorris, serge, kees, keyrings, linux-security-module,
	linux-kernel, linux-hardening, Mohammed EL Kadiri

Replace BUG() in two switch default cases with proper error
returns.

Mohammed EL Kadiri (2):
  keys: request_key: replace BUG with return -EINVAL
  keys: keyctl_pkey: replace BUG with return -EOPNOTSUPP

 security/keys/keyctl_pkey.c | 5 +++--
 security/keys/request_key.c | 2 +-
 2 files changed, 4 insertions(+), 3 deletions(-)

-- 
2.43.0


^ permalink raw reply

* Re: [PATCH] apparmor: fix use-after-free in policy replacement path
From: John Johansen @ 2026-06-13  9:42 UTC (permalink / raw)
  To: Junxiao Chang, paul, jmorris, serge, apparmor,
	linux-security-module, linux-kernel
In-Reply-To: <20260613060424.2213712-1-junxiao.chang@intel.com>

On 6/12/26 23:04, Junxiao Chang wrote:
> A use-after-free issue can be triggered when running the
> following stress-ng workload:
> 
> ```
> sudo stress-ng --apparmor 0 --timeout 30 \
>      --oom-avoid-bytes 10% --skip-silent --verbose
> ```
> 
> The warning looks like:
> 
> ```
> refcount_t: addition on 0; use-after-free
> aa_replace_profiles+0xbe5/0x12a0
> policy_update+0xdb/0x170
> profile_replace+0x4b/0xb0
> ```
> 
> The issue can be reproduced on both v7.1-rc7 and Ubuntu
> 6.17.0-35-generic kernels.
> 
> aa_get_profile_loaddata() requires the supplied loaddata object
> to hold a valid reference. However, the loaddata reference count
> may already have reached zero in the replacement loop, resulting
> in a use-after-free condition.
> 
> Avoid calling aa_get_profile_loaddata() on loaddata objects with
> a zero reference count and skip those entries instead.
> 
> Fixes: a0b7091c4de4 ("apparmor: fix race on rawdata dereference")
> Signed-off-by: Junxiao Chang <junxiao.chang@intel.com>

sorry I went with Ruslan Valiyev's earlier patch that fixes the same
issue
    apparmor: fix use-after-free in rawdata dedup loop

> ---
>   security/apparmor/policy.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
> index b6a5eb4021dbd..98f84d4552697 100644
> --- a/security/apparmor/policy.c
> +++ b/security/apparmor/policy.c
> @@ -1220,7 +1220,7 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label,
>   	/* check for duplicate rawdata blobs: space and file dedup */
>   	if (!list_empty(&ns->rawdata_list)) {
>   		list_for_each_entry(rawdata_ent, &ns->rawdata_list, list) {
> -			if (aa_rawdata_eq(rawdata_ent, udata)) {
> +			if (kref_read(&rawdata_ent->pcount) && aa_rawdata_eq(rawdata_ent, udata)) {
>   				struct aa_loaddata *tmp;
>   
>   				tmp = aa_get_profile_loaddata(rawdata_ent);


^ permalink raw reply

* Re: [PATCH 1/3] apparmor: Fix return in ns_mkdir_op
From: John Johansen @ 2026-06-13  7:13 UTC (permalink / raw)
  To: Hongling Zeng, paul, jmorris, serge, neil, brauner, jlayton, jack
  Cc: apparmor, linux-security-module, linux-kernel, zhongling0719
In-Reply-To: <20260503041243.200895-1-zenghongling@kylinos.cn>

On 5/2/26 21:12, Hongling Zeng wrote:
> Return NULL instead of passing to ERR_PTR while error is zero.
>    Fixes smatch warning:
>      - security/apparmor/apparmorfs.c:1846 ns_mkdir_op() warn:
>        passing zero to 'ERR_PTR'
> 
> Fixes: 88d5baf69082 ("Change inode_operations.mkdir to return struct dentry *")
> Signed-off-by: Hongling Zeng <zenghongling@kylinos.cn>

Acked-by: John Johansen <john.johansen@canonical.com>

this has been pulled in to my tree

> ---
>   security/apparmor/apparmorfs.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
> index ededaf46f3ca..1d7b1c70f22a 100644
> --- a/security/apparmor/apparmorfs.c
> +++ b/security/apparmor/apparmorfs.c
> @@ -1922,7 +1922,7 @@ static struct dentry *ns_mkdir_op(struct mnt_idmap *idmap, struct inode *dir,
>   	mutex_unlock(&parent->lock);
>   	aa_put_ns(parent);
>   
> -	return ERR_PTR(error);
> +	return error ? ERR_PTR(error) : NULL;
>   }
>   
>   static int ns_rmdir_op(struct inode *dir, struct dentry *dentry)


^ permalink raw reply

* Re: [PATCH] apparmor/lsm: Fix aa_dfa_unpack's error handling in aa_setup_dfa_engine
From: John Johansen @ 2026-06-13  4:42 UTC (permalink / raw)
  To: GONG Ruiqi, Paul Moore, James Morris, Serge E . Hallyn,
	Georgia Garcia
  Cc: apparmor, linux-security-module, linux-kernel, lujialin4,
	zhaoyipeng5
In-Reply-To: <20260423031056.563527-1-gongruiqi1@huawei.com>

On 4/22/26 20:10, GONG Ruiqi wrote:
> aa_dfa_unpack returns ERR_PTR not NULL when it fails, but aa_put_dfa
> only checks NULL for its input, which would cause invalid memory access
> in aa_put_dfa. Set nulldfa to NULL explicitly to fix that.
> 
> Fixes: 98b824ff8984 ("apparmor: refcount the pdb")
> Signed-off-by: GONG Ruiqi <gongruiqi1@huawei.com>

sorry for the lateness of the reply my mail wasn't working when I pulled
this in for 7.1

Acked-by: John Johansen <john.johansen@canonical.com>

> ---
>   security/apparmor/lsm.c | 1 +
>   1 file changed, 1 insertion(+)
> 
> diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
> index c1d42fc72fdb..ead2f07982b6 100644
> --- a/security/apparmor/lsm.c
> +++ b/security/apparmor/lsm.c
> @@ -2465,6 +2465,7 @@ static int __init aa_setup_dfa_engine(void)
>   			    TO_ACCEPT2_FLAG(YYTD_DATA32));
>   	if (IS_ERR(nulldfa)) {
>   		error = PTR_ERR(nulldfa);
> +		nulldfa = NULL;
>   		goto fail;
>   	}
>   	nullpdb->dfa = aa_get_dfa(nulldfa);


^ permalink raw reply

* Re: [PATCH RESEND] apparmor: Fix string overrun due to missing termination
From: John Johansen @ 2026-06-13  4:40 UTC (permalink / raw)
  To: Daniel J Blueman, Paul Moore, James Morris, Serge E. Hallyn,
	Thorsten Blum, apparmor, linux-security-module
  Cc: linux-kernel, stable
In-Reply-To: <20260327115833.7572-1-daniel@quora.org>

On 3/27/26 04:58, Daniel J Blueman wrote:
> When booting Ubuntu 26.04 with Linux 7.0-rc4 on an ARM64 Qualcomm
> Snapdragon X1 we see a string buffer overrun:
> 
> BUG: KASAN: slab-out-of-bounds in aa_dfa_match (security/apparmor/match.c:535)
> Read of size 1 at addr ffff0008901cc000 by task snap-update-ns/2120
> 
> CPU: 5 UID: 60578 PID: 2120 Comm: snap-update-ns Not tainted 7.0.0-rc4+ #22 PREEMPTLAZY
> Hardware name: LENOVO 83ED/LNVNB161216, BIOS NHCN60WW 09/11/2025
> Call trace:
> show_stack (arch/arm64/kernel/stacktrace.c:501) (C)
> dump_stack_lvl (lib/dump_stack.c:122)
> print_report (mm/kasan/report.c:379 mm/kasan/report.c:482)
> kasan_report (mm/kasan/report.c:597)
> __asan_report_load1_noabort (mm/kasan/report_generic.c:378)
> aa_dfa_match (security/apparmor/match.c:535)
> match_mnt_path_str (security/apparmor/mount.c:244 security/apparmor/mount.c:336)
> match_mnt (security/apparmor/mount.c:371)
> aa_bind_mount (security/apparmor/mount.c:447 (discriminator 4))
> apparmor_sb_mount (security/apparmor/lsm.c:719 (discriminator 1))
> security_sb_mount (security/security.c:1062 (discriminator 31))
> path_mount (fs/namespace.c:4101)
> __arm64_sys_mount (fs/namespace.c:4172 fs/namespace.c:4361 fs/namespace.c:4338 fs/namespace.c:4338)
> invoke_syscall.constprop.0 (arch/arm64/kernel/syscall.c:35 arch/arm64/kernel/syscall.c:49)
> el0_svc_common.constprop.0 (./include/linux/thread_info.h:142 (discriminator 2) arch/arm64/kernel/syscall.c:140 (discriminator 2))
> do_el0_svc (arch/arm64/kernel/syscall.c:152)
> el0_svc (arch/arm64/kernel/entry-common.c:80 arch/arm64/kernel/entry-common.c:725)
> el0t_64_sync_handler (arch/arm64/kernel/entry-common.c:744)
> el0t_64_sync (arch/arm64/kernel/entry.S:596)
> 
> Allocated by task 2120:
> kasan_save_stack (mm/kasan/common.c:58)
> kasan_save_track (./arch/arm64/include/asm/current.h:19 mm/kasan/common.c:70 mm/kasan/common.c:79)
> kasan_save_alloc_info (mm/kasan/generic.c:571)
> __kasan_kmalloc (mm/kasan/common.c:419)
> __kmalloc_noprof (./include/linux/kasan.h:263 mm/slub.c:5260 mm/slub.c:5272)
> aa_get_buffer (security/apparmor/lsm.c:2201)
> aa_bind_mount (security/apparmor/mount.c:442)
> apparmor_sb_mount (security/apparmor/lsm.c:719 (discriminator 1))
> security_sb_mount (security/security.c:1062 (discriminator 31))
> path_mount (fs/namespace.c:4101)
> __arm64_sys_mount (fs/namespace.c:4172 fs/namespace.c:4361 fs/namespace.c:4338 fs/namespace.c:4338)
> invoke_syscall.constprop.0 (arch/arm64/kernel/syscall.c:35 arch/arm64/kernel/syscall.c:49)
> el0_svc_common.constprop.0 (./include/linux/thread_info.h:142 (discriminator 2) arch/arm64/kernel/syscall.c:140 (discriminator 2))
> do_el0_svc (arch/arm64/kernel/syscall.c:152)
> el0_svc (arch/arm64/kernel/entry-common.c:80 arch/arm64/kernel/entry-common.c:725)
> el0t_64_sync_handler (arch/arm64/kernel/entry-common.c:744)
> el0t_64_sync (arch/arm64/kernel/entry.S:596)
> 
> The buggy address belongs to the object at ffff0008901ca000
> which belongs to the cache kmalloc-rnd-06-8k of size 8192
> The buggy address is located 0 bytes to the right of
> allocated 8192-byte region [ffff0008901ca000, ffff0008901cc000)
> 
> The buggy address belongs to the physical page:
> page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x9101c8
> head: order:3 mapcount:0 entire_mapcount:0 nr_pages_mapped:-1 pincount:0
> flags: 0x8000000000000040(head|zone=2)
> page_type: f5(slab)
> raw: 8000000000000040 ffff000800016c40 fffffdffe2d14e10 ffff000800015c70
> raw: 0000000000000000 0000000800010001 00000000f5000000 0000000000000000
> head: 8000000000000040 ffff000800016c40 fffffdffe2d14e10 ffff000800015c70
> head: 0000000000000000 0000000800010001 00000000f5000000 0000000000000000
> head: 8000000000000003 fffffdffe2407201 fffffdffffffffff 00000000ffffffff
> head: ffffffffffffffff 0000000000000000 00000000ffffffff 0000000000000008
> page dumped because: kasan: bad access detected
> 
> Memory state around the buggy address:
> ffff0008901cbf00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
> ffff0008901cbf80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
>> ffff0008901cc000: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
> ^
> ffff0008901cc080: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
> ffff0008901cc100: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
> 
> This was introduced by previous incorrect conversion from strcpy(). Fix it
> by adding the missing terminator.
> 
> Cc: stable@vger.kernel.org
> Signed-off-by: Daniel J Blueman <daniel@quora.org>
> Fixes: 93d4dbdc8da0 ("apparmor: Replace deprecated strcpy in d_namespace_path")

sorry for the lateness of my reply, my email wasn't working when I pulled this
in for 7.1

just for the record

Acked-by: John Johansen <john.johansen@canonical.com>

> ---
>   security/apparmor/path.c | 8 +++++---
>   1 file changed, 5 insertions(+), 3 deletions(-)
> 
> diff --git a/security/apparmor/path.c b/security/apparmor/path.c
> index 65a0ca5cc1bd..2494e8101538 100644
> --- a/security/apparmor/path.c
> +++ b/security/apparmor/path.c
> @@ -164,14 +164,16 @@ static int d_namespace_path(const struct path *path, char *buf, char **name,
>   	}
>   
>   out:
> -	/* Append "/" to directory paths, except for root "/" which
> -	 * already ends in a slash.
> +	/* Append "/" to directory paths and reterminate string, except for
> +	 * root "/" which already ends in a slash.
>   	 */
>   	if (!error && isdir) {
>   		bool is_root = (*name)[0] == '/' && (*name)[1] == '\0';
>   
> -		if (!is_root)
> +		if (!is_root) {
>   			buf[aa_g_path_max - 2] = '/';
> +			buf[aa_g_path_max - 1] = '\0';
> +		}
>   	}
>   
>   	return error;


^ permalink raw reply

* Re: [PATCH 09/10] docs/zh_CN: add LSM/ipe Chinese translation
From: Fan Wu @ 2026-06-13  2:54 UTC (permalink / raw)
  To: Yan Zhu
  Cc: alexs, si.yanteng, corbet, mic, dzm91, skhan, gnoack, linux-doc,
	linux-security-module
In-Reply-To: <tencent_DADDE291CA580302EB7BB40B83A552D6F006@qq.com>

On Fri, Jun 12, 2026 at 8:59 AM Yan Zhu <zhuyan2015@qq.com> wrote:
>
> Translate Documentation/admin-guide/LSM/ipe.rst into Chinese.
>
> Update the translation through commit d7ba853c0e47
> ("ipe: Update documentation for script enforcement")
>
> Assisted-by: Claude:deepseek-4-pro
> Signed-off-by: Yan Zhu <zhuyan2015@qq.com>
> ---

Have you tried to refine the AI translation? IMO some are really bad translated.

Also how does the doc translation project work? I do notice there is
another IPE design doc translation,
https://docs.kernel.org/next/translations/zh_CN/security/ipe.html
which has a wrong "original link".

-Fan

^ permalink raw reply

* Re: [PATCH bpf-next 0/5] Verify BPF signed loader at load time
From: Paul Moore @ 2026-06-12 20:56 UTC (permalink / raw)
  To: Daniel Borkmann
  Cc: ast, kpsingh, James.Bottomley, bboscaccy, memxor, torvalds, bpf,
	linux-security-module
In-Reply-To: <78107b57-5f4e-42b8-b780-5aebf7362de2@iogearbox.net>

On Fri, Jun 12, 2026 at 5:33 AM Daniel Borkmann <daniel@iogearbox.net> wrote:
> On 6/12/26 12:56 AM, Paul Moore wrote:
> > On Wed, Jun 10, 2026 at 7:03 PM Daniel Borkmann <daniel@iogearbox.net> wrote:
> >>
> >> The BPF signing scheme signs a light skeleton's loader program and lets
> >> the loader vouch for everything else: bpftool bakes the SHA256 of the
> >> metadata map into the loader's instructions, signs the instructions, and
> >> the loader compares the (frozen, exclusive) map against that hash from
> >> within BPF once it runs. The construction is sound as a trusted hash
> >> chain, but the kernel itself never attests the metadata, and that split
> >> has been the recurring objection from the LSM / integrity side since the
> >> scheme was proposed.
> >>
> >> This proposal closes both gaps by having the kernel verify the metadata
> >> at BPF_PROG_LOAD time, before the LSM admission hook and before the
> >> verifier, /without/ growing the UAPI. A signed loader binds its metadata
> >> map(s) through the existing fd_array/fd_array_cnt, and exclusive maps
> >> are already bound to the loader's digest via excl_prog_hash. When a
> >> signature is present, the kernel collects the exclusive maps from the
> >> fd_array and appends their frozen contents to the instructions before
> >> PKCS#7 verification, so the signature covers ...
> >>
> >>      insns || metadata_0 || metadata_1 || [...]
> >>
> >> ... in fd_array order. The in-loader hash check is dropped from the
> >> gen_loader entirely: generated loaders carry no verification logic
> >> anymore, and signing or verifying a skeleton becomes an ordinary CMS
> >> operation over bytes that sit verbatim in the skeleton, reproducible
> >> offline. A signed program is either BPF_SIG_UNSIGNED or BPF_SIG_VERIFIED
> >> with nothing in between.
> >
> > I'll be honest and say I'm a bit surprised to see this patchset,
> > especially since KP and Alexei argued so strongly against this
> > signature scheme, preferring KP's scheme where the loader verified the
> > maps.  I'd be curious to hear the reason for the change of heart if
> > you can share it.  Regardless of the motivation for this change, I
> > obviously think this is a significant improvement over KP's signature
> > scheme which shipped in Linux v6.18.
> >
> > I also think it is worth mentioning the similarities to work Blaise
> > did before the most recent Hornet version:
> >
> > https://lore.kernel.org/linux-security-module/20250929213520.1821223-1-bboscaccy@linux.microsoft.com/
> >
> > While Blaise's patchset added to the UAPI, that was done simply to
> > retain compatibility with KP's signature scheme; your patchset does
> > without any UAPI additions, but loses compatibility with existing
> > signed lskels.  Beyond that, the basic signature scheme between
> > Blaise's patchset and what you are proposing appears the same ...
> > which is a good thing as far as I'm concerned.
>
> For the rework, I've mainly been looking at KP's most recent series as
> well as some of the past discussions. Mainly trying to see if we can get
> away with a simpler model and without having to pull in BTF support for
> the signed loader just for the extra kfunc. Over the last couple of weeks,
> I've also build user space tooling on my side to experiment with some
> real world application which the signed loader would have to deal with.

Out of curiosity, have you discussed these changes with Alexei and/or
KP?  You surely know the history here, and as I mentioned above,
you're basically proposing the same signature scheme that Blaise
proposed last September and we all know how Alexei and KP reacted.  I
believe that Blaise's signature scheme, which you've adopted, is the
better option so I'm happy to see you move forward with this patchset.
However, I don't want to see you spend a lot of time on this if Alexei
and KP are going to react with the same attacks as last September.

> For sending a v2, I'll have to move this slightly deeper into verifier
> side but before the main verifier work happens in order to solve the
> exclusive map race issue, and additionally we could also utilize the
> verifier log to tell the user that the signature validation failed.
>
> I think a couple of things would still stand out imo: i) we sign over the
> raw bytes, not the derived hash anymore, so the hashing is only used in the
> context to tie the map to the loader prog, but not anymore for the signature.

The important part is that the PKCS7 signature covers both the loader
and the maps and it is verified in the native kernel code without
relying on any actions in the loader.

> ii) its one single scheme and not a parallel branch, so the main loader is
> built upon the updated signing scheme rather than having this as an option
> on the side; iow this replaces the in-loader check and there's a single PKCS#7-
> over-bytes path, not an 'if (signature_maps_size)' fork

I think if you look back at Blaise's early efforts you will see that
we've always favored a single signature scheme.  Blaise's various
patchsets only shifted to parallel/compatible mechanisms when it
became clear that Alexei had no interest in anything other than KP's
signature scheme.  We didn't want to remove KP's signature scheme
because we believed that would be a non-starter for any patchset; this
is one of the reasons why I'm so surprised to see KP's signature
scheme completely removed in your patchset.

I'm happy to see someone in BPF land come around to supporting
Blaise's signature scheme, I only wish it happened a little sooner, we
likely could have saved everyone a lot of time and stress.

> iii) given we
> expose the verification result in the BPF prog, we also don't need a new LSM
> hook and can just piggy back on the existing security_bpf_prog() which also
> has the possibility to still reject late at this point.

If you look at Blaise's patchset from last September (the one I linked
in my previous email) you will notice he didn't add any additional
hooks either.

-- 
paul-moore.com

^ permalink raw reply

* [PATCH v2] landlock: Set audit_net.sk for socket access checks
From: Mickaël Salaün @ 2026-06-12 17:27 UTC (permalink / raw)
  To: Günther Noack
  Cc: Mickaël Salaün, linux-security-module, Tingmao Wang,
	Matthieu Buffet, stable

Set audit_net.sk in current_check_access_socket() to provide the socket
object to audit_log_lsm_data().  This makes Landlock consistent with
AppArmor, which always sets .sk for socket operations, and with
SELinux's generic socket permission checks.

The socket's local and foreign address information (laddr, lport, faddr,
fport) is logged by the shared lsm_audit.c infrastructure when the
socket has bound or connected state.  Fields with zero values are
suppressed by print_ipv4_addr()/print_ipv6_addr(), so the audit output
is unchanged for the common case of bind denials on unbound sockets.
For connect denials after a prior bind, the bound local address (laddr,
lport) appears before the existing sockaddr fields (daddr, dest).

No existing fields are removed or reordered, and the new field names
(laddr, lport, faddr, fport) are standard audit fields already emitted
by other LSMs through the same lsm_audit.c code path.

Add a connect_tcp_bound audit test that binds to an allowed port and
then connects to a denied one, verifying that the denial record reports
laddr/lport from the bound socket in addition to the connect
destination.

Cc: Günther Noack <gnoack@google.com>
Cc: Tingmao Wang <m@maowtm.org>
Cc: stable@vger.kernel.org
Fixes: 9f74411a40ce ("landlock: Log TCP bind and connect denials")
Signed-off-by: Mickaël Salaün <mic@digikod.net>
---

Changes since v1:
https://lore.kernel.org/r/20260406143717.1815792-11-mic@digikod.net
- Move the new socket-audit coverage into the network test fixture,
  which sets up an isolated network namespace with a configured
  loopback interface; the previous location ran without a network
  namespace (reported by Tingmao Wang).  Cover the enriched laddr/lport
  via a connect-after-bind denial.
---
 security/landlock/net.c                     |  1 +
 tools/testing/selftests/landlock/net_test.c | 62 +++++++++++++++++++++
 2 files changed, 63 insertions(+)

diff --git a/security/landlock/net.c b/security/landlock/net.c
index c368649985c5..a38bdfcffc22 100644
--- a/security/landlock/net.c
+++ b/security/landlock/net.c
@@ -198,6 +198,7 @@ static int current_check_access_socket(struct socket *const sock,
 		return 0;
 
 	audit_net.family = address->sa_family;
+	audit_net.sk = sock->sk;
 	landlock_log_denial(subject,
 			    &(struct landlock_request){
 				    .type = LANDLOCK_REQUEST_NET_ACCESS,
diff --git a/tools/testing/selftests/landlock/net_test.c b/tools/testing/selftests/landlock/net_test.c
index 4c528154ea92..0c256e7c8675 100644
--- a/tools/testing/selftests/landlock/net_test.c
+++ b/tools/testing/selftests/landlock/net_test.c
@@ -2026,4 +2026,66 @@ TEST_F(audit, connect)
 	EXPECT_EQ(0, close(sock_fd));
 }
 
+static int matches_log_tcp_bound(int audit_fd, const char *const addr,
+				 __u16 lport, __u16 dport)
+{
+	static const char log_template[] = REGEX_LANDLOCK_PREFIX
+		" blockers=net\\.connect_tcp laddr=%s lport=%u daddr=%s dest=%u$";
+	/* Slack for two addresses and two port numbers. */
+	char log_match[sizeof(log_template) + 40];
+	int log_match_len;
+
+	log_match_len = snprintf(log_match, sizeof(log_match), log_template,
+				 addr, lport, addr, dport);
+	if (log_match_len > sizeof(log_match))
+		return -E2BIG;
+
+	return audit_match_record(audit_fd, AUDIT_LANDLOCK_ACCESS, log_match,
+				  NULL);
+}
+
+/*
+ * After a bind() to an allowed port, a denied connect must report laddr/lport
+ * from the bound socket (made available through audit_net.sk) in addition to
+ * the connect sockaddr's daddr/dest.
+ */
+TEST_F(audit, connect_tcp_bound)
+{
+	const struct landlock_ruleset_attr ruleset_attr = {
+		.handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP |
+				      LANDLOCK_ACCESS_NET_CONNECT_TCP,
+	};
+	const struct landlock_net_port_attr rule_bind = {
+		.allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP,
+		.port = self->srv0.port,
+	};
+	struct service_fixture srv_remote;
+	struct audit_records records;
+	int ruleset_fd, sock_fd;
+
+	/* Uses a second port as the denied connect target. */
+	ASSERT_EQ(0, set_service(&srv_remote, variant->prot, 1));
+
+	ruleset_fd =
+		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
+	ASSERT_LE(0, ruleset_fd);
+	ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
+				       &rule_bind, 0));
+	enforce_ruleset(_metadata, ruleset_fd);
+	EXPECT_EQ(0, close(ruleset_fd));
+
+	sock_fd = socket_variant(&self->srv0);
+	ASSERT_LE(0, sock_fd);
+	EXPECT_EQ(0, bind_variant(sock_fd, &self->srv0));
+	EXPECT_EQ(-EACCES, connect_variant(sock_fd, &srv_remote));
+	EXPECT_EQ(0, matches_log_tcp_bound(self->audit_fd, variant->addr,
+					   self->srv0.port, srv_remote.port));
+
+	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
+	EXPECT_EQ(0, records.access);
+	EXPECT_EQ(1, records.domain);
+
+	EXPECT_EQ(0, close(sock_fd));
+}
+
 TEST_HARNESS_MAIN

base-commit: d8dfb4c7faa87c3e41a8678f38f136c2c7c036fa
-- 
2.54.0


^ permalink raw reply related

* [PATCH 03/10] docs/zh_CN: add LSM/LoadPin Chinese translation
From: Yan Zhu @ 2026-06-12 16:03 UTC (permalink / raw)
  To: alexs, si.yanteng, corbet, mic
  Cc: dzm91, skhan, gnoack, zhuyan2015, linux-doc,
	linux-security-module
In-Reply-To: <cover.1781105672.git.zhuyan2015@qq.com>

Translate Documentation/admin-guide/LSM/LoadPin.rst into Chinese.

Update the translation through commit 0860b72d535f
("security/loadpin: Update the changing interface in the source code.")

Assisted-by: Claude:deepseek-4-pro
Signed-off-by: Yan Zhu <zhuyan2015@qq.com>
---
 .../zh_CN/admin-guide/LSM/LoadPin.rst         | 33 +++++++++++++++++++
 1 file changed, 33 insertions(+)
 create mode 100644 Documentation/translations/zh_CN/admin-guide/LSM/LoadPin.rst

diff --git a/Documentation/translations/zh_CN/admin-guide/LSM/LoadPin.rst b/Documentation/translations/zh_CN/admin-guide/LSM/LoadPin.rst
new file mode 100644
index 000000000000..d75a06f515f6
--- /dev/null
+++ b/Documentation/translations/zh_CN/admin-guide/LSM/LoadPin.rst
@@ -0,0 +1,33 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: Documentation/admin-guide/LSM/LoadPin.rst
+:翻译:
+ 朱岩 Yan Zhu <zhuyan2015@qq.com>
+
+
+=======
+LoadPin
+=======
+
+LoadPin 是一种 Linux 安全模块(LSM),保证所有内核加载的文件(模块、固件等)
+均来自同一文件系统,并且该文件系统应当以只读设备(如 dm-verity 或 CDROM)为后
+端存储。这使得在拥有经过验证和/或不可更改的文件系统的系统上,能够在不对每个文
+件单独签名的前提下,强制模块和固件的加载限制。
+
+该 LSM 在编译时通过 ``CONFIG_SECURITY_LOADPIN`` 进行选择,并且可以在启动时通
+过内核命令行参数 ``loadpin.enforce`` 进行控制。默认情况下该功能是启用的,亦可
+在启动时通过 ``loadpin.enforce=0`` 将其关闭。
+
+LoadPin 会在检测到首个文件被加载时开始生效。如果承载该文件系统的块设备不是只
+读的,系统会创建一个 sysctl 条目 ``/proc/sys/kernel/loadpin/enabled`` 用于切
+换锁定功能。可写的文件系统意味着锁定功能亦可被修改,但通过 sysctl 可以在可
+写文件系统上便捷地进行测试。
+
+也可以使用内核命令行参数 ``loadpin.exclude`` 将特定文件类型从 LoadPin 中排除。
+默认情况下所有文件均被包含,但可以通过
+``loadpin.exclude=kernel-module,kexec-image`` 等方式排除相应类型。这允许在使
+用 ``CONFIG_MODULE_SIG``、``CONFIG_KEXEC_VERIFY_SIG`` 等机制对内核模块和内核
+镜像进行校验的同时,仍然利用 LoadPin 保护其他内核加载文件的完整性。有效文件类
+型的完整列表可在 ``include/linux/kernel_read_file.h`` 中的
+``kernel_read_file_str`` 找到。
-- 
2.43.0


^ permalink raw reply related

* [PATCH 08/10] docs/zh_CN: add LSM/SafeSetID Chinese translation
From: Yan Zhu @ 2026-06-12 15:58 UTC (permalink / raw)
  To: alexs, si.yanteng, corbet, mic
  Cc: dzm91, skhan, gnoack, zhuyan2015, linux-doc,
	linux-security-module
In-Reply-To: <cover.1781105672.git.zhuyan2015@qq.com>

Translate Documentation/admin-guide/LSM/SafeSetID.rst into Chinese.

Update the translation through commit c34921670736
("Documentation: Fix admin-guide typos")

Assisted-by: Claude:deepseek-4-pro
Signed-off-by: Yan Zhu <zhuyan2015@qq.com>
---
 .../zh_CN/admin-guide/LSM/SafeSetID.rst       | 82 +++++++++++++++++++
 1 file changed, 82 insertions(+)
 create mode 100644 Documentation/translations/zh_CN/admin-guide/LSM/SafeSetID.rst

diff --git a/Documentation/translations/zh_CN/admin-guide/LSM/SafeSetID.rst b/Documentation/translations/zh_CN/admin-guide/LSM/SafeSetID.rst
new file mode 100644
index 000000000000..3f96df3ed776
--- /dev/null
+++ b/Documentation/translations/zh_CN/admin-guide/LSM/SafeSetID.rst
@@ -0,0 +1,82 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: Documentation/admin-guide/LSM/SafeSetID.rst
+:翻译:
+ 朱岩 Yan Zhu <zhuyan2015@qq.com>
+
+
+=========
+SafeSetID
+=========
+
+SafeSetID 是一个 LSM 模块,用于对 setid 系列系统调用进行门控,限制 UID/GID
+的转变只能在系统范围的白名单中批准的 UID/GID 之间进行。这些限制还禁止给定的
+UID/GID 获得与 ``CAP_SET{U/G}ID`` 关联的辅助特权,例如允许用户设置用户命名空
+间的 UID/GID 映射。
+
+背景
+====
+在缺少文件能力的情况下,需要切换到其他用户的进程必须具备 ``CAP_SETUID`` 权限。
+``CAP_SETUID`` 只授予以 root 身份运行的程序或显式获得 ``CAP_SETUID`` 运行时
+能力的非 root 程序。相较于文件能力,通常更推荐使用 Linux 运行时能力,因为使
+用文件能力以提升的权限运行程序会带来潜在的安全风险——任何拥有该文件访问权限的
+用户都可以通过 ``exec()`` 运行该程序来获得提升的特权。
+
+虽然可以通过为完整的 ``CAP_SET{U/G}ID`` 能力给进程树授予权限来实现,但这与在
+非 root 用户下运行进程树的目标相冲突。尤其 ``CAP_SETUID`` 允许切换到系统上任
+何用户,包括 root,这在很多场景中过于强大。实际中多数程序仅调用 ``setuid()``
+降低特权,而非提升特权。Linux 并未提供通用机制限制用户通过 ``setuid()`` 能切
+换到的 UID 范围,除非允许其切换到系统上任意用户。SafeSetID LSM 正是为了解决
+这一问题。
+
+主要使用场景是允许非 root 程序在不拥有完整 ``CAP_SETUID`` 能力的情况下,安全
+地切换到其他非受信任的 UID。该非 root 程序仍需 ``CAP_SETUID`` 才能执行任何转
+变,但SafeSetID 施加的额外限制,使其成为 ``CAP_SETUID`` 的“安全版”,防止其进
+行未授权操作(如切换到 UID 0 或创建/进入新的用户命名空间)。这为系统服务提供
+基于UID 的沙箱化提供了可能,而无需在大量非 root 程序上分配完整的
+``CAP_SETUID``。
+
+其他已考虑的方案
+================
+
+在用户空间解决此问题
+--------------------
+可以通过在用户空间完全移除 setid 能力并使用特权帮助程序来完成进程的 UID/GID
+转换。然而,这会影响大量与进程生成相关的语义,如 ``fork()`` 后不立即
+``exec()`` 的行为、父进程自定义环境变量或命令行参数、以及文件句柄跨
+``fork()/exec()`` 的继承等。因此,此类方案对依赖特定进程生成语义的现有项目
+支持度较低。
+
+使用用户命名空间
+----------------
+另一种思路是在独立的用户命名空间中运行进程树,并在该命名空间内授予 setid 能力。
+这样,进程可以在自己的命名空间内自由切换 UID/GID,但只能映射到系统范围白名单
+中的 UID/GID。遗憾的是,用户命名空间往往需要与其他命名空间配合使用,例如网络
+或 PID 命名空间,否则会导致失去 ``CAP_NET_ADMIN`` 等关键能力,限制了实际可用
+性。
+
+使用已有 LSM
+------------
+当前树中没有任何其他 LSM 能够对 setid 转换进行门控,也没有实现
+``security_task_fix_setuid`` 钩子。SELinux 对此钩子声明:
+"由于setuid仅影响当前进程,并且由于SELinux的权限控制不基于Linux标识属性。
+因此,SELinux不需要控制此操作。"
+
+使用方法
+========
+SafeSetID 在 ``securityfs`` 中通过写入 ``safesetid/uid_allowlist_policy``
+与 ``safesetid/gid_allowlist_policy`` 文件来配置策略。策略的格式为
+``<UID>:<UID>`` 或 ``<GID>:<GID>``(使用十进制数字),并以换行符结束,例如
+``123:456\n``。写入空字符串 ``""`` 可清空策略。为特定 UID/GID 配置策略后,将
+阻止该 UID/GID 获得 ``CAP_SET{U/G}ID`` 相关的辅助特权,例如设置用户命名空间
+UID/GID 映射。
+
+GID 策略与 ``setgroups()``
+==========================
+在 v5.9 中已加入对 ``CAP_SETGID`` 限制的支持,与之前对 ``CAP_SETUID`` 的处理
+相同。然而,为了兼容用户空间常见的沙箱化代码规范,目前允许具有 ``CAP_SETGID``
+限制的进程调用任意 ``setgroups()``。这意味着在这些 ``setgroups()`` 限制策略
+检查代码就位之前,**当前的 GID 策略并未提供任何有意义的安全保障**。
+``setgroups()`` 的限制将在未来版本中加入策略检查代码后真正生效,该代码将依赖
+于 v5.9 中加入的 GID 策略配置代码。
-- 
2.43.0


^ permalink raw reply related


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