* [RFC v1 0/1] Implement IMA Event Log Trimming
From: Anirudh Venkataramanan @ 2025-11-19 21:33 UTC (permalink / raw)
To: linux-integrity
Cc: Mimi Zohar, Roberto Sassu, Dmitry Kasatkin, Eric Snowberg,
Paul Moore, James Morris, Serge E . Hallyn, linux-security-module,
Anirudh Venkataramanan, Steven Chen, Gregory Lumen,
Lakshmi Ramasubramanian, Sush Shringarputale
==========================================================================
| A. Introduction |
==========================================================================
IMA events are kept in kernel memory and preserved across kexec soft
reboots. This can lead to increased kernel memory usage over time,
especially with aggressive IMA policies that measure everything. To reduce
memory pressure, it becomes necessary to discard IMA events but given that
IMA events are extended into PCRs in the TPM, just discarding events will
break the PCR extension chain, making future verification of the IMA event
log impossible.
This patch series proposes a method to discard IMA events while keeping the
log verifiable. While reducing memory pressure is the primary objective,
the second order benefit of trimming the IMA log is that IMA log verifiers
(local userspace daemon or a remote cloud service) can process smaller IMA
logs on a rolling basis, thus avoiding re-verification of previously
verified events.
The method has other advantages too:
1. It provides a userspace interface that can be used to precisely control
trim point, allowing for trim points to be optionally aligned with
userspace IMA event log validation.
2. It ensures that all necessary information required for continued IMA
log validation is made available via the userspace interface at all
times.
3. It provides a simple mechanism for userspace applications to determine
if the event log has been unexpectedly trimmed.
4. The duration for which the IMA Measurement list mutex must be held (for
trimming) is minimal.
==========================================================================
| B. Solution |
==========================================================================
--------------------------------------------------------------------------
| B.1 Overview |
--------------------------------------------------------------------------
The kernel trims the IMA event log based on PCR values supplied by userspace.
The core principles leveraged are as follows:
- Given an IMA event log, PCR values for each IMA event can be obtained by
recalulating the PCR extension for each event. Thus processing N events
from the start will yield PCR values as of event N. This is referred to
as "IMA event log replay".
- To get the PCR value for event N + 1, only the PCR value as of event N
is needed. If this can be known, events till and including N can be
safely purged.
Putting it all together, we get the following userspace + kernel flow:
1. A userspace application replays the IMA event log to generate PCR
values and then triggers a trim by providing these values to the kernel
(by writing to a pseudo file).
Optionally, the userspace application may verify these PCR values
against the corresponding TPM quote, and trigger trimming only if
the calculated PCR values match up to the expectations in the quote's
PCR digest.
2. The kernel uses the userspace supplied PCR values to trim the IMA
measurements list at a specific point, and so these are referred to as
"trim-to PCR values" in this context.
Note that the kernel doesn't really understand what these userspace
provided PCR values mean or what IMA event they correspond to, and so
it does its own IMA event replay till either the replayed PCR values
match with the userspace provided ones, or it runs out of events.
If a match is found, the kernel can proceed with trimming the IMA
measurements list. This is done in two steps, to keep locking context
minimal.
step 1: Find and return the list entry (as a count from head) of exact
match. This does not lock the measurements list mutex, ensuring
new events can be appended to the log.
step 2: Lock the measurements list mutex and trim the measurements list
at the previously identified list entry.
If the trim is successful, the trim-to PCR values are saved as "starting
PCR values". The next time userspace wants to replay the IMA event log,
it will use the starting PCR values as the base for the IMA event log
replay.
--------------------------------------------------------------------------
| B.2 Kernel Interfaces |
--------------------------------------------------------------------------
A new configfs pseudo file /sys/kernel/config/ima/pcrs that supports the
following operations is exposed.
read: returns starting PCR values stored in the kernel (within IMA
specifically).
write: writes trim-to PCR values to trigger trimming. If trimming is
successful, trim-to PCR values are stored as starting PCR values.
requires root privileges.
--------------------------------------------------------------------------
| B.3 Walk-through with a real example |
--------------------------------------------------------------------------
This is a real example from a test run.
Suppose this IMA policy is deployed:
measure func=FILE_CHECK mask=MAY_READ pcr=10
measure func=FILE_CHECK mask=MAY_WRITE pcr=11
When the policy is deployed, a zero digest starting PCR value will be set
for each PCR used. If the TPM supports multiple hashbanks, there will be
one starting PCR value per PCR, per TPM hashbank. This can be seen in the
following hexdump:
$ sudo hexdump -vC /sys/kernel/config/ima/pcrs
00000000 70 63 72 31 30 3a 73 68 61 31 3a 00 00 00 00 00 |pcr10:sha1:.....|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 70 |...............p|
00000020 63 72 31 31 3a 73 68 61 31 3a 00 00 00 00 00 00 |cr11:sha1:......|
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 70 63 |..............pc|
00000040 72 31 30 3a 73 68 61 32 35 36 3a 00 00 00 00 00 |r10:sha256:.....|
00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000060 00 00 00 00 00 00 00 00 00 00 00 70 63 72 31 31 |...........pcr11|
00000070 3a 73 68 61 32 35 36 3a 00 00 00 00 00 00 00 00 |:sha256:........|
00000080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000090 00 00 00 00 00 00 00 00 70 63 72 31 30 3a 73 68 |........pcr10:sh|
000000a0 61 33 38 34 3a 00 00 00 00 00 00 00 00 00 00 00 |a384:...........|
000000b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000000c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000000d0 00 00 00 00 00 70 63 72 31 31 3a 73 68 61 33 38 |.....pcr11:sha38|
000000e0 34 3a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |4:..............|
000000f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000100 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000110 00 00 |..|
00000112
Let's say that a userspace utility replays the IMA event log, and triggers
trimming by writing the following PCR values (i.e. trim-to PCR values) to the
pseudo file:
pcr10:sha256:8268782906555cf3aefc179f815c878527dd4e67eaa836572ebabab31977922c
pcr11:sha256:4c7f31927183eacb53d51d95b0162916fd3fca51a8d1efc6dde3805eb891fe41
The trim is successful,
1. Some number of entries from the measurements log will disappear. This
can be verified by reading out the ASCII or binary IMA measurements
file.
2. The trim-to PCR values are saved as starting PCR values. This can be
verified by reading out the pseudo file again as shown below. Note that
even through only sha256 PCR values were written, the kernel populated
sha1 and sha384 starting values as well.
$ sudo hexdump -vC /sys/kernel/config/ima/pcrs
00000000 70 63 72 31 30 3a 73 68 61 31 3a c4 7f 9d 00 68 |pcr10:sha1:....h|
00000010 e4 86 71 bf bc ae f0 10 12 ff 68 e2 9e 74 e4 70 |..q.......h..t.p|
00000020 63 72 31 31 3a 73 68 61 31 3a 90 d7 17 ac 60 4d |cr11:sha1:....`M|
00000030 c8 25 ce 77 7d 9d 94 cf 44 7b b2 2e 2e e2 70 63 |.%.w}...D{....pc|
00000040 72 31 30 3a 73 68 61 32 35 36 3a 82 68 78 29 06 |r10:sha256:.hx).|
00000050 55 5c f3 ae fc 17 9f 81 5c 87 85 27 dd 4e 67 ea |U\......\..'.Ng.|
00000060 a8 36 57 2e ba ba b3 19 77 92 2c 70 63 72 31 31 |.6W.....w.,pcr11|
00000070 3a 73 68 61 32 35 36 3a 4c 7f 31 92 71 83 ea cb |:sha256:L.1.q...|
00000080 53 d5 1d 95 b0 16 29 16 fd 3f ca 51 a8 d1 ef c6 |S.....)..?.Q....|
00000090 dd e3 80 5e b8 91 fe 41 70 63 72 31 30 3a 73 68 |...^...Apcr10:sh|
000000a0 61 33 38 34 3a 8e d6 12 18 b1 d6 cd 95 16 98 33 |a384:..........3|
000000b0 2b 7d a2 d6 d9 05 c7 e8 5b 15 b0 91 c5 fc 23 d1 |+}......[.....#.|
000000c0 f9 a8 8d 60 50 5c e9 64 5f d7 b3 b2 f1 9c 90 0a |...`P\.d_.......|
000000d0 45 53 5d b2 57 70 63 72 31 31 3a 73 68 61 33 38 |ES].Wpcr11:sha38|
000000e0 34 3a 25 fc 21 28 31 5a f7 c6 fb 0f 40 c9 06 e6 |4:%.!(1Z....@...|
000000f0 c5 da ed 20 61 a1 03 54 4f 67 18 88 82 0f 48 d1 |... a..TOg....H.|
00000100 2f e0 3d 36 46 5e 94 a4 88 51 f8 91 39 7e e5 97 |/.=6F^...Q..9~..|
00000110 2c c5 |,.|
00000112
--------------------------------------------------------------------------
| C. Footnotes |
--------------------------------------------------------------------------
1. The 'pcrs' pseudo file is currently part of configfs. This was due to
some early internal feedback in a different context. This can as well be
in securityfs with the rest of the IMA pseudo files.
2. PCR values are never read out of the TPM at any point. All PCR values
used are derived from IMA event log replay.
3. Code is "RFC quality". Refinements can be made if the method is accepted.
4. For functional validation, base kernel version was 6.17 stable, with the
most recent tested version being 6.17.8.
5. Code has been validated to some degree using a python-based internal test
tool. This can be published if there is community interest.
Steven Chen (1):
ima: Implement IMA event log trimming
drivers/Kconfig | 2 +
drivers/Makefile | 1 +
drivers/ima/Kconfig | 13 +
drivers/ima/Makefile | 2 +
drivers/ima/ima_config_pcrs.c | 291 ++++++++++++++++++
include/linux/ima.h | 27 ++
security/integrity/ima/Makefile | 4 +
security/integrity/ima/ima.h | 8 +
security/integrity/ima/ima_init.c | 44 +++
security/integrity/ima/ima_log_trim.c | 421 ++++++++++++++++++++++++++
security/integrity/ima/ima_policy.c | 7 +-
security/integrity/ima/ima_queue.c | 5 +-
12 files changed, 821 insertions(+), 4 deletions(-)
create mode 100644 drivers/ima/Kconfig
create mode 100644 drivers/ima/Makefile
create mode 100644 drivers/ima/ima_config_pcrs.c
create mode 100644 security/integrity/ima/ima_log_trim.c
--
2.43.0
^ permalink raw reply
* Re: [PATCH v3 7/9] module: Move lockdown check into generic module loader
From: Paul Moore @ 2025-11-19 19:55 UTC (permalink / raw)
To: Sebastian Andrzej Siewior
Cc: Thomas Weißschuh, Masahiro Yamada, Nathan Chancellor,
Arnd Bergmann, Luis Chamberlain, Petr Pavlu, Sami Tolvanen,
Daniel Gomez, James Morris, Serge E. Hallyn, Jonathan Corbet,
Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
Christophe Leroy, Naveen N Rao, Mimi Zohar, Roberto Sassu,
Dmitry Kasatkin, Eric Snowberg, Nicolas Schier,
Fabian Grünbichler, Arnout Engelen, Mattia Rizzolo, kpcyrd,
Christian Heusel, Câju Mihai-Drosi, linux-kbuild,
linux-kernel, linux-arch, linux-modules, linux-security-module,
linux-doc, linuxppc-dev, linux-integrity
In-Reply-To: <20251119112055.W1l5FOxc@linutronix.de>
On Wed, Nov 19, 2025 at 6:20 AM Sebastian Andrzej Siewior
<bigeasy@linutronix.de> wrote:
> On 2025-04-29 15:04:34 [+0200], Thomas Weißschuh wrote:
> > The lockdown check buried in module_sig_check() will not compose well
> > with the introduction of hash-based module validation.
>
> An explanation of why would be nice.
/me shrugs
I thought the explanation was sufficient.
> > Move it into module_integrity_check() which will work better.
> >
> > Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
--
paul-moore.com
^ permalink raw reply
* [PATCH v2] lockdown: Only log restrictions once
From: Daniel Tang @ 2025-11-19 18:07 UTC (permalink / raw)
To: Nicolas Bouchinet, Xiu Jianfeng, Paul Moore
Cc: linux-security-module, linux-kernel, Nathan Lynch,
Matthew Garrett, Kees Cook, David Howells, James Morris
In-Reply-To: <CAHC9VhQNGnm6NBSrUmfwoEwAxqedYbHckEkb+J47W5gWjrKBOA@mail.gmail.com>
KDE's lockscreen causes systemd-logind to spam dmesg about hibernation.
systemd declined to cache /sys/power/state due to runtime changeability.
Link: https://github.com/systemd/systemd/pull/39802
Signed-off-by: Daniel Tang <danielzgtg.opensource@gmail.com>
---
security/lockdown/lockdown.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/security/lockdown/lockdown.c b/security/lockdown/lockdown.c
index cf83afa1d879..83b50de52f21 100644
--- a/security/lockdown/lockdown.c
+++ b/security/lockdown/lockdown.c
@@ -58,13 +58,16 @@ early_param("lockdown", lockdown_param);
*/
static int lockdown_is_locked_down(enum lockdown_reason what)
{
+ static volatile unsigned long lockdown_reasons_seen;
+ static_assert(ARRAY_SIZE(lockdown_reasons) < sizeof(lockdown_reasons_seen) * 8);
+
if (WARN(what >= LOCKDOWN_CONFIDENTIALITY_MAX,
"Invalid lockdown reason"))
return -EPERM;
if (kernel_locked_down >= what) {
- if (lockdown_reasons[what])
- pr_notice_ratelimited("Lockdown: %s: %s is restricted; see man kernel_lockdown.7\n",
+ if (lockdown_reasons[what] && !test_and_set_bit(what, &lockdown_reasons_seen))
+ pr_notice("Lockdown: %s: %s is restricted; see man kernel_lockdown.7\n",
current->comm, lockdown_reasons[what]);
return -EPERM;
}
--
2.51.0
^ permalink raw reply related
* Re: [PATCH] lockdown: Only log restrictions once
From: Paul Moore @ 2025-11-19 16:05 UTC (permalink / raw)
To: Daniel Tang, Nicolas Bouchinet, Xiu Jianfeng
Cc: linux-security-module, linux-kernel, Nathan Lynch,
Matthew Garrett, Kees Cook, David Howells, James Morris
In-Reply-To: <3641397.L58v44csPz@daniel-desktop3>
On Wed, Nov 19, 2025 at 8:22 AM Daniel Tang
<danielzgtg.opensource@gmail.com> wrote:
>
> KDE's lockscreen causes systemd-logind to spam dmesg about hibernation.
> systemd declined to cache /sys/power/state due to runtime changeability.
>
> Link: https://github.com/systemd/systemd/pull/39802
> Signed-off-by: Daniel Tang <danielzgtg.opensource@gmail.com>
> ---
> security/lockdown/lockdown.c | 6 ++++--
> 1 file changed, 4 insertions(+), 2 deletions(-)
Adding the Lockdown maintainers to the To/CC line.
> diff --git a/security/lockdown/lockdown.c b/security/lockdown/lockdown.c
> index cf83afa1d879..4ced8c76dc6b 100644
> --- a/security/lockdown/lockdown.c
> +++ b/security/lockdown/lockdown.c
> @@ -62,9 +62,11 @@ static int lockdown_is_locked_down(enum lockdown_reason what)
> "Invalid lockdown reason"))
> return -EPERM;
>
> + static volatile unsigned long lockdown_reasons_seen;
I'll let the Lockdown folks comment on the rest, but at the very least
this variable should be declared at the top of the function. Yes, you
*can* declare it in the middle, but just because you can, doesn't mean
you should ;)
> + static_assert(ARRAY_SIZE(lockdown_reasons) < sizeof(lockdown_reasons_seen) * 8);
> if (kernel_locked_down >= what) {
> - if (lockdown_reasons[what])
> - pr_notice_ratelimited("Lockdown: %s: %s is restricted; see man kernel_lockdown.7\n",
> + if (lockdown_reasons[what] && !test_and_set_bit(what, &lockdown_reasons_seen))
> + pr_notice("Lockdown: %s: %s is restricted; see man kernel_lockdown.7\n",
> current->comm, lockdown_reasons[what]);
> return -EPERM;
> }
> --
> 2.51.0
--
paul-moore.com
^ permalink raw reply
* Re: [PATCH v3 0/9] module: Introduce hash-based integrity checking
From: Sebastian Andrzej Siewior @ 2025-11-19 15:48 UTC (permalink / raw)
To: James Bottomley
Cc: Thomas Weißschuh, Masahiro Yamada, Nathan Chancellor,
Arnd Bergmann, Luis Chamberlain, Petr Pavlu, Sami Tolvanen,
Daniel Gomez, Paul Moore, James Morris, Serge E. Hallyn,
Jonathan Corbet, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Christophe Leroy, Naveen N Rao, Mimi Zohar,
Roberto Sassu, Dmitry Kasatkin, Eric Snowberg, Nicolas Schier,
Fabian Grünbichler, Arnout Engelen, Mattia Rizzolo, kpcyrd,
Christian Heusel, Câju Mihai-Drosi, linux-kbuild,
linux-kernel, linux-arch, linux-modules, linux-security-module,
linux-doc, linuxppc-dev, linux-integrity
In-Reply-To: <f1dca9daa01d0d2432c12ecabede3fa1389b1d29.camel@HansenPartnership.com>
On 2025-04-29 10:05:04 [-0400], James Bottomley wrote:
> On Tue, 2025-04-29 at 15:04 +0200, Thomas Weißschuh wrote:
> > The current signature-based module integrity checking has some
> > drawbacks in combination with reproducible builds:
> > Either the module signing key is generated at build time, which makes
> > the build unreproducible,
>
> I don't believe it does: as long as you know what the key was, which
> you can get from the kernel keyring, you can exactly reproduce the core
> build (it's a public key after all and really equivalent to built in
> configuration). Is the fact that you have to boot the kernel to get
> the key the problem? In which case we could insist it be shipped in
> the kernel packaging.
The kernel itself is signed. This is not a problem because distros have
the "unsigned" package which is used for comparison.
The modules are signed by an ephemeral key which is created at build
time. This is where the problem starts:
- the public key is embedded into the kernel. Extracting it with tooling
is possible (or it is part of the kernel package). Adding this key
into the build process while rebuilding the kernel should work.
This will however alter the build process and is not *the* original
one, which was used to build the image.
- the private key remains unknown which means the modules can not be
signed. The rebuilding would need to get past this limitation and the
logic must not be affected by this "change". Then the modules need to
be stripped of their signature for the comparison.
Doing all this requires additional handling/ tooling on the "validation"
infrastructure. This infrastructure works currently without special
care.
Adding special care will not build the package exactly like it has been
built originally _and_ the results need to be interpreted (as in we
remove this signature and do this and now it is fine).
Adding hashes of each module into the kernel image looks like a
reasonable thing to do. I don't see any downsides to this. Yes, you are
limited to the modules available at build time but this is also the case
today with the ephemeral key. It is meant for distros not for individual
developers testing their code.
With this change it is possible to build a kernel and its modules and
put the result in an archive such as tar/ deb/ rpm. You can build the
package _again_ following exactly the same steps as you did before and
the result will be the identical archive.
Bit by bit.
No need for interpreting the results, stripping signatures or altering
the build process.
I fully agree with this approach. I don't like the big hash array but I
have an idea how to optimize that part. So I don't see a problem in the
long term.
> Regards,
>
> James
Sebastian
^ permalink raw reply
* [PATCH v2] lsm: use unrcu_pointer() for current->cred in security_init()
From: Paul Moore @ 2025-11-19 15:36 UTC (permalink / raw)
To: linux-security-module
We need to directly allocate the cred's LSM state for the initial task
when we initialize the LSM framework. Unfortunately, this results in a
RCU related type mismatch, use the unrcu_pointer() macro to handle this
a bit more elegantly.
The explicit type casting still remains as we need to work around the
constification of current->cred in this particular case.
Signed-off-by: Paul Moore <paul@paul-moore.com>
---
security/lsm_init.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/security/lsm_init.c b/security/lsm_init.c
index 6bb67d41ce52..05bd52e6b1f2 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -467,7 +467,8 @@ int __init security_init(void)
blob_sizes.lbs_inode, 0,
SLAB_PANIC, NULL);
- if (lsm_cred_alloc((struct cred __rcu *)current->cred, GFP_KERNEL))
+ if (lsm_cred_alloc((struct cred *)unrcu_pointer(current->cred),
+ GFP_KERNEL))
panic("early LSM cred alloc failed\n");
if (lsm_task_alloc(current))
panic("early LSM task alloc failed\n");
--
2.52.0
^ permalink raw reply related
* Re: [PATCH] lsm: use unrcu_pointer() for current->cred in security_init()
From: Paul Moore @ 2025-11-19 15:36 UTC (permalink / raw)
To: Xiujianfeng; +Cc: linux-security-module
In-Reply-To: <5508241d-7c8f-4caa-a62e-3d8eb2426b55@huaweicloud.com>
On Tue, Nov 18, 2025 at 10:49 PM Xiujianfeng
<xiujianfeng@huaweicloud.com> wrote:
> On 11/19/2025 8:28 AM, Paul Moore wrote:
> > We need to directly allocate the cred's LSM state for the initial task
> > when we initialize the LSM framework. Unfortunately, this results in a
> > RCU related type mismatch, use the unrcu_pointer() macro to handle this
> > a bit more elegantly.
> >
> > The explicit type casting still remains as we need to work around the
> > constification of current->cred in this particular case.
> >
> > Signed-off-by: Paul Moore <paul@paul-moore.com>
> > ---
> > security/lsm_init.c | 3 ++-
> > 1 file changed, 2 insertions(+), 1 deletion(-)
> >
> > diff --git a/security/lsm_init.c b/security/lsm_init.c
> > index 6bb67d41ce52..4dec9199e4c2 100644
> > --- a/security/lsm_init.c
> > +++ b/security/lsm_init.c
> > @@ -467,7 +467,8 @@ int __init security_init(void)
> > blob_sizes.lbs_inode, 0,
> > SLAB_PANIC, NULL);
> >
> > - if (lsm_cred_alloc((struct cred __rcu *)current->cred, GFP_KERNEL))
> > + if (lsm_cred_alloc(unrcu_pointer((struct cred __rcu *)current->cred),
> > + GFP_KERNEL))
>
> Since the casting from const to non-const is inevitable, why not
> directly cast it to (struct cred *)?
I like having the call to the unrcu_pointer() macro as it helps bring
attention to this corner case should things change in the task_struct,
however, I do think you have a point about moving the cast to *after*
the unrcu_pointer() call as we could so a simpler "(struct cred *)"
cast.
v2 coming shortly.
> > panic("early LSM cred alloc failed\n");
> > if (lsm_task_alloc(current))
> > panic("early LSM task alloc failed\n");
--
paul-moore.com
^ permalink raw reply
* Re: [PATCH v4] ima: Access decompressed kernel module to verify appended signature
From: Mimi Zohar @ 2025-11-19 15:29 UTC (permalink / raw)
To: Coiby Xu, linux-integrity
Cc: Karel Srot, Paul Moore, Luis Chamberlain, Petr Pavlu,
Daniel Gomez, Sami Tolvanen, Roberto Sassu, Dmitry Kasatkin,
Eric Snowberg, James Morris, Serge E. Hallyn, Fan Wu,
Stephen Smalley, Ondrej Mosnacek, open list,
open list:MODULE SUPPORT, open list:SECURITY SUBSYSTEM,
open list:SELINUX SECURITY MODULE
In-Reply-To: <20251119140326.787451-1-coxu@redhat.com>
On Wed, 2025-11-19 at 22:03 +0800, Coiby Xu wrote:
> Currently, when in-kernel module decompression (CONFIG_MODULE_DECOMPRESS)
> is enabled, IMA has no way to verify the appended module signature as it
> can't decompress the module.
>
> Define a new kernel_read_file_id enumerate READING_MODULE_COMPRESSED so
> IMA can calculate the compressed kernel module data hash on
> READING_MODULE_COMPRESSED and defer appraising/measuring it until on
> READING_MODULE when the module has been decompressed.
>
> Before enabling in-kernel module decompression, a kernel module in
> initramfs can still be loaded with ima_policy=secure_boot. So adjust the
> kernel module rule in secure_boot policy to allow either an IMA
> signature OR an appended signature i.e. to use
> "appraise func=MODULE_CHECK appraise_type=imasig|modsig".
>
> Reported-by: Karel Srot <ksrot@redhat.com>
> Suggested-by: Mimi Zohar <zohar@linux.ibm.com>
> Suggested-by: Paul Moore <paul@paul-moore.com>
> Signed-off-by: Coiby Xu <coxu@redhat.com>
Thanks, Coiby! The patch is now queued in next-integrity.
--
Mimi
^ permalink raw reply
* Re: [PATCH] KEYS: encrypted: Use pr_fmt()
From: Thorsten Blum @ 2025-11-19 14:45 UTC (permalink / raw)
To: Jarkko Sakkinen
Cc: Mimi Zohar, David Howells, Paul Moore, James Morris,
Serge E. Hallyn, linux-integrity, keyrings, linux-security-module,
linux-kernel
In-Reply-To: <aR0v9mLOKJsr_0Zm@kernel.org>
On 19. Nov 2025, at 03:48, Jarkko Sakkinen wrote:
> On Thu, Nov 13, 2025 at 01:35:44PM +0100, Thorsten Blum wrote:
>> Use pr_fmt() to automatically prefix all pr_<level>() log messages with
>
> This fails to describe what "use" means.
I don't understand what you mean. What's wrong with "use ... to ..."?
>> "encrypted_key: " and remove all manually added prefixes.
>>
>> Reformat the code accordingly and avoid line breaks in log messages.
>>
>> Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
>> ---
>> security/keys/encrypted-keys/encrypted.c | 74 +++++++++++-------------
>> security/keys/encrypted-keys/encrypted.h | 2 +-
>> 2 files changed, 35 insertions(+), 41 deletions(-)
>>
>> diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c
>> index 513c09e2b01c..a8e8bf949b4b 100644
>> --- a/security/keys/encrypted-keys/encrypted.c
>> +++ b/security/keys/encrypted-keys/encrypted.c
>> @@ -11,6 +11,8 @@
>> * See Documentation/security/keys/trusted-encrypted.rst
>> */
>>
>
> Should have undef prepending.
Why is this necessary when the #define is at the top of a source file?
The kernel documentation [1] doesn't mention this anywhere. Isn't #undef
only needed when redefining 'pr_fmt' in the middle of a file to avoid a
compiler warning/error?
>> +#define pr_fmt(fmt) "encrypted_key: " fmt
>> +
>> [...]
Thanks,
Thorsten
[1] https://docs.kernel.org/core-api/printk-basics.html
^ permalink raw reply
* Re: [PATCH v3] ima: Access decompressed kernel module to verify appended signature
From: Coiby Xu @ 2025-11-19 14:05 UTC (permalink / raw)
To: Mimi Zohar
Cc: linux-integrity, Karel Srot, Paul Moore, Luis Chamberlain,
Petr Pavlu, Daniel Gomez, Sami Tolvanen, Roberto Sassu,
Dmitry Kasatkin, Eric Snowberg, James Morris, Serge E. Hallyn,
Fan Wu, Stephen Smalley, Ondrej Mosnacek, open list,
open list:MODULE SUPPORT, open list:SECURITY SUBSYSTEM,
open list:SELINUX SECURITY MODULE
In-Reply-To: <fc1d67e411ef53460517db4c03bdcf1b9d9f8a8f.camel@linux.ibm.com>
On Wed, Nov 19, 2025 at 08:29:22AM -0500, Mimi Zohar wrote:
>Hi Coiby,
Hi Mimi,
>
>On Wed, 2025-11-19 at 11:47 +0800, Coiby Xu wrote:
>> Currently, when in-kernel module decompression (CONFIG_MODULE_DECOMPRESS)
>> is enabled, IMA has no way to verify the appended module signature as it
>> can't decompress the module.
>>
>> Define a new kernel_read_file_id enumerate READING_MODULE_COMPRESSED so
>> IMA can know only to collect original module data hash on
>> READING_MODULE_COMPRESSED and defer appraising/measuring it until on
>> READING_MODULE when the module has been decompressed.
>
>This paragraph is a bit awkward. Perhaps something like:
>
>-> so IMA can calculate the compressed kernel module data hash and defer
>measuring/appraising ...
>
>>
>> Before enabling in-kernel module decompression, a kernel module in
>> initramfs can still be loaded with ima_policy=secure_boot. So adjust the
>> kernel module rule in secure_boot policy to allow either an IMA
>> signature OR an appended signature i.e. to use
>> "appraise func=MODULE_CHECK appraise_type=imasig|modsig".
>>
>> Reported-by: Karel Srot <ksrot@redhat.com>
>> Suggested-by: Mimi Zohar <zohar@linux.ibm.com>
>> Suggested-by: Paul Moore <paul@paul-moore.com>
>> Signed-off-by: Coiby Xu <coxu@redhat.com>
>
>Thanks, Coiby!
>
>The patch applies cleanly to linus' tree, but needs to be applied to next-
>integrity. Please re-base.
I've sent v4 which has been rebased onto next tree with improved
wording as suggested.
>
>--
>
>thanks,
>
>Mimi
>
--
Best regards,
Coiby
^ permalink raw reply
* [PATCH v4] ima: Access decompressed kernel module to verify appended signature
From: Coiby Xu @ 2025-11-19 14:03 UTC (permalink / raw)
To: linux-integrity, Mimi Zohar
Cc: Karel Srot, Paul Moore, Luis Chamberlain, Petr Pavlu,
Daniel Gomez, Sami Tolvanen, Roberto Sassu, Dmitry Kasatkin,
Eric Snowberg, James Morris, Serge E. Hallyn, Fan Wu,
Stephen Smalley, Ondrej Mosnacek, open list,
open list:MODULE SUPPORT, open list:SECURITY SUBSYSTEM,
open list:SELINUX SECURITY MODULE
In-Reply-To: <20251031074016.1975356-1-coxu@redhat.com>
Currently, when in-kernel module decompression (CONFIG_MODULE_DECOMPRESS)
is enabled, IMA has no way to verify the appended module signature as it
can't decompress the module.
Define a new kernel_read_file_id enumerate READING_MODULE_COMPRESSED so
IMA can calculate the compressed kernel module data hash on
READING_MODULE_COMPRESSED and defer appraising/measuring it until on
READING_MODULE when the module has been decompressed.
Before enabling in-kernel module decompression, a kernel module in
initramfs can still be loaded with ima_policy=secure_boot. So adjust the
kernel module rule in secure_boot policy to allow either an IMA
signature OR an appended signature i.e. to use
"appraise func=MODULE_CHECK appraise_type=imasig|modsig".
Reported-by: Karel Srot <ksrot@redhat.com>
Suggested-by: Mimi Zohar <zohar@linux.ibm.com>
Suggested-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Coiby Xu <coxu@redhat.com>
---
include/linux/kernel_read_file.h | 1 +
kernel/module/main.c | 17 ++++++++++++++---
security/integrity/ima/ima_main.c | 24 ++++++++++++++++--------
security/integrity/ima/ima_policy.c | 3 ++-
security/ipe/hooks.c | 1 +
security/selinux/hooks.c | 5 +++--
6 files changed, 37 insertions(+), 14 deletions(-)
diff --git a/include/linux/kernel_read_file.h b/include/linux/kernel_read_file.h
index 90451e2e12bd..d613a7b4dd35 100644
--- a/include/linux/kernel_read_file.h
+++ b/include/linux/kernel_read_file.h
@@ -14,6 +14,7 @@
id(KEXEC_INITRAMFS, kexec-initramfs) \
id(POLICY, security-policy) \
id(X509_CERTIFICATE, x509-certificate) \
+ id(MODULE_COMPRESSED, kernel-module-compressed) \
id(MAX_ID, )
#define __fid_enumify(ENUM, dummy) READING_ ## ENUM,
diff --git a/kernel/module/main.c b/kernel/module/main.c
index c66b26184936..7b3ec2fa6e7c 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -3675,24 +3675,35 @@ static int idempotent_wait_for_completion(struct idempotent *u)
static int init_module_from_file(struct file *f, const char __user * uargs, int flags)
{
+ bool compressed = !!(flags & MODULE_INIT_COMPRESSED_FILE);
struct load_info info = { };
void *buf = NULL;
int len;
+ int err;
- len = kernel_read_file(f, 0, &buf, INT_MAX, NULL, READING_MODULE);
+ len = kernel_read_file(f, 0, &buf, INT_MAX, NULL,
+ compressed ? READING_MODULE_COMPRESSED :
+ READING_MODULE);
if (len < 0) {
mod_stat_inc(&failed_kreads);
return len;
}
- if (flags & MODULE_INIT_COMPRESSED_FILE) {
- int err = module_decompress(&info, buf, len);
+ if (compressed) {
+ err = module_decompress(&info, buf, len);
vfree(buf); /* compressed data is no longer needed */
if (err) {
mod_stat_inc(&failed_decompress);
mod_stat_add_long(len, &invalid_decompress_bytes);
return err;
}
+ err = security_kernel_post_read_file(f, (char *)info.hdr, info.len,
+ READING_MODULE);
+ if (err) {
+ mod_stat_inc(&failed_kreads);
+ free_copy(&info, flags);
+ return err;
+ }
} else {
info.hdr = buf;
info.len = len;
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index ebaebccfbe9a..edd0fd3d77a0 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -235,7 +235,8 @@ static void ima_file_free(struct file *file)
static int process_measurement(struct file *file, const struct cred *cred,
struct lsm_prop *prop, char *buf, loff_t size,
- int mask, enum ima_hooks func)
+ int mask, enum ima_hooks func,
+ enum kernel_read_file_id read_id)
{
struct inode *real_inode, *inode = file_inode(file);
struct ima_iint_cache *iint = NULL;
@@ -406,6 +407,12 @@ static int process_measurement(struct file *file, const struct cred *cred,
if (rc != 0 && rc != -EBADF && rc != -EINVAL)
goto out_locked;
+ /* Defer measuring/appraising kernel modules to READING_MODULE */
+ if (read_id == READING_MODULE_COMPRESSED) {
+ must_appraise = 0;
+ goto out_locked;
+ }
+
if (!pathbuf) /* ima_rdwr_violation possibly pre-fetched */
pathname = ima_d_path(&file->f_path, &pathbuf, filename);
@@ -486,14 +493,14 @@ static int ima_file_mmap(struct file *file, unsigned long reqprot,
if (reqprot & PROT_EXEC) {
ret = process_measurement(file, current_cred(), &prop, NULL,
- 0, MAY_EXEC, MMAP_CHECK_REQPROT);
+ 0, MAY_EXEC, MMAP_CHECK_REQPROT, 0);
if (ret)
return ret;
}
if (prot & PROT_EXEC)
return process_measurement(file, current_cred(), &prop, NULL,
- 0, MAY_EXEC, MMAP_CHECK);
+ 0, MAY_EXEC, MMAP_CHECK, 0);
return 0;
}
@@ -577,7 +584,7 @@ static int ima_bprm_check(struct linux_binprm *bprm)
security_current_getlsmprop_subj(&prop);
return process_measurement(bprm->file, current_cred(),
- &prop, NULL, 0, MAY_EXEC, BPRM_CHECK);
+ &prop, NULL, 0, MAY_EXEC, BPRM_CHECK, 0);
}
/**
@@ -607,7 +614,7 @@ static int ima_creds_check(struct linux_binprm *bprm, const struct file *file)
security_current_getlsmprop_subj(&prop);
return process_measurement((struct file *)file, bprm->cred, &prop, NULL,
- 0, MAY_EXEC, CREDS_CHECK);
+ 0, MAY_EXEC, CREDS_CHECK, 0);
}
/**
@@ -655,7 +662,7 @@ static int ima_file_check(struct file *file, int mask)
security_current_getlsmprop_subj(&prop);
return process_measurement(file, current_cred(), &prop, NULL, 0,
mask & (MAY_READ | MAY_WRITE | MAY_EXEC |
- MAY_APPEND), FILE_CHECK);
+ MAY_APPEND), FILE_CHECK, 0);
}
static int __ima_inode_hash(struct inode *inode, struct file *file, char *buf,
@@ -874,12 +881,13 @@ static int ima_read_file(struct file *file, enum kernel_read_file_id read_id,
func = read_idmap[read_id] ?: FILE_CHECK;
security_current_getlsmprop_subj(&prop);
return process_measurement(file, current_cred(), &prop, NULL, 0,
- MAY_READ, func);
+ MAY_READ, func, 0);
}
const int read_idmap[READING_MAX_ID] = {
[READING_FIRMWARE] = FIRMWARE_CHECK,
[READING_MODULE] = MODULE_CHECK,
+ [READING_MODULE_COMPRESSED] = MODULE_CHECK,
[READING_KEXEC_IMAGE] = KEXEC_KERNEL_CHECK,
[READING_KEXEC_INITRAMFS] = KEXEC_INITRAMFS_CHECK,
[READING_POLICY] = POLICY_CHECK
@@ -917,7 +925,7 @@ static int ima_post_read_file(struct file *file, char *buf, loff_t size,
func = read_idmap[read_id] ?: FILE_CHECK;
security_current_getlsmprop_subj(&prop);
return process_measurement(file, current_cred(), &prop, buf, size,
- MAY_READ, func);
+ MAY_READ, func, read_id);
}
/**
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index 164d62832f8e..7468afaab686 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -244,7 +244,8 @@ static struct ima_rule_entry build_appraise_rules[] __ro_after_init = {
static struct ima_rule_entry secure_boot_rules[] __ro_after_init = {
{.action = APPRAISE, .func = MODULE_CHECK,
- .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED},
+ .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED | IMA_MODSIG_ALLOWED |
+ IMA_CHECK_BLACKLIST},
{.action = APPRAISE, .func = FIRMWARE_CHECK,
.flags = IMA_FUNC | IMA_DIGSIG_REQUIRED},
{.action = APPRAISE, .func = KEXEC_KERNEL_CHECK,
diff --git a/security/ipe/hooks.c b/security/ipe/hooks.c
index d0323b81cd8f..1053a4acf589 100644
--- a/security/ipe/hooks.c
+++ b/security/ipe/hooks.c
@@ -118,6 +118,7 @@ int ipe_kernel_read_file(struct file *file, enum kernel_read_file_id id,
op = IPE_OP_FIRMWARE;
break;
case READING_MODULE:
+ case READING_MODULE_COMPRESSED:
op = IPE_OP_KERNEL_MODULE;
break;
case READING_KEXEC_INITRAMFS:
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index dfc22da42f30..c1ff69d5d76e 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -4275,7 +4275,7 @@ static int selinux_kernel_read_file(struct file *file,
{
int rc = 0;
- BUILD_BUG_ON_MSG(READING_MAX_ID > 7,
+ BUILD_BUG_ON_MSG(READING_MAX_ID > 8,
"New kernel_read_file_id introduced; update SELinux!");
switch (id) {
@@ -4283,6 +4283,7 @@ static int selinux_kernel_read_file(struct file *file,
rc = selinux_kernel_load_from_file(file, SYSTEM__FIRMWARE_LOAD);
break;
case READING_MODULE:
+ case READING_MODULE_COMPRESSED:
rc = selinux_kernel_load_from_file(file, SYSTEM__MODULE_LOAD);
break;
case READING_KEXEC_IMAGE:
@@ -4311,7 +4312,7 @@ static int selinux_kernel_load_data(enum kernel_load_data_id id, bool contents)
{
int rc = 0;
- BUILD_BUG_ON_MSG(LOADING_MAX_ID > 7,
+ BUILD_BUG_ON_MSG(LOADING_MAX_ID > 8,
"New kernel_load_data_id introduced; update SELinux!");
switch (id) {
base-commit: 43369273518f57b7d56c1cf12d636a809b7bd81b
--
2.51.1
^ permalink raw reply related
* Re: [PATCH v3] ima: Access decompressed kernel module to verify appended signature
From: Mimi Zohar @ 2025-11-19 13:29 UTC (permalink / raw)
To: Coiby Xu, linux-integrity
Cc: Karel Srot, Paul Moore, Luis Chamberlain, Petr Pavlu,
Daniel Gomez, Sami Tolvanen, Roberto Sassu, Dmitry Kasatkin,
Eric Snowberg, James Morris, Serge E. Hallyn, Fan Wu,
Stephen Smalley, Ondrej Mosnacek, open list,
open list:MODULE SUPPORT, open list:SECURITY SUBSYSTEM,
open list:SELINUX SECURITY MODULE
In-Reply-To: <20251119034718.618008-1-coxu@redhat.com>
Hi Coiby,
On Wed, 2025-11-19 at 11:47 +0800, Coiby Xu wrote:
> Currently, when in-kernel module decompression (CONFIG_MODULE_DECOMPRESS)
> is enabled, IMA has no way to verify the appended module signature as it
> can't decompress the module.
>
> Define a new kernel_read_file_id enumerate READING_MODULE_COMPRESSED so
> IMA can know only to collect original module data hash on
> READING_MODULE_COMPRESSED and defer appraising/measuring it until on
> READING_MODULE when the module has been decompressed.
This paragraph is a bit awkward. Perhaps something like:
-> so IMA can calculate the compressed kernel module data hash and defer
measuring/appraising ...
>
> Before enabling in-kernel module decompression, a kernel module in
> initramfs can still be loaded with ima_policy=secure_boot. So adjust the
> kernel module rule in secure_boot policy to allow either an IMA
> signature OR an appended signature i.e. to use
> "appraise func=MODULE_CHECK appraise_type=imasig|modsig".
>
> Reported-by: Karel Srot <ksrot@redhat.com>
> Suggested-by: Mimi Zohar <zohar@linux.ibm.com>
> Suggested-by: Paul Moore <paul@paul-moore.com>
> Signed-off-by: Coiby Xu <coxu@redhat.com>
Thanks, Coiby!
The patch applies cleanly to linus' tree, but needs to be applied to next-
integrity. Please re-base.
--
thanks,
Mimi
^ permalink raw reply
* [PATCH] lockdown: Only log restrictions once
From: Daniel Tang @ 2025-11-19 13:22 UTC (permalink / raw)
To: linux-security-module
Cc: linux-kernel, Nathan Lynch, Paul Moore, Matthew Garrett,
Kees Cook, David Howells, James Morris
KDE's lockscreen causes systemd-logind to spam dmesg about hibernation.
systemd declined to cache /sys/power/state due to runtime changeability.
Link: https://github.com/systemd/systemd/pull/39802
Signed-off-by: Daniel Tang <danielzgtg.opensource@gmail.com>
---
security/lockdown/lockdown.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/security/lockdown/lockdown.c b/security/lockdown/lockdown.c
index cf83afa1d879..4ced8c76dc6b 100644
--- a/security/lockdown/lockdown.c
+++ b/security/lockdown/lockdown.c
@@ -62,9 +62,11 @@ static int lockdown_is_locked_down(enum lockdown_reason what)
"Invalid lockdown reason"))
return -EPERM;
+ static volatile unsigned long lockdown_reasons_seen;
+ static_assert(ARRAY_SIZE(lockdown_reasons) < sizeof(lockdown_reasons_seen) * 8);
if (kernel_locked_down >= what) {
- if (lockdown_reasons[what])
- pr_notice_ratelimited("Lockdown: %s: %s is restricted; see man kernel_lockdown.7\n",
+ if (lockdown_reasons[what] && !test_and_set_bit(what, &lockdown_reasons_seen))
+ pr_notice("Lockdown: %s: %s is restricted; see man kernel_lockdown.7\n",
current->comm, lockdown_reasons[what]);
return -EPERM;
}
--
2.51.0
^ permalink raw reply related
* Re: [PATCH v3 7/9] module: Move lockdown check into generic module loader
From: Sebastian Andrzej Siewior @ 2025-11-19 11:20 UTC (permalink / raw)
To: Thomas Weißschuh
Cc: Masahiro Yamada, Nathan Chancellor, Arnd Bergmann,
Luis Chamberlain, Petr Pavlu, Sami Tolvanen, Daniel Gomez,
Paul Moore, James Morris, Serge E. Hallyn, Jonathan Corbet,
Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
Christophe Leroy, Naveen N Rao, Mimi Zohar, Roberto Sassu,
Dmitry Kasatkin, Eric Snowberg, Nicolas Schier,
Fabian Grünbichler, Arnout Engelen, Mattia Rizzolo, kpcyrd,
Christian Heusel, Câju Mihai-Drosi, linux-kbuild,
linux-kernel, linux-arch, linux-modules, linux-security-module,
linux-doc, linuxppc-dev, linux-integrity
In-Reply-To: <20250429-module-hashes-v3-7-00e9258def9e@weissschuh.net>
On 2025-04-29 15:04:34 [+0200], Thomas Weißschuh wrote:
> The lockdown check buried in module_sig_check() will not compose well
> with the introduction of hash-based module validation.
An explanation of why would be nice.
> Move it into module_integrity_check() which will work better.
>
> Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
Sebastian
^ permalink raw reply
* Wiadomość z księgowości
From: Marek Poradecki @ 2025-11-19 9:01 UTC (permalink / raw)
To: linux-security-module
Dzień dobry,
pomagamy przedsiębiorcom wprowadzić model wymiany walut, który minimalizuje wahania kosztów przy rozliczeniach międzynarodowych.
Kiedyv możemy umówić się na 15-minutową rozmowę, aby zaprezentować, jak taki model mógłby działać w Państwa firmie - z gwarancją indywidualnych kursów i pełnym uproszczeniem płatności? Proszę o propozycję dogodnego terminu.
Pozdrawiam
Marek Poradecki
^ permalink raw reply
* Re: [PATCH v2] lsm,ima: new LSM hook security_kernel_module_read_file to access decompressed kernel module
From: Coiby Xu @ 2025-11-19 3:52 UTC (permalink / raw)
To: Mimi Zohar
Cc: Paul Moore, linux-integrity, linux-security-module, Karel Srot,
James Morris, Serge E. Hallyn, Luis Chamberlain, Petr Pavlu,
Daniel Gomez, Sami Tolvanen, Roberto Sassu, Dmitry Kasatkin,
Eric Snowberg, open list, open list:MODULE SUPPORT
In-Reply-To: <fca9a7b41a5e428fadfe2d7e3b004ada2763375c.camel@linux.ibm.com>
On Tue, Nov 18, 2025 at 07:19:50AM -0500, Mimi Zohar wrote:
>On Thu, 2025-11-13 at 12:06 +0800, Coiby Xu wrote:
>> On Fri, Nov 07, 2025 at 02:28:13PM -0500, Mimi Zohar wrote:
>> > On Thu, 2025-11-06 at 17:15 -0500, Mimi Zohar wrote:
>> > > On Thu, 2025-11-06 at 21:29 +0800, Coiby Xu wrote:
>> > > > On Wed, Nov 05, 2025 at 03:47:25PM -0500, Mimi Zohar wrote:
>> > > > > On Wed, 2025-11-05 at 08:18 +0800, Coiby Xu wrote:
>> > > > [...]
>> > > > >
>> > > > > Hi Coiby,
>> > > > >
>> > > > > Based on the conversation with Paul, there is no reason to remove the existing
>> > > > > security_kernel_post_read_file() call.
>> > > > >
>> > > > > The changes are similar to the 2nd link, but a bit different.
>> > > > > - Define a single enumeration named READING_MODULE_COMPRESSED.
>> > > > >
>> > > > > - In module/main.c add a new security_kernel_post_read_file() call immediately
>> > > > > after decompressing the kernel module. Like a previous version of this patch,
>> > > > > call kernel_read_file() with either READING_MODULE or READING_MODULE_COMPRESSED
>> > > > > based on MODULE_INIT_COMPRESSED_FILE.
>> > > > >
>> > > > > - In ima_post_read_file() defer verifying the signature when the enumeration is
>> > > > > READING_MODULE_COMPRESSED. (No need for a new function ima_read_kernel_module.)
>> > > >
>> > > > Hi Mimi,
>> > > >
>> > > > Thanks for summarizing your conversation with Paul! I can confirm Paul's
>> > > > approach works
>> > > > https://github.com/coiby/linux/tree/in_kernel_decompression_ima_no_lsm_hook_paul
>> > > >
>> > > > While testing the patch today, I realized there is another
>> > > > issue/challenge introduced by in-kernel module decompression. IMA
>> > > > appraisal is to verify the digest of compressed kernel module but
>> > > > currently the passed buffer is uncompressed module. When IMA uses
>> > > > uncompressed module data to calculate the digest, xattr signature
>> > > > verification will fail. If we always make IMA read the original kernel
>> > > > module data again to calculate the digest, does it look like a
>> > > > quick-and-dirty fix? If we can assume people won't load kernel module so
>> > > > often, the performance impact is negligible. Otherwise we may have to
>> > > > introduce a new LSM hook so IMA can access uncompressed and original
>> > > > module data one time.
>> > >
>> > > ima_collect_measurement() stores the file hash info in the iint and uses that
>> > > information to verify the signature as stored in the security xattr.
>> > > Decompressing the kernel module shouldn't affect the xattr signature
>> > > verification.
>> >
>> > In the case when the compressed kernel module hasn't previously been measured or
>> > appraised before loading the kernel module, we need to "collect" the file data
>> > hash on READING_MODULE_COMPRESSED, but defer appraising/measuring it.
>> >
>> > An alternative to your suggestion of re-reading the original kernel module data
>> > to calculate the digest or defining a new hook, would be to define "collect" as
>> > a new "action" and pass the kernel_read_file_id enumeration to
>> > process_measurement(). IMA_COLLECTED already exists. Only IMA_COLLECT would
>> > need to be defined. The new collect "action" should be limited to
>> > func=MODULE_CHECK.
>> >
>> > The downside of this alternative is that it requires a new collect rule:
>> > collect func=MODULE_CHECK mask=MAY_READ uid=0
>> > appraise func=MODULE_CHECK appraise_type=imasig|modsig
>
>As it turns out, the "collect" rule is unnecessary. On
>READING_MODULE_COMPRESSED, process_measurement() should calculate the compressed
>file hash. Extending the IMA measurement list and verifying the signature can
>then be differed to READING_MODULE.
>
>>
>> Thank for suggesting an alternative! I've implemented the idea in
>> https://github.com/coiby/linux/tree/in_kernel_decompression_ima_collect
>>
>> Note besides a new collect rule, another change is needed. Currently,
>> process_measurement only accepts enum ima_hooks thus it can't tell if
>> it's READING_MODULE_COMPRESSED so to only do collect action. So I
>> create a fake MODULE_COMPRESSED_CHECK func.
>
>Correct, either extending process_measurement() with the read_idmap enum or
>defining the fake hook would work.
>
>>
>> And for the idea of re-reading the original kernel module data, it has
>> been implemented in
>> https://github.com/coiby/linux/tree/in_kernel_decompression_ima_no_lsm_hook_paul
>>
>> Both branches have applied your requested three changes including
>> respecting the 80 char line limit. Additionally, I made a change to the
>> IPE LSM because of the new READING_MODULE_COMPRESSED kernel_read_file_id
>> enumerate.
>>
>> After comparing the two implementations, personally I prefer re-reading
>> the original kernel module data because the change is smaller and it's
>> more user-friendly. But if there are other reasons I don't know, I'll
>> post the patches of the new collect action approach to the mailing list.
>
>The "re-reading" option fails some of the tests. As the "collect" rule isn't
>needed, let's stick with the first option.
Thanks for evaluating the two options! Yeah, without the "collect" rule,
the 1st option is much better as it doesn't have the issue of re-reading
the module.
--
Best regards,
Coiby
^ permalink raw reply
* Re: [PATCH] lsm: use unrcu_pointer() for current->cred in security_init()
From: Xiujianfeng @ 2025-11-19 3:49 UTC (permalink / raw)
To: Paul Moore, linux-security-module
In-Reply-To: <20251119002808.444259-2-paul@paul-moore.com>
Hi Paul,
On 11/19/2025 8:28 AM, Paul Moore wrote:
> We need to directly allocate the cred's LSM state for the initial task
> when we initialize the LSM framework. Unfortunately, this results in a
> RCU related type mismatch, use the unrcu_pointer() macro to handle this
> a bit more elegantly.
>
> The explicit type casting still remains as we need to work around the
> constification of current->cred in this particular case.
>
> Signed-off-by: Paul Moore <paul@paul-moore.com>
> ---
> security/lsm_init.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index 6bb67d41ce52..4dec9199e4c2 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -467,7 +467,8 @@ int __init security_init(void)
> blob_sizes.lbs_inode, 0,
> SLAB_PANIC, NULL);
>
> - if (lsm_cred_alloc((struct cred __rcu *)current->cred, GFP_KERNEL))
> + if (lsm_cred_alloc(unrcu_pointer((struct cred __rcu *)current->cred),
> + GFP_KERNEL))
Since the casting from const to non-const is inevitable, why not
directly cast it to (struct cred *)?
> panic("early LSM cred alloc failed\n");
> if (lsm_task_alloc(current))
> panic("early LSM task alloc failed\n");
^ permalink raw reply
* [PATCH v3] ima: Access decompressed kernel module to verify appended signature
From: Coiby Xu @ 2025-11-19 3:47 UTC (permalink / raw)
To: linux-integrity, Mimi Zohar
Cc: Karel Srot, Paul Moore, Luis Chamberlain, Petr Pavlu,
Daniel Gomez, Sami Tolvanen, Roberto Sassu, Dmitry Kasatkin,
Eric Snowberg, James Morris, Serge E. Hallyn, Fan Wu,
Stephen Smalley, Ondrej Mosnacek, open list,
open list:MODULE SUPPORT, open list:SECURITY SUBSYSTEM,
open list:SELINUX SECURITY MODULE
In-Reply-To: <20251031074016.1975356-1-coxu@redhat.com>
Currently, when in-kernel module decompression (CONFIG_MODULE_DECOMPRESS)
is enabled, IMA has no way to verify the appended module signature as it
can't decompress the module.
Define a new kernel_read_file_id enumerate READING_MODULE_COMPRESSED so
IMA can know only to collect original module data hash on
READING_MODULE_COMPRESSED and defer appraising/measuring it until on
READING_MODULE when the module has been decompressed.
Before enabling in-kernel module decompression, a kernel module in
initramfs can still be loaded with ima_policy=secure_boot. So adjust the
kernel module rule in secure_boot policy to allow either an IMA
signature OR an appended signature i.e. to use
"appraise func=MODULE_CHECK appraise_type=imasig|modsig".
Reported-by: Karel Srot <ksrot@redhat.com>
Suggested-by: Mimi Zohar <zohar@linux.ibm.com>
Suggested-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Coiby Xu <coxu@redhat.com>
---
include/linux/kernel_read_file.h | 1 +
kernel/module/main.c | 17 ++++++++++++++---
security/integrity/ima/ima_main.c | 24 ++++++++++++++++--------
security/integrity/ima/ima_policy.c | 3 ++-
security/ipe/hooks.c | 1 +
security/selinux/hooks.c | 5 +++--
6 files changed, 37 insertions(+), 14 deletions(-)
diff --git a/include/linux/kernel_read_file.h b/include/linux/kernel_read_file.h
index 90451e2e12bd..d613a7b4dd35 100644
--- a/include/linux/kernel_read_file.h
+++ b/include/linux/kernel_read_file.h
@@ -14,6 +14,7 @@
id(KEXEC_INITRAMFS, kexec-initramfs) \
id(POLICY, security-policy) \
id(X509_CERTIFICATE, x509-certificate) \
+ id(MODULE_COMPRESSED, kernel-module-compressed) \
id(MAX_ID, )
#define __fid_enumify(ENUM, dummy) READING_ ## ENUM,
diff --git a/kernel/module/main.c b/kernel/module/main.c
index c66b26184936..7b3ec2fa6e7c 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -3675,24 +3675,35 @@ static int idempotent_wait_for_completion(struct idempotent *u)
static int init_module_from_file(struct file *f, const char __user * uargs, int flags)
{
+ bool compressed = !!(flags & MODULE_INIT_COMPRESSED_FILE);
struct load_info info = { };
void *buf = NULL;
int len;
+ int err;
- len = kernel_read_file(f, 0, &buf, INT_MAX, NULL, READING_MODULE);
+ len = kernel_read_file(f, 0, &buf, INT_MAX, NULL,
+ compressed ? READING_MODULE_COMPRESSED :
+ READING_MODULE);
if (len < 0) {
mod_stat_inc(&failed_kreads);
return len;
}
- if (flags & MODULE_INIT_COMPRESSED_FILE) {
- int err = module_decompress(&info, buf, len);
+ if (compressed) {
+ err = module_decompress(&info, buf, len);
vfree(buf); /* compressed data is no longer needed */
if (err) {
mod_stat_inc(&failed_decompress);
mod_stat_add_long(len, &invalid_decompress_bytes);
return err;
}
+ err = security_kernel_post_read_file(f, (char *)info.hdr, info.len,
+ READING_MODULE);
+ if (err) {
+ mod_stat_inc(&failed_kreads);
+ free_copy(&info, flags);
+ return err;
+ }
} else {
info.hdr = buf;
info.len = len;
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index cdd225f65a62..49f8b2b1a9af 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -235,7 +235,8 @@ static void ima_file_free(struct file *file)
static int process_measurement(struct file *file, const struct cred *cred,
struct lsm_prop *prop, char *buf, loff_t size,
- int mask, enum ima_hooks func)
+ int mask, enum ima_hooks func,
+ enum kernel_read_file_id read_id)
{
struct inode *real_inode, *inode = file_inode(file);
struct ima_iint_cache *iint = NULL;
@@ -406,6 +407,12 @@ static int process_measurement(struct file *file, const struct cred *cred,
if (rc != 0 && rc != -EBADF && rc != -EINVAL)
goto out_locked;
+ /* Defer measuring/appraising kernel modules to READING_MODULE */
+ if (read_id == READING_MODULE_COMPRESSED) {
+ must_appraise = 0;
+ goto out_locked;
+ }
+
if (!pathbuf) /* ima_rdwr_violation possibly pre-fetched */
pathname = ima_d_path(&file->f_path, &pathbuf, filename);
@@ -486,14 +493,14 @@ static int ima_file_mmap(struct file *file, unsigned long reqprot,
if (reqprot & PROT_EXEC) {
ret = process_measurement(file, current_cred(), &prop, NULL,
- 0, MAY_EXEC, MMAP_CHECK_REQPROT);
+ 0, MAY_EXEC, MMAP_CHECK_REQPROT, 0);
if (ret)
return ret;
}
if (prot & PROT_EXEC)
return process_measurement(file, current_cred(), &prop, NULL,
- 0, MAY_EXEC, MMAP_CHECK);
+ 0, MAY_EXEC, MMAP_CHECK, 0);
return 0;
}
@@ -578,13 +585,13 @@ static int ima_bprm_check(struct linux_binprm *bprm)
security_current_getlsmprop_subj(&prop);
ret = process_measurement(bprm->file, current_cred(),
- &prop, NULL, 0, MAY_EXEC, BPRM_CHECK);
+ &prop, NULL, 0, MAY_EXEC, BPRM_CHECK, 0);
if (ret)
return ret;
security_cred_getlsmprop(bprm->cred, &prop);
return process_measurement(bprm->file, bprm->cred, &prop, NULL, 0,
- MAY_EXEC, CREDS_CHECK);
+ MAY_EXEC, CREDS_CHECK, 0);
}
/**
@@ -632,7 +639,7 @@ static int ima_file_check(struct file *file, int mask)
security_current_getlsmprop_subj(&prop);
return process_measurement(file, current_cred(), &prop, NULL, 0,
mask & (MAY_READ | MAY_WRITE | MAY_EXEC |
- MAY_APPEND), FILE_CHECK);
+ MAY_APPEND), FILE_CHECK, 0);
}
static int __ima_inode_hash(struct inode *inode, struct file *file, char *buf,
@@ -851,12 +858,13 @@ static int ima_read_file(struct file *file, enum kernel_read_file_id read_id,
func = read_idmap[read_id] ?: FILE_CHECK;
security_current_getlsmprop_subj(&prop);
return process_measurement(file, current_cred(), &prop, NULL, 0,
- MAY_READ, func);
+ MAY_READ, func, 0);
}
const int read_idmap[READING_MAX_ID] = {
[READING_FIRMWARE] = FIRMWARE_CHECK,
[READING_MODULE] = MODULE_CHECK,
+ [READING_MODULE_COMPRESSED] = MODULE_CHECK,
[READING_KEXEC_IMAGE] = KEXEC_KERNEL_CHECK,
[READING_KEXEC_INITRAMFS] = KEXEC_INITRAMFS_CHECK,
[READING_POLICY] = POLICY_CHECK
@@ -894,7 +902,7 @@ static int ima_post_read_file(struct file *file, char *buf, loff_t size,
func = read_idmap[read_id] ?: FILE_CHECK;
security_current_getlsmprop_subj(&prop);
return process_measurement(file, current_cred(), &prop, buf, size,
- MAY_READ, func);
+ MAY_READ, func, read_id);
}
/**
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index 128fab897930..ae520e6bb1cf 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -241,7 +241,8 @@ static struct ima_rule_entry build_appraise_rules[] __ro_after_init = {
static struct ima_rule_entry secure_boot_rules[] __ro_after_init = {
{.action = APPRAISE, .func = MODULE_CHECK,
- .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED},
+ .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED | IMA_MODSIG_ALLOWED |
+ IMA_CHECK_BLACKLIST},
{.action = APPRAISE, .func = FIRMWARE_CHECK,
.flags = IMA_FUNC | IMA_DIGSIG_REQUIRED},
{.action = APPRAISE, .func = KEXEC_KERNEL_CHECK,
diff --git a/security/ipe/hooks.c b/security/ipe/hooks.c
index d0323b81cd8f..1053a4acf589 100644
--- a/security/ipe/hooks.c
+++ b/security/ipe/hooks.c
@@ -118,6 +118,7 @@ int ipe_kernel_read_file(struct file *file, enum kernel_read_file_id id,
op = IPE_OP_FIRMWARE;
break;
case READING_MODULE:
+ case READING_MODULE_COMPRESSED:
op = IPE_OP_KERNEL_MODULE;
break;
case READING_KEXEC_INITRAMFS:
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index dfc22da42f30..c1ff69d5d76e 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -4275,7 +4275,7 @@ static int selinux_kernel_read_file(struct file *file,
{
int rc = 0;
- BUILD_BUG_ON_MSG(READING_MAX_ID > 7,
+ BUILD_BUG_ON_MSG(READING_MAX_ID > 8,
"New kernel_read_file_id introduced; update SELinux!");
switch (id) {
@@ -4283,6 +4283,7 @@ static int selinux_kernel_read_file(struct file *file,
rc = selinux_kernel_load_from_file(file, SYSTEM__FIRMWARE_LOAD);
break;
case READING_MODULE:
+ case READING_MODULE_COMPRESSED:
rc = selinux_kernel_load_from_file(file, SYSTEM__MODULE_LOAD);
break;
case READING_KEXEC_IMAGE:
@@ -4311,7 +4312,7 @@ static int selinux_kernel_load_data(enum kernel_load_data_id id, bool contents)
{
int rc = 0;
- BUILD_BUG_ON_MSG(LOADING_MAX_ID > 7,
+ BUILD_BUG_ON_MSG(LOADING_MAX_ID > 8,
"New kernel_load_data_id introduced; update SELinux!");
switch (id) {
base-commit: 6a23ae0a96a600d1d12557add110e0bb6e32730c
--
2.51.1
^ permalink raw reply related
* Re: [PATCH] KEYS: encrypted: Replace deprecated strcpy and improve get_derived_key
From: Jarkko Sakkinen @ 2025-11-19 2:50 UTC (permalink / raw)
To: Thorsten Blum
Cc: Mimi Zohar, David Howells, Paul Moore, James Morris,
Serge E. Hallyn, linux-hardening, linux-integrity, keyrings,
linux-security-module, linux-kernel
In-Reply-To: <20251113135831.98587-1-thorsten.blum@linux.dev>
On Thu, Nov 13, 2025 at 02:58:31PM +0100, Thorsten Blum wrote:
> Determine 'key_name' before allocating memory for 'derived_buf' to only
> allocate as many bytes as needed. Currently, we potentially allocate one
Who is "we"?
> more byte than necessary when 'key_name' is "ENC_KEY".
>
> strcpy() is deprecated and uses an additional strlen() internally; use
> memcpy() directly to copy 'key_name' since we already know its length
> and that it is guaranteed to be NUL-terminated.
>
> Also reuse 'key_name_len' when copying 'master_key' instead of calling
> strlen() again.
>
> Link: https://github.com/KSPP/linux/issues/88
> Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
> ---
> security/keys/encrypted-keys/encrypted.c | 22 +++++++++-------------
> 1 file changed, 9 insertions(+), 13 deletions(-)
>
> diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c
> index 15841466b5d4..b16a5b8b935b 100644
> --- a/security/keys/encrypted-keys/encrypted.c
> +++ b/security/keys/encrypted-keys/encrypted.c
> @@ -12,6 +12,7 @@
> */
>
> #include <linux/uaccess.h>
> +#include <linux/minmax.h>
> #include <linux/module.h>
> #include <linux/init.h>
> #include <linux/slab.h>
> @@ -330,23 +331,18 @@ static int get_derived_key(u8 *derived_key, enum derived_key_type key_type,
> const u8 *master_key, size_t master_keylen)
> {
> u8 *derived_buf;
> - unsigned int derived_buf_len;
> -
> - derived_buf_len = strlen("AUTH_KEY") + 1 + master_keylen;
> - if (derived_buf_len < HASH_SIZE)
> - derived_buf_len = HASH_SIZE;
> + size_t derived_buf_len;
> + const char *key_name;
> + size_t key_name_len;
>
> + key_name = key_type ? "AUTH_KEY" : "ENC_KEY";
> + key_name_len = strlen(key_name) + 1;
> + derived_buf_len = max(key_name_len + master_keylen, HASH_SIZE);
> derived_buf = kzalloc(derived_buf_len, GFP_KERNEL);
> if (!derived_buf)
> return -ENOMEM;
> -
> - if (key_type)
> - strcpy(derived_buf, "AUTH_KEY");
> - else
> - strcpy(derived_buf, "ENC_KEY");
> -
> - memcpy(derived_buf + strlen(derived_buf) + 1, master_key,
> - master_keylen);
> + memcpy(derived_buf, key_name, key_name_len);
> + memcpy(derived_buf + key_name_len, master_key, master_keylen);
> sha256(derived_buf, derived_buf_len, derived_key);
> kfree_sensitive(derived_buf);
> return 0;
> --
> 2.51.1
>
I don't see much value in this other than potentially causing merge
conflicts when backporting bug fixes.
BR, Jarkko
^ permalink raw reply
* Re: [PATCH] KEYS: encrypted: Use pr_fmt()
From: Jarkko Sakkinen @ 2025-11-19 2:48 UTC (permalink / raw)
To: Thorsten Blum
Cc: Mimi Zohar, David Howells, Paul Moore, James Morris,
Serge E. Hallyn, linux-integrity, keyrings, linux-security-module,
linux-kernel
In-Reply-To: <20251113123544.11287-2-thorsten.blum@linux.dev>
On Thu, Nov 13, 2025 at 01:35:44PM +0100, Thorsten Blum wrote:
> Use pr_fmt() to automatically prefix all pr_<level>() log messages with
This fails to describe what "use" means.
> "encrypted_key: " and remove all manually added prefixes.
>
> Reformat the code accordingly and avoid line breaks in log messages.
>
> Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
> ---
> security/keys/encrypted-keys/encrypted.c | 74 +++++++++++-------------
> security/keys/encrypted-keys/encrypted.h | 2 +-
> 2 files changed, 35 insertions(+), 41 deletions(-)
>
> diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c
> index 513c09e2b01c..a8e8bf949b4b 100644
> --- a/security/keys/encrypted-keys/encrypted.c
> +++ b/security/keys/encrypted-keys/encrypted.c
> @@ -11,6 +11,8 @@
> * See Documentation/security/keys/trusted-encrypted.rst
> */
>
Should have undef prepending.
> +#define pr_fmt(fmt) "encrypted_key: " fmt
> +
> #include <linux/uaccess.h>
> #include <linux/module.h>
> #include <linux/init.h>
> @@ -84,8 +86,7 @@ static int aes_get_sizes(void)
>
> tfm = crypto_alloc_skcipher(blkcipher_alg, 0, CRYPTO_ALG_ASYNC);
> if (IS_ERR(tfm)) {
> - pr_err("encrypted_key: failed to alloc_cipher (%ld)\n",
> - PTR_ERR(tfm));
> + pr_err("failed to alloc_cipher (%ld)\n", PTR_ERR(tfm));
> return PTR_ERR(tfm);
> }
> ivsize = crypto_skcipher_ivsize(tfm);
> @@ -106,15 +107,14 @@ static int valid_ecryptfs_desc(const char *ecryptfs_desc)
> int i;
>
> if (strlen(ecryptfs_desc) != KEY_ECRYPTFS_DESC_LEN) {
> - pr_err("encrypted_key: key description must be %d hexadecimal "
> - "characters long\n", KEY_ECRYPTFS_DESC_LEN);
> + pr_err("key description must be %d hexadecimal characters long\n",
> + KEY_ECRYPTFS_DESC_LEN);
> return -EINVAL;
> }
>
> for (i = 0; i < KEY_ECRYPTFS_DESC_LEN; i++) {
> if (!isxdigit(ecryptfs_desc[i])) {
> - pr_err("encrypted_key: key description must contain "
> - "only hexadecimal characters\n");
> + pr_err("key description must contain only hexadecimal characters\n");
> return -EINVAL;
> }
> }
> @@ -180,7 +180,7 @@ static int datablob_parse(char *datablob, const char **format,
>
> keyword = strsep(&datablob, " \t");
> if (!keyword) {
> - pr_info("encrypted_key: insufficient parameters specified\n");
> + pr_info("insufficient parameters specified\n");
> return ret;
> }
> key_cmd = match_token(keyword, key_tokens, args);
> @@ -188,7 +188,7 @@ static int datablob_parse(char *datablob, const char **format,
> /* Get optional format: default | ecryptfs */
> p = strsep(&datablob, " \t");
> if (!p) {
> - pr_err("encrypted_key: insufficient parameters specified\n");
> + pr_err("insufficient parameters specified\n");
> return ret;
> }
>
> @@ -206,20 +206,20 @@ static int datablob_parse(char *datablob, const char **format,
> }
>
> if (!*master_desc) {
> - pr_info("encrypted_key: master key parameter is missing\n");
> + pr_info("master key parameter is missing\n");
> goto out;
> }
>
> if (valid_master_desc(*master_desc, NULL) < 0) {
> - pr_info("encrypted_key: master key parameter \'%s\' "
> - "is invalid\n", *master_desc);
> + pr_info("master key parameter \'%s\' is invalid\n",
> + *master_desc);
> goto out;
> }
>
> if (decrypted_datalen) {
> *decrypted_datalen = strsep(&datablob, " \t");
> if (!*decrypted_datalen) {
> - pr_info("encrypted_key: keylen parameter is missing\n");
> + pr_info("keylen parameter is missing\n");
> goto out;
> }
> }
> @@ -227,8 +227,8 @@ static int datablob_parse(char *datablob, const char **format,
> switch (key_cmd) {
> case Opt_new:
> if (!decrypted_datalen) {
> - pr_info("encrypted_key: keyword \'%s\' not allowed "
> - "when called from .update method\n", keyword);
> + pr_info("keyword \'%s\' not allowed when called from .update method\n",
> + keyword);
> break;
> }
> *decrypted_data = strsep(&datablob, " \t");
> @@ -236,29 +236,27 @@ static int datablob_parse(char *datablob, const char **format,
> break;
> case Opt_load:
> if (!decrypted_datalen) {
> - pr_info("encrypted_key: keyword \'%s\' not allowed "
> - "when called from .update method\n", keyword);
> + pr_info("keyword \'%s\' not allowed when called from .update method\n",
> + keyword);
> break;
> }
> *hex_encoded_iv = strsep(&datablob, " \t");
> if (!*hex_encoded_iv) {
> - pr_info("encrypted_key: hex blob is missing\n");
> + pr_info("hex blob is missing\n");
> break;
> }
> ret = 0;
> break;
> case Opt_update:
> if (decrypted_datalen) {
> - pr_info("encrypted_key: keyword \'%s\' not allowed "
> - "when called from .instantiate method\n",
> + pr_info("keyword \'%s\' not allowed when called from .instantiate method\n",
> keyword);
> break;
> }
> ret = 0;
> break;
> case Opt_err:
> - pr_info("encrypted_key: keyword \'%s\' not recognized\n",
> - keyword);
> + pr_info("keyword \'%s\' not recognized\n", keyword);
> break;
> }
> out:
> @@ -362,22 +360,21 @@ static struct skcipher_request *init_skcipher_req(const u8 *key,
>
> tfm = crypto_alloc_skcipher(blkcipher_alg, 0, CRYPTO_ALG_ASYNC);
> if (IS_ERR(tfm)) {
> - pr_err("encrypted_key: failed to load %s transform (%ld)\n",
> - blkcipher_alg, PTR_ERR(tfm));
> + pr_err("failed to load %s transform (%ld)\n", blkcipher_alg,
> + PTR_ERR(tfm));
> return ERR_CAST(tfm);
> }
>
> ret = crypto_skcipher_setkey(tfm, key, key_len);
> if (ret < 0) {
> - pr_err("encrypted_key: failed to setkey (%d)\n", ret);
> + pr_err("failed to setkey (%d)\n", ret);
> crypto_free_skcipher(tfm);
> return ERR_PTR(ret);
> }
>
> req = skcipher_request_alloc(tfm, GFP_KERNEL);
> if (!req) {
> - pr_err("encrypted_key: failed to allocate request for %s\n",
> - blkcipher_alg);
> + pr_err("failed to allocate request for %s\n", blkcipher_alg);
> crypto_free_skcipher(tfm);
> return ERR_PTR(-ENOMEM);
> }
> @@ -406,13 +403,10 @@ static struct key *request_master_key(struct encrypted_key_payload *epayload,
>
> if (IS_ERR(mkey)) {
> int ret = PTR_ERR(mkey);
> -
> if (ret == -ENOTSUPP)
> - pr_info("encrypted_key: key %s not supported",
> - epayload->master_desc);
> + pr_info("key %s not supported", epayload->master_desc);
> else
> - pr_info("encrypted_key: key %s not found",
> - epayload->master_desc);
> + pr_info("key %s not found", epayload->master_desc);
> goto out;
> }
>
> @@ -457,7 +451,7 @@ static int derived_key_encrypt(struct encrypted_key_payload *epayload,
> skcipher_request_free(req);
> crypto_free_skcipher(tfm);
> if (ret < 0)
> - pr_err("encrypted_key: failed to encrypt (%d)\n", ret);
> + pr_err("failed to encrypt (%d)\n", ret);
> else
> dump_encrypted_data(epayload, encrypted_datalen);
> out:
> @@ -596,16 +590,16 @@ static struct encrypted_key_payload *encrypted_key_alloc(struct key *key,
>
> if (decrypted_data) {
> if (!user_decrypted_data) {
> - pr_err("encrypted key: instantiation of keys using provided decrypted data is disabled since CONFIG_USER_DECRYPTED_DATA is set to false\n");
> + pr_err("instantiation of keys using provided decrypted data is disabled since CONFIG_USER_DECRYPTED_DATA is set to false\n");
> return ERR_PTR(-EINVAL);
> }
> if (strlen(decrypted_data) != decrypted_datalen * 2) {
> - pr_err("encrypted key: decrypted data provided does not match decrypted data length provided\n");
> + pr_err("decrypted data provided does not match decrypted data length provided\n");
> return ERR_PTR(-EINVAL);
> }
> for (i = 0; i < strlen(decrypted_data); i++) {
> if (!isxdigit(decrypted_data[i])) {
> - pr_err("encrypted key: decrypted data provided must contain only hexadecimal characters\n");
> + pr_err("decrypted data provided must contain only hexadecimal characters\n");
> return ERR_PTR(-EINVAL);
> }
> }
> @@ -614,7 +608,7 @@ static struct encrypted_key_payload *encrypted_key_alloc(struct key *key,
> if (format) {
> if (!strcmp(format, key_format_ecryptfs)) {
> if (dlen != ECRYPTFS_MAX_KEY_BYTES) {
> - pr_err("encrypted_key: keylen for the ecryptfs format must be equal to %d bytes\n",
> + pr_err("keylen for the ecryptfs format must be equal to %d bytes\n",
> ECRYPTFS_MAX_KEY_BYTES);
> return ERR_PTR(-EINVAL);
> }
> @@ -622,8 +616,8 @@ static struct encrypted_key_payload *encrypted_key_alloc(struct key *key,
> payload_datalen = sizeof(struct ecryptfs_auth_tok);
> } else if (!strcmp(format, key_format_enc32)) {
> if (decrypted_datalen != KEY_ENC32_PAYLOAD_LEN) {
> - pr_err("encrypted_key: enc32 key payload incorrect length: %d\n",
> - decrypted_datalen);
> + pr_err("enc32 key payload incorrect length: %d\n",
> + decrypted_datalen);
> return ERR_PTR(-EINVAL);
> }
> }
> @@ -689,7 +683,7 @@ static int encrypted_key_decrypt(struct encrypted_key_payload *epayload,
>
> ret = datablob_hmac_verify(epayload, format, master_key, master_keylen);
> if (ret < 0) {
> - pr_err("encrypted_key: bad hmac (%d)\n", ret);
> + pr_err("bad hmac (%d)\n", ret);
> goto out;
> }
>
> @@ -699,7 +693,7 @@ static int encrypted_key_decrypt(struct encrypted_key_payload *epayload,
>
> ret = derived_key_decrypt(epayload, derived_key, sizeof derived_key);
> if (ret < 0)
> - pr_err("encrypted_key: failed to decrypt key (%d)\n", ret);
> + pr_err("failed to decrypt key (%d)\n", ret);
> out:
> up_read(&mkey->sem);
> key_put(mkey);
> diff --git a/security/keys/encrypted-keys/encrypted.h b/security/keys/encrypted-keys/encrypted.h
> index 1809995db452..7b05c66bafa6 100644
> --- a/security/keys/encrypted-keys/encrypted.h
> +++ b/security/keys/encrypted-keys/encrypted.h
> @@ -41,7 +41,7 @@ static inline void dump_hmac(const char *str, const u8 *digest,
> unsigned int hmac_size)
> {
> if (str)
> - pr_info("encrypted_key: %s", str);
> + pr_info("%s", str);
> print_hex_dump(KERN_ERR, "hmac: ", DUMP_PREFIX_NONE, 32, 1, digest,
> hmac_size, 0);
> }
> --
> 2.51.1
>
BR, Jarkko
^ permalink raw reply
* Re: [PATCH] keys: Replace memcpy with strscpy in proc_keys_show
From: Jarkko Sakkinen @ 2025-11-19 2:36 UTC (permalink / raw)
To: Thorsten Blum
Cc: David Howells, Paul Moore, James Morris, Serge E. Hallyn,
keyrings, linux-security-module, linux-kernel
In-Reply-To: <20251112172620.4254-2-thorsten.blum@linux.dev>
On Wed, Nov 12, 2025 at 06:26:21PM +0100, Thorsten Blum wrote:
> Use strscpy() to copy strings into the fixed-size buffer 'xbuf' instead
> of hardcoding the number of bytes to copy. This improves maintainability
I don't consider maintainaibility as a stimulus of applying change given
that as a word it means me absolutely nothing.
> and ensures the buffer is always NUL-terminated.
>
> Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
> ---
> security/keys/proc.c | 5 +++--
> 1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/security/keys/proc.c b/security/keys/proc.c
> index 4f4e2c1824f1..1d380766f45d 100644
> --- a/security/keys/proc.c
> +++ b/security/keys/proc.c
> @@ -10,6 +10,7 @@
> #include <linux/fs.h>
> #include <linux/proc_fs.h>
> #include <linux/seq_file.h>
> +#include <linux/string.h>
> #include <asm/errno.h>
> #include "internal.h"
>
> @@ -199,9 +200,9 @@ static int proc_keys_show(struct seq_file *m, void *v)
> /* come up with a suitable timeout value */
> expiry = READ_ONCE(key->expiry);
> if (expiry == TIME64_MAX) {
> - memcpy(xbuf, "perm", 5);
> + strscpy(xbuf, "perm");
> } else if (now >= expiry) {
> - memcpy(xbuf, "expd", 5);
> + strscpy(xbuf, "expd");
> } else {
> timo = expiry - now;
>
> --
> 2.51.0
>
BR, Jarkko
^ permalink raw reply
* Re: [PATCH] KEYS: Remove the ad-hoc compilation flag CAAM_DEBUG
From: Jarkko Sakkinen @ 2025-11-19 2:25 UTC (permalink / raw)
To: Ye Bin
Cc: a.fatoum, kernel, James.Bottomley, zohar, dhowells, paul, jmorris,
serge, linux-integrity, keyrings, linux-security-module, yebin10
In-Reply-To: <20251028132254.841715-1-yebin@huaweicloud.com>
On Tue, Oct 28, 2025 at 09:22:54PM +0800, Ye Bin wrote:
> From: Ye Bin <yebin10@huawei.com>
>
> Fix the broken design based on Jarkko Sakkinen's suggestions as follows:
>
> 1. Remove the ad-hoc compilation flag (i.e., CAAM_DEBUG).
> 2. Substitute pr_info calls with pr_debug calls.
>
> Closes: https://patchwork.kernel.org/project/linux-integrity/patch/20251024061153.61470-1-yebin@huaweicloud.com/
> Signed-off-by: Ye Bin <yebin10@huawei.com>
$ git am -3 20251028_yebin_keys_remove_the_ad_hoc_compilation_flag_caam_debug.mbx
Applying: KEYS: Remove the ad-hoc compilation flag CAAM_DEBUG
error: sha1 information is lacking or useless (security/keys/trusted-keys/trusted_caam.c).
error: could not build fake ancestor
Patch failed at 0001 KEYS: Remove the ad-hoc compilation flag CAAM_DEBUG
hint: Use 'git am --show-current-patch=diff' to see the failed patch
hint: When you have resolved this problem, run "git am --continue".
hint: If you prefer to skip this patch, run "git am --skip" instead.
hint: To restore the original branch and stop patching, run "git am --abort".
hint: Disable this message with "git config set advice.mergeConflict false"
Hmm.. Could you send me a new revision rebased on top of my tree?
BR, Jarkko
^ permalink raw reply
* Re: [PATCH] Clarify the rootid_owns_currentns
From: Paul Moore @ 2025-11-19 0:29 UTC (permalink / raw)
To: Serge E. Hallyn
Cc: lkml, linux-security-module, Ryan Foster, Christian Brauner
In-Reply-To: <aR0JrOvDxDKZPELd@mail.hallyn.com>
On Tue, Nov 18, 2025 at 7:05 PM Serge E. Hallyn <serge@hallyn.com> wrote:
> On Tue, Nov 18, 2025 at 10:47:06AM -0500, Paul Moore wrote:
> > On Tue, Nov 18, 2025 at 9:16 AM Serge E. Hallyn <serge@hallyn.com> wrote:
> > > On Fri, Nov 14, 2025 at 03:33:19PM -0600, Serge E. Hallyn wrote:
> > > > Split most of the rootid_owns_currentns() functionality
> > > > into a more generic rootid_owns_ns() function which
> > > > will be easier to write tests for.
> > > >
> > > > Rename the functions and variables to make clear that
> > > > the ids being tested could be any uid.
> > > >
> > > > Signed-off-by: Serge Hallyn <serge@hallyn.com>
> > > > CC: Ryan Foster <foster.ryan.r@gmail.com>
> > > > CC: Christian Brauner <brauner@kernel.org>
> > >
> > > Paul, Christian, let me know if you have any objections, else I will
> > > queue this up in caps-next.
> >
> > Seems reasonable to me, but it would be good to fix the parameter doc
> > bug that the kernel test robot identified. I suspect it is just the
> > extra vertical comment space between the top one line summary and the
> > parameter list.
>
> Actually I think it was probably the use of - instead of : after the
> parameter name, but I went ahead and changed both, thanks.
Ah, yeah, at least one of those was it I'm sure.
> Pushed the below patch for linux-next.
Thanks.
--
paul-moore.com
^ permalink raw reply
* [PATCH] lsm: use unrcu_pointer() for current->cred in security_init()
From: Paul Moore @ 2025-11-19 0:28 UTC (permalink / raw)
To: linux-security-module
We need to directly allocate the cred's LSM state for the initial task
when we initialize the LSM framework. Unfortunately, this results in a
RCU related type mismatch, use the unrcu_pointer() macro to handle this
a bit more elegantly.
The explicit type casting still remains as we need to work around the
constification of current->cred in this particular case.
Signed-off-by: Paul Moore <paul@paul-moore.com>
---
security/lsm_init.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/security/lsm_init.c b/security/lsm_init.c
index 6bb67d41ce52..4dec9199e4c2 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -467,7 +467,8 @@ int __init security_init(void)
blob_sizes.lbs_inode, 0,
SLAB_PANIC, NULL);
- if (lsm_cred_alloc((struct cred __rcu *)current->cred, GFP_KERNEL))
+ if (lsm_cred_alloc(unrcu_pointer((struct cred __rcu *)current->cred),
+ GFP_KERNEL))
panic("early LSM cred alloc failed\n");
if (lsm_task_alloc(current))
panic("early LSM task alloc failed\n");
--
2.52.0
^ permalink raw reply related
* Re: [PATCH] Clarify the rootid_owns_currentns
From: Serge E. Hallyn @ 2025-11-19 0:05 UTC (permalink / raw)
To: Paul Moore
Cc: Serge E. Hallyn, lkml, linux-security-module, Ryan Foster,
Christian Brauner
In-Reply-To: <CAHC9VhQu7gSVO-QZFE_iaCB0qBqB3surdHQo4Vg71zc890uEhA@mail.gmail.com>
On Tue, Nov 18, 2025 at 10:47:06AM -0500, Paul Moore wrote:
> On Tue, Nov 18, 2025 at 9:16 AM Serge E. Hallyn <serge@hallyn.com> wrote:
> > On Fri, Nov 14, 2025 at 03:33:19PM -0600, Serge E. Hallyn wrote:
> > > Split most of the rootid_owns_currentns() functionality
> > > into a more generic rootid_owns_ns() function which
> > > will be easier to write tests for.
> > >
> > > Rename the functions and variables to make clear that
> > > the ids being tested could be any uid.
> > >
> > > Signed-off-by: Serge Hallyn <serge@hallyn.com>
> > > CC: Ryan Foster <foster.ryan.r@gmail.com>
> > > CC: Christian Brauner <brauner@kernel.org>
> >
> > Paul, Christian, let me know if you have any objections, else I will
> > queue this up in caps-next.
>
> Seems reasonable to me, but it would be good to fix the parameter doc
> bug that the kernel test robot identified. I suspect it is just the
> extra vertical comment space between the top one line summary and the
> parameter list.
Actually I think it was probably the use of - instead of : after the
parameter name, but I went ahead and changed both, thanks.
Pushed the below patch for linux-next.
Subject: [PATCH 1/1] Clarify the rootid_owns_currentns
Split most of the rootid_owns_currentns() functionality
into a more generic rootid_owns_ns() function which
will be easier to write tests for.
Rename the functions and variables to make clear that
the ids being tested could be any uid.
Signed-off-by: Serge Hallyn <serge@hallyn.com>
CC: Ryan Foster <foster.ryan.r@gmail.com>
CC: Christian Brauner <brauner@kernel.org>
---
v2: change the function parameter documentation to mollify the bot.
---
security/commoncap.c | 34 ++++++++++++++++++++++------------
1 file changed, 22 insertions(+), 12 deletions(-)
diff --git a/security/commoncap.c b/security/commoncap.c
index 6bd4adeb4795..496e054c5d37 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -358,17 +358,17 @@ int cap_inode_killpriv(struct mnt_idmap *idmap, struct dentry *dentry)
return error;
}
-static bool rootid_owns_currentns(vfsuid_t rootvfsuid)
+/**
+ * kuid_root_in_ns - check whether the given kuid is root in the given ns
+ * @kuid: the kuid to be tested
+ * @ns: the user namespace to test against
+ *
+ * Returns true if @kuid represents the root user in @ns, false otherwise.
+ */
+static bool kuid_root_in_ns(kuid_t kuid, struct user_namespace *ns)
{
- struct user_namespace *ns;
- kuid_t kroot;
-
- if (!vfsuid_valid(rootvfsuid))
- return false;
-
- kroot = vfsuid_into_kuid(rootvfsuid);
- for (ns = current_user_ns();; ns = ns->parent) {
- if (from_kuid(ns, kroot) == 0)
+ for (;; ns = ns->parent) {
+ if (from_kuid(ns, kuid) == 0)
return true;
if (ns == &init_user_ns)
break;
@@ -377,6 +377,16 @@ static bool rootid_owns_currentns(vfsuid_t rootvfsuid)
return false;
}
+static bool vfsuid_root_in_currentns(vfsuid_t vfsuid)
+{
+ kuid_t kuid;
+
+ if (!vfsuid_valid(vfsuid))
+ return false;
+ kuid = vfsuid_into_kuid(vfsuid);
+ return kuid_root_in_ns(kuid, current_user_ns());
+}
+
static __u32 sansflags(__u32 m)
{
return m & ~VFS_CAP_FLAGS_EFFECTIVE;
@@ -481,7 +491,7 @@ int cap_inode_getsecurity(struct mnt_idmap *idmap,
goto out_free;
}
- if (!rootid_owns_currentns(vfsroot)) {
+ if (!vfsuid_root_in_currentns(vfsroot)) {
size = -EOVERFLOW;
goto out_free;
}
@@ -722,7 +732,7 @@ int get_vfs_caps_from_disk(struct mnt_idmap *idmap,
/* Limit the caps to the mounter of the filesystem
* or the more limited uid specified in the xattr.
*/
- if (!rootid_owns_currentns(rootvfsuid))
+ if (!vfsuid_root_in_currentns(rootvfsuid))
return -ENODATA;
cpu_caps->permitted.val = le32_to_cpu(caps->data[0].permitted);
--
2.34.1
^ permalink raw reply related
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