* Re: [PATCH v4 0/2] Delete task_euid()
From: Alice Ryhl @ 2026-07-03 6:57 UTC (permalink / raw)
To: Paul Moore
Cc: 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, Jann Horn, linux-security-module,
linux-doc, linux-kernel, rust-for-linux
In-Reply-To: <CAHC9VhTfOnOgOzGk9==wJYKx5gAi3Zf3oTwbj183o0_xxrfKag@mail.gmail.com>
On Thu, Jul 02, 2026 at 05:12:52PM -0400, Paul Moore wrote:
> On Wed, Jun 3, 2026 at 1:05 PM Alice Ryhl <aliceryhl@google.com> wrote:
> > On Wed, Jun 3, 2026 at 6:05 PM Paul Moore <paul@paul-moore.com> wrote:
> > >
> > > On Tue, Jun 2, 2026 at 2:15 AM Alice Ryhl <aliceryhl@google.com> wrote:
> > > > On Mon, Jun 01, 2026 at 07:13:37PM -0400, Paul Moore wrote:
> > > > > On Fri, May 29, 2026 at 5:33 AM Alice Ryhl <aliceryhl@google.com> wrote:
> > > > > >
> > > > > > The task_euid() method is a very weird method, and Binder was the only
> > > > > > user. As of commit 65b672152289 ("binder: use current_euid() for
> > > > > > transaction sender identity") Binder doesn't use task_euid() anymore,
> > > > > > so we can delete this method.
> > > > >
> > > > > Given the problems from last time, it seems like it might be prudent
> > > > > to let the commit have some time to "breathe" in a proper release, I'd
> > > > > suggest merging this not for the upcoming v7.2 merge window but
> > > > > instead waiting for v7.3.
> > > >
> > > > Sure, that makes sense. I'll resend after the merge window.
> > >
> > > No need to resend if there are no changes (see below), it's in
> > > patchwork and I'm tracking it so you're all set. I'll send another
> > > notice when I merge it.
> > >
> > > > > > My suggestion would be to merge this through the LSM tree.
> > > > >
> > > > > That's fine with me. I'd also suggest updating the commit description
> > > > > in patch 1/2 to indicate that binder is no longer using task_euid();
> > > > > it currently reads like it is still being used.
> > > >
> > > > I guess this occurred because when patch 1 was written, it really *was*
> > > > still being used.
> > >
> > > Yeah, I understand the world has changed since patch 1/2 was written,
> > > which is okay, we just need to update the commit description ... which
> > > should be a trivial task.
> > >
> > > > Perhaps we could pick up only patch 1 now since even
> > > > if we run into problems and Binder has to go back to using task_euid(),
> > > > clarifying the docs is still useful.
> > >
> > > I assumed that was one of the reasons for splitting the changes across
> > > two patches (reverting patch 2/2 leaves patch 1/2 intact).
> > > Regardless, we're at -rc6 and with patch 1/2 being purely a comment
> > > update I don't see an urgent rush on this, especially considering that
> > > if I did pick it up now, it would be for the v7.2 merge window and the
> > > binder/current_euid() change will ship in v7.1.
> > >
> > > Let's update the commit description - you've got a couple of weeks to
> > > do that - and then we'll merge everything once the v7.2 merge window
> > > closes.
> >
> > Sounds good, thanks!
>
> Just wanted to check in and see if this is still on your todo list?
> No rush, we are only at -rc1, but I was reminded of this while merging
> other patches and just wanted to check ;)
Resent!
Alice
^ permalink raw reply
* [PATCH v5 2/2] cred: delete task_euid()
From: Alice Ryhl @ 2026-07-03 6:57 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,
Jann Horn, linux-security-module, linux-doc, linux-kernel,
rust-for-linux, Alice Ryhl
In-Reply-To: <20260703-remove-task-euid-v5-0-c90c7e2ddf54@google.com>
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, and since adjusted as per Alex Shi's
feedback.
Suggested-by: Jann Horn <jannh@google.com>
Reviewed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
---
Documentation/security/credentials.rst | 6 ++----
Documentation/translations/zh_CN/security/credentials.rst | 4 +---
include/linux/cred.h | 1 -
rust/helpers/task.c | 5 -----
rust/kernel/task.rs | 10 ----------
5 files changed, 3 insertions(+), 23 deletions(-)
diff --git a/Documentation/security/credentials.rst b/Documentation/security/credentials.rst
index 4996838491b1..a39a2a2f67aa 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 88fcd9152ffe..20c8696f8198 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读锁,则应使用::
__task_cred(task)->uid
- __task_cred(task)->euid
类似地,如果需要访问任务凭据的多个方面,应使用RCU读锁,调用 ``__task_cred()``
函数,将结果存储在临时指针中,然后从临时指针中调用凭据的各个方面,最后释放锁。
diff --git a/include/linux/cred.h b/include/linux/cred.h
index c6676265a985..6ef1750c93e2 100644
--- a/include/linux/cred.h
+++ b/include/linux/cred.h
@@ -371,7 +371,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 c0e1a06ede78..b46b1433a67e 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 eabd65bfde12..c2b3457b700c 100644
--- a/rust/kernel/task.rs
+++ b/rust/kernel/task.rs
@@ -217,16 +217,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 {
--
2.55.0.rc0.799.gd6f94ed593-goog
^ permalink raw reply related
* [PATCH v5 1/2] rust: task: clarify comments on task UID accessors
From: Alice Ryhl @ 2026-07-03 6:57 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,
Jann Horn, linux-security-module, linux-doc, linux-kernel,
rust-for-linux, Alice Ryhl
In-Reply-To: <20260703-remove-task-euid-v5-0-c90c7e2ddf54@google.com>
From: Jann Horn <jannh@google.com>
Linux has separate subjective and objective task credentials, see the
comment above `struct cred`. Clarify which accessor functions operate on
which set of credentials.
Also document that Task::euid() is a very weird operation. You can see how
weird it is by grepping for task_euid() in the history - binder was 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 [...]").
For context:
Arguably, binder's use of task_euid() is a theoretical security problem,
which only has no impact on Android because Android has no setuid binaries
executable by apps.
commit 29bc22ac5e5b ("binder: use euid from cred instead of using task")
originally fixed that by removing that only user of task_euid(), but the
fix got reverted in commit c21a80ca0684 ("binder: fix test regression
due to sender_euid change") because some Android test started failing.
It was since fixed again by commit 65b672152289 ("binder: use
current_euid() for transaction sender identity"), which uses
current_euid() instead.
Signed-off-by: Jann Horn <jannh@google.com>
Reviewed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
---
Originally sent as:
https://lore.kernel.org/r/20260212-rust-uid-v1-1-deff4214c766@google.com
---
rust/kernel/task.rs | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/rust/kernel/task.rs b/rust/kernel/task.rs
index 38273f4eedb5..eabd65bfde12 100644
--- a/rust/kernel/task.rs
+++ b/rust/kernel/task.rs
@@ -210,14 +210,17 @@ pub fn pid(&self) -> Pid {
unsafe { *ptr::addr_of!((*self.as_ptr()).pid) }
}
- /// Returns the UID of the given task.
+ /// Returns the objective real UID of the given task.
#[inline]
pub fn uid(&self) -> Kuid {
// SAFETY: It's always safe to call `task_uid` on a valid task.
Kuid::from_raw(unsafe { bindings::task_uid(self.as_ptr()) })
}
- /// Returns the effective UID of the given task.
+ /// 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.
@@ -371,7 +374,7 @@ fn eq(&self, other: &Self) -> bool {
impl Eq for Task {}
impl Kuid {
- /// Get the current euid.
+ /// Get the current subjective effective UID.
#[inline]
pub fn current_euid() -> Kuid {
// SAFETY: Just an FFI call.
--
2.55.0.rc0.799.gd6f94ed593-goog
^ permalink raw reply related
* [PATCH v5 0/2] Delete task_euid()
From: Alice Ryhl @ 2026-07-03 6:57 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,
Jann Horn, linux-security-module, linux-doc, linux-kernel,
rust-for-linux, Alice Ryhl
The task_euid() method is a very weird method, and Binder was the only
user. As of commit 65b672152289 ("binder: use current_euid() for
transaction sender identity") Binder doesn't use task_euid() anymore,
so we can delete this method.
My suggestion would be to merge this through the LSM tree.
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
---
Changes in v5:
- Rebase on v7.2-rc1.
- Reword patch 1 commit message to take into account that usage has now
been removed from Binder.
- Pick up Gary's Reviewed-by.
- Link to v4: https://lore.kernel.org/r/20260529-remove-task-euid-v4-0-07cbdf3af980@google.com
Changes in v4:
- Reword 'euid' -> 'effective UID' in 'Kuid::current_euid()' docs.
- Link to v3: https://lore.kernel.org/r/20260507-remove-task-euid-v3-0-27f22f335c2c@google.com
Changes in v3:
- Include 'task' clarification commit in series.
- Rebase and resend.
- Link to v2: https://lore.kernel.org/r/20260227-remove-task-euid-v2-1-9a9c80a82eb6@google.com
Changes in v2:
- Update translation as per Alex Shi.
- Pick up Reviewed-by Gary.
- Update commit title to use cred: prefix.
- Link to v1: https://lore.kernel.org/r/20260219-remove-task-euid-v1-1-904060826e07@google.com
---
Alice Ryhl (1):
cred: delete task_euid()
Jann Horn (1):
rust: task: clarify comments on task UID accessors
Documentation/security/credentials.rst | 6 ++----
Documentation/translations/zh_CN/security/credentials.rst | 4 +---
include/linux/cred.h | 1 -
rust/helpers/task.c | 5 -----
rust/kernel/task.rs | 11 ++---------
5 files changed, 5 insertions(+), 22 deletions(-)
---
base-commit: dc59e4fea9d83f03bad6bddf3fa2e52491777482
change-id: 20260219-remove-task-euid-19e4b00beebe
Best regards,
--
Alice Ryhl <aliceryhl@google.com>
^ permalink raw reply
* Re: [PATCH] selftests/lsm: Fix memory leak in attr_lsm_count
From: William Roberts @ 2026-07-03 3:01 UTC (permalink / raw)
To: Wang Yan
Cc: linux-security-module, paul, jmorris, serge, shuah, casey, mic,
linux-kselftest, linux-kernel
In-Reply-To: <20260703025247.940055-1-wangyan01@kylinos.cn>
On Thu, Jul 2, 2026 at 9:53 PM Wang Yan <wangyan01@kylinos.cn> wrote:
>
> The calloc-allocated buffer in attr_lsm_count() is never released on
> any exit path, including both the normal return path and the early
> return when read_sysfs_lsms fails, resulting in a heap memory leak.
>
> Add free() for the buffer on all return branches to fix the leak.
>
> Fixes: d3d929a8b0cd ("LSM: selftests for Linux Security Module syscalls")
> Signed-off-by: Wang Yan <wangyan01@kylinos.cn>
> ---
> tools/testing/selftests/lsm/common.c | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/tools/testing/selftests/lsm/common.c b/tools/testing/selftests/lsm/common.c
> index 9ad258912646..4fa8310750a0 100644
> --- a/tools/testing/selftests/lsm/common.c
> +++ b/tools/testing/selftests/lsm/common.c
> @@ -76,6 +76,7 @@ int attr_lsm_count(void)
> return 0;
>
> if (read_sysfs_lsms(names, sysconf(_SC_PAGESIZE)))
> + free(names);
> return 0;
Did you test this, let alone even compile it? All the C code after
this return is dead code.
Please ensure that you test and compile your patches checking for
warnings. Sending
untested patches is "spammy".
>
> if (strstr(names, "selinux"))
> @@ -85,5 +86,6 @@ int attr_lsm_count(void)
> if (strstr(names, "apparmor"))
> count++;
>
> + free(names);
Do this instead:
if (read_sysfs_lsms(names, sysconf(_SC_PAGESIZE)))
goto out;
<existing code>
out:
free(names);
> return count;
> }
> --
> 2.25.1
>
>
^ permalink raw reply
* [PATCH] selftests/lsm: Fix memory leak in attr_lsm_count
From: Wang Yan @ 2026-07-03 2:52 UTC (permalink / raw)
To: linux-security-module
Cc: paul, jmorris, serge, shuah, casey, mic, linux-kselftest,
linux-kernel, Wang Yan
The calloc-allocated buffer in attr_lsm_count() is never released on
any exit path, including both the normal return path and the early
return when read_sysfs_lsms fails, resulting in a heap memory leak.
Add free() for the buffer on all return branches to fix the leak.
Fixes: d3d929a8b0cd ("LSM: selftests for Linux Security Module syscalls")
Signed-off-by: Wang Yan <wangyan01@kylinos.cn>
---
tools/testing/selftests/lsm/common.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/tools/testing/selftests/lsm/common.c b/tools/testing/selftests/lsm/common.c
index 9ad258912646..4fa8310750a0 100644
--- a/tools/testing/selftests/lsm/common.c
+++ b/tools/testing/selftests/lsm/common.c
@@ -76,6 +76,7 @@ int attr_lsm_count(void)
return 0;
if (read_sysfs_lsms(names, sysconf(_SC_PAGESIZE)))
+ free(names);
return 0;
if (strstr(names, "selinux"))
@@ -85,5 +86,6 @@ int attr_lsm_count(void)
if (strstr(names, "apparmor"))
count++;
+ free(names);
return count;
}
--
2.25.1
^ permalink raw reply related
* Re: [PATCH bpf-next v3 2/6] bpf: Verify signed loader metadata at load time
From: Alexei Starovoitov @ 2026-07-02 22:33 UTC (permalink / raw)
To: Paul Moore, Daniel Borkmann
Cc: ast, kpsingh, James.Bottomley, bboscaccy, memxor, torvalds,
a.s.protopopov, bpf, linux-security-module
In-Reply-To: <CAHC9VhQD4RHsGiTMVCCTN+eB71-Ueopke8XghExpNJ2PSNa_jQ@mail.gmail.com>
On Thu Jul 2, 2026 at 3:05 PM PDT, Paul Moore wrote:
>
> As I mentioned previously, the security_bpf_prog_load() hook should
> not be moved. Its placement was deliberate, and moving it as you've
> done in this patch creates a security regression.
not true.
> Without this patch,
> for processes where SELinux is preventing BPF programs from being
> loaded, it is able to do so before the process allocates a potentially
> very large chunk of kernel memory, up to one million BPF instructions.
only when signature verification is requested and the hash over insns
is what your hornet thingy did too.
So no regression whatsoever. Exact same behavior.
> With this patch, even in cases where SELinux will prevent the BPF
> program load operation, it is not able to do so before the process
> triggers a potential sizable memory allocation, opening the door for a
> local DoS attack.
Not true either. Worst case is 1M which is 8Mbyte.
Not even close to anything DoS worthy.
> In an effort to work with you on this, I did bring up two alternative
> solutions: a new LSM hook for the signature verification, or the use
> of the existing security_bpf_prog() hook.
Sorry we're not going to add new hook because Paul has
non-technical grudge against bpf.
> While I don't like to do this, you haven't given me much of a choice;
> the security regression can not be ignored:
>
> Nacked-by: Paul Moore (don't move bpf_prog_load LSM hook) <paul@paul-moore.com>
of course. will keep it and let Linus decide during the merge window.
^ permalink raw reply
* Re: [PATCH bpf-next v3 2/6] bpf: Verify signed loader metadata at load time
From: Paul Moore @ 2026-07-02 22:05 UTC (permalink / raw)
To: Daniel Borkmann
Cc: ast, kpsingh, James.Bottomley, bboscaccy, memxor, torvalds,
a.s.protopopov, bpf, linux-security-module
In-Reply-To: <20260702143605.252797-3-daniel@iogearbox.net>
On Thu, Jul 2, 2026 at 10:36 AM Daniel Borkmann <daniel@iogearbox.net> wrote:
>
> A signed gen_loader program carries the programs, maps and relocations it
> installs in a metadata array map. The loader instructions are covered by
> the PKCS#7 signature, but the metadata map is not: Today the loader
> compares the map contents from within BPF against a hash baked into its
> (signed) instructions, using the kernel-cached map hash. The kernel itself
> never actually attests that the metadata the loader installs is the
> metadata that was signed.
>
> This split is the core of the long-standing objection to the BPF signing
> scheme from the LSM / integrity side: the integrity check of a light
> skeleton only completes once the loader program runs, that is, after the
> security_bpf_prog_load() hook, so at admission time an LSM observes a
> program whose payload has not yet been verified [0]. Auditing the chain
> link is also not a purely cryptographic operation: whoever signs or reviews
> an lskel has to disassemble the loader's preamble to convince themselves
> that the embedded hash check is present and correct [1][2]. Two acceptable
> fixes were identified in those threads: Complete the integrity check
> before the admission hook fires, or add a second hook that collects the
> verification result after the loader ran [3]. Let's implement the former,
> without growing the UAPI.
While you've documented some of the objections from the LSM side,
you've missed the largest objection to the existing BPF signing
scheme: KP's scheme runs the PKCS7 signature over the lskel loader,
while the scheme that Blaise proposed (in multiple forms, not just
Hornet), runs the PKCS7 signature over both the lskel loader and the
associated maps, just as you are doing in this patchset. Moving
towards a scheme where the PKCS7 signature encompasses both the lskel
loader and the maps is a good thing, I'm happy to see that. However,
I do have other issues with this patch that I've mentioned previously
(more below).
> A signed loader binds its metadata map(s) through the existing fd_array,
> and an exclusive map is already bound to a program digest (excl_prog_hash).
> So when a signature is present, collect the exclusive maps from fd_array
> and append their frozen contents to the instructions before verification:
> the signature now covers insns || metadata_0 || metadata_1 || [...] in the
> fd_array order, and verification completes in bpf_check(), once the
> fd_array maps are resolved into used_maps, before the LSM admission hook
> and the rest of verification.
>
> A program is either BPF_SIG_UNSIGNED or BPF_SIG_VERIFIED, with nothing in
> between. While folding the fd_array maps, a non-exclusive map bound to
> a signed program is rejected, so every map folded into the signature is
> exclusive. A signed loader that fails to cover its metadata thus does not
> load, and BPF_SIG_VERIFIED always means the instructions and every
> exclusive map are authentic.
>
> The maps must be frozen so the hashed bytes cannot change before the
> loader runs; the map <-> program digest binding is enforced by the
> verifier for every used map. Binding maps through fd_array_cnt makes the
> verifier resolve and excl-check them (excl_prog_sha vs prog->digest)
> before it would otherwise compute the digest, so compute prog->digest
> up front in bpf_check(), over the unmodified instructions the
> signature covers, for a load that folds metadata.
>
> Unsigned programs are not affected. Note, signed loaders generated by
> older libbpf/bpftool versions need to be regenerated; some of the recent
> fixes we've had on the signed loader side require the latter already to
> close gaps.
>
> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
> Link: https://lore.kernel.org/bpf/CAHC9VhSDkwGgPfrBUh7EgBKEJj_JjnY68c0YAmuuLT_i--GskQ@mail.gmail.com [0]
> Link: https://lore.kernel.org/bpf/2f71d6c03698eb17d51f7247efde777627ee578a.camel@HansenPartnership.com [1]
> Link: https://lore.kernel.org/lkml/ecf0521ed302db672672ebfbc670ecfba36a6e00.camel@HansenPartnership.com [2]
> Link: https://lore.kernel.org/bpf/88703f00d5b7a779728451008626efa45e42db3d.camel@HansenPartnership.com [3]
> ---
> include/linux/bpf_verifier.h | 1 +
> kernel/bpf/syscall.c | 76 +--------------
> kernel/bpf/verifier.c | 175 +++++++++++++++++++++++++++++++++++
> 3 files changed, 178 insertions(+), 74 deletions(-)
...
> diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
> index 6db306d23b47..e898fad01aaf 100644
> --- a/kernel/bpf/syscall.c
> +++ b/kernel/bpf/syscall.c
> @@ -3189,10 +3121,6 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, struct bpf_log_at
> if (err < 0)
> goto free_prog;
>
> - err = security_bpf_prog_load(prog, attr, token, uattr.is_kernel);
> - if (err)
> - goto free_prog;
> -
> /* run eBPF verifier */
> err = bpf_check(&prog, attr, uattr, attr_log);
> if (err < 0)
As I mentioned previously, the security_bpf_prog_load() hook should
not be moved. Its placement was deliberate, and moving it as you've
done in this patch creates a security regression. Without this patch,
for processes where SELinux is preventing BPF programs from being
loaded, it is able to do so before the process allocates a potentially
very large chunk of kernel memory, up to one million BPF instructions.
With this patch, even in cases where SELinux will prevent the BPF
program load operation, it is not able to do so before the process
triggers a potential sizable memory allocation, opening the door for a
local DoS attack.
In an effort to work with you on this, I did bring up two alternative
solutions: a new LSM hook for the signature verification, or the use
of the existing security_bpf_prog() hook. The latter option is
conceptually less clean than the former, but it should still work to
control access to the BPF program based on the signature results.
You've mentioned that you are not in favor of adding a new hook, but
you have ignored the other potential solution of using the
security_bpf_prog() hook.
You can (re)read my earlier comments at the lore link below:
https://lore.kernel.org/linux-security-module/CAHC9VhTtaT_8AXSfNKiq4cGq7T=6Dh=huM8niBCwOP8kj+ugjQ@mail.gmail.com/
While I don't like to do this, you haven't given me much of a choice;
the security regression can not be ignored:
Nacked-by: Paul Moore (don't move bpf_prog_load LSM hook) <paul@paul-moore.com>
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 44bb6ce17a1c..1609053a0eeb 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -19901,11 +20060,27 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr,
> ret = bpf_vlog_init(&env->log, attr_log->level, attr_log->ubuf, attr_log->size);
> if (ret)
> goto err_unlock;
> + if (env->signature) {
> + ret = bpf_prog_calc_tag(env->prog);
> + if (ret < 0)
> + goto skip_full_check;
> + }
>
> ret = process_fd_array(env, attr, uattr);
> if (ret)
> goto skip_full_check;
>
> + if (env->signature) {
> + ret = bpf_prog_verify_signature(env, attr, uattr.is_kernel);
> + if (ret)
> + goto skip_full_check;
> + }
> +
> + ret = security_bpf_prog_load(env->prog, attr, env->prog->aux->token,
> + uattr.is_kernel);
> + if (ret)
> + goto skip_full_check;
> +
> mark_verifier_state_clean(env);
>
> if (IS_ERR(btf_vmlinux)) {
> --
> 2.43.0
--
paul-moore.com
^ permalink raw reply
* Re: [PATCH bpf-next v3 1/6] bpf: Resolve and cache fd_array objects at load time
From: Daniel Borkmann @ 2026-07-02 21:16 UTC (permalink / raw)
To: Anton Protopopov
Cc: ast, kpsingh, James.Bottomley, paul, bboscaccy, memxor, torvalds,
bpf, linux-security-module
In-Reply-To: <aka2yR6IUZMAOUwJ@mail.gmail.com>
On 7/2/26 9:06 PM, Anton Protopopov wrote:
> On 26/07/02 04:36PM, Daniel Borkmann wrote:
>> The fd_array passed to BPF_PROG_LOAD carries the map and module BTF file
>> descriptors a program binds. The verifier reads it more than once during
>> a load: process_fd_array() walks it to bind the maps and BTFs, and
>> check_and_resolve_insns() and the kfunc BTF resolver later read it again
>> to resolve the program's BPF_PSEUDO_MAP_IDX and module kfunc refs.
>>
>> For signed BPF, we need these upfront in memory, thus resolve each fd to
>> its object once and cache it by fd_array index, then bind that cached
>> object for the rest of the load. env->fd_array becomes a small per-slot
>> {map, btf} cache rather than a bpfptr_t; every later reference is then
>> an in-bounds lookup of an already-resolved object, and an index outside
>> the cache is rejected instead of read from user memory:
>>
>> - continuous (fd_array_cnt given): the caller declares the length and
>> every entry is resolved and bound up front (used also by signed loader)
>>
>> - sparse (no fd_array_cnt): left as the legacy path with no fd_array
>> cache; each reference reads its fd from the caller's fd_array and
>> resolves it on the spot. Deduplication in used_maps and the kfunc BTF
>> table keeps this correct, and only unsigned programs use this shape.
>>
>> UAPI-wise nothing changes, its just the internals on how BPF processes
>> and caches the fd_array favors. Split these into separate helpers for
>> continuous versus sparse to make it easier to follow.
>
> Overall looks ok. A few comments below.
>
[...]
>> - /* Check for integer overflow */
>> - if (attr->fd_array_cnt >= (U32_MAX / size)) {
>> - verbose(env, "fd_array_cnt is too big (%u)\n", attr->fd_array_cnt);
>> - return -EINVAL;
>> + if (cnt > MAX_FD_ARRAY_CNT) {
>
> So, I _think_ I've done the "unlimited" thing because there can be duplicates
> in fd_array. The limit is actually tracked by __add_{map_btf} So here we hard
> limit on the size of the fd_array itself. (Even without duplicates, this
> fd_array can contain, say, MAX_KFUNC_BTFS different maps, which will be in any
> case rejected by __add_used_map.)
>
>> + verbose(env, "fd_array has too many entries (%u, max %u)\n",
>> + cnt, MAX_FD_ARRAY_CNT);
>> + return -E2BIG;
>> }
>>
[...]
>>
>> +static int process_fd_array(struct bpf_verifier_env *env,
>> + union bpf_attr *attr, bpfptr_t uattr)
>> +{
>> + bpfptr_t fd_array = make_bpfptr(attr->fd_array, uattr.is_kernel);
>> +
>> + if (bpfptr_is_null(fd_array))
>> + return 0;
>> + /*
>> + * New API: the caller passes fd_array_cnt and a continuous array that
>> + * is resolved and bound up front. Legacy API (no fd_array_cnt): keep
>> + * the caller's array and resolve entries lazily, on first reference.
>> + */
>> + if (attr->fd_array_cnt)
>> + return process_fd_array_continuous(env, fd_array,
>> + attr->fd_array_cnt);
>
> Looks like this returns success in case (!fd_array && attr->fd_array_cnt),
> which is a misconfiguration and should be rejected.
Thanks for the review, addressing both in v4!
^ permalink raw reply
* Re: [PATCH] lsm: cleanup repeated lsm_blob_size_update() calls in lsm_prepare()
From: Paul Moore @ 2026-07-02 21:15 UTC (permalink / raw)
To: Matt Bobrowski; +Cc: linux-security-module, James Morris, Serge E . Hallyn
In-Reply-To: <akbHgKxaNmRQEfqs@google.com>
On Thu, Jul 2, 2026 at 4:18 PM Matt Bobrowski <mattbobrowski@google.com> wrote:
> On Thu, Jul 02, 2026 at 03:15:02PM -0400, Paul Moore wrote:
> > On Jun 29, 2026 Matt Bobrowski <mattbobrowski@google.com> wrote:
> > >
> > > Centralize the definition of LSM security blob fields using an X-macro
> > > (LSM_BLOBS_LIST). This reduces repetitive boilerplate code across
> > > struct lsm_blob_sizes, blob size registration in lsm_prepare(), and
> > > debug log printing in security_init().
> > >
> > > Signed-off-by: Matt Bobrowski <mattbobrowski@google.com>
> > > ---
> > > include/linux/lsm_hooks.h | 42 ++++++++++++++++------------
> > > security/lsm_init.c | 59 ++++++++++-----------------------------
> > > 2 files changed, 38 insertions(+), 63 deletions(-)
> > >
> > > diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
> > > index b4f8cad53ddb..0e73b22bdeea 100644
> > > --- a/include/linux/lsm_hooks.h
> > > +++ b/include/linux/lsm_hooks.h
> > > @@ -98,28 +98,34 @@ struct security_hook_list {
> > > const struct lsm_id *lsmid;
> > > } __randomize_layout;
> > >
> > > +#define LSM_BLOBS_LIST(X) \
> > > + X(cred) \
> > > + X(file) \
> > > + X(backing_file) \
> > > + X(ib) \
> > > + X(inode) \
> > > + X(sock) \
> > > + X(superblock) \
> > > + X(ipc) \
> > > + X(key) \
> > > + X(msg_msg) \
> > > + X(perf_event) \
> > > + X(task) \
> > > + X(tun_dev) \
> > > + X(xattr_count) \
> > > + X(bdev) \
> > > + X(bpf_map) \
> > > + X(bpf_prog) \
> > > + X(bpf_token)
> > > +
> > > /*
> > > * Security blob size or offset data.
> > > + * Note: lbs_xattr_count is the number of xattr slots in new_xattrs array.
> > > */
> > > struct lsm_blob_sizes {
> > > - unsigned int lbs_cred;
> > > - unsigned int lbs_file;
> > > - unsigned int lbs_backing_file;
> > > - unsigned int lbs_ib;
> > > - unsigned int lbs_inode;
> > > - unsigned int lbs_sock;
> > > - unsigned int lbs_superblock;
> > > - unsigned int lbs_ipc;
> > > - unsigned int lbs_key;
> > > - unsigned int lbs_msg_msg;
> > > - unsigned int lbs_perf_event;
> > > - unsigned int lbs_task;
> > > - unsigned int lbs_xattr_count; /* num xattr slots in new_xattrs array */
> > > - unsigned int lbs_tun_dev;
> > > - unsigned int lbs_bdev;
> > > - unsigned int lbs_bpf_map;
> > > - unsigned int lbs_bpf_prog;
> > > - unsigned int lbs_bpf_token;
> > > +#define LSM_BLOB_SIZE(name) unsigned int lbs_##name;
> > > + LSM_BLOBS_LIST(LSM_BLOB_SIZE);
> > > +#undef LSM_BLOB_SIZE
> > > };
> >
> > Generally speaking I greatly prefer to see the structure fields typed out
> > as it makes it easier to find them using grep, code indexers, etc. There
> > is a similar argument for the security_init() changes (below).
> >
> > > diff --git a/security/lsm_init.c b/security/lsm_init.c
> > > index 7c0fd17f1601..c256f1c33efa 100644
> > > --- a/security/lsm_init.c
> > > +++ b/security/lsm_init.c
> > > @@ -282,40 +282,24 @@ static void __init lsm_blob_size_update(unsigned int *sz_req,
> > > * lsm_prepare - Prepare the LSM framework for a new LSM
> > > * @lsm: LSM definition
> > > */
> > > -static void __init lsm_prepare(struct lsm_info *lsm)
> > > +static void __init lsm_prepare(const struct lsm_info *lsm)
> > > {
> > > struct lsm_blob_sizes *blobs = lsm->blobs;
> > >
> > > if (!blobs)
> > > return;
> > >
> > > - /* Register the LSM blob sizes. */
> > > - blobs = lsm->blobs;
> > > - lsm_blob_size_update(&blobs->lbs_cred, &blob_sizes.lbs_cred);
> > > - lsm_blob_size_update(&blobs->lbs_file, &blob_sizes.lbs_file);
> > > - lsm_blob_size_update(&blobs->lbs_backing_file,
> > > - &blob_sizes.lbs_backing_file);
> > > - lsm_blob_size_update(&blobs->lbs_ib, &blob_sizes.lbs_ib);
> > > - /* inode blob gets an rcu_head in addition to LSM blobs. */
> > > + /* The inode blob (inode->i_security) gets an rcu_head in addition to
> > > + * LSM blobs.
> > > + */
> > > if (blobs->lbs_inode && blob_sizes.lbs_inode == 0)
> > > blob_sizes.lbs_inode = sizeof(struct rcu_head);
> > > - lsm_blob_size_update(&blobs->lbs_inode, &blob_sizes.lbs_inode);
> > > - lsm_blob_size_update(&blobs->lbs_ipc, &blob_sizes.lbs_ipc);
> > > - lsm_blob_size_update(&blobs->lbs_key, &blob_sizes.lbs_key);
> > > - lsm_blob_size_update(&blobs->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
> > > - lsm_blob_size_update(&blobs->lbs_perf_event,
> > > - &blob_sizes.lbs_perf_event);
> > > - lsm_blob_size_update(&blobs->lbs_sock, &blob_sizes.lbs_sock);
> > > - lsm_blob_size_update(&blobs->lbs_superblock,
> > > - &blob_sizes.lbs_superblock);
> > > - lsm_blob_size_update(&blobs->lbs_task, &blob_sizes.lbs_task);
> > > - lsm_blob_size_update(&blobs->lbs_tun_dev, &blob_sizes.lbs_tun_dev);
> > > - lsm_blob_size_update(&blobs->lbs_xattr_count,
> > > - &blob_sizes.lbs_xattr_count);
> > > - lsm_blob_size_update(&blobs->lbs_bdev, &blob_sizes.lbs_bdev);
> > > - lsm_blob_size_update(&blobs->lbs_bpf_map, &blob_sizes.lbs_bpf_map);
> > > - lsm_blob_size_update(&blobs->lbs_bpf_prog, &blob_sizes.lbs_bpf_prog);
> > > - lsm_blob_size_update(&blobs->lbs_bpf_token, &blob_sizes.lbs_bpf_token);
> > > +
> > > + /* Register the LSM blob sizes. */
> > > +#define UPDATE_LSM_BLOB_SIZE(name) \
> > > + lsm_blob_size_update(&blobs->lbs_##name, &blob_sizes.lbs_##name);
> > > + LSM_BLOBS_LIST(UPDATE_LSM_BLOB_SIZE);
> > > +#undef UPDATE_LSM_BLOB_SIZE
> > > }
> >
> > This is one case where the macro approach *might* have some value, but as
> > it is the one instance, and multiple sequential blob operations like this
> > are going to be *very* limited, I'm not sure there is enough value to
> > be worth the change.
> >
> > I appreciate the initiative to search out areas that you think could use
> > improvement, but for the reasons mentioned, I'm not going to merge this
> > patch.
>
> That's not a problem. Perhaps you may want to consider only taking the
> minor cleanup targets the redundant lsm->blobs access within
> lsm_prepare().
I did think about that, but I ever *so* slightly prefer it the way it
is now, although as I said this is the one case where there may be
some value. If there had been other areas where it was a clear cut
win I likely would have just accepted this change too, but there
wasn't (at least not now, and with this revision) so I just decided to
leave it well enough alone.
However, as I said, thank you taking the initiative on this.
--
paul-moore.com
^ permalink raw reply
* Re: [PATCH v4 0/2] Delete task_euid()
From: Paul Moore @ 2026-07-02 21:12 UTC (permalink / raw)
To: Alice Ryhl
Cc: 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, Jann Horn, linux-security-module,
linux-doc, linux-kernel, rust-for-linux
In-Reply-To: <CAH5fLghJaFXheAZqKyM9Cdo6iqTw1W=haA79POhmZWEfuKujRA@mail.gmail.com>
On Wed, Jun 3, 2026 at 1:05 PM Alice Ryhl <aliceryhl@google.com> wrote:
> On Wed, Jun 3, 2026 at 6:05 PM Paul Moore <paul@paul-moore.com> wrote:
> >
> > On Tue, Jun 2, 2026 at 2:15 AM Alice Ryhl <aliceryhl@google.com> wrote:
> > > On Mon, Jun 01, 2026 at 07:13:37PM -0400, Paul Moore wrote:
> > > > On Fri, May 29, 2026 at 5:33 AM Alice Ryhl <aliceryhl@google.com> wrote:
> > > > >
> > > > > The task_euid() method is a very weird method, and Binder was the only
> > > > > user. As of commit 65b672152289 ("binder: use current_euid() for
> > > > > transaction sender identity") Binder doesn't use task_euid() anymore,
> > > > > so we can delete this method.
> > > >
> > > > Given the problems from last time, it seems like it might be prudent
> > > > to let the commit have some time to "breathe" in a proper release, I'd
> > > > suggest merging this not for the upcoming v7.2 merge window but
> > > > instead waiting for v7.3.
> > >
> > > Sure, that makes sense. I'll resend after the merge window.
> >
> > No need to resend if there are no changes (see below), it's in
> > patchwork and I'm tracking it so you're all set. I'll send another
> > notice when I merge it.
> >
> > > > > My suggestion would be to merge this through the LSM tree.
> > > >
> > > > That's fine with me. I'd also suggest updating the commit description
> > > > in patch 1/2 to indicate that binder is no longer using task_euid();
> > > > it currently reads like it is still being used.
> > >
> > > I guess this occurred because when patch 1 was written, it really *was*
> > > still being used.
> >
> > Yeah, I understand the world has changed since patch 1/2 was written,
> > which is okay, we just need to update the commit description ... which
> > should be a trivial task.
> >
> > > Perhaps we could pick up only patch 1 now since even
> > > if we run into problems and Binder has to go back to using task_euid(),
> > > clarifying the docs is still useful.
> >
> > I assumed that was one of the reasons for splitting the changes across
> > two patches (reverting patch 2/2 leaves patch 1/2 intact).
> > Regardless, we're at -rc6 and with patch 1/2 being purely a comment
> > update I don't see an urgent rush on this, especially considering that
> > if I did pick it up now, it would be for the v7.2 merge window and the
> > binder/current_euid() change will ship in v7.1.
> >
> > Let's update the commit description - you've got a couple of weeks to
> > do that - and then we'll merge everything once the v7.2 merge window
> > closes.
>
> Sounds good, thanks!
Just wanted to check in and see if this is still on your todo list?
No rush, we are only at -rc1, but I was reminded of this while merging
other patches and just wanted to check ;)
--
paul-moore.com
^ permalink raw reply
* Re: [PATCH 2/2] security: Fix call security_backing_file_free second time
From: Paul Moore @ 2026-07-02 21:09 UTC (permalink / raw)
To: Cai Xinchen, jmorris, serge, stephen.smalley.work, omosnace,
amir73il, brauner
Cc: linux-security-module, linux-kernel, selinux, caixinchen1,
lujialin4
In-Reply-To: <20260626011720.1144213-3-caixinchen1@huawei.com>
On Jun 25, 2026 Cai Xinchen <caixinchen1@huawei.com> wrote:
>
> I found the following path:
>
> alloc_empty_backing-file
> init_file(&ff->file, xxx)
> -> file_ref_init(&f->f_ref, 1); // only 1
> error = init_backing_file
> -> security_backing_file_alloc
> -> rc = call_int_hook(backing_file_alloc, ...)
The good news is that as you mentioned, only SELinux defines a
backing_file_alloc hook and it always returns success/0.
> if (unlikely(rc))
> security_backing_file_free(backing_file); // first call
> if (unlikely(error)) {
> fput(&ff->file);
> -> if (unlikely(file_ref_put(&file->f_ref))) // zero
> __fput_deferred(file);
> -> ____fput -> __fput -> file_free(file);
> -> backing_file_free(backing_file(f));
> -> security_backing_file_free(&ff->file); // second call
>
> Currently, only SELinux has the lsm backing_file_alloc hook, and the
> backing_file_free hook is not set. When security_backing_file_free is
> called for the first time, the blobs pointer is set to NULL. Therefore,
> double free will not occur in the code.
>
> Fixes: 6af36aeb147a ("lsm: add backing_file LSM hooks")
> Signed-off-by: Cai Xinchen <caixinchen1@huawei.com>
> ---
> security/security.c | 5 +----
> 1 file changed, 1 insertion(+), 4 deletions(-)
>
> diff --git a/security/security.c b/security/security.c
> index 71aea8fdf014..595d3c73253e 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -2468,11 +2468,8 @@ int security_backing_file_alloc(struct file *backing_file,
> rc = lsm_backing_file_alloc(backing_file);
> if (rc)
> return rc;
> - rc = call_int_hook(backing_file_alloc, backing_file, user_file);
> - if (unlikely(rc))
> - security_backing_file_free(backing_file);
>
> - return rc;
> + return call_int_hook(backing_file_alloc, backing_file, user_file);
> }
I think the better option would be to move the
call_void_hook(backing_file_free, ...) call in security_backing_file_free()
into the if-statment true block before we set the backing file's LSM blob
pointer to NULL and free the LSM blob.
--
paul-moore.com
^ permalink raw reply
* Re: [PATCH 1/2] security: Some cleanup code
From: Paul Moore @ 2026-07-02 21:09 UTC (permalink / raw)
To: Cai Xinchen, jmorris, serge, stephen.smalley.work, omosnace,
amir73il, brauner
Cc: linux-security-module, linux-kernel, selinux, caixinchen1,
lujialin4
In-Reply-To: <20260626011720.1144213-2-caixinchen1@huawei.com>
On Jun 25, 2026 Cai Xinchen <caixinchen1@huawei.com> wrote:
>
> Delete an unnecessary blank line and a blobs variable with
> duplicate assignment.
>
> Signed-off-by: Cai Xinchen <caixinchen1@huawei.com>
> ---
> security/lsm_init.c | 1 -
> security/selinux/hooks.c | 1 -
> 2 files changed, 2 deletions(-)
Please split this into two patches: one for the LSM (lsm_init.c) and
one for SELinux (hooks.c). They are two different subsystems, mailing
lists, etc.
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index 7c0fd17f1601..d7384866e3a5 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -290,7 +290,6 @@ static void __init lsm_prepare(struct lsm_info *lsm)
> return;
>
> /* Register the LSM blob sizes. */
> - blobs = lsm->blobs;
> lsm_blob_size_update(&blobs->lbs_cred, &blob_sizes.lbs_cred);
> lsm_blob_size_update(&blobs->lbs_file, &blob_sizes.lbs_file);
> lsm_blob_size_update(&blobs->lbs_backing_file,
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index 1a713d96206f..e5930ebc9e37 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -1748,7 +1748,6 @@ static int bpf_fd_pass(const struct file *file, u32 sid);
>
> static int __file_has_perm(const struct cred *cred, const struct file *file,
> u32 av, bool bf_user_file)
> -
> {
> struct common_audit_data ad;
> struct inode *inode;
> --
> 2.34.1
--
paul-moore.com
^ permalink raw reply
* Re: [PATCH] lsm: cleanup repeated lsm_blob_size_update() calls in lsm_prepare()
From: Matt Bobrowski @ 2026-07-02 20:18 UTC (permalink / raw)
To: Paul Moore; +Cc: linux-security-module, James Morris, Serge E . Hallyn
In-Reply-To: <dde355196558210f6ca87c1a0745a3a8@paul-moore.com>
On Thu, Jul 02, 2026 at 03:15:02PM -0400, Paul Moore wrote:
> On Jun 29, 2026 Matt Bobrowski <mattbobrowski@google.com> wrote:
> >
> > Centralize the definition of LSM security blob fields using an X-macro
> > (LSM_BLOBS_LIST). This reduces repetitive boilerplate code across
> > struct lsm_blob_sizes, blob size registration in lsm_prepare(), and
> > debug log printing in security_init().
> >
> > Signed-off-by: Matt Bobrowski <mattbobrowski@google.com>
> > ---
> > include/linux/lsm_hooks.h | 42 ++++++++++++++++------------
> > security/lsm_init.c | 59 ++++++++++-----------------------------
> > 2 files changed, 38 insertions(+), 63 deletions(-)
> >
> > diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
> > index b4f8cad53ddb..0e73b22bdeea 100644
> > --- a/include/linux/lsm_hooks.h
> > +++ b/include/linux/lsm_hooks.h
> > @@ -98,28 +98,34 @@ struct security_hook_list {
> > const struct lsm_id *lsmid;
> > } __randomize_layout;
> >
> > +#define LSM_BLOBS_LIST(X) \
> > + X(cred) \
> > + X(file) \
> > + X(backing_file) \
> > + X(ib) \
> > + X(inode) \
> > + X(sock) \
> > + X(superblock) \
> > + X(ipc) \
> > + X(key) \
> > + X(msg_msg) \
> > + X(perf_event) \
> > + X(task) \
> > + X(tun_dev) \
> > + X(xattr_count) \
> > + X(bdev) \
> > + X(bpf_map) \
> > + X(bpf_prog) \
> > + X(bpf_token)
> > +
> > /*
> > * Security blob size or offset data.
> > + * Note: lbs_xattr_count is the number of xattr slots in new_xattrs array.
> > */
> > struct lsm_blob_sizes {
> > - unsigned int lbs_cred;
> > - unsigned int lbs_file;
> > - unsigned int lbs_backing_file;
> > - unsigned int lbs_ib;
> > - unsigned int lbs_inode;
> > - unsigned int lbs_sock;
> > - unsigned int lbs_superblock;
> > - unsigned int lbs_ipc;
> > - unsigned int lbs_key;
> > - unsigned int lbs_msg_msg;
> > - unsigned int lbs_perf_event;
> > - unsigned int lbs_task;
> > - unsigned int lbs_xattr_count; /* num xattr slots in new_xattrs array */
> > - unsigned int lbs_tun_dev;
> > - unsigned int lbs_bdev;
> > - unsigned int lbs_bpf_map;
> > - unsigned int lbs_bpf_prog;
> > - unsigned int lbs_bpf_token;
> > +#define LSM_BLOB_SIZE(name) unsigned int lbs_##name;
> > + LSM_BLOBS_LIST(LSM_BLOB_SIZE);
> > +#undef LSM_BLOB_SIZE
> > };
>
> Generally speaking I greatly prefer to see the structure fields typed out
> as it makes it easier to find them using grep, code indexers, etc. There
> is a similar argument for the security_init() changes (below).
>
> > diff --git a/security/lsm_init.c b/security/lsm_init.c
> > index 7c0fd17f1601..c256f1c33efa 100644
> > --- a/security/lsm_init.c
> > +++ b/security/lsm_init.c
> > @@ -282,40 +282,24 @@ static void __init lsm_blob_size_update(unsigned int *sz_req,
> > * lsm_prepare - Prepare the LSM framework for a new LSM
> > * @lsm: LSM definition
> > */
> > -static void __init lsm_prepare(struct lsm_info *lsm)
> > +static void __init lsm_prepare(const struct lsm_info *lsm)
> > {
> > struct lsm_blob_sizes *blobs = lsm->blobs;
> >
> > if (!blobs)
> > return;
> >
> > - /* Register the LSM blob sizes. */
> > - blobs = lsm->blobs;
> > - lsm_blob_size_update(&blobs->lbs_cred, &blob_sizes.lbs_cred);
> > - lsm_blob_size_update(&blobs->lbs_file, &blob_sizes.lbs_file);
> > - lsm_blob_size_update(&blobs->lbs_backing_file,
> > - &blob_sizes.lbs_backing_file);
> > - lsm_blob_size_update(&blobs->lbs_ib, &blob_sizes.lbs_ib);
> > - /* inode blob gets an rcu_head in addition to LSM blobs. */
> > + /* The inode blob (inode->i_security) gets an rcu_head in addition to
> > + * LSM blobs.
> > + */
> > if (blobs->lbs_inode && blob_sizes.lbs_inode == 0)
> > blob_sizes.lbs_inode = sizeof(struct rcu_head);
> > - lsm_blob_size_update(&blobs->lbs_inode, &blob_sizes.lbs_inode);
> > - lsm_blob_size_update(&blobs->lbs_ipc, &blob_sizes.lbs_ipc);
> > - lsm_blob_size_update(&blobs->lbs_key, &blob_sizes.lbs_key);
> > - lsm_blob_size_update(&blobs->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
> > - lsm_blob_size_update(&blobs->lbs_perf_event,
> > - &blob_sizes.lbs_perf_event);
> > - lsm_blob_size_update(&blobs->lbs_sock, &blob_sizes.lbs_sock);
> > - lsm_blob_size_update(&blobs->lbs_superblock,
> > - &blob_sizes.lbs_superblock);
> > - lsm_blob_size_update(&blobs->lbs_task, &blob_sizes.lbs_task);
> > - lsm_blob_size_update(&blobs->lbs_tun_dev, &blob_sizes.lbs_tun_dev);
> > - lsm_blob_size_update(&blobs->lbs_xattr_count,
> > - &blob_sizes.lbs_xattr_count);
> > - lsm_blob_size_update(&blobs->lbs_bdev, &blob_sizes.lbs_bdev);
> > - lsm_blob_size_update(&blobs->lbs_bpf_map, &blob_sizes.lbs_bpf_map);
> > - lsm_blob_size_update(&blobs->lbs_bpf_prog, &blob_sizes.lbs_bpf_prog);
> > - lsm_blob_size_update(&blobs->lbs_bpf_token, &blob_sizes.lbs_bpf_token);
> > +
> > + /* Register the LSM blob sizes. */
> > +#define UPDATE_LSM_BLOB_SIZE(name) \
> > + lsm_blob_size_update(&blobs->lbs_##name, &blob_sizes.lbs_##name);
> > + LSM_BLOBS_LIST(UPDATE_LSM_BLOB_SIZE);
> > +#undef UPDATE_LSM_BLOB_SIZE
> > }
>
> This is one case where the macro approach *might* have some value, but as
> it is the one instance, and multiple sequential blob operations like this
> are going to be *very* limited, I'm not sure there is enough value to
> be worth the change.
>
> I appreciate the initiative to search out areas that you think could use
> improvement, but for the reasons mentioned, I'm not going to merge this
> patch.
That's not a problem. Perhaps you may want to consider only taking the
minor cleanup targets the redundant lsm->blobs access within
lsm_prepare().
> > @@ -441,25 +425,10 @@ int __init security_init(void)
> > lsm_prepare(*lsm);
> >
> > if (lsm_debug) {
> > - lsm_pr("blob(cred) size %d\n", blob_sizes.lbs_cred);
> > - lsm_pr("blob(file) size %d\n", blob_sizes.lbs_file);
> > - lsm_pr("blob(backing_file) size %d\n",
> > - blob_sizes.lbs_backing_file);
> > - lsm_pr("blob(ib) size %d\n", blob_sizes.lbs_ib);
> > - lsm_pr("blob(inode) size %d\n", blob_sizes.lbs_inode);
> > - lsm_pr("blob(ipc) size %d\n", blob_sizes.lbs_ipc);
> > - lsm_pr("blob(key) size %d\n", blob_sizes.lbs_key);
> > - lsm_pr("blob(msg_msg)_size %d\n", blob_sizes.lbs_msg_msg);
> > - lsm_pr("blob(sock) size %d\n", blob_sizes.lbs_sock);
> > - lsm_pr("blob(superblock) size %d\n", blob_sizes.lbs_superblock);
> > - lsm_pr("blob(perf_event) size %d\n", blob_sizes.lbs_perf_event);
> > - lsm_pr("blob(task) size %d\n", blob_sizes.lbs_task);
> > - lsm_pr("blob(tun_dev) size %d\n", blob_sizes.lbs_tun_dev);
> > - lsm_pr("blob(xattr) count %d\n", blob_sizes.lbs_xattr_count);
> > - lsm_pr("blob(bdev) size %d\n", blob_sizes.lbs_bdev);
> > - lsm_pr("blob(bpf_map) size %d\n", blob_sizes.lbs_bpf_map);
> > - lsm_pr("blob(bpf_prog) size %d\n", blob_sizes.lbs_bpf_prog);
> > - lsm_pr("blob(bpf_token) size %d\n", blob_sizes.lbs_bpf_token);
> > +#define PRINT_LSM_BLOB_SIZE(name) \
> > + lsm_pr("blob(" #name ") size %d\n", blob_sizes.lbs_##name);
> > + LSM_BLOBS_LIST(PRINT_LSM_BLOB_SIZE);
> > +#undef PRINT_LSM_BLOB_SIZE
>
> This is another case where having the text string grep'able can be a good
> thing.
>
> --
> paul-moore.com
^ permalink raw reply
* Re: [PATCH v6 1/4] security: lsm: allow LSMs to register for late_initcall_sync init
From: Yeoreum Yun @ 2026-07-02 19:42 UTC (permalink / raw)
To: Paul Moore
Cc: zohar, linux-security-module, linux-kernel, linux-integrity,
roberto.sassu, noodles, jarkko, sudeep.holla, jmorris, serge,
dmitry.kasatkin, eric.snowberg, jgg
In-Reply-To: <CAHC9VhQXwXHjKcr0SRNQyzKZgCwG1RLPT6kWDLLwEKExfXzzOw@mail.gmail.com>
> On Fri, Jun 5, 2026 at 10:43 AM Yeoreum Yun <yeoreum.yun@arm.com> wrote:
> >
> > There are situations where LSMs have dependencies that might mean they
> > want to be initialised later in the boot process, to ensure those
> > dependencies are available. In particular there are some TPM setups (Arm
> > FF-A devices, SPI attached TPMs) required by IMA which are not
> > guaranteed to be initialised for regular initcall_late.
> >
> > Add an initcall_late_sync option that can be used in these situations.
> >
> > Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
> > ---
> > include/linux/lsm_hooks.h | 2 ++
> > security/lsm_init.c | 13 +++++++++++--
> > 2 files changed, 13 insertions(+), 2 deletions(-)
>
> Looks good to me, thanks for working on sorting this out.
>
> Acked-by: Paul Moore <paul@paul-moore.com>
Thanks!
>
> --
> paul-moore.com
--
Sincerely,
Yeoreum Yun
^ permalink raw reply
* [PATCH] ipe: fix bracket
From: Manuel Ebner @ 2026-07-02 19:22 UTC (permalink / raw)
To: Fan Wu, Jonathan Corbet, Shuah Khan
Cc: Manuel Ebner, linux-security-module, linux-doc, linux-kernel
Replace nonsensical ')' with '0'.
Signed-off-by: Manuel Ebner <manuelebner@mailbox.org>
---
I'm not 100% sure this patch is good. Please check if this makes sense.
---
Documentation/admin-guide/LSM/ipe.rst | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Documentation/admin-guide/LSM/ipe.rst b/Documentation/admin-guide/LSM/ipe.rst
index a756d8158531..bebf14fc2411 100644
--- a/Documentation/admin-guide/LSM/ipe.rst
+++ b/Documentation/admin-guide/LSM/ipe.rst
@@ -502,11 +502,11 @@ The following table lists the error codes that may appear in the errno field whi
Event Examples::
type=1404 audit(1653425689.008:55): enforcing=0 old_enforcing=1 auid=4294967295 ses=4294967295 enabled=1 old-enabled=1 lsm=ipe res=1
- type=1300 audit(1653425689.008:55): arch=c000003e syscall=1 success=yes exit=2 a0=1 a1=55c1065e5c60 a2=2 a3=0 items=0 ppid=405 pid=441 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=)
+ type=1300 audit(1653425689.008:55): arch=c000003e syscall=1 success=yes exit=2 a0=1 a1=55c1065e5c60 a2=2 a3=0 items=0 ppid=405 pid=441 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0
type=1327 audit(1653425689.008:55): proctitle="-bash"
type=1404 audit(1653425689.008:55): enforcing=1 old_enforcing=0 auid=4294967295 ses=4294967295 enabled=1 old-enabled=1 lsm=ipe res=1
- type=1300 audit(1653425689.008:55): arch=c000003e syscall=1 success=yes exit=2 a0=1 a1=55c1065e5c60 a2=2 a3=0 items=0 ppid=405 pid=441 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=)
+ type=1300 audit(1653425689.008:55): arch=c000003e syscall=1 success=yes exit=2 a0=1 a1=55c1065e5c60 a2=2 a3=0 items=0 ppid=405 pid=441 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0
type=1327 audit(1653425689.008:55): proctitle="-bash"
This record will always be emitted in conjunction with a ``AUDITSYSCALL`` record for the ``write`` syscall.
--
2.54.0
^ permalink raw reply related
* Re: [PATCH] lsm: cleanup repeated lsm_blob_size_update() calls in lsm_prepare()
From: Paul Moore @ 2026-07-02 19:15 UTC (permalink / raw)
To: Matt Bobrowski, linux-security-module
Cc: James Morris, Serge E . Hallyn, Matt Bobrowski
In-Reply-To: <20260629210150.832576-1-mattbobrowski@google.com>
On Jun 29, 2026 Matt Bobrowski <mattbobrowski@google.com> wrote:
>
> Centralize the definition of LSM security blob fields using an X-macro
> (LSM_BLOBS_LIST). This reduces repetitive boilerplate code across
> struct lsm_blob_sizes, blob size registration in lsm_prepare(), and
> debug log printing in security_init().
>
> Signed-off-by: Matt Bobrowski <mattbobrowski@google.com>
> ---
> include/linux/lsm_hooks.h | 42 ++++++++++++++++------------
> security/lsm_init.c | 59 ++++++++++-----------------------------
> 2 files changed, 38 insertions(+), 63 deletions(-)
>
> diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
> index b4f8cad53ddb..0e73b22bdeea 100644
> --- a/include/linux/lsm_hooks.h
> +++ b/include/linux/lsm_hooks.h
> @@ -98,28 +98,34 @@ struct security_hook_list {
> const struct lsm_id *lsmid;
> } __randomize_layout;
>
> +#define LSM_BLOBS_LIST(X) \
> + X(cred) \
> + X(file) \
> + X(backing_file) \
> + X(ib) \
> + X(inode) \
> + X(sock) \
> + X(superblock) \
> + X(ipc) \
> + X(key) \
> + X(msg_msg) \
> + X(perf_event) \
> + X(task) \
> + X(tun_dev) \
> + X(xattr_count) \
> + X(bdev) \
> + X(bpf_map) \
> + X(bpf_prog) \
> + X(bpf_token)
> +
> /*
> * Security blob size or offset data.
> + * Note: lbs_xattr_count is the number of xattr slots in new_xattrs array.
> */
> struct lsm_blob_sizes {
> - unsigned int lbs_cred;
> - unsigned int lbs_file;
> - unsigned int lbs_backing_file;
> - unsigned int lbs_ib;
> - unsigned int lbs_inode;
> - unsigned int lbs_sock;
> - unsigned int lbs_superblock;
> - unsigned int lbs_ipc;
> - unsigned int lbs_key;
> - unsigned int lbs_msg_msg;
> - unsigned int lbs_perf_event;
> - unsigned int lbs_task;
> - unsigned int lbs_xattr_count; /* num xattr slots in new_xattrs array */
> - unsigned int lbs_tun_dev;
> - unsigned int lbs_bdev;
> - unsigned int lbs_bpf_map;
> - unsigned int lbs_bpf_prog;
> - unsigned int lbs_bpf_token;
> +#define LSM_BLOB_SIZE(name) unsigned int lbs_##name;
> + LSM_BLOBS_LIST(LSM_BLOB_SIZE);
> +#undef LSM_BLOB_SIZE
> };
Generally speaking I greatly prefer to see the structure fields typed out
as it makes it easier to find them using grep, code indexers, etc. There
is a similar argument for the security_init() changes (below).
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index 7c0fd17f1601..c256f1c33efa 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -282,40 +282,24 @@ static void __init lsm_blob_size_update(unsigned int *sz_req,
> * lsm_prepare - Prepare the LSM framework for a new LSM
> * @lsm: LSM definition
> */
> -static void __init lsm_prepare(struct lsm_info *lsm)
> +static void __init lsm_prepare(const struct lsm_info *lsm)
> {
> struct lsm_blob_sizes *blobs = lsm->blobs;
>
> if (!blobs)
> return;
>
> - /* Register the LSM blob sizes. */
> - blobs = lsm->blobs;
> - lsm_blob_size_update(&blobs->lbs_cred, &blob_sizes.lbs_cred);
> - lsm_blob_size_update(&blobs->lbs_file, &blob_sizes.lbs_file);
> - lsm_blob_size_update(&blobs->lbs_backing_file,
> - &blob_sizes.lbs_backing_file);
> - lsm_blob_size_update(&blobs->lbs_ib, &blob_sizes.lbs_ib);
> - /* inode blob gets an rcu_head in addition to LSM blobs. */
> + /* The inode blob (inode->i_security) gets an rcu_head in addition to
> + * LSM blobs.
> + */
> if (blobs->lbs_inode && blob_sizes.lbs_inode == 0)
> blob_sizes.lbs_inode = sizeof(struct rcu_head);
> - lsm_blob_size_update(&blobs->lbs_inode, &blob_sizes.lbs_inode);
> - lsm_blob_size_update(&blobs->lbs_ipc, &blob_sizes.lbs_ipc);
> - lsm_blob_size_update(&blobs->lbs_key, &blob_sizes.lbs_key);
> - lsm_blob_size_update(&blobs->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
> - lsm_blob_size_update(&blobs->lbs_perf_event,
> - &blob_sizes.lbs_perf_event);
> - lsm_blob_size_update(&blobs->lbs_sock, &blob_sizes.lbs_sock);
> - lsm_blob_size_update(&blobs->lbs_superblock,
> - &blob_sizes.lbs_superblock);
> - lsm_blob_size_update(&blobs->lbs_task, &blob_sizes.lbs_task);
> - lsm_blob_size_update(&blobs->lbs_tun_dev, &blob_sizes.lbs_tun_dev);
> - lsm_blob_size_update(&blobs->lbs_xattr_count,
> - &blob_sizes.lbs_xattr_count);
> - lsm_blob_size_update(&blobs->lbs_bdev, &blob_sizes.lbs_bdev);
> - lsm_blob_size_update(&blobs->lbs_bpf_map, &blob_sizes.lbs_bpf_map);
> - lsm_blob_size_update(&blobs->lbs_bpf_prog, &blob_sizes.lbs_bpf_prog);
> - lsm_blob_size_update(&blobs->lbs_bpf_token, &blob_sizes.lbs_bpf_token);
> +
> + /* Register the LSM blob sizes. */
> +#define UPDATE_LSM_BLOB_SIZE(name) \
> + lsm_blob_size_update(&blobs->lbs_##name, &blob_sizes.lbs_##name);
> + LSM_BLOBS_LIST(UPDATE_LSM_BLOB_SIZE);
> +#undef UPDATE_LSM_BLOB_SIZE
> }
This is one case where the macro approach *might* have some value, but as
it is the one instance, and multiple sequential blob operations like this
are going to be *very* limited, I'm not sure there is enough value to
be worth the change.
I appreciate the initiative to search out areas that you think could use
improvement, but for the reasons mentioned, I'm not going to merge this
patch.
> @@ -441,25 +425,10 @@ int __init security_init(void)
> lsm_prepare(*lsm);
>
> if (lsm_debug) {
> - lsm_pr("blob(cred) size %d\n", blob_sizes.lbs_cred);
> - lsm_pr("blob(file) size %d\n", blob_sizes.lbs_file);
> - lsm_pr("blob(backing_file) size %d\n",
> - blob_sizes.lbs_backing_file);
> - lsm_pr("blob(ib) size %d\n", blob_sizes.lbs_ib);
> - lsm_pr("blob(inode) size %d\n", blob_sizes.lbs_inode);
> - lsm_pr("blob(ipc) size %d\n", blob_sizes.lbs_ipc);
> - lsm_pr("blob(key) size %d\n", blob_sizes.lbs_key);
> - lsm_pr("blob(msg_msg)_size %d\n", blob_sizes.lbs_msg_msg);
> - lsm_pr("blob(sock) size %d\n", blob_sizes.lbs_sock);
> - lsm_pr("blob(superblock) size %d\n", blob_sizes.lbs_superblock);
> - lsm_pr("blob(perf_event) size %d\n", blob_sizes.lbs_perf_event);
> - lsm_pr("blob(task) size %d\n", blob_sizes.lbs_task);
> - lsm_pr("blob(tun_dev) size %d\n", blob_sizes.lbs_tun_dev);
> - lsm_pr("blob(xattr) count %d\n", blob_sizes.lbs_xattr_count);
> - lsm_pr("blob(bdev) size %d\n", blob_sizes.lbs_bdev);
> - lsm_pr("blob(bpf_map) size %d\n", blob_sizes.lbs_bpf_map);
> - lsm_pr("blob(bpf_prog) size %d\n", blob_sizes.lbs_bpf_prog);
> - lsm_pr("blob(bpf_token) size %d\n", blob_sizes.lbs_bpf_token);
> +#define PRINT_LSM_BLOB_SIZE(name) \
> + lsm_pr("blob(" #name ") size %d\n", blob_sizes.lbs_##name);
> + LSM_BLOBS_LIST(PRINT_LSM_BLOB_SIZE);
> +#undef PRINT_LSM_BLOB_SIZE
This is another case where having the text string grep'able can be a good
thing.
--
paul-moore.com
^ permalink raw reply
* Re: [PATCH] security: clarify task_prctl hook documentation
From: Paul Moore @ 2026-07-02 18:59 UTC (permalink / raw)
To: Bill Roberts, James Morris, Serge E. Hallyn
Cc: casey, Bill Roberts, linux-security-module, linux-kernel
In-Reply-To: <20260615200325.260057-1-bill.roberts@arm.com>
On Jun 15, 2026 Bill Roberts <bill.roberts@arm.com> wrote:
>
> The task_prctl hook comment incorrectly described the hook as checking
> whether a prctl operation is allowed. In reality, the hook exists for
> LSMs to handle LSM-specific prctl operations.
>
> Update the function description and kernel-doc comment to reflect the
> actual behavior. The old wording appears to have been copied from other
> permission-check hooks despite differing semantics.
>
> Signed-off-by: Bill Roberts <bill.roberts@arm.com>
> Acked-by: Casey Schaufler <casey@schaufler-ca.com>
> Reviewed-by: Serge Hallyn <serge@hallyn.com>
> ---
> security/security.c | 5 ++---
> 1 file changed, 2 insertions(+), 3 deletions(-)
Good catch, thanks! Merged into lsm/dev.
--
paul-moore.com
^ permalink raw reply
* Re: [PATCH bpf-next v3 1/6] bpf: Resolve and cache fd_array objects at load time
From: Anton Protopopov @ 2026-07-02 19:06 UTC (permalink / raw)
To: Daniel Borkmann
Cc: ast, kpsingh, James.Bottomley, paul, bboscaccy, memxor, torvalds,
bpf, linux-security-module
In-Reply-To: <20260702143605.252797-2-daniel@iogearbox.net>
On 26/07/02 04:36PM, Daniel Borkmann wrote:
> The fd_array passed to BPF_PROG_LOAD carries the map and module BTF file
> descriptors a program binds. The verifier reads it more than once during
> a load: process_fd_array() walks it to bind the maps and BTFs, and
> check_and_resolve_insns() and the kfunc BTF resolver later read it again
> to resolve the program's BPF_PSEUDO_MAP_IDX and module kfunc refs.
>
> For signed BPF, we need these upfront in memory, thus resolve each fd to
> its object once and cache it by fd_array index, then bind that cached
> object for the rest of the load. env->fd_array becomes a small per-slot
> {map, btf} cache rather than a bpfptr_t; every later reference is then
> an in-bounds lookup of an already-resolved object, and an index outside
> the cache is rejected instead of read from user memory:
>
> - continuous (fd_array_cnt given): the caller declares the length and
> every entry is resolved and bound up front (used also by signed loader)
>
> - sparse (no fd_array_cnt): left as the legacy path with no fd_array
> cache; each reference reads its fd from the caller's fd_array and
> resolves it on the spot. Deduplication in used_maps and the kfunc BTF
> table keeps this correct, and only unsigned programs use this shape.
>
> UAPI-wise nothing changes, its just the internals on how BPF processes
> and caches the fd_array favors. Split these into separate helpers for
> continuous versus sparse to make it easier to follow.
Overall looks ok. A few comments below.
> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
> Cc: Anton Protopopov <a.s.protopopov@gmail.com>
> ---
> include/linux/bpf_verifier.h | 22 +++-
> kernel/bpf/verifier.c | 209 ++++++++++++++++++++++++++---------
> 2 files changed, 179 insertions(+), 52 deletions(-)
>
> diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
> index 76b8b7627a10..9f0a4e9a15d7 100644
> --- a/include/linux/bpf_verifier.h
> +++ b/include/linux/bpf_verifier.h
> @@ -898,6 +898,14 @@ struct bpf_scc_info {
>
> struct bpf_liveness;
>
> +struct bpf_fd_array {
> + union {
> + struct bpf_map *map;
> + struct btf *btf;
> + unsigned long val;
> + };
> +};
> +
> /* single container for all structs
> * one verifier_env per bpf_check() call
> */
> @@ -989,7 +997,19 @@ struct bpf_verifier_env {
> u32 free_list_size;
> u32 explored_states_size;
> u32 num_backedges;
> - bpfptr_t fd_array;
> + /*
> + * The program's fd_array comes in two shapes, told apart by whether
> + * the caller passed fd_array_cnt. They are mutually exclusive:
> + * - continuous (fd_array_cnt given): ->fd_array holds every entry
> + * resolved to its object up front, indexed by fd_array position,
> + * with ->fd_array_cnt slots; ->fd_array_raw is unused.
> + * - sparse (no fd_array_cnt): ->fd_array is NULL, and entries are
> + * read from ->fd_array_raw (the caller's fd_array) and resolved
> + * lazily on first reference.
> + */
> + struct bpf_fd_array *fd_array;
> + u32 fd_array_cnt;
> + bpfptr_t fd_array_raw;
>
> /* bit mask to keep track of whether a register has been accessed
> * since the last time the function state was printed
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 25aea4271cd0..44bb6ce17a1c 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -2490,6 +2490,79 @@ int bpf_get_kfunc_addr(const struct bpf_prog *prog, u32 func_id,
> return 0;
> }
>
> +#define BPF_FD_SLOT_BTF 1UL
> +
> +static void fd_slot_set_map(struct bpf_fd_array *slot, struct bpf_map *map)
> +{
> + slot->val = (unsigned long)map;
> +}
> +
> +static void fd_slot_set_btf(struct bpf_fd_array *slot, struct btf *btf)
> +{
> + slot->val = (unsigned long)btf | BPF_FD_SLOT_BTF;
> +}
> +
> +static struct bpf_map *fd_slot_map(struct bpf_fd_array slot)
> +{
> + if (slot.val & BPF_FD_SLOT_BTF)
> + return NULL;
> + return (struct bpf_map *)slot.val;
> +}
> +
> +static struct btf *fd_slot_btf(struct bpf_fd_array slot)
> +{
> + if (!(slot.val & BPF_FD_SLOT_BTF))
> + return NULL;
> + return (struct btf *)(slot.val & ~BPF_FD_SLOT_BTF);
> +}
> +
> +static struct btf *
> +fd_array_get_btf_continuous(struct bpf_verifier_env *env, u32 idx)
> +{
> + struct btf *btf;
> +
> + if (idx >= env->fd_array_cnt) {
> + verbose(env, "kfunc fd_idx %u out of bounds, fd_array_cnt %u\n",
> + idx, env->fd_array_cnt);
> + return ERR_PTR(-EINVAL);
> + }
> + btf = fd_slot_btf(env->fd_array[idx]);
> + if (!btf) {
> + verbose(env, "kfunc fd_idx %u is not a module BTF\n", idx);
> + return ERR_PTR(-EINVAL);
> + }
> + btf_get(btf);
> + return btf;
> +}
> +
> +static struct btf *
> +fd_array_get_btf_sparse(struct bpf_verifier_env *env, u32 idx)
> +{
> + struct btf *btf;
> + int btf_fd;
> +
> + if (copy_from_bpfptr_offset(&btf_fd, env->fd_array_raw,
> + (size_t)idx * sizeof(btf_fd), sizeof(btf_fd)))
> + return ERR_PTR(-EFAULT);
> + btf = btf_get_by_fd(btf_fd);
> + if (IS_ERR(btf)) {
> + verbose(env, "invalid module BTF fd specified\n");
> + return btf;
> + }
> + return btf;
> +}
> +
> +static struct btf *fd_array_get_btf(struct bpf_verifier_env *env, u32 idx)
> +{
> + if (env->fd_array)
> + return fd_array_get_btf_continuous(env, idx);
> + if (!bpfptr_is_null(env->fd_array_raw))
> + return fd_array_get_btf_sparse(env, idx);
> +
> + verbose(env, "kfunc offset > 0 without fd_array is invalid\n");
> + return ERR_PTR(-EPROTO);
> +}
> +
> static struct btf *__find_kfunc_desc_btf(struct bpf_verifier_env *env,
> s16 offset)
> {
> @@ -2498,7 +2571,6 @@ static struct btf *__find_kfunc_desc_btf(struct bpf_verifier_env *env,
> struct bpf_kfunc_btf *b;
> struct module *mod;
> struct btf *btf;
> - int btf_fd;
>
> tab = env->prog->aux->kfunc_btf_tab;
> b = bsearch(&kf_btf, tab->descs, tab->nr_descs,
> @@ -2509,22 +2581,9 @@ static struct btf *__find_kfunc_desc_btf(struct bpf_verifier_env *env,
> return ERR_PTR(-E2BIG);
> }
>
> - if (bpfptr_is_null(env->fd_array)) {
> - verbose(env, "kfunc offset > 0 without fd_array is invalid\n");
> - return ERR_PTR(-EPROTO);
> - }
> -
> - if (copy_from_bpfptr_offset(&btf_fd, env->fd_array,
> - offset * sizeof(btf_fd),
> - sizeof(btf_fd)))
> - return ERR_PTR(-EFAULT);
> -
> - btf = btf_get_by_fd(btf_fd);
> - if (IS_ERR(btf)) {
> - verbose(env, "invalid module BTF fd specified\n");
> + btf = fd_array_get_btf(env, offset);
> + if (IS_ERR(btf))
> return btf;
> - }
> -
> if (!btf_is_module(btf)) {
> verbose(env, "BTF fd for kfunc is not a module BTF\n");
> btf_put(btf);
> @@ -17911,6 +17970,44 @@ static int add_used_map(struct bpf_verifier_env *env, int fd)
> return __add_used_map(env, map);
> }
>
> +static int fd_array_get_map_idx_continuous(struct bpf_verifier_env *env, u32 idx)
> +{
> + struct bpf_map *map;
> +
> + if (idx >= env->fd_array_cnt) {
> + verbose(env, "fd_idx %u out of bounds, fd_array_cnt %u\n",
> + idx, env->fd_array_cnt);
> + return -EINVAL;
> + }
> + map = fd_slot_map(env->fd_array[idx]);
> + if (!map) {
> + verbose(env, "fd_idx %u is not a map\n", idx);
> + return -EINVAL;
> + }
> + return __add_used_map(env, map);
> +}
> +
> +static int fd_array_get_map_idx_sparse(struct bpf_verifier_env *env, u32 idx)
> +{
> + int fd;
> +
> + if (copy_from_bpfptr_offset(&fd, env->fd_array_raw,
> + (size_t)idx * sizeof(fd), sizeof(fd)))
> + return -EFAULT;
> + return add_used_map(env, fd);
> +}
> +
> +static int fd_array_get_map_idx(struct bpf_verifier_env *env, u32 idx)
> +{
> + if (env->fd_array)
> + return fd_array_get_map_idx_continuous(env, idx);
> + if (!bpfptr_is_null(env->fd_array_raw))
> + return fd_array_get_map_idx_sparse(env, idx);
> +
> + verbose(env, "fd_idx without fd_array is invalid\n");
> + return -EPROTO;
> +}
> +
> static int check_alu_fields(struct bpf_verifier_env *env, struct bpf_insn *insn)
> {
> u8 class = BPF_CLASS(insn->code);
> @@ -18128,7 +18225,6 @@ static int check_and_resolve_insns(struct bpf_verifier_env *env)
> struct bpf_map *map;
> int map_idx;
> u64 addr;
> - u32 fd;
>
> if (i == insn_cnt - 1 || insn[1].code != 0 ||
> insn[1].dst_reg != 0 || insn[1].src_reg != 0 ||
> @@ -18180,21 +18276,13 @@ static int check_and_resolve_insns(struct bpf_verifier_env *env)
> switch (insn[0].src_reg) {
> case BPF_PSEUDO_MAP_IDX_VALUE:
> case BPF_PSEUDO_MAP_IDX:
> - if (bpfptr_is_null(env->fd_array)) {
> - verbose(env, "fd_idx without fd_array is invalid\n");
> - return -EPROTO;
> - }
> - if (copy_from_bpfptr_offset(&fd, env->fd_array,
> - insn[0].imm * sizeof(fd),
> - sizeof(fd)))
> - return -EFAULT;
> + map_idx = fd_array_get_map_idx(env, insn[0].imm);
> break;
> default:
> - fd = insn[0].imm;
> + map_idx = add_used_map(env, insn[0].imm);
> break;
> }
>
> - map_idx = add_used_map(env, fd);
> if (map_idx < 0)
> return map_idx;
> map = env->used_maps[map_idx];
> @@ -19469,7 +19557,7 @@ struct btf *bpf_get_btf_vmlinux(void)
> * this case expect that every file descriptor in the array is either a map or
> * a BTF. Everything else is considered to be trash.
> */
> -static int add_fd_from_fd_array(struct bpf_verifier_env *env, int fd)
> +static int add_fd_from_fd_array(struct bpf_verifier_env *env, u32 idx, int fd)
> {
> struct bpf_map *map;
> struct btf *btf;
> @@ -19481,51 +19569,69 @@ static int add_fd_from_fd_array(struct bpf_verifier_env *env, int fd)
> err = __add_used_map(env, map);
> if (err < 0)
> return err;
> + fd_slot_set_map(&env->fd_array[idx], map);
> return 0;
> }
>
> btf = __btf_get_by_fd(f);
> if (!IS_ERR(btf)) {
> btf_get(btf);
> - return __add_used_btf(env, btf);
> + err = __add_used_btf(env, btf);
> + if (err < 0)
> + return err;
> + fd_slot_set_btf(&env->fd_array[idx], btf);
> + return 0;
> }
>
> verbose(env, "fd %d is not pointing to valid bpf_map or btf\n", fd);
> return PTR_ERR(map);
> }
>
> -static int process_fd_array(struct bpf_verifier_env *env, union bpf_attr *attr, bpfptr_t uattr)
> +#define MAX_FD_ARRAY_CNT (MAX_USED_MAPS + MAX_KFUNC_BTFS)
> +
> +static int process_fd_array_continuous(struct bpf_verifier_env *env,
> + bpfptr_t fd_array, u32 cnt)
> {
> - size_t size = sizeof(int);
> - int ret;
> - int fd;
> + int fd, ret;
> u32 i;
>
> - env->fd_array = make_bpfptr(attr->fd_array, uattr.is_kernel);
> -
> - /*
> - * The only difference between old (no fd_array_cnt is given) and new
> - * APIs is that in the latter case the fd_array is expected to be
> - * continuous and is scanned for map fds right away
> - */
> - if (!attr->fd_array_cnt)
> - return 0;
> -
> - /* Check for integer overflow */
> - if (attr->fd_array_cnt >= (U32_MAX / size)) {
> - verbose(env, "fd_array_cnt is too big (%u)\n", attr->fd_array_cnt);
> - return -EINVAL;
> + if (cnt > MAX_FD_ARRAY_CNT) {
So, I _think_ I've done the "unlimited" thing because there can be duplicates
in fd_array. The limit is actually tracked by __add_{map_btf} So here we hard
limit on the size of the fd_array itself. (Even without duplicates, this
fd_array can contain, say, MAX_KFUNC_BTFS different maps, which will be in any
case rejected by __add_used_map.)
> + verbose(env, "fd_array has too many entries (%u, max %u)\n",
> + cnt, MAX_FD_ARRAY_CNT);
> + return -E2BIG;
> }
>
> - for (i = 0; i < attr->fd_array_cnt; i++) {
> - if (copy_from_bpfptr_offset(&fd, env->fd_array, i * size, size))
> + env->fd_array = kvcalloc(cnt, sizeof(*env->fd_array), GFP_KERNEL);
> + if (!env->fd_array)
> + return -ENOMEM;
> + env->fd_array_cnt = cnt;
> + for (i = 0; i < cnt; i++) {
> + if (copy_from_bpfptr_offset(&fd, fd_array,
> + (size_t)i * sizeof(fd), sizeof(fd)))
> return -EFAULT;
> -
> - ret = add_fd_from_fd_array(env, fd);
> + ret = add_fd_from_fd_array(env, i, fd);
> if (ret)
> return ret;
> }
> + return 0;
> +}
>
> +static int process_fd_array(struct bpf_verifier_env *env,
> + union bpf_attr *attr, bpfptr_t uattr)
> +{
> + bpfptr_t fd_array = make_bpfptr(attr->fd_array, uattr.is_kernel);
> +
> + if (bpfptr_is_null(fd_array))
> + return 0;
> + /*
> + * New API: the caller passes fd_array_cnt and a continuous array that
> + * is resolved and bound up front. Legacy API (no fd_array_cnt): keep
> + * the caller's array and resolve entries lazily, on first reference.
> + */
> + if (attr->fd_array_cnt)
> + return process_fd_array_continuous(env, fd_array,
> + attr->fd_array_cnt);
Looks like this returns success in case (!fd_array && attr->fd_array_cnt),
which is a misconfiguration and should be rejected.
> + env->fd_array_raw = fd_array;
> return 0;
> }
>
> @@ -20027,6 +20133,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr,
> bpf_clear_insn_aux_data(env, 0, env->prog->len);
> vfree(env->insn_aux_data);
> err_free_env:
> + kvfree(env->fd_array);
> bpf_stack_liveness_free(env);
> kvfree(env->cfg.insn_postorder);
> kvfree(env->scc_info);
> --
> 2.43.0
>
^ permalink raw reply
* Re: [PATCH v6 1/4] security: lsm: allow LSMs to register for late_initcall_sync init
From: Paul Moore @ 2026-07-02 18:36 UTC (permalink / raw)
To: Yeoreum Yun, zohar
Cc: linux-security-module, linux-kernel, linux-integrity,
roberto.sassu, noodles, jarkko, sudeep.holla, jmorris, serge,
dmitry.kasatkin, eric.snowberg, jgg
In-Reply-To: <20260605144325.434436-2-yeoreum.yun@arm.com>
On Fri, Jun 5, 2026 at 10:43 AM Yeoreum Yun <yeoreum.yun@arm.com> wrote:
>
> There are situations where LSMs have dependencies that might mean they
> want to be initialised later in the boot process, to ensure those
> dependencies are available. In particular there are some TPM setups (Arm
> FF-A devices, SPI attached TPMs) required by IMA which are not
> guaranteed to be initialised for regular initcall_late.
>
> Add an initcall_late_sync option that can be used in these situations.
>
> Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
> ---
> include/linux/lsm_hooks.h | 2 ++
> security/lsm_init.c | 13 +++++++++++--
> 2 files changed, 13 insertions(+), 2 deletions(-)
Looks good to me, thanks for working on sorting this out.
Acked-by: Paul Moore <paul@paul-moore.com>
--
paul-moore.com
^ permalink raw reply
* [PATCH v3] hardening: Default randstruct off with rust for better allmodconfig support
From: Mark Brown @ 2026-07-02 17:37 UTC (permalink / raw)
To: Kees Cook, Gustavo A. R. Silva, Paul Moore, James Morris,
Serge E. Hallyn, Miguel Ojeda, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich
Cc: linux-hardening, linux-security-module, linux-kernel,
rust-for-linux, Mark Brown
Currently randstruct does not support rust so we have Kconfig dependencies
which prevent rust being enabled when randstruct is. Unfortunately this
prevents rust being enabled in allmodconfig, our standard coverage build.
randstruct gets turned on by default, then the dependency on !RANDSTRUCT
causes rust to get disabled.
Work around this by disabling randstruct by default if we have a usable
rust toolchain and rust support for the architecture, circular
dependencies prevent us directly depending on !RUST. This means we might
end up with a configuration that disables both rust and randstruct but
hopefully it's more likely go give the expected result.
Signed-off-by: Mark Brown <broonie@kernel.org>
---
Changes in v3:
- Rebase onto v7.2-rc1.
- Link to v2: https://patch.msgid.link/20260605-rust-reverse-randstruct-dep-v2-1-93d38023b6f9@kernel.org
Changes in v2:
- Add a HAVE_RUST in there too.
- Link to v1: https://patch.msgid.link/20260605-rust-reverse-randstruct-dep-v1-1-45ce9ee8d0d1@kernel.org
---
security/Kconfig.hardening | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/security/Kconfig.hardening b/security/Kconfig.hardening
index 6923036e1a2f..81c81ad983ad 100644
--- a/security/Kconfig.hardening
+++ b/security/Kconfig.hardening
@@ -278,7 +278,7 @@ config CC_HAS_RANDSTRUCT
choice
prompt "Randomize layout of sensitive kernel structures"
- default RANDSTRUCT_FULL if COMPILE_TEST && (GCC_PLUGINS || CC_HAS_RANDSTRUCT)
+ default RANDSTRUCT_FULL if !(RUST_IS_AVAILABLE && HAVE_RUST) && COMPILE_TEST && (GCC_PLUGINS || CC_HAS_RANDSTRUCT)
default RANDSTRUCT_NONE
help
If you enable this, the layouts of structures that are entirely
---
base-commit: dc59e4fea9d83f03bad6bddf3fa2e52491777482
change-id: 20260605-rust-reverse-randstruct-dep-5a504c861128
Best regards,
--
Mark Brown <broonie@kernel.org>
^ permalink raw reply related
* Re: [PATCH -next] lockdown: Add break in lockdown_write
From: Paul Moore @ 2026-07-02 16:50 UTC (permalink / raw)
To: Xiu Jianfeng, nicolas.bouchinet
Cc: Cai Xinchen, jmorris, serge, linux-security-module, linux-kernel
In-Reply-To: <CAHC9VhRokERQGaB-1Xf0AoAzmT5tys4d+e4pmVY-W-88GQ8Jpg@mail.gmail.com>
On Thu, Jan 22, 2026 at 12:41 PM Paul Moore <paul@paul-moore.com> wrote:
>
> On Thu, Jan 22, 2026 at 4:31 AM Xiu Jianfeng <xiujianfeng@huawei.com> wrote:
> > On 1/19/2026 5:12 PM, Cai Xinchen wrote:
> > > After the label is matched successful, any other levels judgements
> > > are meaningless. Therefore, add break to return early
> > >
> > > Signed-off-by: Cai Xinchen <caixinchen1@huawei.com>
> >
> > Looks good to me, thanks.
> >
> > Acked-by: Xiu Jianfeng <xiujianfeng@huawei.com>
> >
> > Paul,
> >
> > Would you mind if this patch went through the LSM tree? :)
>
> Assuming Nicolas is okay with that, I can take this through the LSM tree.
Following up on this as I never saw a response on-list and the patch
doesn't appear to be in Linus' tree.
--
paul-moore.com
^ permalink raw reply
* Re: [PATCH v3 4/5] xfs: replace ns_capable_noaudit
From: Darrick J. Wong @ 2026-07-02 15:58 UTC (permalink / raw)
To: cem
Cc: Jan Kara, Christoph Hellwig, Serge E. Hallyn, Dave Chinner,
Eric Sandeen, linux-xfs, linux-fsdevel, linux-security-module,
linux-kernel
In-Reply-To: <20260702093324.127450-9-cem@kernel.org>
On Thu, Jul 02, 2026 at 11:33:23AM +0200, cem@kernel.org wrote:
> From: Carlos Maiolino <cem@kernel.org>
>
> Now that capable_noaudit() is available, we don't need to keep
> using ns_capable_noaudit() and specifying the usernaspace every single
> time.
>
> Signed-off-by: Carlos Maiolino <cmaiolino@redhat.com>
> Cc: Jan Kara <jack@suse.cz>
> Cc: Christoph Hellwig <hch@lst.de>
> Cc: Serge E. Hallyn <serge@hallyn.com>
> Cc: Darrick J. Wong <djwong@kernel.org>
> Cc: Dave Chinner <david@fromorbit.com>
> Cc: Eric Sandeen <sandeen@redhat.com>
> Cc: Dr. Thomas Orgis" <thomas.orgis@uni-hamburg.de>
> Cc: linux-xfs@vger.kernel.org
> Cc: linux-fsdevel@vger.kernel.org
> Cc: linux-security-module@vger.kernel.org
> Cc: linux-kernel@vger.kernel.org
> ---
> fs/xfs/xfs_fsmap.c | 3 +--
> fs/xfs/xfs_ioctl.c | 2 +-
> fs/xfs/xfs_iops.c | 2 +-
> 3 files changed, 3 insertions(+), 4 deletions(-)
>
> diff --git a/fs/xfs/xfs_fsmap.c b/fs/xfs/xfs_fsmap.c
> index 7c79fbe0a74c..041bb2105ec6 100644
> --- a/fs/xfs/xfs_fsmap.c
> +++ b/fs/xfs/xfs_fsmap.c
> @@ -1174,8 +1174,7 @@ xfs_getfsmap(
> if (!xfs_getfsmap_check_keys(&head->fmh_keys[0], &head->fmh_keys[1]))
> return -EINVAL;
>
> - use_rmap = xfs_has_rmapbt(mp) &&
> - ns_capable_noaudit(&init_user_ns, CAP_SYS_ADMIN);
> + use_rmap = xfs_has_rmapbt(mp) && capable_noaudit(CAP_SYS_ADMIN);
> head->fmh_entries = 0;
>
> /* Set up our device handlers. */
> diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
> index 1a8af827dde1..374b488f0416 100644
> --- a/fs/xfs/xfs_ioctl.c
> +++ b/fs/xfs/xfs_ioctl.c
> @@ -647,7 +647,7 @@ xfs_ioctl_setattr_get_trans(
> goto out_error;
>
> error = xfs_trans_alloc_ichange(ip, NULL, NULL, pdqp,
> - ns_capable_noaudit(&init_user_ns, CAP_FOWNER), &tp);
> + capable_noaudit(CAP_FOWNER), &tp);
Not sure why the indentation changed, otherwise the patch looks fine to
me.
--D
> if (error)
> goto out_error;
>
> diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
> index 205fe2dae732..ce9f8b8468fc 100644
> --- a/fs/xfs/xfs_iops.c
> +++ b/fs/xfs/xfs_iops.c
> @@ -835,7 +835,7 @@ xfs_setattr_nonsize(
> }
>
> error = xfs_trans_alloc_ichange(ip, udqp, gdqp, NULL,
> - ns_capable_noaudit(&init_user_ns, CAP_FOWNER),
> + capable_noaudit(CAP_FOWNER),
> &tp);
> if (error)
> goto out_dqrele;
> --
> 2.54.0
>
>
^ permalink raw reply
* Re: [PATCH v3 2/5] capability: Add new capable_noaudit
From: Darrick J. Wong @ 2026-07-02 15:56 UTC (permalink / raw)
To: cem
Cc: Jan Kara, Dave Chinner, Eric Sandeen, linux-xfs, linux-fsdevel,
linux-security-module, linux-kernel, Christoph Hellwig,
Serge Hallyn
In-Reply-To: <20260702093324.127450-5-cem@kernel.org>
On Thu, Jul 02, 2026 at 11:33:19AM +0200, cem@kernel.org wrote:
> From: Carlos Maiolino <cem@kernel.org>
>
> In some situations (quota enforcement bypass in this case) we'd like to
> check for a specific capability without triggering spurious audit
> messages from security modules like selinux.
>
> Add a new helper so we don't need to use ns_capable_noaudit() directly.
>
> V3: remove the extern declaration
>
> Signed-off-by: Carlos Maiolino <cmaiolino@redhat.com>
> Cc: Jan Kara <jack@suse.cz>
> Cc: Darrick J. Wong <djwong@kernel.org>
> Cc: Dave Chinner <david@fromorbit.com>
> Cc: Eric Sandeen <sandeen@redhat.com>
> Cc: Dr. Thomas Orgis" <thomas.orgis@uni-hamburg.de>
> Cc: linux-xfs@vger.kernel.org
> Cc: linux-fsdevel@vger.kernel.org
> Cc: linux-security-module@vger.kernel.org
> Cc: linux-kernel@vger.kernel.org
> Reviewed-by: Christoph Hellwig <hch@lst.de>
> Reviewed-by: Serge Hallyn <serge@hallyn.com>
> ---
> include/linux/capability.h | 5 +++++
> kernel/capability.c | 17 +++++++++++++++++
> 2 files changed, 22 insertions(+)
>
> diff --git a/include/linux/capability.h b/include/linux/capability.h
> index 37db92b3d6f8..f8532d92fcad 100644
> --- a/include/linux/capability.h
> +++ b/include/linux/capability.h
> @@ -145,6 +145,7 @@ extern bool has_capability_noaudit(struct task_struct *t, int cap);
> extern bool has_ns_capability_noaudit(struct task_struct *t,
> struct user_namespace *ns, int cap);
> extern bool capable(int cap);
> +bool capable_noaudit(int cap);
> extern bool ns_capable(struct user_namespace *ns, int cap);
> extern bool ns_capable_noaudit(struct user_namespace *ns, int cap);
> extern bool ns_capable_setid(struct user_namespace *ns, int cap);
> @@ -167,6 +168,10 @@ static inline bool capable(int cap)
> {
> return true;
> }
> +static inline bool capable_noaudit(int cap)
> +{
> + return true;
> +}
> static inline bool ns_capable(struct user_namespace *ns, int cap)
> {
> return true;
> diff --git a/kernel/capability.c b/kernel/capability.c
> index 829f49ae07b9..2c2d1e8300bd 100644
> --- a/kernel/capability.c
> +++ b/kernel/capability.c
> @@ -416,6 +416,23 @@ bool capable(int cap)
> return ns_capable(&init_user_ns, cap);
> }
> EXPORT_SYMBOL(capable);
> +
> +/**
> + * capable_noaudit - Determine if the current task has a superior
> + * capability in effect (unaudited).
> + * @cap: The capability to be tested for
> + *
> + * This is the same as capable(), except it uses CAP_OPT_NOAUDIT as to prevent
> + * issuing spurious audit messages.
> + *
> + * This sets PF_SUPERPRIV on the task if the capability is available on the
> + * assumption that it's about to be used.
Same complaint about the documentation as last time:
https://lore.kernel.org/linux-fsdevel/20260626151656.GT6078@frogsfrogsfrogs/
--D
> + */
> +bool capable_noaudit(int cap)
> +{
> + return ns_capable_noaudit(&init_user_ns, cap);
> +}
> +EXPORT_SYMBOL(capable_noaudit);
> #endif /* CONFIG_MULTIUSER */
>
> /**
> --
> 2.54.0
>
>
^ permalink raw reply
* Re: [PATCH bpf-next v3 5/6] selftests/bpf: Verify load-time signed loader metadata
From: Daniel Borkmann @ 2026-07-02 15:28 UTC (permalink / raw)
To: bot+bpf-ci, ast
Cc: kpsingh, James.Bottomley, paul, bboscaccy, memxor, torvalds,
a.s.protopopov, bpf, linux-security-module, andrii, martin.lau,
eddyz87, yonghong.song, clm, ihor.solodrai
In-Reply-To: <038b4c7b60a311cb9905bc88e7f27e6846e9578413afa4b902b0684f44dfd980@mail.kernel.org>
On 7/2/26 5:17 PM, bot+bpf-ci@kernel.org wrote:
[...]
>> +cleanup:
>> + if (btf)
>> + btf__free(btf);
>> + if (map_fd >= 0)
>> + close(map_fd);
>
> This isn't a bug, but was map_fd meant to be dropped from this test?
> It's initialized to -1 and never changed, so the cleanup branch is
> unreachable. The sibling tests signed_map_by_fd_rejected and
> signed_sparse_fd_array_rejected create and close a map_fd, but
> signed_module_kfunc_rejected only uses BTF fds and never assigns
> map_fd.
Ack, will clean up in a v4.
^ 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