* [PATCH] ima: don't clear IMA_DIGSIG flag when setting non-IMA xattr
From: Coiby Xu @ 2025-09-02 4:25 UTC (permalink / raw)
To: linux-integrity
Cc: Mimi Zohar, Roberto Sassu, Dmitry Kasatkin, Eric Snowberg,
Paul Moore, James Morris, Serge E. Hallyn,
open list:SECURITY SUBSYSTEM, open list
Currently when both IMA and EVM are in fix mode, the IMA signature will
be reset to IMA hash if a program first stores IMA signature in
security.ima and then sets security.selinux for a file. For example, on
Fedora, after booting the kernel with "ima_appraise=fix evm=fix
ima_policy=appraise_tcb" and installing rpm-plugin-ima, reinstalling a
package will not make good reference IMA signature generated. Instead
IMA hash is generated,
# getfattr -m - -d -e hex /usr/bin/bash
# file: usr/bin/bash
security.ima=0x0404...
This happens because when setting selinux.selinux, the IMA_DIGSIG flag
that had been set early was cleared. As a result, IMA hash is generated
when the file is closed.
Here's a minimal C reproducer,
#include <stdio.h>
#include <sys/xattr.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main() {
const char* file_path = "/usr/sbin/test_binary";
const char* hex_string = "030204d33204490066306402304";
int length = strlen(hex_string);
char* ima_attr_value;
int fd;
fd = open(file_path, O_WRONLY|O_CREAT|O_EXCL, 0644);
if (fd == -1) {
perror("Error opening file");
return 1;
}
ima_attr_value = (char*)malloc(length / 2 );
for (int i = 0, j = 0; i < length; i += 2, j++) {
sscanf(hex_string + i, "%2hhx", &ima_attr_value[j]);
}
if (fsetxattr(fd, "security.ima", ima_attr_value, length/2, 0) == -1) {
perror("Error setting extended attribute");
close(fd);
return 1;
}
const char* selinux_value= "system_u:object_r:bin_t:s0";
if (fsetxattr(fd, "security.selinux", selinux_value, strlen(selinux_value), 0) == -1) {
perror("Error setting extended attribute");
close(fd);
return 1;
}
close(fd);
return 0;
}
Signed-off-by: Coiby Xu <coxu@redhat.com>
---
security/integrity/ima/ima_appraise.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index f435eff4667f..fc82161f8b30 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -708,7 +708,7 @@ static void ima_reset_appraise_flags(struct inode *inode, int digsig)
set_bit(IMA_CHANGE_XATTR, &iint->atomic_flags);
if (digsig)
set_bit(IMA_DIGSIG, &iint->atomic_flags);
- else
+ else if (digsig != -1)
clear_bit(IMA_DIGSIG, &iint->atomic_flags);
}
@@ -794,6 +794,8 @@ static int ima_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
digsig = (xvalue->type == EVM_IMA_XATTR_DIGSIG);
} else if (!strcmp(xattr_name, XATTR_NAME_EVM) && xattr_value_len > 0) {
digsig = (xvalue->type == EVM_XATTR_PORTABLE_DIGSIG);
+ } else if (result != 1) {
+ digsig = -1;
}
if (result == 1 || evm_revalidate_status(xattr_name)) {
ima_reset_appraise_flags(d_backing_inode(dentry), digsig);
--
2.51.0
^ permalink raw reply related
* Re: [PATCH v2 3/4] arch: copy_thread: pass clone_flags as u64
From: Andreas Larsson @ 2025-09-02 7:02 UTC (permalink / raw)
To: schuster.simon, Dinh Nguyen, Christian Brauner, Arnd Bergmann,
Andrew Morton, David Hildenbrand, Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Ingo Molnar, Peter Zijlstra,
Juri Lelli, Vincent Guittot, Dietmar Eggemann, Steven Rostedt,
Ben Segall, Mel Gorman, Valentin Schneider, Kees Cook,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Guo Ren, Oleg Nesterov, Jens Axboe, Alexander Viro, Jan Kara,
Tejun Heo, Johannes Weiner, Michal Koutný, Paul Moore,
Serge Hallyn, James Morris, Serge E. Hallyn, Anna-Maria Behnsen,
Frederic Weisbecker, Thomas Gleixner, Masami Hiramatsu,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Mathieu Desnoyers, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, John Johansen, Stephen Smalley,
Ondrej Mosnacek, Kentaro Takeda, Tetsuo Handa, Richard Henderson,
Matt Turner, Vineet Gupta, Russell King, Catalin Marinas,
Will Deacon, Brian Cain, Huacai Chen, WANG Xuerui,
Geert Uytterhoeven, Michal Simek, Thomas Bogendoerfer, Jonas Bonn,
Stefan Kristiansson, Stafford Horne, James E.J. Bottomley,
Helge Deller, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Christophe Leroy, Heiko Carstens, Vasily Gorbik,
Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
Yoshinori Sato, Rich Felker, John Paul Adrian Glaubitz,
Richard Weinberger, Anton Ivanov, Johannes Berg, Borislav Petkov,
Dave Hansen, x86, H. Peter Anvin, Chris Zankel, Max Filippov
Cc: linux-mm, linux-kernel, linux-riscv, linux-csky, linux-block,
linux-fsdevel, cgroups, linux-security-module, linux-trace-kernel,
netdev, linux-perf-users, apparmor, selinux, linux-alpha,
linux-snps-arc, linux-arm-kernel, linux-hexagon, loongarch,
linux-m68k, linux-mips, linux-openrisc, linux-parisc,
linuxppc-dev, linux-s390, linux-sh, sparclinux, linux-um
In-Reply-To: <20250901-nios2-implement-clone3-v2-3-53fcf5577d57@siemens-energy.com>
On 2025-09-01 15:09, Simon Schuster via B4 Relay wrote:
> From: Simon Schuster <schuster.simon@siemens-energy.com>
>
> With the introduction of clone3 in commit 7f192e3cd316 ("fork: add
> clone3") the effective bit width of clone_flags on all architectures was
> increased from 32-bit to 64-bit, with a new type of u64 for the flags.
> However, for most consumers of clone_flags the interface was not
> changed from the previous type of unsigned long.
>
> While this works fine as long as none of the new 64-bit flag bits
> (CLONE_CLEAR_SIGHAND and CLONE_INTO_CGROUP) are evaluated, this is still
> undesirable in terms of the principle of least surprise.
>
> Thus, this commit fixes all relevant interfaces of the copy_thread
> function that is called from copy_process to consistently pass
> clone_flags as u64, so that no truncation to 32-bit integers occurs on
> 32-bit architectures.
>
> Signed-off-by: Simon Schuster <schuster.simon@siemens-energy.com>
> ---
Thanks for this and for the whole series! Needed foundation for a
sparc32 clone3 implementation as well.
> arch/sparc/kernel/process_32.c | 2 +-
> arch/sparc/kernel/process_64.c | 2 +-
Acked-by: Andreas Larsson <andreas@gaisler.com> # sparc
Cheers,
Andreas
^ permalink raw reply
* Re: [PATCH v2 3/4] arch: copy_thread: pass clone_flags as u64
From: John Paul Adrian Glaubitz @ 2025-09-02 7:15 UTC (permalink / raw)
To: Andreas Larsson, schuster.simon, Dinh Nguyen, Christian Brauner,
Arnd Bergmann, Andrew Morton, David Hildenbrand, Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Ingo Molnar, Peter Zijlstra,
Juri Lelli, Vincent Guittot, Dietmar Eggemann, Steven Rostedt,
Ben Segall, Mel Gorman, Valentin Schneider, Kees Cook,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Guo Ren, Oleg Nesterov, Jens Axboe, Alexander Viro, Jan Kara,
Tejun Heo, Johannes Weiner, Michal Koutný, Paul Moore,
Serge Hallyn, James Morris, Serge E. Hallyn, Anna-Maria Behnsen,
Frederic Weisbecker, Thomas Gleixner, Masami Hiramatsu,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Mathieu Desnoyers, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, John Johansen, Stephen Smalley,
Ondrej Mosnacek, Kentaro Takeda, Tetsuo Handa, Richard Henderson,
Matt Turner, Vineet Gupta, Russell King, Catalin Marinas,
Will Deacon, Brian Cain, Huacai Chen, WANG Xuerui,
Geert Uytterhoeven, Michal Simek, Thomas Bogendoerfer, Jonas Bonn,
Stefan Kristiansson, Stafford Horne, James E.J. Bottomley,
Helge Deller, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Christophe Leroy, Heiko Carstens, Vasily Gorbik,
Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
Yoshinori Sato, Rich Felker, Richard Weinberger, Anton Ivanov,
Johannes Berg, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
Chris Zankel, Max Filippov
Cc: linux-mm, linux-kernel, linux-riscv, linux-csky, linux-block,
linux-fsdevel, cgroups, linux-security-module, linux-trace-kernel,
netdev, linux-perf-users, apparmor, selinux, linux-alpha,
linux-snps-arc, linux-arm-kernel, linux-hexagon, loongarch,
linux-m68k, linux-mips, linux-openrisc, linux-parisc,
linuxppc-dev, linux-s390, linux-sh, sparclinux, linux-um
In-Reply-To: <f2371539-cd4e-4d70-9576-4bb1c677104c@gaisler.com>
Hi Andreas,
On Tue, 2025-09-02 at 09:02 +0200, Andreas Larsson wrote:
> On 2025-09-01 15:09, Simon Schuster via B4 Relay wrote:
> > From: Simon Schuster <schuster.simon@siemens-energy.com>
> >
> > With the introduction of clone3 in commit 7f192e3cd316 ("fork: add
> > clone3") the effective bit width of clone_flags on all architectures was
> > increased from 32-bit to 64-bit, with a new type of u64 for the flags.
> > However, for most consumers of clone_flags the interface was not
> > changed from the previous type of unsigned long.
> >
> > While this works fine as long as none of the new 64-bit flag bits
> > (CLONE_CLEAR_SIGHAND and CLONE_INTO_CGROUP) are evaluated, this is still
> > undesirable in terms of the principle of least surprise.
> >
> > Thus, this commit fixes all relevant interfaces of the copy_thread
> > function that is called from copy_process to consistently pass
> > clone_flags as u64, so that no truncation to 32-bit integers occurs on
> > 32-bit architectures.
> >
> > Signed-off-by: Simon Schuster <schuster.simon@siemens-energy.com>
> > ---
>
> Thanks for this and for the whole series! Needed foundation for a
> sparc32 clone3 implementation as well.
Can you implement clone3 for sparc64 as well?
Adrian
--
.''`. John Paul Adrian Glaubitz
: :' : Debian Developer
`. `' Physicist
`- GPG: 62FF 8A75 84E0 2956 9546 0006 7426 3B37 F5B5 F913
^ permalink raw reply
* Re: [RFC PATCH v1 0/2] Add O_DENY_WRITE (complement AT_EXECVE_CHECK)
From: Roberto Sassu @ 2025-09-02 8:57 UTC (permalink / raw)
To: Andy Lutomirski
Cc: Aleksa Sarai, Mickaël Salaün, Christian Brauner,
Al Viro, Kees Cook, Paul Moore, Serge Hallyn, Arnd Bergmann,
Christian Heimes, Dmitry Vyukov, Elliott Hughes, Fan Wu,
Florian Weimer, Jann Horn, Jeff Xu, Jonathan Corbet,
Jordan R Abrahams, Lakshmi Ramasubramanian, Luca Boccassi,
Matt Bobrowski, Miklos Szeredi, Mimi Zohar, Nicolas Bouchinet,
Robert Waite, Roberto Sassu, Scott Shell, Steve Dower,
Steve Grubb, kernel-hardening, linux-api, linux-fsdevel,
linux-integrity, linux-kernel, linux-security-module
In-Reply-To: <3d89a03f31cacb53a2ed8017899f2dab10476b62.camel@huaweicloud.com>
On Mon, 2025-09-01 at 19:01 +0200, Roberto Sassu wrote:
> On Mon, 2025-09-01 at 09:25 -0700, Andy Lutomirski wrote:
> > Can you clarify this a bit for those of us who are not well-versed in
> > exactly what "measurement" does?
Ah, sorry, I missed that.
Measurement refers to the process of collecting the file digest and
storing it in the measurement list, as opposed to appraisal which
instead compares the collected file digest with a reference value
(assumed to be good), and denies access in case of a mismatch.
Integrity violations are detected and reported only for measurement.
Roberto
> > On Mon, Sep 1, 2025 at 2:42 AM Roberto Sassu
> > <roberto.sassu@huaweicloud.com> wrote:
> > > > Now, in cases where you have IMA or something and you only permit signed
> > > > binaries to execute, you could argue there is a different race here (an
> > > > attacker creates a malicious script, runs it, and then replaces it with
> > > > a valid script's contents and metadata after the fact to get
> > > > AT_EXECVE_CHECK to permit the execution). However, I'm not sure that
> > >
> > > Uhm, let's consider measurement, I'm more familiar with.
> > >
> > > I think the race you wanted to express was that the attacker replaces
> > > the good script, verified with AT_EXECVE_CHECK, with the bad script
> > > after the IMA verification but before the interpreter reads it.
> > >
> > > Fortunately, IMA is able to cope with this situation, since this race
> > > can happen for any file open, where of course a file can be not read-
> > > locked.
> >
> > I assume you mean that this has nothing specifically to do with
> > scripts, as IMA tries to protect ordinary (non-"execute" file access)
> > as well. Am I right?
>
> Yes, correct, violations are checked for all open() and mmap()
> involving regular files. It would not be special to do it for scripts.
>
> > > If the attacker tries to concurrently open the script for write in this
> > > race window, IMA will report this event (called violation) in the
> > > measurement list, and during remote attestation it will be clear that
> > > the interpreter did not read what was measured.
> > >
> > > We just need to run the violation check for the BPRM_CHECK hook too
> > > (then, probably for us the O_DENY_WRITE flag or alternative solution
> > > would not be needed, for measurement).
> >
> > This seems consistent with my interpretation above, but ...
>
> The comment here [1] seems to be clear on why the violation check it is
> not done for execution (BPRM_CHECK hook). Since the OS read-locks the
> files during execution, this implicitly guarantees that there will not
> be concurrent writes, and thus no IMA violations.
>
> However, recently, we took advantage of AT_EXECVE_CHECK to also
> evaluate the integrity of scripts (when not executed via ./). Since we
> are using the same hook for both executed files (read-locked) and
> scripts (I guess non-read-locked), then we need to do a violation check
> for BPRM_CHECK too, although it will be redundant for the first
> category.
>
> > > Please, let us know when you apply patches like 2a010c412853 ("fs:
> > > don't block i_writecount during exec"). We had a discussion [1], but
> > > probably I missed when it was decided to be applied (I saw now it was
> > > in the same thread, but didn't get that at the time). We would have
> > > needed to update our code accordingly. In the future, we will try to
> > > clarify better our expectations from the VFS.
> >
> > ... I didn't follow this.
> >
> > Suppose there's some valid contents of /bin/sleep. I execute
> > /bin/sleep 1m. While it's running, I modify /bin/sleep (by opening it
> > for write, not by replacing it), and the kernel in question doesn't do
> > ETXTBSY. Then the sleep process reads (and executes) the modified
> > contents. Wouldn't a subsequent attestation fail? Why is ETXTBSY
> > needed?
>
> Ok, this is actually a good opportunity to explain what it will be
> missing. If you do the operations in the order you proposed, actually a
> violation will be emitted, because the violating operation is an open()
> and the check is done for this system call.
>
> However, if you do the opposite, first open for write and then
> execution, IMA will not be aware of that since it trusts the OS to not
> make it happen and will not check for violations.
>
> So yes, in your case the remote attestation will fail (actually it is
> up to the remote verifier to decide...). But in the opposite case, the
> writer could wait for IMA to measure the genuine content and then
> modify the content conveniently. The remote attestation will succeed.
>
> Adding the violation check on BPRM_CHECK should be sufficient to avoid
> such situation, but I would try to think if there are other
> implications for IMA of not read-locking the files on execution.
>
> Roberto
>
> [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/security/integrity/ima/ima_main.c?h=v6.17-rc4#n565
>
^ permalink raw reply
* Re: [PATCH v2 3/4] arch: copy_thread: pass clone_flags as u64
From: Guo Ren @ 2025-09-02 9:48 UTC (permalink / raw)
To: schuster.simon
Cc: Dinh Nguyen, Christian Brauner, Arnd Bergmann, Andrew Morton,
David Hildenbrand, Lorenzo Stoakes, Liam R. Howlett,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Ingo Molnar, Peter Zijlstra, Juri Lelli, Vincent Guittot,
Dietmar Eggemann, Steven Rostedt, Ben Segall, Mel Gorman,
Valentin Schneider, Kees Cook, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Oleg Nesterov, Jens Axboe,
Alexander Viro, Jan Kara, Tejun Heo, Johannes Weiner,
Michal Koutný, Paul Moore, Serge Hallyn, James Morris,
Serge E. Hallyn, Anna-Maria Behnsen, Frederic Weisbecker,
Thomas Gleixner, Masami Hiramatsu, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Mathieu Desnoyers,
Arnaldo Carvalho de Melo, Namhyung Kim, Mark Rutland,
Alexander Shishkin, Jiri Olsa, Ian Rogers, Adrian Hunter,
John Johansen, Stephen Smalley, Ondrej Mosnacek, Kentaro Takeda,
Tetsuo Handa, Richard Henderson, Matt Turner, Vineet Gupta,
Russell King, Catalin Marinas, Will Deacon, Brian Cain,
Huacai Chen, WANG Xuerui, Geert Uytterhoeven, Michal Simek,
Thomas Bogendoerfer, Jonas Bonn, Stefan Kristiansson,
Stafford Horne, James E.J. Bottomley, Helge Deller,
Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
Christophe Leroy, Heiko Carstens, Vasily Gorbik,
Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
Yoshinori Sato, Rich Felker, John Paul Adrian Glaubitz,
Andreas Larsson, Richard Weinberger, Anton Ivanov, Johannes Berg,
Borislav Petkov, Dave Hansen, x86, H. Peter Anvin, Chris Zankel,
Max Filippov, linux-mm, linux-kernel, linux-riscv, linux-csky,
linux-block, linux-fsdevel, cgroups, linux-security-module,
linux-trace-kernel, netdev, linux-perf-users, apparmor, selinux,
linux-alpha, linux-snps-arc, linux-arm-kernel, linux-hexagon,
loongarch, linux-m68k, linux-mips, linux-openrisc, linux-parisc,
linuxppc-dev, linux-s390, linux-sh, sparclinux, linux-um
In-Reply-To: <20250901-nios2-implement-clone3-v2-3-53fcf5577d57@siemens-energy.com>
On Mon, Sep 1, 2025 at 9:10 PM Simon Schuster via B4 Relay
<devnull+schuster.simon.siemens-energy.com@kernel.org> wrote:
>
> From: Simon Schuster <schuster.simon@siemens-energy.com>
>
> With the introduction of clone3 in commit 7f192e3cd316 ("fork: add
> clone3") the effective bit width of clone_flags on all architectures was
> increased from 32-bit to 64-bit, with a new type of u64 for the flags.
> However, for most consumers of clone_flags the interface was not
> changed from the previous type of unsigned long.
>
> While this works fine as long as none of the new 64-bit flag bits
> (CLONE_CLEAR_SIGHAND and CLONE_INTO_CGROUP) are evaluated, this is still
> undesirable in terms of the principle of least surprise.
>
> Thus, this commit fixes all relevant interfaces of the copy_thread
> function that is called from copy_process to consistently pass
> clone_flags as u64, so that no truncation to 32-bit integers occurs on
> 32-bit architectures.
>
> Signed-off-by: Simon Schuster <schuster.simon@siemens-energy.com>
> ---
> arch/alpha/kernel/process.c | 2 +-
> arch/arc/kernel/process.c | 2 +-
> arch/arm/kernel/process.c | 2 +-
> arch/arm64/kernel/process.c | 2 +-
> arch/csky/kernel/process.c | 2 +-
> arch/hexagon/kernel/process.c | 2 +-
> arch/loongarch/kernel/process.c | 2 +-
> arch/m68k/kernel/process.c | 2 +-
> arch/microblaze/kernel/process.c | 2 +-
> arch/mips/kernel/process.c | 2 +-
> arch/nios2/kernel/process.c | 2 +-
> arch/openrisc/kernel/process.c | 2 +-
> arch/parisc/kernel/process.c | 2 +-
> arch/powerpc/kernel/process.c | 2 +-
> arch/riscv/kernel/process.c | 2 +-
> arch/s390/kernel/process.c | 2 +-
> arch/sh/kernel/process_32.c | 2 +-
> arch/sparc/kernel/process_32.c | 2 +-
> arch/sparc/kernel/process_64.c | 2 +-
> arch/um/kernel/process.c | 2 +-
> arch/x86/include/asm/fpu/sched.h | 2 +-
> arch/x86/include/asm/shstk.h | 4 ++--
> arch/x86/kernel/fpu/core.c | 2 +-
> arch/x86/kernel/process.c | 2 +-
> arch/x86/kernel/shstk.c | 2 +-
> arch/xtensa/kernel/process.c | 2 +-
> 26 files changed, 27 insertions(+), 27 deletions(-)
>
> diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
> index 582d96548385..06522451f018 100644
> --- a/arch/alpha/kernel/process.c
> +++ b/arch/alpha/kernel/process.c
> @@ -231,7 +231,7 @@ flush_thread(void)
> */
> int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
> {
> - unsigned long clone_flags = args->flags;
> + u64 clone_flags = args->flags;
> unsigned long usp = args->stack;
> unsigned long tls = args->tls;
> extern void ret_from_fork(void);
> diff --git a/arch/arc/kernel/process.c b/arch/arc/kernel/process.c
> index 186ceab661eb..8166d0908713 100644
> --- a/arch/arc/kernel/process.c
> +++ b/arch/arc/kernel/process.c
> @@ -166,7 +166,7 @@ asmlinkage void ret_from_fork(void);
> */
> int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
> {
> - unsigned long clone_flags = args->flags;
> + u64 clone_flags = args->flags;
> unsigned long usp = args->stack;
> unsigned long tls = args->tls;
> struct pt_regs *c_regs; /* child's pt_regs */
> diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
> index e16ed102960c..d7aa95225c70 100644
> --- a/arch/arm/kernel/process.c
> +++ b/arch/arm/kernel/process.c
> @@ -234,7 +234,7 @@ asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
>
> int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
> {
> - unsigned long clone_flags = args->flags;
> + u64 clone_flags = args->flags;
> unsigned long stack_start = args->stack;
> unsigned long tls = args->tls;
> struct thread_info *thread = task_thread_info(p);
> diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
> index 96482a1412c6..fba7ca102a8c 100644
> --- a/arch/arm64/kernel/process.c
> +++ b/arch/arm64/kernel/process.c
> @@ -409,7 +409,7 @@ asmlinkage void ret_from_fork(void) asm("ret_from_fork");
>
> int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
> {
> - unsigned long clone_flags = args->flags;
> + u64 clone_flags = args->flags;
> unsigned long stack_start = args->stack;
> unsigned long tls = args->tls;
> struct pt_regs *childregs = task_pt_regs(p);
> diff --git a/arch/csky/kernel/process.c b/arch/csky/kernel/process.c
> index 0c6e4b17fe00..a7a90340042a 100644
> --- a/arch/csky/kernel/process.c
> +++ b/arch/csky/kernel/process.c
> @@ -32,7 +32,7 @@ void flush_thread(void){}
>
> int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
> {
> - unsigned long clone_flags = args->flags;
> + u64 clone_flags = args->flags;
Acked-by: Guo Ren (Alibaba Damo Academy) <guoren@kernel.org>
> unsigned long usp = args->stack;
> unsigned long tls = args->tls;
> struct switch_stack *childstack;
> diff --git a/arch/hexagon/kernel/process.c b/arch/hexagon/kernel/process.c
> index 2a77bfd75694..15b4992bfa29 100644
> --- a/arch/hexagon/kernel/process.c
> +++ b/arch/hexagon/kernel/process.c
> @@ -52,7 +52,7 @@ void arch_cpu_idle(void)
> */
> int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
> {
> - unsigned long clone_flags = args->flags;
> + u64 clone_flags = args->flags;
> unsigned long usp = args->stack;
> unsigned long tls = args->tls;
> struct thread_info *ti = task_thread_info(p);
> diff --git a/arch/loongarch/kernel/process.c b/arch/loongarch/kernel/process.c
> index 3582f591bab2..efd9edf65603 100644
> --- a/arch/loongarch/kernel/process.c
> +++ b/arch/loongarch/kernel/process.c
> @@ -167,7 +167,7 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
> unsigned long childksp;
> unsigned long tls = args->tls;
> unsigned long usp = args->stack;
> - unsigned long clone_flags = args->flags;
> + u64 clone_flags = args->flags;
> struct pt_regs *childregs, *regs = current_pt_regs();
>
> childksp = (unsigned long)task_stack_page(p) + THREAD_SIZE;
> diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c
> index fda7eac23f87..f5a07a70e938 100644
> --- a/arch/m68k/kernel/process.c
> +++ b/arch/m68k/kernel/process.c
> @@ -141,7 +141,7 @@ asmlinkage int m68k_clone3(struct pt_regs *regs)
>
> int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
> {
> - unsigned long clone_flags = args->flags;
> + u64 clone_flags = args->flags;
> unsigned long usp = args->stack;
> unsigned long tls = args->tls;
> struct fork_frame {
> diff --git a/arch/microblaze/kernel/process.c b/arch/microblaze/kernel/process.c
> index 56342e11442d..6cbf642d7b80 100644
> --- a/arch/microblaze/kernel/process.c
> +++ b/arch/microblaze/kernel/process.c
> @@ -54,7 +54,7 @@ void flush_thread(void)
>
> int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
> {
> - unsigned long clone_flags = args->flags;
> + u64 clone_flags = args->flags;
> unsigned long usp = args->stack;
> unsigned long tls = args->tls;
> struct pt_regs *childregs = task_pt_regs(p);
> diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
> index 02aa6a04a21d..29191fa1801e 100644
> --- a/arch/mips/kernel/process.c
> +++ b/arch/mips/kernel/process.c
> @@ -107,7 +107,7 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
> */
> int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
> {
> - unsigned long clone_flags = args->flags;
> + u64 clone_flags = args->flags;
> unsigned long usp = args->stack;
> unsigned long tls = args->tls;
> struct thread_info *ti = task_thread_info(p);
> diff --git a/arch/nios2/kernel/process.c b/arch/nios2/kernel/process.c
> index f84021303f6a..151404139085 100644
> --- a/arch/nios2/kernel/process.c
> +++ b/arch/nios2/kernel/process.c
> @@ -101,7 +101,7 @@ void flush_thread(void)
>
> int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
> {
> - unsigned long clone_flags = args->flags;
> + u64 clone_flags = args->flags;
> unsigned long usp = args->stack;
> unsigned long tls = args->tls;
> struct pt_regs *childregs = task_pt_regs(p);
> diff --git a/arch/openrisc/kernel/process.c b/arch/openrisc/kernel/process.c
> index eef99fee2110..73ffb9fa3118 100644
> --- a/arch/openrisc/kernel/process.c
> +++ b/arch/openrisc/kernel/process.c
> @@ -165,7 +165,7 @@ extern asmlinkage void ret_from_fork(void);
> int
> copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
> {
> - unsigned long clone_flags = args->flags;
> + u64 clone_flags = args->flags;
> unsigned long usp = args->stack;
> unsigned long tls = args->tls;
> struct pt_regs *userregs;
> diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c
> index ed93bd8c1545..e64ab5d2a40d 100644
> --- a/arch/parisc/kernel/process.c
> +++ b/arch/parisc/kernel/process.c
> @@ -201,7 +201,7 @@ arch_initcall(parisc_idle_init);
> int
> copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
> {
> - unsigned long clone_flags = args->flags;
> + u64 clone_flags = args->flags;
> unsigned long usp = args->stack;
> unsigned long tls = args->tls;
> struct pt_regs *cregs = &(p->thread.regs);
> diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
> index 855e09886503..eb23966ac0a9 100644
> --- a/arch/powerpc/kernel/process.c
> +++ b/arch/powerpc/kernel/process.c
> @@ -1805,7 +1805,7 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
> f = ret_from_kernel_user_thread;
> } else {
> struct pt_regs *regs = current_pt_regs();
> - unsigned long clone_flags = args->flags;
> + u64 clone_flags = args->flags;
> unsigned long usp = args->stack;
>
> /* Copy registers */
> diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c
> index a0a40889d79a..31a392993cb4 100644
> --- a/arch/riscv/kernel/process.c
> +++ b/arch/riscv/kernel/process.c
> @@ -223,7 +223,7 @@ asmlinkage void ret_from_fork_user(struct pt_regs *regs)
>
> int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
> {
> - unsigned long clone_flags = args->flags;
> + u64 clone_flags = args->flags;
> unsigned long usp = args->stack;
> unsigned long tls = args->tls;
> struct pt_regs *childregs = task_pt_regs(p);
> diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
> index f55f09cda6f8..b107dbca4ed7 100644
> --- a/arch/s390/kernel/process.c
> +++ b/arch/s390/kernel/process.c
> @@ -106,7 +106,7 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
>
> int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
> {
> - unsigned long clone_flags = args->flags;
> + u64 clone_flags = args->flags;
> unsigned long new_stackp = args->stack;
> unsigned long tls = args->tls;
> struct fake_frame
> diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c
> index 92b6649d4929..62f753a85b89 100644
> --- a/arch/sh/kernel/process_32.c
> +++ b/arch/sh/kernel/process_32.c
> @@ -89,7 +89,7 @@ asmlinkage void ret_from_kernel_thread(void);
>
> int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
> {
> - unsigned long clone_flags = args->flags;
> + u64 clone_flags = args->flags;
> unsigned long usp = args->stack;
> unsigned long tls = args->tls;
> struct thread_info *ti = task_thread_info(p);
> diff --git a/arch/sparc/kernel/process_32.c b/arch/sparc/kernel/process_32.c
> index 9c7c662cb565..5a28c0e91bf1 100644
> --- a/arch/sparc/kernel/process_32.c
> +++ b/arch/sparc/kernel/process_32.c
> @@ -260,7 +260,7 @@ extern void ret_from_kernel_thread(void);
>
> int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
> {
> - unsigned long clone_flags = args->flags;
> + u64 clone_flags = args->flags;
> unsigned long sp = args->stack;
> unsigned long tls = args->tls;
> struct thread_info *ti = task_thread_info(p);
> diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c
> index 529adfecd58c..25781923788a 100644
> --- a/arch/sparc/kernel/process_64.c
> +++ b/arch/sparc/kernel/process_64.c
> @@ -567,7 +567,7 @@ void fault_in_user_windows(struct pt_regs *regs)
> */
> int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
> {
> - unsigned long clone_flags = args->flags;
> + u64 clone_flags = args->flags;
> unsigned long sp = args->stack;
> unsigned long tls = args->tls;
> struct thread_info *t = task_thread_info(p);
> diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c
> index 1be644de9e41..9c9c66dc45f0 100644
> --- a/arch/um/kernel/process.c
> +++ b/arch/um/kernel/process.c
> @@ -143,7 +143,7 @@ static void fork_handler(void)
>
> int copy_thread(struct task_struct * p, const struct kernel_clone_args *args)
> {
> - unsigned long clone_flags = args->flags;
> + u64 clone_flags = args->flags;
> unsigned long sp = args->stack;
> unsigned long tls = args->tls;
> void (*handler)(void);
> diff --git a/arch/x86/include/asm/fpu/sched.h b/arch/x86/include/asm/fpu/sched.h
> index c060549c6c94..89004f4ca208 100644
> --- a/arch/x86/include/asm/fpu/sched.h
> +++ b/arch/x86/include/asm/fpu/sched.h
> @@ -11,7 +11,7 @@
>
> extern void save_fpregs_to_fpstate(struct fpu *fpu);
> extern void fpu__drop(struct task_struct *tsk);
> -extern int fpu_clone(struct task_struct *dst, unsigned long clone_flags, bool minimal,
> +extern int fpu_clone(struct task_struct *dst, u64 clone_flags, bool minimal,
> unsigned long shstk_addr);
> extern void fpu_flush_thread(void);
>
> diff --git a/arch/x86/include/asm/shstk.h b/arch/x86/include/asm/shstk.h
> index ba6f2fe43848..0f50e0125943 100644
> --- a/arch/x86/include/asm/shstk.h
> +++ b/arch/x86/include/asm/shstk.h
> @@ -16,7 +16,7 @@ struct thread_shstk {
>
> long shstk_prctl(struct task_struct *task, int option, unsigned long arg2);
> void reset_thread_features(void);
> -unsigned long shstk_alloc_thread_stack(struct task_struct *p, unsigned long clone_flags,
> +unsigned long shstk_alloc_thread_stack(struct task_struct *p, u64 clone_flags,
> unsigned long stack_size);
> void shstk_free(struct task_struct *p);
> int setup_signal_shadow_stack(struct ksignal *ksig);
> @@ -28,7 +28,7 @@ static inline long shstk_prctl(struct task_struct *task, int option,
> unsigned long arg2) { return -EINVAL; }
> static inline void reset_thread_features(void) {}
> static inline unsigned long shstk_alloc_thread_stack(struct task_struct *p,
> - unsigned long clone_flags,
> + u64 clone_flags,
> unsigned long stack_size) { return 0; }
> static inline void shstk_free(struct task_struct *p) {}
> static inline int setup_signal_shadow_stack(struct ksignal *ksig) { return 0; }
> diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c
> index aefd412a23dc..1f71cc135e9a 100644
> --- a/arch/x86/kernel/fpu/core.c
> +++ b/arch/x86/kernel/fpu/core.c
> @@ -631,7 +631,7 @@ static int update_fpu_shstk(struct task_struct *dst, unsigned long ssp)
> }
>
> /* Clone current's FPU state on fork */
> -int fpu_clone(struct task_struct *dst, unsigned long clone_flags, bool minimal,
> +int fpu_clone(struct task_struct *dst, u64 clone_flags, bool minimal,
> unsigned long ssp)
> {
> /*
> diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
> index 1b7960cf6eb0..e3a3987b0c4f 100644
> --- a/arch/x86/kernel/process.c
> +++ b/arch/x86/kernel/process.c
> @@ -159,7 +159,7 @@ __visible void ret_from_fork(struct task_struct *prev, struct pt_regs *regs,
>
> int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
> {
> - unsigned long clone_flags = args->flags;
> + u64 clone_flags = args->flags;
> unsigned long sp = args->stack;
> unsigned long tls = args->tls;
> struct inactive_task_frame *frame;
> diff --git a/arch/x86/kernel/shstk.c b/arch/x86/kernel/shstk.c
> index 2ddf23387c7e..5eba6c5a6775 100644
> --- a/arch/x86/kernel/shstk.c
> +++ b/arch/x86/kernel/shstk.c
> @@ -191,7 +191,7 @@ void reset_thread_features(void)
> current->thread.features_locked = 0;
> }
>
> -unsigned long shstk_alloc_thread_stack(struct task_struct *tsk, unsigned long clone_flags,
> +unsigned long shstk_alloc_thread_stack(struct task_struct *tsk, u64 clone_flags,
> unsigned long stack_size)
> {
> struct thread_shstk *shstk = &tsk->thread.shstk;
> diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c
> index 7bd66677f7b6..94d43f44be13 100644
> --- a/arch/xtensa/kernel/process.c
> +++ b/arch/xtensa/kernel/process.c
> @@ -267,7 +267,7 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
>
> int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
> {
> - unsigned long clone_flags = args->flags;
> + u64 clone_flags = args->flags;
> unsigned long usp_thread_fn = args->stack;
> unsigned long tls = args->tls;
> struct pt_regs *childregs = task_pt_regs(p);
>
> --
> 2.39.5
>
>
--
Best Regards
Guo Ren
^ permalink raw reply
* Re: LSM namespacing API
From: John Johansen @ 2025-09-02 10:55 UTC (permalink / raw)
To: Dr. Greg
Cc: Serge E. Hallyn, Stephen Smalley, Paul Moore,
linux-security-module, selinux
In-Reply-To: <20250901160102.GA9179@wind.enjellic.com>
On 9/1/25 09:01, Dr. Greg wrote:
> On Thu, Aug 21, 2025 at 07:57:11AM -0700, John Johansen wrote:
>
> Good morning, I hope the week is starting well for everyone.
>
> Now that everyone is getting past the summer holiday season, it would
> seem useful to specifically clarify some of the LSM namespace
> implementation details.
>
>> On 8/21/25 07:26, Serge E. Hallyn wrote:
>>> On Thu, Aug 21, 2025 at 12:46:10AM -0700, John Johansen wrote:
>>>> On 8/19/25 10:47, Stephen Smalley wrote:
>>>>> On Tue, Aug 19, 2025 at 10:56???AM Paul Moore <paul@paul-moore.com>
>>>>> wrote:
>>>>>>
>>>>>> Hello all,
>>>>>>
>>>>>> As most of you are likely aware, Stephen Smalley has been working on
>>>>>> adding namespace support to SELinux, and the work has now progressed
>>>>>> to the point where a serious discussion on the API is warranted. For
>>>>>> those of you are unfamiliar with the details or Stephen's patchset, or
>>>>>> simply need a refresher, he has some excellent documentation in his
>>>>>> work-in-progress repo:
>>>>>>
>>>>>> * https://github.com/stephensmalley/selinuxns
>>>>>>
>>>>>> Stephen also gave a (pre-recorded) presentation at LSS-NA this year
>>>>>> about SELinux namespacing, you can watch the presentation here:
>>>>>>
>>>>>> * https://www.youtube.com/watch?v=AwzGCOwxLoM
>>>>>>
>>>>>> In the past you've heard me state, rather firmly at times, that I
>>>>>> believe namespacing at the LSM framework layer to be a mistake,
>>>>>> although if there is something that can be done to help facilitate the
>>>>>> namespacing of individual LSMs at the framework layer, I would be
>>>>>> supportive of that. I think that a single LSM namespace API, similar
>>>>>> to our recently added LSM syscalls, may be such a thing, so I'd like
>>>>>> us to have a discussion to see if we all agree on that, and if so,
>>>>>> what such an API might look like.
>>>>>>
>>>>>> At LSS-NA this year, John Johansen and I had a brief discussion where
>>>>>> he suggested a single LSM wide clone*(2) flag that individual LSM's
>>>>>> could opt into via callbacks. John is directly CC'd on this mail, so
>>>>>> I'll let him expand on this idea.
>>>>>>
>>>>>> While I agree with John that a fs based API is problematic (see all of
>>>>>> our discussions around the LSM syscalls), I'm concerned that a single
>>>>>> clone*(2) flag will significantly limit our flexibility around how
>>>>>> individual LSMs are namespaced, something I don't want to see happen.
>>>>>> This makes me wonder about the potential for expanding
>>>>>> lsm_set_self_attr(2) to support a new LSM attribute that would support
>>>>>> a namespace "unshare" operation, e.g. LSM_ATTR_UNSHARE. This would
>>>>>> provide a single LSM framework API for an unshare operation while also
>>>>>> providing a mechanism to pass LSM specific via the lsm_ctx struct if
>>>>>> needed. Just as we do with the other LSM_ATTR_* flags today,
>>>>>> individual LSMs can opt-in to the API fairly easily by providing a
>>>>>> setselfattr() LSM callback.
>>>>>>
>>>>>> Thoughts?
>>>>>
>>>>> I think we want to be able to unshare a specific security module
>>>>> namespace without unsharing the others, i.e. just SELinux or just
>>>>> AppArmor.
>>>>
>>>> yes which is part of the problem with the single flag. That choice
>>>> would be entirely at the policy level, without any input from userspace.
>>>
>>> AIUI Paul's suggestion is the user can pre-set the details of which
>>> lsms to unshare and how with the lsm_set_self_attr(), and then a
>>> single CLONE_LSM effects that.
>
>> yes, I was specifically addressing the conversation I had with Paul at
>> LSS that Paul brought up. That is
>>
>> At LSS-NA this year, John Johansen and I had a brief discussion where
>> he suggested a single LSM wide clone*(2) flag that individual LSM's
>> could opt into via callbacks.
>>
>> the idea there isn't all that different than what Paul proposed. You
>> could have a single flag, if you can provide ancillary information. But
>> a single flag on its own isn't sufficient.
>
> If one thing has come out of this thread, it would seem to be the fact
> that there is going to be little commonality in the requirements that
> various LSM's will have for the creation of a namespace.
>
yes
> Given that, the most infrastructure that the LSM should provide would
> be a common API for a resource orchestrator to request namespace
> separation and to provide a framework for configuring the namespace
> prior to when execution begins in the context of the namespace.
>
hrmmm, certainly a common API. Any task could theoretically use the API
it doesn't have to be a resource orchestrator, but I suppose you could
call it such.
I also dont know that we need to provide a framework for configuring
the namespace prior to when execcution begins in the context of the
namespace. It might be a nice to have, but configuring of LSMs is
very LSM specific.
We don't even have a common LSM policy load interface atm, though there
is a proposal. Configuration is a step beyond that. Would it be nice
to have, sure. Are we going to get that far, I don't know.
> The first issue to resolve would seem to be what namespace separation
> implies.
>
> John, if I interpret your comments in this discussion correctly, your
> contention is that when namespace separation is requested, all of the
> LSM's that implement namespaces will create a subordinate namespace,
> is that a correct assumption?
>
No, not necessarily. The task can request to "unshare/create" LSMs
similar to requesting a set of system namespaces. Then every LSM,
whether part of the request or not get to do their thing. If every
LSM agrees, then a transition hook will process and each LSM will
again do its thing. This would likely be what was requested but its
possible that an LSM not in the request will do something, based
on its model.
In the end usespace gets to make a request, each security policy is
responsible for staying withing its security model/policy.
> It would seem, consistent with the 'stacking' concept, that any LSM
> with namespace capability that chooses not to separate, will result in
> denial of the separation request. That in turn will imply the need to
Not necessarily. They could allow and choose not to transition. Or they
could not create a namespace but update some state.
> unwind or delete any namespace context that other LSM's may have
> allocated before the refusal occurred.
The request does need to be split into a permission hook and a
transition hook similar to exec. If any LSM in the permission hook
denies, the request is denied. If any LSM in the transition hook fails
again the request will fail, and the LSMs would get their regular clean
up hook called for the object associated.
>
> This model also implies that the orchestrator requesting the
> separation will need to pass a set of parameters describing the
> characteristics of each namespace, described by the LSM identifier
> that they pertain to. Since there may be a need to configure multiple
> namespaces there would be a requirement to pass an array or list of
> these parameter sets.
>
yes it will require a list/array see lsm_set_self_attr(2)
> There will also be a need to inject, possibly substantial amounts of
> policy or model information into the namespace, before execution in
> the context of the namespace begins.
>
Allowing for this and requiring this are two different things. Like I
said above we don't even currently have a common policy load interface.
Configuration is another step beyond policy load.
> There will also be a need to decide whether namespace separation
> should occur at the request of the orchestrator or at the next fork,
Or allow both, but yes a decision needs to be made
> the latter model being what the other resource namespaces use. We
> believe the argument for direct separation can be made by looking at
> the gymnastics that orchestrators need to jump through with the
> 'change-on-fork' model.
>
Looking at current system namespacing we have clone/unshare which
really or on fork. setns enters existing namespaces.
We either need to create new variants of clone/unshare or potentially
have an LSM syscall that setups addition parameters that then are
triggered by clone/unshare. If going the latter route then its just
a matter whether the LSM call returns a handle that can be operated
on or not.
> Case in point, it would seem realistic that a process with sufficient
> privilege, may desire to place itself in a new LSM namespace context
> in a manner that does not require re-execution of itself.
>
yes, but it is questionable whether security policy should allow that.
At the very least security policy should be consulted and may deny
it.
> With respect to separation, the remaining issue is if a new security
> capability bit needs to be implemented to gate namespace separation.
> John, based on your comments, I believe you would support this need?
>
No, I don't think a capability (as in posix.1e) per say is needed. I
think an LSM permission request is.
>> You can do a subset with a single flag and only policy directing things,
>> but that would cut container managers out of the decision. Without a
>> universal container identifier that really limits what you can do. In
>> another email I likend it to the MCS label approach to the container
>> where you have a single security policy for the container and each
>> container gets to be a unique instance of that policy. Its not a perfect
>> analogy as with namespace policy can be loaded into the namespace making
>> it unique. I don't think the approach is right because not all namespaces
>> implement a loadable policy, and even when they do I think we can do a
>> better job if the container manager is allowed to provide additional
>> context with the namespacing request.
>
> In order to be relevant, the configuration of LSM namespaces need to
> be under control of a resource orchestrator or container manager.
>
No, the must be under the control of the LSMs.
> What we hear from people doing Kubernetes, at scale, is a desire to be
> able to request that a container be run somewhere in the hardware
> resource pool and for that container to implement a security model
> specific to the needs of the workload running in that container. In a
> manner that is orthogonal from other security policies that may be in
> effect for other workloads, on the host or in other containers.
>
sure, assuming the host policy allows it. Otherwise it is just a host
policy by-pass, which can not be allowed. K8s people have a specific
use case, they need to configure the host for that use case. They can
not expect that use case to work on host that has been configured
for say an MLS security constraint.
> Hopefully the above will be of assistance in furthering discussion.
>
> Have a good week.
>
> As always,
> Dr. Greg
>
> The Quixote Project - Flailing at the Travails of Cybersecurity
> https://github.com/Quixote-Project
^ permalink raw reply
* Re: [PATCH v2 3/4] arch: copy_thread: pass clone_flags as u64
From: Andreas Larsson @ 2025-09-02 11:44 UTC (permalink / raw)
To: John Paul Adrian Glaubitz, Arnd Bergmann
Cc: linux-mm, linux-kernel, linux-riscv, linux-csky, linux-block,
linux-fsdevel, cgroups, linux-security-module, linux-trace-kernel,
netdev, linux-perf-users, apparmor, selinux, linux-alpha,
linux-snps-arc, linux-arm-kernel, linux-hexagon, loongarch,
linux-m68k, linux-mips, linux-openrisc, linux-parisc,
linuxppc-dev, linux-s390, linux-sh, sparclinux, linux-um
In-Reply-To: <11a4d0a953e3a9405177d67f287c69379a2b2f8f.camel@physik.fu-berlin.de>
On 2025-09-02 09:15, John Paul Adrian Glaubitz wrote:
>> Thanks for this and for the whole series! Needed foundation for a
>> sparc32 clone3 implementation as well.
>
> Can you implement clone3 for sparc64 as well?
(heavily pairing down the to list)
We'll take a look at that as well.
Cheers,
Andreas
^ permalink raw reply
* Re: [PATCH v3 31/34] ima,evm: move initcalls to the LSM framework
From: Roberto Sassu @ 2025-09-02 12:50 UTC (permalink / raw)
To: Paul Moore, Mimi Zohar, Roberto Sassu
Cc: linux-security-module, linux-integrity, selinux, John Johansen,
Fan Wu, Mickaël Salaün, Günther Noack, Kees Cook,
Micah Morton, Casey Schaufler, Tetsuo Handa, Nicolas Bouchinet,
Xiu Jianfeng
In-Reply-To: <CAHC9VhS3KdVO9n-dgk1qFzTae0i+Oab8atMmt0CAsMEm1D4v5w@mail.gmail.com>
On Fri, 2025-08-22 at 16:45 -0400, Paul Moore wrote:
> On Thu, Aug 14, 2025 at 6:55 PM Paul Moore <paul@paul-moore.com> wrote:
> >
> > This patch converts IMA and EVM to use the LSM frameworks's initcall
> > mechanism. There was a minor challenge in this conversion that wasn't
> > seen when converting the other LSMs brought about by the resource
> > sharing between the two related, yes independent IMA and EVM LSMs.
> > This was resolved by registering the same initcalls for each LSM and
> > including code in each registered initcall to ensure it only executes
> > once during each boot.
> >
> > It is worth mentioning that this patch does not touch any of the
> > "platform certs" code that lives in the security/integrity/platform_certs
> > directory as the IMA/EVM maintainers have assured me that this code is
> > unrelated to IMA/EVM, despite the location, and will be moved to a more
> > relevant subsystem in the future.
> >
> > Signed-off-by: Paul Moore <paul@paul-moore.com>
> > ---
> > security/integrity/Makefile | 2 +-
> > security/integrity/evm/evm_main.c | 6 ++---
> > security/integrity/iint.c | 4 +--
> > security/integrity/ima/ima_main.c | 6 ++---
> > security/integrity/initcalls.c | 41 +++++++++++++++++++++++++++++++
> > security/integrity/initcalls.h | 28 +++++++++++++++++++++
> > 6 files changed, 78 insertions(+), 9 deletions(-)
> > create mode 100644 security/integrity/initcalls.c
> > create mode 100644 security/integrity/initcalls.h
>
> Mimi, Roberto, I believe I've incorporated all of your feedback thus
> far, does this patch look okay to you? If so, can I get an ACK from
> one or both of you?
I just realized that it could be rewritten without exposing the IMA and
EVM init functions. I also added the logic to cleanup the integrity
directory itself.
Sending soon...
Roberto
> > diff --git a/security/integrity/Makefile b/security/integrity/Makefile
> > index 92b63039c654..6ea330ea88b1 100644
> > --- a/security/integrity/Makefile
> > +++ b/security/integrity/Makefile
> > @@ -5,7 +5,7 @@
> >
> > obj-$(CONFIG_INTEGRITY) += integrity.o
> >
> > -integrity-y := iint.o
> > +integrity-y := iint.o initcalls.o
> > integrity-$(CONFIG_INTEGRITY_AUDIT) += integrity_audit.o
> > integrity-$(CONFIG_INTEGRITY_SIGNATURE) += digsig.o
> > integrity-$(CONFIG_INTEGRITY_ASYMMETRIC_KEYS) += digsig_asymmetric.o
> > diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
> > index db8e324ed4e6..823573bcaa27 100644
> > --- a/security/integrity/evm/evm_main.c
> > +++ b/security/integrity/evm/evm_main.c
> > @@ -25,6 +25,7 @@
> > #include <crypto/hash.h>
> > #include <crypto/hash_info.h>
> > #include <crypto/utils.h>
> > +#include "../initcalls.h"
> > #include "evm.h"
> >
> > int evm_initialized;
> > @@ -1112,7 +1113,7 @@ void __init evm_load_x509(void)
> > }
> > #endif
> >
> > -static int __init init_evm(void)
> > +int __init init_evm(void)
> > {
> > int error;
> > struct list_head *pos, *q;
> > @@ -1179,6 +1180,5 @@ DEFINE_LSM(evm) = {
> > .init = init_evm_lsm,
> > .order = LSM_ORDER_LAST,
> > .blobs = &evm_blob_sizes,
> > + .initcall_late = integrity_late_init,
> > };
> > -
> > -late_initcall(init_evm);
> > diff --git a/security/integrity/iint.c b/security/integrity/iint.c
> > index 068ac6c2ae1e..a4b88d67ff43 100644
> > --- a/security/integrity/iint.c
> > +++ b/security/integrity/iint.c
> > @@ -11,6 +11,7 @@
> > */
> > #include <linux/security.h>
> > #include "integrity.h"
> > +#include "initcalls.h"
> >
> > struct dentry *integrity_dir;
> >
> > @@ -42,7 +43,7 @@ void __init integrity_load_keys(void)
> > evm_load_x509();
> > }
> >
> > -static int __init integrity_fs_init(void)
> > +int __init integrity_fs_init(void)
> > {
> > integrity_dir = securityfs_create_dir("integrity", NULL);
> > if (IS_ERR(integrity_dir)) {
> > @@ -58,4 +59,3 @@ static int __init integrity_fs_init(void)
> > return 0;
> > }
> >
> > -late_initcall(integrity_fs_init)
> > diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
> > index eade8e1e3cb1..06ae59cd77f4 100644
> > --- a/security/integrity/ima/ima_main.c
> > +++ b/security/integrity/ima/ima_main.c
> > @@ -28,6 +28,7 @@
> > #include <linux/iversion.h>
> > #include <linux/evm.h>
> > #include <linux/crash_dump.h>
> > +#include "../initcalls.h"
> >
> > #include "ima.h"
> >
> > @@ -1202,7 +1203,7 @@ static int ima_kernel_module_request(char *kmod_name)
> >
> > #endif /* CONFIG_INTEGRITY_ASYMMETRIC_KEYS */
> >
> > -static int __init init_ima(void)
> > +int __init init_ima(void)
> > {
> > int error;
> >
> > @@ -1283,6 +1284,5 @@ DEFINE_LSM(ima) = {
> > .init = init_ima_lsm,
> > .order = LSM_ORDER_LAST,
> > .blobs = &ima_blob_sizes,
> > + .initcall_late = integrity_late_init,
> > };
> > -
> > -late_initcall(init_ima); /* Start IMA after the TPM is available */
> > diff --git a/security/integrity/initcalls.c b/security/integrity/initcalls.c
> > new file mode 100644
> > index 000000000000..6afa411068f2
> > --- /dev/null
> > +++ b/security/integrity/initcalls.c
> > @@ -0,0 +1,41 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * IMA/EVM initcalls
> > + *
> > + */
> > +
> > +#include <linux/init.h>
> > +
> > +#include "initcalls.h"
> > +
> > +/**
> > + * integrity_late_init - late_initcalls for IMA/EVM
> > + *
> > + * This helper function wraps all of the late_initcalls for both IMA and EVM.
> > + * It can be called multiple times, e.g. once from IMA and once from EVM,
> > + * without problem as it maintains an internal static state variable which
> > + * ensures that any setup/initialization is only done once.
> > + */
> > +int __init integrity_late_init(void)
> > +{
> > + int rc = 0, rc_tmp;
> > + static bool setup = false;
> > +
> > + if (setup)
> > + return 0;
> > + setup = true;
> > +
> > + rc_tmp = integrity_fs_init();
> > + if (!rc && rc_tmp)
> > + rc = rc_tmp;
> > +
> > + rc_tmp = init_ima();
> > + if (!rc && rc_tmp)
> > + rc = rc_tmp;
> > +
> > + rc_tmp = init_evm();
> > + if (!rc && rc_tmp)
> > + rc = rc_tmp;
> > +
> > + return rc;
> > +}
> > diff --git a/security/integrity/initcalls.h b/security/integrity/initcalls.h
> > new file mode 100644
> > index 000000000000..b56e9c576505
> > --- /dev/null
> > +++ b/security/integrity/initcalls.h
> > @@ -0,0 +1,28 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +
> > +#ifndef _INTEGRITY_INITCALLS_H
> > +#define _INTEGRITY_INITCALLS_H
> > +
> > +int integrity_fs_init(void);
> > +
> > +#ifdef CONFIG_IMA
> > +int init_ima(void);
> > +#else
> > +static inline int init_ima(void)
> > +{
> > + return 0;
> > +}
> > +#endif
> > +
> > +#ifdef CONFIG_EVM
> > +int init_evm(void);
> > +#else
> > +static inline int init_evm(void)
> > +{
> > + return 0;
> > +}
> > +#endif
> > +
> > +int integrity_late_init(void);
> > +
> > +#endif
> > --
> > 2.50.1
>
^ permalink raw reply
* [PATCH] ima,evm: move initcalls to the LSM framework
From: Roberto Sassu @ 2025-09-02 12:54 UTC (permalink / raw)
To: paul, zohar, roberto.sassu
Cc: linux-security-module, linux-integrity, selinux, john.johansen,
wufan, mic, kees, mortonm, casey, penguin-kernel,
nicolas.bouchinet, xiujianfeng
In-Reply-To: <9f35539de7188c6b853c55b76958a286131f5928.camel@huaweicloud.com>
From: Paul Moore <paul@paul-moore.com>
This patch converts IMA and EVM to use the LSM frameworks's initcall
mechanism. It moved the integrity_fs_init() call to ima_fs_init() and
evm_init_secfs(), to work around the fact that there is no "integrity" LSM,
and introduced integrity_fs_fini() to remove the integrity directory, if
empty. Both integrity_fs_init() and integrity_fs_fini() support the
scenario of being called by both the IMA and EVM LSMs.
It is worth mentioning that this patch does not touch any of the
"platform certs" code that lives in the security/integrity/platform_certs
directory as the IMA/EVM maintainers have assured me that this code is
unrelated to IMA/EVM, despite the location, and will be moved to a more
relevant subsystem in the future.
Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
security/integrity/evm/evm_main.c | 3 +--
security/integrity/evm/evm_secfs.c | 11 +++++++++--
security/integrity/iint.c | 14 ++++++++++++--
security/integrity/ima/ima_fs.c | 11 +++++++++--
security/integrity/ima/ima_main.c | 4 ++--
security/integrity/integrity.h | 2 ++
6 files changed, 35 insertions(+), 10 deletions(-)
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index db8e324ed4e6..73d500a375cb 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -1179,6 +1179,5 @@ DEFINE_LSM(evm) = {
.init = init_evm_lsm,
.order = LSM_ORDER_LAST,
.blobs = &evm_blob_sizes,
+ .initcall_late = init_evm,
};
-
-late_initcall(init_evm);
diff --git a/security/integrity/evm/evm_secfs.c b/security/integrity/evm/evm_secfs.c
index b0d2aad27850..c26724690cec 100644
--- a/security/integrity/evm/evm_secfs.c
+++ b/security/integrity/evm/evm_secfs.c
@@ -302,10 +302,16 @@ int __init evm_init_secfs(void)
int error = 0;
struct dentry *dentry;
- evm_dir = securityfs_create_dir("evm", integrity_dir);
- if (IS_ERR(evm_dir))
+ error = integrity_fs_init();
+ if (error < 0)
return -EFAULT;
+ evm_dir = securityfs_create_dir("evm", integrity_dir);
+ if (IS_ERR(evm_dir)) {
+ error = -EFAULT;
+ goto out;
+ }
+
dentry = securityfs_create_file("evm", 0660,
evm_dir, NULL, &evm_key_ops);
if (IS_ERR(dentry)) {
@@ -329,5 +335,6 @@ int __init evm_init_secfs(void)
out:
securityfs_remove(evm_symlink);
securityfs_remove(evm_dir);
+ integrity_fs_fini();
return error;
}
diff --git a/security/integrity/iint.c b/security/integrity/iint.c
index 068ac6c2ae1e..8ec1a3436a71 100644
--- a/security/integrity/iint.c
+++ b/security/integrity/iint.c
@@ -42,8 +42,11 @@ void __init integrity_load_keys(void)
evm_load_x509();
}
-static int __init integrity_fs_init(void)
+int __init integrity_fs_init(void)
{
+ if (integrity_dir)
+ return 0;
+
integrity_dir = securityfs_create_dir("integrity", NULL);
if (IS_ERR(integrity_dir)) {
int ret = PTR_ERR(integrity_dir);
@@ -58,4 +61,11 @@ static int __init integrity_fs_init(void)
return 0;
}
-late_initcall(integrity_fs_init)
+void __init integrity_fs_fini(void)
+{
+ if (!integrity_dir || !simple_empty(integrity_dir))
+ return;
+
+ securityfs_remove(integrity_dir);
+ integrity_dir = NULL;
+}
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index 87045b09f120..012a58959ff0 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -499,9 +499,15 @@ int __init ima_fs_init(void)
struct dentry *dentry;
int ret;
+ ret = integrity_fs_init();
+ if (ret < 0)
+ return ret;
+
ima_dir = securityfs_create_dir("ima", integrity_dir);
- if (IS_ERR(ima_dir))
- return PTR_ERR(ima_dir);
+ if (IS_ERR(ima_dir)) {
+ ret = PTR_ERR(ima_dir);
+ goto out;
+ }
ima_symlink = securityfs_create_symlink("ima", NULL, "integrity/ima",
NULL);
@@ -555,6 +561,7 @@ int __init ima_fs_init(void)
out:
securityfs_remove(ima_symlink);
securityfs_remove(ima_dir);
+ integrity_fs_fini();
return ret;
}
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index eade8e1e3cb1..b703bfc2f470 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -1283,6 +1283,6 @@ DEFINE_LSM(ima) = {
.init = init_ima_lsm,
.order = LSM_ORDER_LAST,
.blobs = &ima_blob_sizes,
+ /* Start IMA after the TPM is available */
+ .initcall_late = init_ima,
};
-
-late_initcall(init_ima); /* Start IMA after the TPM is available */
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index c2c2da691123..7b388b66cf80 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -114,6 +114,8 @@ struct ima_file_id {
int integrity_kernel_read(struct file *file, loff_t offset,
void *addr, unsigned long count);
+int __init integrity_fs_init(void);
+void __init integrity_fs_fini(void);
#define INTEGRITY_KEYRING_EVM 0
#define INTEGRITY_KEYRING_IMA 1
--
2.43.0
^ permalink raw reply related
* Re: [PATCH v3 03/34] lsm: consolidate lsm_allowed() and prepare_lsm() into lsm_prepare()
From: John Johansen @ 2025-09-02 16:33 UTC (permalink / raw)
To: Paul Moore, linux-security-module, linux-integrity, selinux
Cc: Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
Tetsuo Handa, Nicolas Bouchinet, Xiu Jianfeng
In-Reply-To: <20250814225159.275901-39-paul@paul-moore.com>
On 8/14/25 15:50, Paul Moore wrote:
> Simplify and consolidate the lsm_allowed() and prepare_lsm() functions
> into a new function, lsm_prepare().
>
> Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
> Signed-off-by: Paul Moore <paul@paul-moore.com>
Looks good
Reviewed-by: John Johansen <john.johhansen@canonical.com>
> ---
> security/lsm_init.c | 109 +++++++++++++++++++-------------------------
> 1 file changed, 46 insertions(+), 63 deletions(-)
>
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index 124213b906af..6f40ab1d2f54 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -123,22 +123,6 @@ static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from)
> is_enabled(lsm) ? "enabled" : "disabled");
> }
>
> -/* Is an LSM allowed to be initialized? */
> -static bool __init lsm_allowed(struct lsm_info *lsm)
> -{
> - /* Skip if the LSM is disabled. */
> - if (!is_enabled(lsm))
> - return false;
> -
> - /* Not allowed if another exclusive LSM already initialized. */
> - if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && exclusive) {
> - init_debug("exclusive disabled: %s\n", lsm->name);
> - return false;
> - }
> -
> - return true;
> -}
> -
> static void __init lsm_set_blob_size(int *need, int *lbs)
> {
> int offset;
> @@ -151,54 +135,53 @@ static void __init lsm_set_blob_size(int *need, int *lbs)
> *need = offset;
> }
>
> -static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
> +/**
> + * lsm_prepare - Prepare the LSM framework for a new LSM
> + * @lsm: LSM definition
> + */
> +static void __init lsm_prepare(struct lsm_info *lsm)
> {
> - if (!needed)
> + struct lsm_blob_sizes *blobs;
> +
> + if (!is_enabled(lsm)) {
> + set_enabled(lsm, false);
> + return;
> + } else if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && exclusive) {
> + init_debug("exclusive disabled: %s\n", lsm->name);
> + set_enabled(lsm, false);
> return;
> -
> - lsm_set_blob_size(&needed->lbs_cred, &blob_sizes.lbs_cred);
> - lsm_set_blob_size(&needed->lbs_file, &blob_sizes.lbs_file);
> - lsm_set_blob_size(&needed->lbs_ib, &blob_sizes.lbs_ib);
> - /*
> - * The inode blob gets an rcu_head in addition to
> - * what the modules might need.
> - */
> - if (needed->lbs_inode && blob_sizes.lbs_inode == 0)
> - blob_sizes.lbs_inode = sizeof(struct rcu_head);
> - lsm_set_blob_size(&needed->lbs_inode, &blob_sizes.lbs_inode);
> - lsm_set_blob_size(&needed->lbs_ipc, &blob_sizes.lbs_ipc);
> - lsm_set_blob_size(&needed->lbs_key, &blob_sizes.lbs_key);
> - lsm_set_blob_size(&needed->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
> - lsm_set_blob_size(&needed->lbs_perf_event, &blob_sizes.lbs_perf_event);
> - lsm_set_blob_size(&needed->lbs_sock, &blob_sizes.lbs_sock);
> - lsm_set_blob_size(&needed->lbs_superblock, &blob_sizes.lbs_superblock);
> - lsm_set_blob_size(&needed->lbs_task, &blob_sizes.lbs_task);
> - lsm_set_blob_size(&needed->lbs_tun_dev, &blob_sizes.lbs_tun_dev);
> - lsm_set_blob_size(&needed->lbs_xattr_count,
> - &blob_sizes.lbs_xattr_count);
> - lsm_set_blob_size(&needed->lbs_bdev, &blob_sizes.lbs_bdev);
> - lsm_set_blob_size(&needed->lbs_bpf_map, &blob_sizes.lbs_bpf_map);
> - lsm_set_blob_size(&needed->lbs_bpf_prog, &blob_sizes.lbs_bpf_prog);
> - lsm_set_blob_size(&needed->lbs_bpf_token, &blob_sizes.lbs_bpf_token);
> -}
> -
> -/* Prepare LSM for initialization. */
> -static void __init prepare_lsm(struct lsm_info *lsm)
> -{
> - int enabled = lsm_allowed(lsm);
> -
> - /* Record enablement (to handle any following exclusive LSMs). */
> - set_enabled(lsm, enabled);
> -
> - /* If enabled, do pre-initialization work. */
> - if (enabled) {
> - if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !exclusive) {
> - exclusive = lsm;
> - init_debug("exclusive chosen: %s\n", lsm->name);
> - }
> -
> - lsm_set_blob_sizes(lsm->blobs);
> }
> +
> + /* Mark the LSM as enabled. */
> + set_enabled(lsm, true);
> + if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !exclusive) {
> + init_debug("exclusive chosen: %s\n", lsm->name);
> + exclusive = lsm;
> + }
> +
> + /* Register the LSM blob sizes. */
> + blobs = lsm->blobs;
> + lsm_set_blob_size(&blobs->lbs_cred, &blob_sizes.lbs_cred);
> + lsm_set_blob_size(&blobs->lbs_file, &blob_sizes.lbs_file);
> + lsm_set_blob_size(&blobs->lbs_ib, &blob_sizes.lbs_ib);
> + /* inode blob 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_set_blob_size(&blobs->lbs_inode, &blob_sizes.lbs_inode);
> + lsm_set_blob_size(&blobs->lbs_ipc, &blob_sizes.lbs_ipc);
> + lsm_set_blob_size(&blobs->lbs_key, &blob_sizes.lbs_key);
> + lsm_set_blob_size(&blobs->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
> + lsm_set_blob_size(&blobs->lbs_perf_event, &blob_sizes.lbs_perf_event);
> + lsm_set_blob_size(&blobs->lbs_sock, &blob_sizes.lbs_sock);
> + lsm_set_blob_size(&blobs->lbs_superblock, &blob_sizes.lbs_superblock);
> + lsm_set_blob_size(&blobs->lbs_task, &blob_sizes.lbs_task);
> + lsm_set_blob_size(&blobs->lbs_tun_dev, &blob_sizes.lbs_tun_dev);
> + lsm_set_blob_size(&blobs->lbs_xattr_count,
> + &blob_sizes.lbs_xattr_count);
> + lsm_set_blob_size(&blobs->lbs_bdev, &blob_sizes.lbs_bdev);
> + lsm_set_blob_size(&blobs->lbs_bpf_map, &blob_sizes.lbs_bpf_map);
> + lsm_set_blob_size(&blobs->lbs_bpf_prog, &blob_sizes.lbs_bpf_prog);
> + lsm_set_blob_size(&blobs->lbs_bpf_token, &blob_sizes.lbs_bpf_token);
> }
>
> /* Initialize a given LSM, if it is enabled. */
> @@ -361,7 +344,7 @@ static void __init ordered_lsm_init(void)
> ordered_lsm_parse(builtin_lsm_order, "builtin");
>
> for (lsm = ordered_lsms; *lsm; lsm++)
> - prepare_lsm(*lsm);
> + lsm_prepare(*lsm);
>
> report_lsm_order();
>
> @@ -505,7 +488,7 @@ int __init early_security_init(void)
> for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
> if (!lsm->enabled)
> lsm->enabled = &lsm_enabled_true;
> - prepare_lsm(lsm);
> + lsm_prepare(lsm);
> initialize_lsm(lsm);
> }
>
^ permalink raw reply
* Re: [PATCH v3 04/34] lsm: introduce looping macros for the initialization code
From: John Johansen @ 2025-09-02 16:37 UTC (permalink / raw)
To: Paul Moore, linux-security-module, linux-integrity, selinux
Cc: Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
Tetsuo Handa, Nicolas Bouchinet, Xiu Jianfeng
In-Reply-To: <20250814225159.275901-40-paul@paul-moore.com>
On 8/14/25 15:50, Paul Moore wrote:
> There are three common for loop patterns in the LSM initialization code
> to loop through the ordered LSM list and the registered "early" LSMs.
> This patch implements these loop patterns as macros to help simplify the
> code and reduce the change for errors.
^
chance
otherwise looks good, and you can add my
Reviewed-by: John Johansen <john.johansen@canonical.com>
> Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
> Signed-off-by: Paul Moore <paul@paul-moore.com>
> ---
> security/lsm_init.c | 42 +++++++++++++++++++++++++++---------------
> 1 file changed, 27 insertions(+), 15 deletions(-)
>
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index 6f40ab1d2f54..18828a65c364 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -32,6 +32,15 @@ static __initdata bool debug;
> pr_info(__VA_ARGS__); \
> } while (0)
>
> +#define lsm_order_for_each(iter) \
> + for ((iter) = ordered_lsms; *(iter); (iter)++)
> +#define lsm_for_each_raw(iter) \
> + for ((iter) = __start_lsm_info; \
> + (iter) < __end_lsm_info; (iter)++)
> +#define lsm_early_for_each_raw(iter) \
> + for ((iter) = __start_early_lsm_info; \
> + (iter) < __end_early_lsm_info; (iter)++)
> +
> static int lsm_append(const char *new, char **result);
>
> /* Save user chosen LSM */
> @@ -96,9 +105,10 @@ static bool __init exists_ordered_lsm(struct lsm_info *lsm)
> {
> struct lsm_info **check;
>
> - for (check = ordered_lsms; *check; check++)
> + lsm_order_for_each(check) {
> if (*check == lsm)
> return true;
> + }
>
> return false;
> }
> @@ -209,7 +219,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
> char *sep, *name, *next;
>
> /* LSM_ORDER_FIRST is always first. */
> - for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
> + lsm_for_each_raw(lsm) {
> if (lsm->order == LSM_ORDER_FIRST)
> append_ordered_lsm(lsm, " first");
> }
> @@ -224,8 +234,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
> * if the selected one was separately disabled: disable
> * all non-matching Legacy Major LSMs.
> */
> - for (major = __start_lsm_info; major < __end_lsm_info;
> - major++) {
> + lsm_for_each_raw(major) {
> if ((major->flags & LSM_FLAG_LEGACY_MAJOR) &&
> strcmp(major->name, chosen_major_lsm) != 0) {
> set_enabled(major, false);
> @@ -241,7 +250,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
> while ((name = strsep(&next, ",")) != NULL) {
> bool found = false;
>
> - for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
> + lsm_for_each_raw(lsm) {
> if (strcmp(lsm->name, name) == 0) {
> if (lsm->order == LSM_ORDER_MUTABLE)
> append_ordered_lsm(lsm, origin);
> @@ -256,7 +265,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
>
> /* Process "security=", if given. */
> if (chosen_major_lsm) {
> - for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
> + lsm_for_each_raw(lsm) {
> if (exists_ordered_lsm(lsm))
> continue;
> if (strcmp(lsm->name, chosen_major_lsm) == 0)
> @@ -265,13 +274,13 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
> }
>
> /* LSM_ORDER_LAST is always last. */
> - for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
> + lsm_for_each_raw(lsm) {
> if (lsm->order == LSM_ORDER_LAST)
> append_ordered_lsm(lsm, " last");
> }
>
> /* Disable all LSMs not in the ordered list. */
> - for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
> + lsm_for_each_raw(lsm) {
> if (exists_ordered_lsm(lsm))
> continue;
> set_enabled(lsm, false);
> @@ -290,13 +299,14 @@ static void __init report_lsm_order(void)
> pr_info("initializing lsm=");
>
> /* Report each enabled LSM name, comma separated. */
> - for (early = __start_early_lsm_info;
> - early < __end_early_lsm_info; early++)
> + lsm_early_for_each_raw(early) {
> if (is_enabled(early))
> pr_cont("%s%s", first++ == 0 ? "" : ",", early->name);
> - for (lsm = ordered_lsms; *lsm; lsm++)
> + }
> + lsm_order_for_each(lsm) {
> if (is_enabled(*lsm))
> pr_cont("%s%s", first++ == 0 ? "" : ",", (*lsm)->name);
> + }
>
> pr_cont("\n");
> }
> @@ -343,8 +353,9 @@ static void __init ordered_lsm_init(void)
> } else
> ordered_lsm_parse(builtin_lsm_order, "builtin");
>
> - for (lsm = ordered_lsms; *lsm; lsm++)
> + lsm_order_for_each(lsm) {
> lsm_prepare(*lsm);
> + }
>
> report_lsm_order();
>
> @@ -382,8 +393,9 @@ static void __init ordered_lsm_init(void)
>
> lsm_early_cred((struct cred *) current->cred);
> lsm_early_task(current);
> - for (lsm = ordered_lsms; *lsm; lsm++)
> + lsm_order_for_each(lsm) {
> initialize_lsm(*lsm);
> + }
> }
>
> static bool match_last_lsm(const char *list, const char *lsm)
> @@ -485,7 +497,7 @@ int __init early_security_init(void)
> {
> struct lsm_info *lsm;
>
> - for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
> + lsm_early_for_each_raw(lsm) {
> if (!lsm->enabled)
> lsm->enabled = &lsm_enabled_true;
> lsm_prepare(lsm);
> @@ -512,7 +524,7 @@ int __init security_init(void)
> * Append the names of the early LSM modules now that kmalloc() is
> * available
> */
> - for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
> + lsm_early_for_each_raw(lsm) {
> init_debug(" early started: %s (%s)\n", lsm->name,
> is_enabled(lsm) ? "enabled" : "disabled");
> if (lsm->enabled)
^ permalink raw reply
* Re: [PATCH v3 05/34] lsm: integrate report_lsm_order() code into caller
From: John Johansen @ 2025-09-02 16:53 UTC (permalink / raw)
To: Paul Moore, linux-security-module, linux-integrity, selinux
Cc: Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
Tetsuo Handa, Nicolas Bouchinet, Xiu Jianfeng
In-Reply-To: <20250814225159.275901-41-paul@paul-moore.com>
On 8/14/25 15:50, Paul Moore wrote:
> With only one caller of report_lsm_order(), insert the function's code
> directly into the caller and ger rid of report_lsm_order().
>
> Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
> Signed-off-by: Paul Moore <paul@paul-moore.com>
Reviewed-by: John Johansen <john.johansen@canonical.com>
> ---
> security/lsm_init.c | 33 ++++++++++++---------------------
> 1 file changed, 12 insertions(+), 21 deletions(-)
>
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index 18828a65c364..09afa7ad719e 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -291,26 +291,6 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
> kfree(sep);
> }
>
> -static void __init report_lsm_order(void)
> -{
> - struct lsm_info **lsm, *early;
> - int first = 0;
> -
> - pr_info("initializing lsm=");
> -
> - /* Report each enabled LSM name, comma separated. */
> - lsm_early_for_each_raw(early) {
> - if (is_enabled(early))
> - pr_cont("%s%s", first++ == 0 ? "" : ",", early->name);
> - }
> - lsm_order_for_each(lsm) {
> - if (is_enabled(*lsm))
> - pr_cont("%s%s", first++ == 0 ? "" : ",", (*lsm)->name);
> - }
> -
> - pr_cont("\n");
> -}
> -
> /**
> * lsm_early_cred - during initialization allocate a composite cred blob
> * @cred: the cred that needs a blob
> @@ -341,7 +321,9 @@ static void __init lsm_early_task(struct task_struct *task)
>
> static void __init ordered_lsm_init(void)
> {
> + unsigned int first = 0;
> struct lsm_info **lsm;
> + struct lsm_info *early;
>
> if (chosen_lsm_order) {
> if (chosen_major_lsm) {
> @@ -357,7 +339,16 @@ static void __init ordered_lsm_init(void)
> lsm_prepare(*lsm);
> }
>
> - report_lsm_order();
> + pr_info("initializing lsm=");
> + lsm_early_for_each_raw(early) {
> + if (is_enabled(early))
> + pr_cont("%s%s", first++ == 0 ? "" : ",", early->name);
> + }
> + lsm_order_for_each(lsm) {
> + if (is_enabled(*lsm))
> + pr_cont("%s%s", first++ == 0 ? "" : ",", (*lsm)->name);
> + }
> + pr_cont("\n");
>
> init_debug("cred blob size = %d\n", blob_sizes.lbs_cred);
> init_debug("file blob size = %d\n", blob_sizes.lbs_file);
^ permalink raw reply
* Re: [PATCH v3 06/34] lsm: integrate lsm_early_cred() and lsm_early_task() into caller
From: John Johansen @ 2025-09-02 16:55 UTC (permalink / raw)
To: Paul Moore, linux-security-module, linux-integrity, selinux
Cc: Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
Tetsuo Handa, Nicolas Bouchinet, Xiu Jianfeng
In-Reply-To: <20250814225159.275901-42-paul@paul-moore.com>
On 8/14/25 15:50, Paul Moore wrote:
> With only one caller of lsm_early_cred() and lsm_early_task(), insert
> the functions' code directly into the caller and ger rid of the two
> functions.
>
> Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
> Signed-off-by: Paul Moore <paul@paul-moore.com>
Reviewed-by: John Johansen <john.johansen@canonical.com>
> ---
> security/lsm_init.c | 35 +++++------------------------------
> 1 file changed, 5 insertions(+), 30 deletions(-)
>
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index 09afa7ad719e..a8b82329c76a 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -291,34 +291,6 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
> kfree(sep);
> }
>
> -/**
> - * lsm_early_cred - during initialization allocate a composite cred blob
> - * @cred: the cred that needs a blob
> - *
> - * Allocate the cred blob for all the modules
> - */
> -static void __init lsm_early_cred(struct cred *cred)
> -{
> - int rc = lsm_cred_alloc(cred, GFP_KERNEL);
> -
> - if (rc)
> - panic("%s: Early cred alloc failed.\n", __func__);
> -}
> -
> -/**
> - * lsm_early_task - during initialization allocate a composite task blob
> - * @task: the task that needs a blob
> - *
> - * Allocate the task blob for all the modules
> - */
> -static void __init lsm_early_task(struct task_struct *task)
> -{
> - int rc = lsm_task_alloc(task);
> -
> - if (rc)
> - panic("%s: Early task alloc failed.\n", __func__);
> -}
> -
> static void __init ordered_lsm_init(void)
> {
> unsigned int first = 0;
> @@ -382,8 +354,11 @@ static void __init ordered_lsm_init(void)
> blob_sizes.lbs_inode, 0,
> SLAB_PANIC, NULL);
>
> - lsm_early_cred((struct cred *) current->cred);
> - lsm_early_task(current);
> + if (lsm_cred_alloc((struct cred *)current->cred, GFP_KERNEL))
> + panic("%s: early cred alloc failed.\n", __func__);
> + if (lsm_task_alloc(current))
> + panic("%s: early task alloc failed.\n", __func__);
> +
> lsm_order_for_each(lsm) {
> initialize_lsm(*lsm);
> }
^ permalink raw reply
* Re: [PATCH v3 07/34] lsm: rename ordered_lsm_init() to lsm_init_ordered()
From: John Johansen @ 2025-09-02 16:56 UTC (permalink / raw)
To: Paul Moore, linux-security-module, linux-integrity, selinux
Cc: Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
Tetsuo Handa, Nicolas Bouchinet, Xiu Jianfeng
In-Reply-To: <20250814225159.275901-43-paul@paul-moore.com>
On 8/14/25 15:50, Paul Moore wrote:
> The new name more closely fits the rest of the naming scheme in
> security/lsm_init.c. This patch also adds a trivial comment block to
> the top of the function.
>
> Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
> Signed-off-by: Paul Moore <paul@paul-moore.com>
Reviewed-by: John Johansen <john.johansen@canonical.com>
> ---
> security/lsm_init.c | 10 +++++-----
> 1 file changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index a8b82329c76a..4a108b03c23d 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -291,7 +291,10 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
> kfree(sep);
> }
>
> -static void __init ordered_lsm_init(void)
> +/**
> + * lsm_init_ordered - Initialize the ordered LSMs
> + */
> +static void __init lsm_init_ordered(void)
> {
> unsigned int first = 0;
> struct lsm_info **lsm;
> @@ -342,9 +345,6 @@ static void __init ordered_lsm_init(void)
> init_debug("bpf prog blob size = %d\n", blob_sizes.lbs_bpf_prog);
> init_debug("bpf token blob size = %d\n", blob_sizes.lbs_bpf_token);
>
> - /*
> - * Create any kmem_caches needed for blobs
> - */
> if (blob_sizes.lbs_file)
> lsm_file_cache = kmem_cache_create("lsm_file_cache",
> blob_sizes.lbs_file, 0,
> @@ -498,7 +498,7 @@ int __init security_init(void)
> }
>
> /* Load LSMs in specified order. */
> - ordered_lsm_init();
> + lsm_init_ordered();
>
> return 0;
> }
^ permalink raw reply
* Re: [PATCH v3 10/34] lsm: rework lsm_active_cnt and lsm_idlist[]
From: John Johansen @ 2025-09-02 17:01 UTC (permalink / raw)
To: Paul Moore, linux-security-module, linux-integrity, selinux
Cc: Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
Tetsuo Handa, Nicolas Bouchinet, Xiu Jianfeng
In-Reply-To: <20250814225159.275901-46-paul@paul-moore.com>
On 8/14/25 15:50, Paul Moore wrote:
> Move the LSM active count and lsm_id list declarations out of a header
> that is visible across the kernel and into a header that is limited to
> the LSM framework. This not only helps keep the include/linux headers
> smaller and cleaner, it helps prevent misuse of these variables.
>
> Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
> Signed-off-by: Paul Moore <paul@paul-moore.com>
Reviewed-by: John Johansen <john.johansen@canonical.com>
> ---
> include/linux/security.h | 2 --
> security/lsm.h | 5 +++++
> security/lsm_init.c | 6 ------
> security/lsm_syscalls.c | 2 ++
> security/security.c | 3 +++
> 5 files changed, 10 insertions(+), 8 deletions(-)
>
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 521bcb5b9717..8560c50edd2e 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -167,8 +167,6 @@ struct lsm_prop {
> };
>
> extern const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1];
> -extern u32 lsm_active_cnt;
> -extern const struct lsm_id *lsm_idlist[];
>
> /* These functions are in security/commoncap.c */
> extern int cap_capable(const struct cred *cred, struct user_namespace *ns,
> diff --git a/security/lsm.h b/security/lsm.h
> index 0e1731bad4a7..dbe755c45e57 100644
> --- a/security/lsm.h
> +++ b/security/lsm.h
> @@ -7,6 +7,11 @@
> #define _LSM_H_
>
> #include <linux/lsm_hooks.h>
> +#include <linux/lsm_count.h>
> +
> +/* List of configured LSMs */
> +extern unsigned int lsm_active_cnt;
> +extern const struct lsm_id *lsm_idlist[];
>
> /* LSM blob configuration */
> extern struct lsm_blob_sizes blob_sizes;
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index 2e76cefb1585..9e495a36a332 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -217,12 +217,6 @@ static void __init initialize_lsm(struct lsm_info *lsm)
> }
> }
>
> -/*
> - * Current index to use while initializing the lsm id list.
> - */
> -u32 lsm_active_cnt __ro_after_init;
> -const struct lsm_id *lsm_idlist[MAX_LSM_COUNT];
> -
> /* Populate ordered LSMs list from comma-separated LSM name list. */
> static void __init ordered_lsm_parse(const char *order, const char *origin)
> {
> diff --git a/security/lsm_syscalls.c b/security/lsm_syscalls.c
> index 8440948a690c..5648b1f0ce9c 100644
> --- a/security/lsm_syscalls.c
> +++ b/security/lsm_syscalls.c
> @@ -17,6 +17,8 @@
> #include <linux/lsm_hooks.h>
> #include <uapi/linux/lsm.h>
>
> +#include "lsm.h"
> +
> /**
> * lsm_name_to_attr - map an LSM attribute name to its ID
> * @name: name of the attribute
> diff --git a/security/security.c b/security/security.c
> index ff6da6735e2a..add46073af0c 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -73,6 +73,9 @@ const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX + 1] = {
> [LOCKDOWN_CONFIDENTIALITY_MAX] = "confidentiality",
> };
>
> +unsigned int lsm_active_cnt __ro_after_init;
> +const struct lsm_id *lsm_idlist[MAX_LSM_COUNT];
> +
> struct lsm_blob_sizes blob_sizes;
>
> struct kmem_cache *lsm_file_cache;
^ permalink raw reply
* Re: [PATCH v3 11/34] lsm: get rid of the lsm_names list and do some cleanup
From: John Johansen @ 2025-09-02 17:20 UTC (permalink / raw)
To: Paul Moore, linux-security-module, linux-integrity, selinux
Cc: Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
Tetsuo Handa, Nicolas Bouchinet, Xiu Jianfeng
In-Reply-To: <20250814225159.275901-47-paul@paul-moore.com>
On 8/14/25 15:50, Paul Moore wrote:
> The LSM currently has a lot of code to maintain a list of the currently
> active LSMs in a human readable string, with the only user being the
> "/sys/kernel/security/lsm" code. Let's drop all of that code and
> generate the string on first use and then cache it for subsequent use.
>
> Signed-off-by: Paul Moore <paul@paul-moore.com>
> ---
> include/linux/lsm_hooks.h | 1 -
> security/inode.c | 59 +++++++++++++++++++++++++++++++++++++--
> security/lsm_init.c | 49 --------------------------------
> 3 files changed, 57 insertions(+), 52 deletions(-)
>
> diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
> index 7343dd60b1d5..65a8227bece7 100644
> --- a/include/linux/lsm_hooks.h
> +++ b/include/linux/lsm_hooks.h
> @@ -172,7 +172,6 @@ struct lsm_info {
>
>
> /* DO NOT tamper with these variables outside of the LSM framework */
> -extern char *lsm_names;
> extern struct lsm_static_calls_table static_calls_table __ro_after_init;
>
> /**
> diff --git a/security/inode.c b/security/inode.c
> index 43382ef8896e..a5e7a073e672 100644
> --- a/security/inode.c
> +++ b/security/inode.c
> @@ -22,6 +22,8 @@
> #include <linux/lsm_hooks.h>
> #include <linux/magic.h>
>
> +#include "lsm.h"
> +
> static struct vfsmount *mount;
> static int mount_count;
>
> @@ -315,12 +317,65 @@ void securityfs_remove(struct dentry *dentry)
> EXPORT_SYMBOL_GPL(securityfs_remove);
>
> #ifdef CONFIG_SECURITY
> +#include <linux/spinlock.h>
> +
> static struct dentry *lsm_dentry;
> +
> +/* NOTE: we never free the string below once it is set. */
> +static DEFINE_SPINLOCK(lsm_read_lock);
nit, this is only used on the write side, so not the best name
> +static char *lsm_read_str = NULL;
> +static ssize_t lsm_read_len = 0;
> +
> static ssize_t lsm_read(struct file *filp, char __user *buf, size_t count,
> loff_t *ppos)
> {
> - return simple_read_from_buffer(buf, count, ppos, lsm_names,
> - strlen(lsm_names));
> + int i;
> + char *str;
> + ssize_t len;
> +
> +restart:
> +
> + rcu_read_lock();
> + if (!lsm_read_str) {
should probably be
if (!rcu_access_pointer(lsm_read_str)) {
> + /* we need to generate the string and try again */
> + rcu_read_unlock();
> + goto generate_string;
> + }
> + len = simple_read_from_buffer(buf, count, ppos,
> + rcu_dereference(lsm_read_str),
> + lsm_read_len);
> + rcu_read_unlock();
> + return len;
> +
> +generate_string:
> +
> + for (i = 0; i < lsm_active_cnt; i++)
> + /* the '+ 1' accounts for either a comma or a NUL */
> + len += strlen(lsm_idlist[i]->name) + 1;
> +
> + str = kmalloc(len, GFP_KERNEL);
> + if (!str)
> + return -ENOMEM;
> + str[0] = '\0';
> +
> + for (i = 0; i < lsm_active_cnt; i++) {
> + if (i > 0)
> + strcat(str, ",");
> + strcat(str, lsm_idlist[i]->name);
> + }
> +
> + spin_lock(&lsm_read_lock);
> + if (lsm_read_str) {
> + /* we raced and lost */
> + spin_unlock(&lsm_read_lock);
> + kfree(str);
> + goto restart;
> + }
> + lsm_read_str = str;
> + lsm_read_len = len - 1;
> + spin_unlock(&lsm_read_lock);
> +
> + goto restart;
> }
>
> static const struct file_operations lsm_ops = {
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index 9e495a36a332..87e2147016b3 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -10,8 +10,6 @@
>
> #include "lsm.h"
>
> -char *lsm_names;
> -
> /* Pointers to LSM sections defined in include/asm-generic/vmlinux.lds.h */
> extern struct lsm_info __start_lsm_info[], __end_lsm_info[];
> extern struct lsm_info __start_early_lsm_info[], __end_early_lsm_info[];
> @@ -371,42 +369,6 @@ static void __init lsm_init_ordered(void)
> }
> }
>
> -static bool match_last_lsm(const char *list, const char *lsm)
> -{
> - const char *last;
> -
> - if (WARN_ON(!list || !lsm))
> - return false;
> - last = strrchr(list, ',');
> - if (last)
> - /* Pass the comma, strcmp() will check for '\0' */
> - last++;
> - else
> - last = list;
> - return !strcmp(last, lsm);
> -}
> -
> -static int lsm_append(const char *new, char **result)
> -{
> - char *cp;
> -
> - if (*result == NULL) {
> - *result = kstrdup(new, GFP_KERNEL);
> - if (*result == NULL)
> - return -ENOMEM;
> - } else {
> - /* Check if it is the last registered name */
> - if (match_last_lsm(*result, new))
> - return 0;
> - cp = kasprintf(GFP_KERNEL, "%s,%s", *result, new);
> - if (cp == NULL)
> - return -ENOMEM;
> - kfree(*result);
> - *result = cp;
> - }
> - return 0;
> -}
> -
> static void __init lsm_static_call_init(struct security_hook_list *hl)
> {
> struct lsm_static_call *scall = hl->scalls;
> @@ -443,15 +405,6 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count,
> hooks[i].lsmid = lsmid;
> lsm_static_call_init(&hooks[i]);
> }
> -
> - /*
> - * Don't try to append during early_security_init(), we'll come back
> - * and fix this up afterwards.
> - */
> - if (slab_is_available()) {
> - if (lsm_append(lsmid->name, &lsm_names) < 0)
> - panic("%s - Cannot get early memory.\n", __func__);
> - }
> }
>
> int __init early_security_init(void)
> @@ -488,8 +441,6 @@ int __init security_init(void)
> lsm_early_for_each_raw(lsm) {
> init_debug(" early started: %s (%s)\n", lsm->id->name,
> is_enabled(lsm) ? "enabled" : "disabled");
> - if (lsm->enabled)
> - lsm_append(lsm->id->name, &lsm_names);
> }
>
> /* Load LSMs in specified order. */
^ permalink raw reply
* Re: [PATCH] x86/bpf: use bpf_capable() instead of capable(CAP_SYS_ADMIN)
From: Alexei Starovoitov @ 2025-09-02 17:36 UTC (permalink / raw)
To: Ondrej Mosnacek
Cc: Serge E. Hallyn, daniel.sneddon, Pawan Gupta, Dave Hansen,
alexandre.chartre, Alexei Starovoitov, Daniel Borkmann, bpf,
selinux, LSM List
In-Reply-To: <CAFqZXNtAfzFJtL3gG7ViEFOWoAE2VNrvCOA5DxqMmWt7z6g5Yg@mail.gmail.com>
On Wed, Aug 13, 2025 at 2:49 AM Ondrej Mosnacek <omosnace@redhat.com> wrote:
>
> On Sat, Aug 9, 2025 at 2:46 AM Alexei Starovoitov
> <alexei.starovoitov@gmail.com> wrote:
> >
> > On Fri, Aug 8, 2025 at 4:59 PM Serge E. Hallyn <serge@hallyn.com> wrote:
> > >
> > > On Wed, Aug 06, 2025 at 08:18:55PM -0500, Serge E. Hallyn wrote:
> > > > On Wed, Aug 06, 2025 at 04:31:05PM +0200, Ondrej Mosnacek wrote:
> > > > > Don't check against the overloaded CAP_SYS_ADMINin do_jit(), but instead
> > > > > use bpf_capable(), which checks against the more granular CAP_BPF first.
> > > > > Going straight to CAP_SYS_ADMIN may cause unnecessary audit log spam
> > > > > under SELinux, as privileged domains using BPF would usually only be
> > > > > allowed CAP_BPF and not CAP_SYS_ADMIN.
> > > > >
> > > > > Link: https://bugzilla.redhat.com/show_bug.cgi?id=2369326
> > > > > Fixes: d4e89d212d40 ("x86/bpf: Call branch history clearing sequence on exit")
> > > > > Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
> > > >
> > > > So this seems correct, *provided* that we consider it within the purview of
> > > > CAP_BPF to be able to avoid clearing the branch history buffer.
> >
> > true, but...
> >
> > > >
> > > > I suspect that's the case, but it might warrant discussion.
> > > >
> > > > Reviewed-by: Serge Hallyn <serge@hallyn.com>
> > >
> > > (BTW, I'm assuming this will get pulled into a BPF tree or something, and
> > > doesn't need to go into the capabilities tree. Let me know if that's wrong)
> >
> > Right.
> > scripts/get_maintainer.pl arch/x86/net/bpf_jit_comp.c
> > is your friend.
> >
> > Pls cc author-s of the commit in question in the future.
> > Adding them now.
> >
> > > > > diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
> > > > > index 15672cb926fc1..2a825e5745ca1 100644
> > > > > --- a/arch/x86/net/bpf_jit_comp.c
> > > > > +++ b/arch/x86/net/bpf_jit_comp.c
> > > > > @@ -2591,8 +2591,7 @@ emit_jmp:
> > > > > seen_exit = true;
> > > > > /* Update cleanup_addr */
> > > > > ctx->cleanup_addr = proglen;
> > > > > - if (bpf_prog_was_classic(bpf_prog) &&
> > > > > - !capable(CAP_SYS_ADMIN)) {
> > > > > + if (bpf_prog_was_classic(bpf_prog) && !bpf_capable()) {
> >
> > This looks wrong for several reasons.
> >
> > 1.
> > bpf_capable() and CAP_BPF in general applies to eBPF only.
> > There is no precedent so far to do anything differently
> > for cBPF when CAP_BPF is present.
>
> That's not entirely true, see below.
>
> > 2.
> > commit log states that
> > "privileged domains using BPF would usually only be allowed CAP_BPF
> > and not CAP_SYS_ADMIN"
> > which is true for eBPF only, since cBPF is always allowed for
> > all unpriv users.
> > Start chrome browser and you get cBPF loaded.
>
> Processes using cBPF (via SO_ATTACH_FILTER) already can trigger a
> CAP_BPF check - when the net.core.bpf_jit_harden sysctl is set to 1,
> then the sequence sk_attach_filter() -> __get_filter() ->
> bpf_prog_alloc() -> bpf_prog_alloc_no_stats() ->
> bpf_jit_blinding_enabled() -> bpf_token_capable() happens for the same
> iio-sensor-proxy syscall as the one that hits the CAP_SYS_ADMIN check.
Agree that it's a similar case and we should standardize on
the way to check whether mitigation is necessary.
But I think in both cases it should be "_noaudit" version.
In other words, everywhere where jit, verifier or anything else
is checking caps to apply a mitigation or not we should use "_noaudit".
> Because of this we have already granted the BPF capability in
> Fedora/RHEL SELinux policy to many domains that would usually run as
> root and that use SO_ATTACH_FILTER. The logic being that they are
> legitimately using BPF + without SELinux they would be fully
> privileged (root) and they would pass that check + it seemed they
> could otherwise lose some performance due to the hardening (though I'm
> not sure now if it applies to cBPF, so this point could be moot) +
> CAP_BPF doesn't grant any excess privileges beyond this (as opposed to
> e.g. CAP_SYS_ADMIN). This is what I meant behind that commit log
> statement, though I didn't remember the details, so I didn't state it
> as clearly as I could have (my apologies).
>
> Now this same usage started triggering the new plain CAP_SYS_ADMIN
> check so I naturally assumed that changing it to bpf_capable() would
> be the most logical solution (as it would let us keep the services
> excluded from the hardening via CAP_BPF without granting the broad
> CAP_SYS_ADMIN).
I see. Sounds like you identified bpf_jit_blinding_enabled() case
and special cased it selinux. So doing bpf_capable() in JIT
would fit the existing selinux handling.
>
> Is the fact that CAP_BPF check is reachable via cBPF use unexpected
> behavior? If both cBPF and eBPF can be JIT'd and CAP_BPF is already
> being used for the "exempt from JIT hardening" semantics in one place,
> why should cBPF and eBPF be treated differently? In fact, shouldn't
> the decision to apply the Spectre mitigation also take into account
> the net.core.bpf_jit_harden sysctl even when the program is not cBPF?
>
> > 3.
> > glancing over bugzilla it seems that the issue is
> > excessive audit spam and not related to CAP_BPF and privileges.
> > If so then the fix is to use
> > ns_capable_noaudit(&init_user_ns, CAP_SYS_ADMIN)
> >
> > 4.
> > I don't understand how the patch is supposed to fix the issue.
> > iio-sensor-proxy is probably unpriv. Why would it use CAP_BPF?
> > It's using cBPF, so there is no reason for it to have CAP_BPF.
> > So capable(CAP_BPF) will fail just like capable(CAP_SYS_ADMIN),
> > but since CAP_BPF check was done first, the audit won't
> > be printed, because it's some undocumented internal selinux behavior ?
> > None of it is in the commit log :(
>
> It is not unprivileged. It runs as root and without SELinux it would
> have all capabilities allowed. If it were running without any
> capabilities, then indeed there would be no SELinux checks.
>
> > 5.
> > And finally all that looks like a selinux bug.
> > Just because something in the kernel is asking capable(CAP_SYS_ADMIN)
> > there is no need to spam users with the wrong message:
> > "SELinux is preventing iio-sensor-prox from using the 'sys_admin' capabilities."
> > iio-sensor-prox is not trying to use 'sys_admin' capabilities.
> > cBPF prog will be loaded anyway, with or without BHB clearing.
>
> Well, it depends... In this case the AVC denial informs us that the
> kernel is making some decision depending on the capability and that a
> decision should be made in the policy to allow or silence the access
> vector. Even when the consequence is not a failure of the syscall, it
> still may be useful to have the denial reported, since there is a
> potential performance impact. OTOH, with CAP_SYS_ADMIN if the decision
> is to not allow it, then silencing it via a dontaudit rule would
> potentially hide other more critical CAP_SYS_ADMIN denials, so it's
> hard to decide what is better - to silence this specific case in the
> kernel vs. to let the user allow/silence the specific AV in the
> policy...
imo we should apply a general rule for using "_noaudit"
for all checks that don't end up as a denial.
There are various bpf_allow_ptr_leaks(), bpf_bypass_spec_v[14]()
checks in the verifier that should be converted to "_noaudit".
It's true that the check affects performance and users could be
interested in the end result, but if they enable mitigations they
expect the performance hit across the board, so skipping a mitigation
for a privileged process is a bonus. A prog will be tiny bit faster.
So not worth flagging anywhere.
^ permalink raw reply
* Re: [PATCH v3 12/34] lsm: rework the LSM enable/disable setter/getter functions
From: John Johansen @ 2025-09-02 17:39 UTC (permalink / raw)
To: Paul Moore, linux-security-module, linux-integrity, selinux
Cc: Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
Tetsuo Handa, Nicolas Bouchinet, Xiu Jianfeng
In-Reply-To: <20250814225159.275901-48-paul@paul-moore.com>
On 8/14/25 15:50, Paul Moore wrote:
> In addition to style changes, rename set_enabled() to lsm_enabled_set()
not a fan of the ordering of enabled_set() vs. set_enabled() but not
terribly important either
> and is_enabled() to lsm_is_enabled() to better fit within the LSM
> initialization code.
>
> Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
> Signed-off-by: Paul Moore <paul@paul-moore.com>
Reviewed-by: John Johansen <john.johansen@canonical.com>
> ---
> security/lsm_init.c | 62 ++++++++++++++++++++++-----------------------
> 1 file changed, 31 insertions(+), 31 deletions(-)
>
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index 87e2147016b3..2cfd72ade6fb 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -10,6 +10,10 @@
>
> #include "lsm.h"
>
> +/* LSM enabled constants. */
> +static __initdata int lsm_enabled_true = 1;
> +static __initdata int lsm_enabled_false = 0;
> +
> /* Pointers to LSM sections defined in include/asm-generic/vmlinux.lds.h */
> extern struct lsm_info __start_lsm_info[], __end_lsm_info[];
> extern struct lsm_info __start_early_lsm_info[], __end_early_lsm_info[];
> @@ -75,37 +79,33 @@ static int __init lsm_debug_enable(char *str)
> }
> __setup("lsm.debug", lsm_debug_enable);
>
> -/* Mark an LSM's enabled flag. */
> -static int lsm_enabled_true __initdata = 1;
> -static int lsm_enabled_false __initdata = 0;
> -static void __init set_enabled(struct lsm_info *lsm, bool enabled)
> +/**
> + * lsm_enabled_set - Mark a LSM as enabled
> + * @lsm: LSM definition
> + * @enabled: enabled flag
> + */
> +static void __init lsm_enabled_set(struct lsm_info *lsm, bool enabled)
> {
> /*
> * When an LSM hasn't configured an enable variable, we can use
> * a hard-coded location for storing the default enabled state.
> */
> - if (!lsm->enabled) {
> - if (enabled)
> - lsm->enabled = &lsm_enabled_true;
> - else
> - lsm->enabled = &lsm_enabled_false;
> - } else if (lsm->enabled == &lsm_enabled_true) {
> - if (!enabled)
> - lsm->enabled = &lsm_enabled_false;
> - } else if (lsm->enabled == &lsm_enabled_false) {
> - if (enabled)
> - lsm->enabled = &lsm_enabled_true;
> + if (!lsm->enabled ||
> + lsm->enabled == &lsm_enabled_true ||
> + lsm->enabled == &lsm_enabled_false) {
> + lsm->enabled = enabled ? &lsm_enabled_true : &lsm_enabled_false;
> } else {
> *lsm->enabled = enabled;
> }
> }
>
> -static inline bool is_enabled(struct lsm_info *lsm)
> +/**
> + * lsm_is_enabled - Determine if a LSM is enabled
> + * @lsm: LSM definition
> + */
> +static inline bool lsm_is_enabled(struct lsm_info *lsm)
> {
> - if (!lsm->enabled)
> - return false;
> -
> - return *lsm->enabled;
> + return (lsm->enabled ? *lsm->enabled : false);
> }
>
> /* Is an LSM already listed in the ordered LSMs list? */
> @@ -139,7 +139,7 @@ static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from)
> lsm_idlist[last_lsm++] = lsm->id;
>
> init_debug("%s ordered: %s (%s)\n", from, lsm->id->name,
> - is_enabled(lsm) ? "enabled" : "disabled");
> + lsm_is_enabled(lsm) ? "enabled" : "disabled");
> }
>
> static void __init lsm_set_blob_size(int *need, int *lbs)
> @@ -162,17 +162,17 @@ static void __init lsm_prepare(struct lsm_info *lsm)
> {
> struct lsm_blob_sizes *blobs;
>
> - if (!is_enabled(lsm)) {
> - set_enabled(lsm, false);
> + if (!lsm_is_enabled(lsm)) {
> + lsm_enabled_set(lsm, false);
> return;
> } else if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && lsm_exclusive) {
> init_debug("exclusive disabled: %s\n", lsm->id->name);
> - set_enabled(lsm, false);
> + lsm_enabled_set(lsm, false);
> return;
> }
>
> /* Mark the LSM as enabled. */
> - set_enabled(lsm, true);
> + lsm_enabled_set(lsm, true);
> if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !lsm_exclusive) {
> init_debug("exclusive chosen: %s\n", lsm->id->name);
> lsm_exclusive = lsm;
> @@ -206,7 +206,7 @@ static void __init lsm_prepare(struct lsm_info *lsm)
> /* Initialize a given LSM, if it is enabled. */
> static void __init initialize_lsm(struct lsm_info *lsm)
> {
> - if (is_enabled(lsm)) {
> + if (lsm_is_enabled(lsm)) {
> int ret;
>
> init_debug("initializing %s\n", lsm->id->name);
> @@ -240,7 +240,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
> lsm_for_each_raw(major) {
> if ((major->flags & LSM_FLAG_LEGACY_MAJOR) &&
> strcmp(major->id->name, lsm_order_legacy) != 0) {
> - set_enabled(major, false);
> + lsm_enabled_set(major, false);
> init_debug("security=%s disabled: %s (only one legacy major LSM)\n",
> lsm_order_legacy, major->id->name);
> }
> @@ -286,7 +286,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
> lsm_for_each_raw(lsm) {
> if (exists_ordered_lsm(lsm))
> continue;
> - set_enabled(lsm, false);
> + lsm_enabled_set(lsm, false);
> init_debug("%s skipped: %s (not in requested order)\n",
> origin, lsm->id->name);
> }
> @@ -319,12 +319,12 @@ static void __init lsm_init_ordered(void)
>
> pr_info("initializing lsm=");
> lsm_early_for_each_raw(early) {
> - if (is_enabled(early))
> + if (lsm_is_enabled(early))
> pr_cont("%s%s",
> first++ == 0 ? "" : ",", early->id->name);
> }
> lsm_order_for_each(lsm) {
> - if (is_enabled(*lsm))
> + if (lsm_is_enabled(*lsm))
> pr_cont("%s%s",
> first++ == 0 ? "" : ",", (*lsm)->id->name);
> }
> @@ -440,7 +440,7 @@ int __init security_init(void)
> */
> lsm_early_for_each_raw(lsm) {
> init_debug(" early started: %s (%s)\n", lsm->id->name,
> - is_enabled(lsm) ? "enabled" : "disabled");
> + lsm_is_enabled(lsm) ? "enabled" : "disabled");
> }
>
> /* Load LSMs in specified order. */
^ permalink raw reply
* Re: [PATCH v3 13/34] lsm: rename exists_ordered_lsm() to lsm_order_exists()
From: John Johansen @ 2025-09-02 17:42 UTC (permalink / raw)
To: Paul Moore, linux-security-module, linux-integrity, selinux
Cc: Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
Tetsuo Handa, Nicolas Bouchinet, Xiu Jianfeng
In-Reply-To: <20250814225159.275901-49-paul@paul-moore.com>
On 8/14/25 15:50, Paul Moore wrote:
> Also add a header comment block to the function.
>
> Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
> Signed-off-by: Paul Moore <paul@paul-moore.com>
Reviewed-by: John Johansen <john.johansen@canonical.com>
> ---
> security/lsm_init.c | 13 ++++++++-----
> 1 file changed, 8 insertions(+), 5 deletions(-)
>
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index 2cfd72ade6fb..ec46ddb18e1e 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -108,8 +108,11 @@ static inline bool lsm_is_enabled(struct lsm_info *lsm)
> return (lsm->enabled ? *lsm->enabled : false);
> }
>
> -/* Is an LSM already listed in the ordered LSMs list? */
> -static bool __init exists_ordered_lsm(struct lsm_info *lsm)
> +/**
> + * lsm_order_exists - Determine if a LSM exists in the ordered list
> + * @lsm: LSM definition
> + */
> +static bool __init lsm_order_exists(struct lsm_info *lsm)
> {
> struct lsm_info **check;
>
> @@ -126,7 +129,7 @@ static int last_lsm __initdata;
> static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from)
> {
> /* Ignore duplicate selections. */
> - if (exists_ordered_lsm(lsm))
> + if (lsm_order_exists(lsm))
> return;
>
> if (WARN(last_lsm == MAX_LSM_COUNT, "%s: out of LSM static calls!?\n", from))
> @@ -269,7 +272,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
> /* Process "security=", if given. */
> if (lsm_order_legacy) {
> lsm_for_each_raw(lsm) {
> - if (exists_ordered_lsm(lsm))
> + if (lsm_order_exists(lsm))
> continue;
> if (strcmp(lsm->id->name, lsm_order_legacy) == 0)
> append_ordered_lsm(lsm, "security=");
> @@ -284,7 +287,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
>
> /* Disable all LSMs not in the ordered list. */
> lsm_for_each_raw(lsm) {
> - if (exists_ordered_lsm(lsm))
> + if (lsm_order_exists(lsm))
> continue;
> lsm_enabled_set(lsm, false);
> init_debug("%s skipped: %s (not in requested order)\n",
^ permalink raw reply
* Re: [PATCH v3 22/34] lsm: group lsm_order_parse() with the other lsm_order_*() functions
From: John Johansen @ 2025-09-02 17:46 UTC (permalink / raw)
To: Paul Moore, linux-security-module, linux-integrity, selinux
Cc: Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
Tetsuo Handa, Nicolas Bouchinet, Xiu Jianfeng
In-Reply-To: <20250814225159.275901-58-paul@paul-moore.com>
On 8/14/25 15:50, Paul Moore wrote:
> Move the lsm_order_parse() function near the other lsm_order_*()
> functions to improve readability.
>
> No code changes.
>
> Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
> Signed-off-by: Paul Moore <paul@paul-moore.com>
Reviewed-by: John Johansen <john.johansen@canonical.com>
> ---
> security/lsm_init.c | 140 ++++++++++++++++++++++----------------------
> 1 file changed, 70 insertions(+), 70 deletions(-)
>
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index c6aea57a01e6..363aac92a8da 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -169,6 +169,76 @@ static void __init lsm_order_append(struct lsm_info *lsm, const char *src)
> lsm_pr_dbg("enabling LSM %s:%s\n", src, lsm->id->name);
> }
>
> +/**
> + * lsm_order_parse - Parse the comma delimited LSM list
> + * @list: LSM list
> + * @src: source of the list
> + */
> +static void __init lsm_order_parse(const char *list, const char *src)
> +{
> + struct lsm_info *lsm;
> + char *sep, *name, *next;
> +
> + /* Handle any Legacy LSM exclusions if one was specified. */
> + if (lsm_order_legacy) {
> + /*
> + * To match the original "security=" behavior, this explicitly
> + * does NOT fallback to another Legacy Major if the selected
> + * one was separately disabled: disable all non-matching
> + * Legacy Major LSMs.
> + */
> + lsm_for_each_raw(lsm) {
> + if ((lsm->flags & LSM_FLAG_LEGACY_MAJOR) &&
> + strcmp(lsm->id->name, lsm_order_legacy)) {
> + lsm_enabled_set(lsm, false);
> + lsm_pr_dbg("skip legacy LSM conflict %s:%s\n",
> + src, lsm->id->name);
> + }
> + }
> + }
> +
> + /* LSM_ORDER_FIRST */
> + lsm_for_each_raw(lsm) {
> + if (lsm->order == LSM_ORDER_FIRST)
> + lsm_order_append(lsm, "first");
> + }
> +
> + /* Normal or "mutable" LSMs */
> + sep = kstrdup(list, GFP_KERNEL);
> + next = sep;
> + /* Walk the list, looking for matching LSMs. */
> + while ((name = strsep(&next, ",")) != NULL) {
> + lsm_for_each_raw(lsm) {
> + if (!strcmp(lsm->id->name, name) &&
> + lsm->order == LSM_ORDER_MUTABLE)
> + lsm_order_append(lsm, src);
> + }
> + }
> + kfree(sep);
> +
> + /* Legacy LSM if specified. */
> + if (lsm_order_legacy) {
> + lsm_for_each_raw(lsm) {
> + if (!strcmp(lsm->id->name, lsm_order_legacy))
> + lsm_order_append(lsm, src);
> + }
> + }
> +
> + /* LSM_ORDER_LAST */
> + lsm_for_each_raw(lsm) {
> + if (lsm->order == LSM_ORDER_LAST)
> + lsm_order_append(lsm, "last");
> + }
> +
> + /* Disable all LSMs not previously enabled. */
> + lsm_for_each_raw(lsm) {
> + if (lsm_order_exists(lsm))
> + continue;
> + lsm_enabled_set(lsm, false);
> + lsm_pr_dbg("skip disabled LSM %s:%s\n", src, lsm->id->name);
> + }
> +}
> +
> /**
> * lsm_blob_size_update - Update the LSM blob size and offset information
> * @sz_req: the requested additional blob size
> @@ -241,76 +311,6 @@ static void __init lsm_init_single(struct lsm_info *lsm)
> WARN(ret, "%s failed to initialize: %d\n", lsm->id->name, ret);
> }
>
> -/**
> - * lsm_order_parse - Parse the comma delimited LSM list
> - * @list: LSM list
> - * @src: source of the list
> - */
> -static void __init lsm_order_parse(const char *list, const char *src)
> -{
> - struct lsm_info *lsm;
> - char *sep, *name, *next;
> -
> - /* Handle any Legacy LSM exclusions if one was specified. */
> - if (lsm_order_legacy) {
> - /*
> - * To match the original "security=" behavior, this explicitly
> - * does NOT fallback to another Legacy Major if the selected
> - * one was separately disabled: disable all non-matching
> - * Legacy Major LSMs.
> - */
> - lsm_for_each_raw(lsm) {
> - if ((lsm->flags & LSM_FLAG_LEGACY_MAJOR) &&
> - strcmp(lsm->id->name, lsm_order_legacy)) {
> - lsm_enabled_set(lsm, false);
> - lsm_pr_dbg("skip legacy LSM conflict %s:%s\n",
> - src, lsm->id->name);
> - }
> - }
> - }
> -
> - /* LSM_ORDER_FIRST */
> - lsm_for_each_raw(lsm) {
> - if (lsm->order == LSM_ORDER_FIRST)
> - lsm_order_append(lsm, "first");
> - }
> -
> - /* Normal or "mutable" LSMs */
> - sep = kstrdup(list, GFP_KERNEL);
> - next = sep;
> - /* Walk the list, looking for matching LSMs. */
> - while ((name = strsep(&next, ",")) != NULL) {
> - lsm_for_each_raw(lsm) {
> - if (!strcmp(lsm->id->name, name) &&
> - lsm->order == LSM_ORDER_MUTABLE)
> - lsm_order_append(lsm, src);
> - }
> - }
> - kfree(sep);
> -
> - /* Legacy LSM if specified. */
> - if (lsm_order_legacy) {
> - lsm_for_each_raw(lsm) {
> - if (!strcmp(lsm->id->name, lsm_order_legacy))
> - lsm_order_append(lsm, src);
> - }
> - }
> -
> - /* LSM_ORDER_LAST */
> - lsm_for_each_raw(lsm) {
> - if (lsm->order == LSM_ORDER_LAST)
> - lsm_order_append(lsm, "last");
> - }
> -
> - /* Disable all LSMs not previously enabled. */
> - lsm_for_each_raw(lsm) {
> - if (lsm_order_exists(lsm))
> - continue;
> - lsm_enabled_set(lsm, false);
> - lsm_pr_dbg("skip disabled LSM %s:%s\n", src, lsm->id->name);
> - }
> -}
> -
> /**
> * lsm_static_call_init - Initialize a LSM's static calls
> * @hl: LSM hook list
^ permalink raw reply
* Re: [PATCH v3 23/34] lsm: introduce an initcall mechanism into the LSM framework
From: John Johansen @ 2025-09-02 17:50 UTC (permalink / raw)
To: Paul Moore, linux-security-module, linux-integrity, selinux
Cc: Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
Tetsuo Handa, Nicolas Bouchinet, Xiu Jianfeng
In-Reply-To: <20250814225159.275901-59-paul@paul-moore.com>
On 8/14/25 15:50, Paul Moore wrote:
> Currently the individual LSMs register their own initcalls, and while
> this should be harmless, it can be wasteful in the case where a LSM
> is disabled at boot as the initcall will still be executed. This
> patch introduces support for managing the initcalls in the LSM
> framework, and future patches will convert the existing LSMs over to
> this new mechanism.
>
> Only initcall types which are used by the current in-tree LSMs are
> supported, additional initcall types can easily be added in the future
> if needed.
>
> Reviewed-by: Kees Cook <kees@kernel.org>
> Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
> Signed-off-by: Paul Moore <paul@paul-moore.com>
Reviewed-by: John Johansen <john.johansen@canonical.com>
> ---
> include/linux/lsm_hooks.h | 33 ++++++++++++---
> security/lsm_init.c | 89 +++++++++++++++++++++++++++++++++++++++
> 2 files changed, 117 insertions(+), 5 deletions(-)
>
> diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
> index 86e457aa8809..b92008641242 100644
> --- a/include/linux/lsm_hooks.h
> +++ b/include/linux/lsm_hooks.h
> @@ -151,13 +151,36 @@ enum lsm_order {
> LSM_ORDER_LAST = 1, /* This is only for integrity. */
> };
>
> +/**
> + * struct lsm_info - Define an individual LSM for the LSM framework.
> + * @id: LSM name/ID info
> + * @order: ordering with respect to other LSMs, optional
> + * @flags: descriptive flags, optional
> + * @blobs: LSM blob sharing, optional
> + * @enabled: controlled by CONFIG_LSM, optional
> + * @init: LSM specific initialization routine
> + * @initcall_pure: LSM callback for initcall_pure() setup, optional
> + * @initcall_early: LSM callback for early_initcall setup, optional
> + * @initcall_core: LSM callback for core_initcall() setup, optional
> + * @initcall_subsys: LSM callback for subsys_initcall() setup, optional
> + * @initcall_fs: LSM callback for fs_initcall setup, optional
> + * @nitcall_device: LSM callback for device_initcall() setup, optional
> + * @initcall_late: LSM callback for late_initcall() setup, optional
> + */
> struct lsm_info {
> const struct lsm_id *id;
> - enum lsm_order order; /* Optional: default is LSM_ORDER_MUTABLE */
> - unsigned long flags; /* Optional: flags describing LSM */
> - int *enabled; /* Optional: controlled by CONFIG_LSM */
> - int (*init)(void); /* Required. */
> - struct lsm_blob_sizes *blobs; /* Optional: for blob sharing. */
> + enum lsm_order order;
> + unsigned long flags;
> + struct lsm_blob_sizes *blobs;
> + int *enabled;
> + int (*init)(void);
> + int (*initcall_pure)(void);
> + int (*initcall_early)(void);
> + int (*initcall_core)(void);
> + int (*initcall_subsys)(void);
> + int (*initcall_fs)(void);
> + int (*initcall_device)(void);
> + int (*initcall_late)(void);
> };
>
> #define DEFINE_LSM(lsm) \
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index 363aac92a8da..697482a22a02 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -39,6 +39,27 @@ static __initdata struct lsm_info *lsm_exclusive;
> for ((iter) = __start_early_lsm_info; \
> (iter) < __end_early_lsm_info; (iter)++)
>
> +#define lsm_initcall(level) \
> + ({ \
> + int _r, _rc = 0; \
> + struct lsm_info **_lp, *_l; \
> + lsm_order_for_each(_lp) { \
> + _l = *_lp; \
> + if (!_l->initcall_##level) \
> + continue; \
> + lsm_pr_dbg("running %s %s initcall", \
> + _l->id->name, #level); \
> + _r = _l->initcall_##level(); \
> + if (_r) { \
> + pr_warn("failed LSM %s %s initcall with errno %d\n", \
> + _l->id->name, #level, _r); \
> + if (!_rc) \
> + _rc = _r; \
> + } \
> + } \
> + _rc; \
> + })
> +
> /**
> * lsm_choose_security - Legacy "major" LSM selection
> * @str: kernel command line parameter
> @@ -461,3 +482,71 @@ int __init security_init(void)
>
> return 0;
> }
> +
> +/**
> + * security_initcall_pure - Run the LSM pure initcalls
> + */
> +static int __init security_initcall_pure(void)
> +{
> + return lsm_initcall(pure);
> +}
> +pure_initcall(security_initcall_pure);
> +
> +/**
> + * security_initcall_early - Run the LSM early initcalls
> + */
> +static int __init security_initcall_early(void)
> +{
> + return lsm_initcall(early);
> +}
> +early_initcall(security_initcall_early);
> +
> +/**
> + * security_initcall_core - Run the LSM core initcalls
> + */
> +static int __init security_initcall_core(void)
> +{
> + return lsm_initcall(core);
> +}
> +core_initcall(security_initcall_core);
> +
> +/**
> + * security_initcall_subsys - Run the LSM subsys initcalls
> + */
> +static int __init security_initcall_subsys(void)
> +{
> + return lsm_initcall(subsys);
> +}
> +subsys_initcall(security_initcall_subsys);
> +
> +/**
> + * security_initcall_fs - Run the LSM fs initcalls
> + */
> +static int __init security_initcall_fs(void)
> +{
> + return lsm_initcall(fs);
> +}
> +fs_initcall(security_initcall_fs);
> +
> +/**
> + * security_initcall_device - Run the LSM device initcalls
> + */
> +static int __init security_initcall_device(void)
> +{
> + return lsm_initcall(device);
> +}
> +device_initcall(security_initcall_device);
> +
> +/**
> + * security_initcall_late - Run the LSM late initcalls
> + */
> +static int __init security_initcall_late(void)
> +{
> + int rc;
> +
> + rc = lsm_initcall(late);
> + lsm_pr_dbg("all enabled LSMs fully activated\n");
> +
> + return rc;
> +}
> +late_initcall(security_initcall_late);
^ permalink raw reply
* Re: [PATCH v3 24/34] loadpin: move initcalls to the LSM framework
From: John Johansen @ 2025-09-02 17:51 UTC (permalink / raw)
To: Paul Moore, linux-security-module, linux-integrity, selinux
Cc: Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
Tetsuo Handa, Nicolas Bouchinet, Xiu Jianfeng
In-Reply-To: <20250814225159.275901-60-paul@paul-moore.com>
On 8/14/25 15:50, Paul Moore wrote:
> Acked-by: Kees Cook <kees@kernel.org>
> Signed-off-by: Paul Moore <paul@paul-moore.com>
Reviewed-by: John Johansen <john.johansen@canonical.com>
> ---
> security/loadpin/loadpin.c | 15 ++++++++-------
> 1 file changed, 8 insertions(+), 7 deletions(-)
>
> diff --git a/security/loadpin/loadpin.c b/security/loadpin/loadpin.c
> index b9ddf05c5c16..273ffbd6defe 100644
> --- a/security/loadpin/loadpin.c
> +++ b/security/loadpin/loadpin.c
> @@ -270,11 +270,6 @@ static int __init loadpin_init(void)
> return 0;
> }
>
> -DEFINE_LSM(loadpin) = {
> - .id = &loadpin_lsmid,
> - .init = loadpin_init,
> -};
> -
> #ifdef CONFIG_SECURITY_LOADPIN_VERITY
>
> enum loadpin_securityfs_interface_index {
> @@ -434,10 +429,16 @@ static int __init init_loadpin_securityfs(void)
> return 0;
> }
>
> -fs_initcall(init_loadpin_securityfs);
> -
> #endif /* CONFIG_SECURITY_LOADPIN_VERITY */
>
> +DEFINE_LSM(loadpin) = {
> + .id = &loadpin_lsmid,
> + .init = loadpin_init,
> +#ifdef CONFIG_SECURITY_LOADPIN_VERITY
> + .initcall_fs = init_loadpin_securityfs,
> +#endif /* CONFIG_SECURITY_LOADPIN_VERITY */
> +};
> +
> /* Should not be mutable after boot, so not listed in sysfs (perm == 0). */
> module_param(enforce, int, 0);
> MODULE_PARM_DESC(enforce, "Enforce module/firmware pinning");
^ permalink raw reply
* Re: [PATCH v3 25/34] ipe: move initcalls to the LSM framework
From: John Johansen @ 2025-09-02 17:52 UTC (permalink / raw)
To: Paul Moore, linux-security-module, linux-integrity, selinux
Cc: Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
Tetsuo Handa, Nicolas Bouchinet, Xiu Jianfeng
In-Reply-To: <20250814225159.275901-61-paul@paul-moore.com>
On 8/14/25 15:50, Paul Moore wrote:
> Reviewed-by: Kees Cook <kees@kernel.org>
> Tested-by: Fan Wu <wufan@kernel.org>
> Acked-by: Fan Wu <wufan@kernel.org>
> Signed-off-by: Paul Moore <paul@paul-moore.com>
Reviewed-by: John Johansen <john.johansen@canonical.com>
> ---
> security/ipe/fs.c | 4 +---
> security/ipe/ipe.c | 1 +
> security/ipe/ipe.h | 2 ++
> 3 files changed, 4 insertions(+), 3 deletions(-)
>
> diff --git a/security/ipe/fs.c b/security/ipe/fs.c
> index 0bb9468b8026..076c111c85c8 100644
> --- a/security/ipe/fs.c
> +++ b/security/ipe/fs.c
> @@ -193,7 +193,7 @@ static const struct file_operations enforce_fops = {
> * Return: %0 on success. If an error occurs, the function will return
> * the -errno.
> */
> -static int __init ipe_init_securityfs(void)
> +int __init ipe_init_securityfs(void)
> {
> int rc = 0;
> struct ipe_policy *ap;
> @@ -244,5 +244,3 @@ static int __init ipe_init_securityfs(void)
> securityfs_remove(root);
> return rc;
> }
> -
> -fs_initcall(ipe_init_securityfs);
> diff --git a/security/ipe/ipe.c b/security/ipe/ipe.c
> index 2426441181dc..71644748ed56 100644
> --- a/security/ipe/ipe.c
> +++ b/security/ipe/ipe.c
> @@ -95,4 +95,5 @@ DEFINE_LSM(ipe) = {
> .id = &ipe_lsmid,
> .init = ipe_init,
> .blobs = &ipe_blobs,
> + .initcall_fs = ipe_init_securityfs,
> };
> diff --git a/security/ipe/ipe.h b/security/ipe/ipe.h
> index fb37513812dd..25cfdb8f0c20 100644
> --- a/security/ipe/ipe.h
> +++ b/security/ipe/ipe.h
> @@ -23,4 +23,6 @@ struct ipe_bdev *ipe_bdev(struct block_device *b);
> struct ipe_inode *ipe_inode(const struct inode *inode);
> #endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */
>
> +int ipe_init_securityfs(void);
> +
> #endif /* _IPE_H */
^ permalink raw reply
* Re: [PATCH v3 26/34] smack: move initcalls to the LSM framework
From: John Johansen @ 2025-09-02 18:08 UTC (permalink / raw)
To: Paul Moore, linux-security-module, linux-integrity, selinux
Cc: Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
Tetsuo Handa, Nicolas Bouchinet, Xiu Jianfeng
In-Reply-To: <20250814225159.275901-62-paul@paul-moore.com>
On 8/14/25 15:50, Paul Moore wrote:
> As the LSM framework only supports one LSM initcall callback for each
> initcall type, the init_smk_fs() and smack_nf_ip_init() functions were
> wrapped with a new function, smack_initcall() that is registered with
> the LSM framework.
>
> Acked-by: Casey Schaufler <casey@schaufler-ca.com>
> Signed-off-by: Paul Moore <paul@paul-moore.com>
Reviewed-by: John Johansen <john.johansen@canonical.com>
> ---
> security/smack/smack.h | 14 ++++++++++++++
> security/smack/smack_lsm.c | 9 +++++++++
> security/smack/smack_netfilter.c | 4 +---
> security/smack/smackfs.c | 4 +---
> 4 files changed, 25 insertions(+), 6 deletions(-)
>
> diff --git a/security/smack/smack.h b/security/smack/smack.h
> index bf6a6ed3946c..c56e1e876f7c 100644
> --- a/security/smack/smack.h
> +++ b/security/smack/smack.h
> @@ -275,6 +275,20 @@ struct smk_audit_info {
> #endif
> };
>
> +/*
> + * Initialization
> + */
> +#if defined(CONFIG_SECURITY_SMACK_NETFILTER)
> +int smack_nf_ip_init(void);
> +#else
> +static inline int smack_nf_ip_init(void)
> +{
> + return 0;
> +}
> +#endif
> +int init_smk_fs(void);
> +int smack_initcall(void);
> +
> /*
> * These functions are in smack_access.c
> */
> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
> index e09490c75f59..f14d536c516b 100644
> --- a/security/smack/smack_lsm.c
> +++ b/security/smack/smack_lsm.c
> @@ -5270,6 +5270,14 @@ static __init int smack_init(void)
> return 0;
> }
>
> +int __init smack_initcall(void)
> +{
> + int rc_fs = init_smk_fs();
> + int rc_nf = smack_nf_ip_init();
> +
> + return rc_fs ? rc_fs : rc_nf;
> +}
> +
> /*
> * Smack requires early initialization in order to label
> * all processes and objects when they are created.
> @@ -5279,4 +5287,5 @@ DEFINE_LSM(smack) = {
> .flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
> .blobs = &smack_blob_sizes,
> .init = smack_init,
> + .initcall_device = smack_initcall,
> };
> diff --git a/security/smack/smack_netfilter.c b/security/smack/smack_netfilter.c
> index 8fd747b3653a..17ba578b1308 100644
> --- a/security/smack/smack_netfilter.c
> +++ b/security/smack/smack_netfilter.c
> @@ -68,7 +68,7 @@ static struct pernet_operations smack_net_ops = {
> .exit = smack_nf_unregister,
> };
>
> -static int __init smack_nf_ip_init(void)
> +int __init smack_nf_ip_init(void)
> {
> if (smack_enabled == 0)
> return 0;
> @@ -76,5 +76,3 @@ static int __init smack_nf_ip_init(void)
> printk(KERN_DEBUG "Smack: Registering netfilter hooks\n");
> return register_pernet_subsys(&smack_net_ops);
> }
> -
> -__initcall(smack_nf_ip_init);
> diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
> index b1e5e62f5cbd..405ace6db109 100644
> --- a/security/smack/smackfs.c
> +++ b/security/smack/smackfs.c
> @@ -2978,7 +2978,7 @@ static struct vfsmount *smackfs_mount;
> * Returns true if we were not chosen on boot or if
> * we were chosen and filesystem registration succeeded.
> */
> -static int __init init_smk_fs(void)
> +int __init init_smk_fs(void)
> {
> int err;
> int rc;
> @@ -3021,5 +3021,3 @@ static int __init init_smk_fs(void)
>
> return err;
> }
> -
> -__initcall(init_smk_fs);
^ permalink raw reply
* Re: [PATCH v3 27/34] tomoyo: move initcalls to the LSM framework
From: John Johansen @ 2025-09-02 18:09 UTC (permalink / raw)
To: Paul Moore, linux-security-module, linux-integrity, selinux
Cc: Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
Tetsuo Handa, Nicolas Bouchinet, Xiu Jianfeng
In-Reply-To: <20250814225159.275901-63-paul@paul-moore.com>
On 8/14/25 15:50, Paul Moore wrote:
> Reviewed-by: Kees Cook <kees@kernel.org>
> Signed-off-by: Paul Moore <paul@paul-moore.com>
Reviewed-by: John Johansen <john.johansen@canonical.com>
> ---
> security/tomoyo/common.h | 2 ++
> security/tomoyo/securityfs_if.c | 4 +---
> security/tomoyo/tomoyo.c | 1 +
> 3 files changed, 4 insertions(+), 3 deletions(-)
>
> diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h
> index 0e8e2e959aef..3b2a97d10a5d 100644
> --- a/security/tomoyo/common.h
> +++ b/security/tomoyo/common.h
> @@ -924,6 +924,8 @@ struct tomoyo_task {
>
> /********** Function prototypes. **********/
>
> +int tomoyo_interface_init(void);
> +
> bool tomoyo_address_matches_group(const bool is_ipv6, const __be32 *address,
> const struct tomoyo_group *group);
> bool tomoyo_compare_number_union(const unsigned long value,
> diff --git a/security/tomoyo/securityfs_if.c b/security/tomoyo/securityfs_if.c
> index 7e69747b2f77..33933645f5b9 100644
> --- a/security/tomoyo/securityfs_if.c
> +++ b/security/tomoyo/securityfs_if.c
> @@ -233,7 +233,7 @@ static void __init tomoyo_create_entry(const char *name, const umode_t mode,
> *
> * Returns 0.
> */
> -static int __init tomoyo_interface_init(void)
> +int __init tomoyo_interface_init(void)
> {
> struct tomoyo_domain_info *domain;
> struct dentry *tomoyo_dir;
> @@ -269,5 +269,3 @@ static int __init tomoyo_interface_init(void)
> tomoyo_load_builtin_policy();
> return 0;
> }
> -
> -fs_initcall(tomoyo_interface_init);
> diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
> index ed0f7b052a85..a015cf0c4a00 100644
> --- a/security/tomoyo/tomoyo.c
> +++ b/security/tomoyo/tomoyo.c
> @@ -617,4 +617,5 @@ DEFINE_LSM(tomoyo) = {
> .flags = LSM_FLAG_LEGACY_MAJOR,
> .blobs = &tomoyo_blob_sizes,
> .init = tomoyo_init,
> + .initcall_fs = tomoyo_interface_init,
> };
^ 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