* Re: [PATCH -next] ima: Handle error code returned by ima_filter_rule_match()
From: Roberto Sassu @ 2025-11-20 9:17 UTC (permalink / raw)
To: Zhao Yipeng, zohar, roberto.sassu, dmitry.kasatkin, eric.snowberg
Cc: lujialin4, linux-integrity, linux-security-module, linux-kernel
In-Reply-To: <20251120071805.1604864-1-zhaoyipeng5@huawei.com>
On Thu, 2025-11-20 at 15:18 +0800, Zhao Yipeng wrote:
> In ima_match_rules(), if ima_filter_rule_match() returns -ENOENT due to
> the rule being NULL, the function incorrectly skips the 'if (!rc)' check
> and sets 'result = true'. The LSM rule is considered a match, causing
> extra files to be measured by IMA.
>
> This issue can be reproduced in the following scenario:
> After unloading the SELinux policy module via 'semodule -d', if an IMA
> measurement is triggered before ima_lsm_rules is updated,
> in ima_match_rules(), the first call to ima_filter_rule_match() returns
> -ESTALE. This causes the code to enter the 'if (rc == -ESTALE &&
> !rule_reinitialized)' block, perform ima_lsm_copy_rule() and retry. In
> ima_lsm_copy_rule(), since the SELinux module has been removed, the rule
> becomes NULL, and the second call to ima_filter_rule_match() returns
> -ENOENT. This bypasses the 'if (!rc)' check and results in a false match.
>
> Call trace:
> selinux_audit_rule_match+0x310/0x3b8
> security_audit_rule_match+0x60/0xa0
> ima_match_rules+0x2e4/0x4a0
> ima_match_policy+0x9c/0x1e8
> ima_get_action+0x48/0x60
> process_measurement+0xf8/0xa98
> ima_bprm_check+0x98/0xd8
> security_bprm_check+0x5c/0x78
> search_binary_handler+0x6c/0x318
> exec_binprm+0x58/0x1b8
> bprm_execve+0xb8/0x130
> do_execveat_common.isra.0+0x1a8/0x258
> __arm64_sys_execve+0x48/0x68
> invoke_syscall+0x50/0x128
> el0_svc_common.constprop.0+0xc8/0xf0
> do_el0_svc+0x24/0x38
> el0_svc+0x44/0x200
> el0t_64_sync_handler+0x100/0x130
> el0t_64_sync+0x3c8/0x3d0
>
> Fix this by changing 'if (!rc)' to 'if (rc <= 0)' to ensure that error
> codes like -ENOENT do not bypass the check and accidentally result in a
> successful match.
Thanks, it makes sense.
Reviewed-by: Roberto Sassu <roberto.sassu@huawei.com>
Roberto
> Fixes: 4af4662fa4a9d ("integrity: IMA policy")
> Signed-off-by: Zhao Yipeng <zhaoyipeng5@huawei.com>
> ---
> security/integrity/ima/ima_policy.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
> index 128fab897930..db6d55af5a80 100644
> --- a/security/integrity/ima/ima_policy.c
> +++ b/security/integrity/ima/ima_policy.c
> @@ -674,7 +674,7 @@ static bool ima_match_rules(struct ima_rule_entry *rule,
> goto retry;
> }
> }
> - if (!rc) {
> + if (rc <= 0) {
> result = false;
> goto out;
> }
^ permalink raw reply
* Re: [PATCH 00/44] Change a lot of min_t() that might mask high bits
From: Lorenzo Stoakes @ 2025-11-20 9:38 UTC (permalink / raw)
To: david.laight.linux
Cc: linux-kernel, Alan Stern, Alexander Viro, Alexei Starovoitov,
Andi Shyti, Andreas Dilger, Andrew Lunn, Andrew Morton,
Andrii Nakryiko, Andy Shevchenko, Ard Biesheuvel,
Arnaldo Carvalho de Melo, Bjorn Helgaas, Borislav Petkov,
Christian Brauner, Christian König, Christoph Hellwig,
Daniel Borkmann, Dan Williams, Dave Hansen, Dave Jiang,
David Ahern, David Hildenbrand, Davidlohr Bueso, David S. Miller,
Dennis Zhou, Eric Dumazet, Greg Kroah-Hartman, Herbert Xu,
Ingo Molnar, Jakub Kicinski, Jakub Sitnicki, James E.J. Bottomley,
Jarkko Sakkinen, Jason A. Donenfeld, Jens Axboe, Jiri Slaby,
Johannes Weiner, John Allen, Jonathan Cameron, Juergen Gross,
Kees Cook, KP Singh, Linus Walleij, Martin K. Petersen,
Matthew Wilcox (Oracle), Mika Westerberg, Mike Rapoport,
Miklos Szeredi, Namhyung Kim, Neal Cardwell, nic_swsd,
OGAWA Hirofumi, Olivia Mackall, Paolo Abeni, Paolo Bonzini,
Peter Huewe, Peter Zijlstra, Rafael J. Wysocki,
Sean Christopherson, Srinivas Kandagatla, Stefano Stabellini,
Steven Rostedt, Tejun Heo, Theodore Ts'o, Thomas Gleixner,
Tom Lendacky, Willem de Bruijn, x86, Yury Norov, amd-gfx, bpf,
cgroups, dri-devel, io-uring, kvm, linux-acpi, linux-block,
linux-crypto, linux-cxl, linux-efi, linux-ext4, linux-fsdevel,
linux-gpio, linux-i2c, linux-integrity, linux-mm, linux-nvme,
linux-pci, linux-perf-users, linux-scsi, linux-serial,
linux-trace-kernel, linux-usb, mptcp, netdev, usb-storage
In-Reply-To: <20251119224140.8616-1-david.laight.linux@gmail.com>
On Wed, Nov 19, 2025 at 10:40:56PM +0000, david.laight.linux@gmail.com wrote:
> From: David Laight <david.laight.linux@gmail.com>
>
> It in not uncommon for code to use min_t(uint, a, b) when one of a or b
> is 64bit and can have a value that is larger than 2^32;
> This is particularly prevelant with:
> uint_var = min_t(uint, uint_var, uint64_expression);
>
> Casts to u8 and u16 are very likely to discard significant bits.
>
> These can be detected at compile time by changing min_t(), for example:
> #define CHECK_SIZE(fn, type, val) \
> BUILD_BUG_ON_MSG(sizeof (val) > sizeof (type) && \
> !statically_true(((val) >> 8 * (sizeof (type) - 1)) < 256), \
> fn "() significant bits of '" #val "' may be discarded")
>
> #define min_t(type, x, y) ({ \
> CHECK_SIZE("min_t", type, x); \
> CHECK_SIZE("min_t", type, y); \
> __cmp_once(min, type, x, y); })
>
> (and similar changes to max_t() and clamp_t().)
Have we made sure that the introduction of these don't cause a combinatorial
explosion like previous min()/max() changes did?
>
> This shows up some real bugs, some unlikely bugs and some false positives.
> In most cases both arguments are unsigned type (just different ones)
> and min_t() can just be replaced by min().
>
> The patches are all independant and are most of the ones needed to
> get the x86-64 kernel I build to compile.
> I've not tried building an allyesconfig or allmodconfig kernel.
Well I have a beefy box at my disposal so tried thiese for you :)
Both allyesconfig & allmodconfig works fine for x86-64 (I tried both for good
measure)
> I've also not included the patch to minmax.h itself.
>
> I've tried to put the patches that actually fix things first.
> The last one is 0009.
>
> I gave up on fixing sched/fair.c - it is too broken for a single patch!
> The patch for net/ipv4/tcp.c is also absent because do_tcp_getsockopt()
> needs multiple/larger changes to make it 'sane'.
I guess this isn't broken per se there just retain min_t()/max_t() right?
>
> I've had to trim the 124 maintainers/lists that get_maintainer.pl finds
> from 124 to under 100 to be able to send the cover letter.
> The individual patches only go to the addresses found for the associated files.
> That reduces the number of emails to a less unsane number.
>
> David Laight (44):
> x86/asm/bitops: Change the return type of variable__ffs() to unsigned
> int
> ext4: Fix saturation of 64bit inode times for old filesystems
> perf: Fix branch stack callchain limit
> io_uring/net: Change some dubious min_t()
> ipc/msg: Fix saturation of percpu counts in msgctl_info()
> bpf: Verifier, remove some unusual uses of min_t() and max_t()
> net/core/flow_dissector: Fix cap of __skb_flow_dissect() return value.
> net: ethtool: Use min3() instead of nested min_t(u16,...)
> ipv6: __ip6_append_data() don't abuse max_t() casts
> x86/crypto: ctr_crypt() use min() instead of min_t()
> arch/x96/kvm: use min() instead of min_t()
> block: use min() instead of min_t()
> drivers/acpi: use min() instead of min_t()
> drivers/char/hw_random: use min3() instead of nested min_t()
> drivers/char/tpm: use min() instead of min_t()
> drivers/crypto/ccp: use min() instead of min_t()
> drivers/cxl: use min() instead of min_t()
> drivers/gpio: use min() instead of min_t()
> drivers/gpu/drm/amd: use min() instead of min_t()
> drivers/i2c/busses: use min() instead of min_t()
> drivers/net/ethernet/realtek: use min() instead of min_t()
> drivers/nvme: use min() instead of min_t()
> arch/x86/mm: use min() instead of min_t()
> drivers/nvmem: use min() instead of min_t()
> drivers/pci: use min() instead of min_t()
> drivers/scsi: use min() instead of min_t()
> drivers/tty/vt: use umin() instead of min_t(u16, ...) for row/col
> limits
> drivers/usb/storage: use min() instead of min_t()
> drivers/xen: use min() instead of min_t()
> fs: use min() or umin() instead of min_t()
> block: bvec.h: use min() instead of min_t()
> nodemask: use min() instead of min_t()
> ipc: use min() instead of min_t()
> bpf: use min() instead of min_t()
> bpf_trace: use min() instead of min_t()
> lib/bucket_locks: use min() instead of min_t()
> lib/crypto/mpi: use min() instead of min_t()
> lib/dynamic_queue_limits: use max() instead of max_t()
> mm: use min() instead of min_t()
> net: Don't pass bitfields to max_t()
> net/core: Change loop conditions so min() can be used
> net: use min() instead of min_t()
> net/netlink: Use umin() to avoid min_t(int, ...) discarding high bits
> net/mptcp: Change some dubious min_t(int, ...) to min()
>
> arch/x86/crypto/aesni-intel_glue.c | 3 +-
> arch/x86/include/asm/bitops.h | 18 +++++-------
> arch/x86/kvm/emulate.c | 3 +-
> arch/x86/kvm/lapic.c | 2 +-
> arch/x86/kvm/mmu/mmu.c | 2 +-
> arch/x86/mm/pat/set_memory.c | 12 ++++----
> block/blk-iocost.c | 6 ++--
> block/blk-settings.c | 2 +-
> block/partitions/efi.c | 3 +-
> drivers/acpi/property.c | 2 +-
> drivers/char/hw_random/core.c | 2 +-
> drivers/char/tpm/tpm1-cmd.c | 2 +-
> drivers/char/tpm/tpm_tis_core.c | 4 +--
> drivers/crypto/ccp/ccp-dev.c | 2 +-
> drivers/cxl/core/mbox.c | 2 +-
> drivers/gpio/gpiolib-acpi-core.c | 2 +-
> .../gpu/drm/amd/amdgpu/amdgpu_doorbell_mgr.c | 4 +--
> drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 2 +-
> .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 +-
> drivers/i2c/busses/i2c-designware-master.c | 2 +-
> drivers/net/ethernet/realtek/r8169_main.c | 3 +-
> drivers/nvme/host/pci.c | 3 +-
> drivers/nvme/host/zns.c | 3 +-
> drivers/nvmem/core.c | 2 +-
> drivers/pci/probe.c | 3 +-
> drivers/scsi/hosts.c | 2 +-
> drivers/tty/vt/selection.c | 9 +++---
> drivers/usb/storage/protocol.c | 3 +-
> drivers/xen/grant-table.c | 2 +-
> fs/buffer.c | 2 +-
> fs/exec.c | 2 +-
> fs/ext4/ext4.h | 2 +-
> fs/ext4/mballoc.c | 3 +-
> fs/ext4/resize.c | 2 +-
> fs/ext4/super.c | 2 +-
> fs/fat/dir.c | 4 +--
> fs/fat/file.c | 3 +-
> fs/fuse/dev.c | 2 +-
> fs/fuse/file.c | 8 ++---
> fs/splice.c | 2 +-
> include/linux/bvec.h | 3 +-
> include/linux/nodemask.h | 9 +++---
> include/linux/perf_event.h | 2 +-
> include/net/tcp_ecn.h | 5 ++--
> io_uring/net.c | 6 ++--
> ipc/mqueue.c | 4 +--
> ipc/msg.c | 6 ++--
> kernel/bpf/core.c | 4 +--
> kernel/bpf/log.c | 2 +-
> kernel/bpf/verifier.c | 29 +++++++------------
> kernel/trace/bpf_trace.c | 2 +-
> lib/bucket_locks.c | 2 +-
> lib/crypto/mpi/mpicoder.c | 2 +-
> lib/dynamic_queue_limits.c | 2 +-
> mm/gup.c | 4 +--
> mm/memblock.c | 2 +-
> mm/memory.c | 2 +-
> mm/percpu.c | 2 +-
> mm/truncate.c | 3 +-
> mm/vmscan.c | 2 +-
> net/core/datagram.c | 6 ++--
> net/core/flow_dissector.c | 7 ++---
> net/core/net-sysfs.c | 3 +-
> net/core/skmsg.c | 4 +--
> net/ethtool/cmis_cdb.c | 7 ++---
> net/ipv4/fib_trie.c | 2 +-
> net/ipv4/tcp_input.c | 4 +--
> net/ipv4/tcp_output.c | 5 ++--
> net/ipv4/tcp_timer.c | 4 +--
> net/ipv6/addrconf.c | 8 ++---
> net/ipv6/ip6_output.c | 7 +++--
> net/ipv6/ndisc.c | 5 ++--
> net/mptcp/protocol.c | 8 ++---
> net/netlink/genetlink.c | 9 +++---
> net/packet/af_packet.c | 2 +-
> net/unix/af_unix.c | 4 +--
> 76 files changed, 141 insertions(+), 176 deletions(-)
>
> --
> 2.39.5
>
^ permalink raw reply
* Re: [RFC v1 0/1] Implement IMA Event Log Trimming
From: Roberto Sassu @ 2025-11-20 11:02 UTC (permalink / raw)
To: Anirudh Venkataramanan, linux-integrity
Cc: Mimi Zohar, Roberto Sassu, Dmitry Kasatkin, Eric Snowberg,
Paul Moore, James Morris, Serge E . Hallyn, linux-security-module,
Steven Chen, Gregory Lumen, Lakshmi Ramasubramanian,
Sush Shringarputale
In-Reply-To: <20251119213359.39397-1-anirudhve@linux.microsoft.com>
On Wed, 2025-11-19 at 13:33 -0800, Anirudh Venkataramanan wrote:
> ==========================================================================
> > 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.
Hi Anirudh
I will rephrase this paragraph, to be sure that I understood it
correctly.
You are proposing a method to trim the measurement list and, at the
same time, to keep the measurement list verifiable after trimming. The
way you would like to achieve that is to keep the verification state in
the kernel in the form of PCR values.
Those values mean what verifiers have already verified. Thus, for the
next verification attempt, verifiers take the current PCR values as
starting values, replay the truncated IMA measurement list, and again
you match with the current PCR values and you trim until that point.
So the benefit of this proposal is that you keep the verification of
the IMA measurement list self-contained by using the last verification
state (PCR starting value) and the truncated IMA measurement list as
the inputs of your verification.
Let me reiterate on the trusted computing principles IMA relies on for
providing the evidence about a system's integrity.
Unless you are at the beginning of the measurement chain, where the
Root of Trust for Measurement (RTM) is trusted by assumption, the
measurements done by a component can be trusted because that component
was already measured by the previous component in the boot chain,
before it had any chance to corrupt the system.
In the context of IMA, IMA can be trusted to make new measurements
because it measures every file before those files could cause any harm
to the system. So, potentially IMA and the kernel can be corrupted by
any file.
What you are proposing would not work, because you are placing trust in
an input (the PCR starting value) that can be manipulated at any time
by a corrupted kernel, before you had the chance to detect such
corruption.
Let me describe a scenario where I could take advantage of such
weakness. After the first measurement list trim, I perform an attack on
the system such that it corrupts the kernel. IMA added a new entry in
the measurement list, which would reveal the attack.
But, since I have control of the kernel, I conveniently update the PCR
starting value to replay the new measurement entry, and remove the
measurement entry from the measurement list.
Now, from the perspective of the user space verifiers everything is
fine, the truncated IMA measurement list is clean, no attack, and the
current PCR values match by replaying the new PCR starting value with
the remaining of the IMA measurement list.
So, in my opinion the kernel should just offer the ability to trim the
measurement list, and a remote verifier should be responsible to verify
the measurement list, without relying on anything from the system being
evaluated.
Sure, the remote verifier can verify just the trimmed IMA measurement
list, but the remote verifier must solely rely on state information
maintained internally.
Roberto
> 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
>
^ permalink raw reply
* Re: (subset) [PATCH 00/44] Change a lot of min_t() that might mask high bits
From: Jens Axboe @ 2025-11-20 14:52 UTC (permalink / raw)
To: linux-kernel, david.laight.linux
Cc: Alan Stern, Alexander Viro, Alexei Starovoitov, Andi Shyti,
Andreas Dilger, Andrew Lunn, Andrew Morton, Andrii Nakryiko,
Andy Shevchenko, Ard Biesheuvel, Arnaldo Carvalho de Melo,
Bjorn Helgaas, Borislav Petkov, Christian Brauner,
Christian König, Christoph Hellwig, Daniel Borkmann,
Dan Williams, Dave Hansen, Dave Jiang, David Ahern,
Davidlohr Bueso, David S. Miller, Dennis Zhou, Eric Dumazet,
Greg Kroah-Hartman, Herbert Xu, Ingo Molnar, Jakub Kicinski,
Jakub Sitnicki, James E.J. Bottomley, Jarkko Sakkinen,
Jason A. Donenfeld, Jiri Slaby, Johannes Weiner, John Allen,
Jonathan Cameron, Juergen Gross, Kees Cook, KP Singh,
Linus Walleij, Martin K. Petersen, Matthew Wilcox (Oracle),
Mika Westerberg, Mike Rapoport, Miklos Szeredi, Namhyung Kim,
Neal Cardwell, nic_swsd, OGAWA Hirofumi, Olivia Mackall,
Paolo Abeni, Paolo Bonzini, Peter Huewe, Peter Zijlstra,
Rafael J. Wysocki, Sean Christopherson, Srinivas Kandagatla,
Stefano Stabellini, Steven Rostedt, Tejun Heo, Theodore Ts'o,
Thomas Gleixner, Tom Lendacky, Willem de Bruijn, x86, Yury Norov,
amd-gfx, bpf, cgroups, dri-devel, io-uring, kvm, linux-acpi,
linux-block, linux-crypto, linux-cxl, linux-efi, linux-ext4,
linux-fsdevel, linux-gpio, linux-i2c, linux-integrity, linux-mm,
linux-nvme, linux-pci, linux-perf-users, linux-scsi, linux-serial,
linux-trace-kernel, linux-usb, mptcp, netdev, usb-storage,
David Hildenbrand
In-Reply-To: <20251119224140.8616-1-david.laight.linux@gmail.com>
On Wed, 19 Nov 2025 22:40:56 +0000, david.laight.linux@gmail.com wrote:
> It in not uncommon for code to use min_t(uint, a, b) when one of a or b
> is 64bit and can have a value that is larger than 2^32;
> This is particularly prevelant with:
> uint_var = min_t(uint, uint_var, uint64_expression);
>
> Casts to u8 and u16 are very likely to discard significant bits.
>
> [...]
Applied, thanks!
[12/44] block: use min() instead of min_t()
commit: 9420e720ad192c53c8d2803c5a2313b2d586adbd
Best regards,
--
Jens Axboe
^ permalink raw reply
* Re: [Patch V1] ima: avoid duplicate policy rules insertions
From: Mimi Zohar @ 2025-11-20 15:39 UTC (permalink / raw)
To: Tahera Fahimi, roberto.sassu, dmitry.kasatkin, eric.snowberg,
paul, jmorris, serge, linux-integrity, linux-security-module,
linux-kernel, code
Cc: Lennart Poettering
In-Reply-To: <16c73b4e0761a1622770102d1d48982fe9ae86ac.camel@linux.ibm.com>
On Tue, 2025-11-11 at 06:40 -0500, Mimi Zohar wrote:
> [Cc'ing Lennart Poettering]
>
> On Thu, 2025-11-06 at 18:14 +0000, Tahera Fahimi wrote:
> > Prevent redundant IMA policy rules by checking for duplicates before insertion. This ensures that
> > rules are not re-added when userspace is restarted (using systemd-soft-reboot) without a full system
> > reboot. ima_rule_exists() detects duplicates in both temporary and active rule lists.
> >
> > Signed-off-by: Tahera Fahimi <taherafahimi@linux.microsoft.com>
>
> Sorry for the delay in responding ...
>
> Before trying to fix the "problem", let's try to understand it first. At least
> on my test system (-rc5), kexec is working as designed. On boot, systemd
> replaces the existing builtin IMA policy with a custom IMA policy. The arch
> specific policies are not affected, as they are persistent. On a soft reboot
> (kexec), the IMA custom policy is re-loaded as expected.
>
> To verify the above behavior, extend the IMA policy before the soft reboot.
> Notice after the soft reboot that the original custom IMA policy is loaded and
> not the extended IMA policy. Roberto, if there is a problem with this behavior,
> we'll discuss it independently of this proposed patch.
>
> The question is why are you seeing duplicate IMA policy rules? What is special
> about your environment?
I'm now able to reproduce what you're seeing by executing "systemctl soft-
reboot". After each soft-reboot the custom IMA policy rules are re-loaded and
appended to the existing IMA policy. As Roberto mentioned, there is no option
to replace the existing custom IMA policy rules with a new custom policy. We
might consider doing so in the future, but for now the onus for not re-loading
the custom IMA policy should not be on IMA, but on systemd.
Reading the same securityfs policy file used for loading the IMA policy will
return the current IMA policy. systemd could detect whether the existing IMA
policy contains the custom policy rules, before actually loading them. There's
no reason for adding this functionality in the kernel.
--
thanks,
Mimi
^ permalink raw reply
* Re: [RFC v1 0/1] Implement IMA Event Log Trimming
From: Mimi Zohar @ 2025-11-20 22:58 UTC (permalink / raw)
To: Anirudh Venkataramanan, linux-integrity
Cc: Roberto Sassu, Dmitry Kasatkin, Eric Snowberg, Paul Moore,
James Morris, Serge E . Hallyn, linux-security-module,
Steven Chen, Gregory Lumen, Lakshmi Ramasubramanian,
Sush Shringarputale
In-Reply-To: <20251119213359.39397-1-anirudhve@linux.microsoft.com>
On Wed, 2025-11-19 at 13:33 -0800, Anirudh Venkataramanan wrote:
>
>
> 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.
Depending on the IMA policy, the IMA measurement list may contain integrity
violations, such as "ToM/ToU" (Time of Measurement/Time of Use) or "open-
writer". Either the userspace supplied PCR values will not match any measurement
record or the PCR values will be "fixed" to match the well known violation hash
value extended into the TPM. Depending on how the userspace PCR values will
subsequently be used, saving the "fixed" PCR values could result in whitewashing
the integrity of the measurement list.
--
thanks,
Mimi
^ permalink raw reply
* [PATCH v2 1/4] shell: Add tst_sudo.c helper
From: Petr Vorel @ 2025-11-21 15:21 UTC (permalink / raw)
To: ltp
Cc: Petr Vorel, Mimi Zohar, linux-integrity, selinux, Cyril Hrubis,
Jan Stancek, Li Wang
In-Reply-To: <20251121152111.10419-1-pvorel@suse.cz>
It will be used in LTP IMA tests. Not only it removes external
dependency, but also fixes problem when 'nobody' user is not possible to
use due using /usr/sbin/nologin shell.
Suggested-by: Jan Stancek <jstancek@redhat.com>
Signed-off-by: Petr Vorel <pvorel@suse.cz>
---
New in v2, suggested by Jan Stancek.
https://lore.kernel.org/ltp/CAASaF6yjdrLLVnehESx1TjsrB_z48nmN_2i585GPfkG3Vvg15Q@mail.gmail.com/
doc/users/setup_tests.rst | 4 ++++
testcases/lib/.gitignore | 1 +
testcases/lib/Makefile | 2 +-
testcases/lib/tst_sudo.c | 50 +++++++++++++++++++++++++++++++++++++++
4 files changed, 56 insertions(+), 1 deletion(-)
create mode 100644 testcases/lib/tst_sudo.c
diff --git a/doc/users/setup_tests.rst b/doc/users/setup_tests.rst
index 38976f3b0a..9c49852830 100644
--- a/doc/users/setup_tests.rst
+++ b/doc/users/setup_tests.rst
@@ -71,6 +71,10 @@ users.
* - LTP_IMA_LOAD_POLICY
- Load IMA example policy, see :master:`testcases/kernel/security/integrity/ima/README.md`.
+ * - LTP_USR_UID, LTP_USR_GID
+ - Set UID and GID of ``nobody`` user for :doc:`../developers/api_shell_tests`,
+ see :master:`testcases/lib/tst_sudo.c`.
+
* - LTP_VIRT_OVERRIDE
- Overrides virtual machine detection in the test library. Setting it to
empty string, tells the library that system is not a virtual machine.
diff --git a/testcases/lib/.gitignore b/testcases/lib/.gitignore
index 385f3c3ca6..602abdee1f 100644
--- a/testcases/lib/.gitignore
+++ b/testcases/lib/.gitignore
@@ -25,3 +25,4 @@
/tst_timeout_kill
/tst_res_
/tst_run_shell
+/tst_sudo
diff --git a/testcases/lib/Makefile b/testcases/lib/Makefile
index b3a9181c11..9973090cfc 100644
--- a/testcases/lib/Makefile
+++ b/testcases/lib/Makefile
@@ -17,6 +17,6 @@ MAKE_TARGETS := tst_sleep tst_random tst_checkpoint tst_rod tst_kvcmp\
tst_get_median tst_hexdump tst_get_free_pids tst_timeout_kill\
tst_check_kconfigs tst_cgctl tst_fsfreeze tst_ns_create tst_ns_exec\
tst_ns_ifmove tst_lockdown_enabled tst_secureboot_enabled tst_res_\
- tst_run_shell
+ tst_run_shell tst_sudo
include $(top_srcdir)/include/mk/generic_trunk_target.mk
diff --git a/testcases/lib/tst_sudo.c b/testcases/lib/tst_sudo.c
new file mode 100644
index 0000000000..e8d5d8dd9d
--- /dev/null
+++ b/testcases/lib/tst_sudo.c
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2025 Petr Vorel <pvorel@suse.cz>
+ */
+
+#define LTP_USR_UID 65534
+#define LTP_USR_GID 65534
+
+#define TST_NO_DEFAULT_MAIN
+#include "tst_test.h"
+
+static void print_help(void)
+{
+ fprintf(stderr, "Usage: %s cmd [args] ...\n", __FILE__);
+ fprintf(stderr, "Usage: %s cmd [-h] print help\n\n", __FILE__);
+
+ fprintf(stderr, "Environment Variables\n");
+ fprintf(stderr, "LTP_USR_UID: UID of 'nobody' user, defaults %d\n",
+ LTP_USR_UID);
+ fprintf(stderr, "LTP_USR_GID: GID of 'nobody' user, defaults %d\n",
+ LTP_USR_GID);
+}
+
+int main(int argc, char *argv[])
+{
+ if (argc < 2 || !strcmp(argv[1], "-h")) {
+ print_help();
+ return 1;
+ }
+
+ unsigned uid = LTP_USR_UID, gid = LTP_USR_GID;
+
+ char *uid_env = getenv(TST_TO_STR_(LTP_USR_UID));
+ char *gid_env = getenv(TST_TO_STR_(LTP_USR_GID));
+
+ if (uid_env)
+ uid = SAFE_STRTOL(uid_env, 1, INT_MAX);
+
+ if (gid_env)
+ gid = SAFE_STRTOL(gid_env, 1, INT_MAX);
+
+ tst_res(TINFO, "UID: %d, GID: %d", uid, gid);
+ SAFE_SETGROUPS(0, NULL);
+ SAFE_SETRESGID(gid, gid, gid);
+ SAFE_SETRESUID(uid, uid, uid);
+
+ SAFE_CMD((const char * const *)&argv[1], NULL, NULL);
+
+ return 0;
+}
--
2.51.0
^ permalink raw reply related
* [PATCH v2 0/4] tst_sudo.c, ima_{conditionals,measurements}.sh enhancements
From: Petr Vorel @ 2025-11-21 15:21 UTC (permalink / raw)
To: ltp
Cc: Petr Vorel, Mimi Zohar, linux-integrity, selinux, Cyril Hrubis,
Jan Stancek, Li Wang
Hi,
Changes v1->v2:
Main change is implementing LTP binary tst_sudo.c as suggested by Jan
Stancek [1] instead of creating new user.
Links to v1:
https://lore.kernel.org/ltp/20251002083701.315334-1-pvorel@suse.cz/
https://patchwork.ozlabs.org/project/ltp/list/?series=476004&state=*
[1] https://lore.kernel.org/ltp/CAASaF6yjdrLLVnehESx1TjsrB_z48nmN_2i585GPfkG3Vvg15Q@mail.gmail.com/
Petr Vorel (4):
shell: Add tst_sudo.c helper
tst_test.sh: Add TST_USR_{G,U}ID variables
ima_{conditionals,measurements}.sh: Use tst_sudo
ima_conditionals.sh: Split test by request
doc/users/setup_tests.rst | 4 +
runtest/ima | 5 +-
.../integrity/ima/tests/ima_conditionals.sh | 78 +++++++++++--------
.../integrity/ima/tests/ima_measurements.sh | 11 +--
testcases/lib/.gitignore | 1 +
testcases/lib/Makefile | 2 +-
testcases/lib/tst_sudo.c | 51 ++++++++++++
testcases/lib/tst_test.sh | 6 +-
8 files changed, 115 insertions(+), 43 deletions(-)
create mode 100644 testcases/lib/tst_sudo.c
--
2.51.0
^ permalink raw reply
* [PATCH v2 2/4] tst_test.sh: Add TST_USR_{G,U}ID variables
From: Petr Vorel @ 2025-11-21 15:21 UTC (permalink / raw)
To: ltp
Cc: Petr Vorel, Mimi Zohar, linux-integrity, selinux, Cyril Hrubis,
Jan Stancek, Li Wang
In-Reply-To: <20251121152111.10419-1-pvorel@suse.cz>
Add TST_USR_{G,U}ID variables with the default values from tst_sudo.c.
These can be used as a default values for tests which use tst_sudo and
need to know UID/GID for other commands.
It will be used in LTP IMA tests.
Signed-off-by: Petr Vorel <pvorel@suse.cz>
---
New in v2.
testcases/lib/tst_sudo.c | 1 +
testcases/lib/tst_test.sh | 6 +++++-
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/testcases/lib/tst_sudo.c b/testcases/lib/tst_sudo.c
index e8d5d8dd9d..e937828273 100644
--- a/testcases/lib/tst_sudo.c
+++ b/testcases/lib/tst_sudo.c
@@ -3,6 +3,7 @@
* Copyright (c) 2025 Petr Vorel <pvorel@suse.cz>
*/
+/* update also tst_test.sh */
#define LTP_USR_UID 65534
#define LTP_USR_GID 65534
diff --git a/testcases/lib/tst_test.sh b/testcases/lib/tst_test.sh
index 4be10a4f94..49f282d7c8 100644
--- a/testcases/lib/tst_test.sh
+++ b/testcases/lib/tst_test.sh
@@ -17,6 +17,10 @@ export TST_ITERATIONS=1
export TST_TMPDIR_RHOST=0
export TST_LIB_LOADED=1
+# see testcases/lib/tst_sudo.c
+export TST_USR_UID="${LTP_USR_UID:-65534}"
+export TST_USR_GID="${LTP_USR_GID:-65534}"
+
. tst_ansi_color.sh
. tst_security.sh
@@ -689,7 +693,7 @@ tst_run()
CHECKPOINT_WAKE2|CHECKPOINT_WAKE_AND_WAIT);;
DEV_EXTRA_OPTS|DEV_FS_OPTS|FORMAT_DEVICE|MOUNT_DEVICE);;
SKIP_FILESYSTEMS|SKIP_IN_LOCKDOWN|SKIP_IN_SECUREBOOT);;
- DEVICE_SIZE);;
+ DEVICE_SIZE|USR_UID|USR_GID);;
*) tst_res TWARN "Reserved variable TST_$_tst_i used!";;
esac
done
--
2.51.0
^ permalink raw reply related
* [PATCH v2 3/4] ima_{conditionals,measurements}.sh: Use tst_sudo
From: Petr Vorel @ 2025-11-21 15:21 UTC (permalink / raw)
To: ltp
Cc: Petr Vorel, Mimi Zohar, linux-integrity, selinux, Cyril Hrubis,
Jan Stancek, Li Wang
In-Reply-To: <20251121152111.10419-1-pvorel@suse.cz>
Replace 'sudo' and 'sg' with 'tst_sudo'.
This not only removes 'sudo' external dependency, but it s required
because new releases of many distros (e.g. Debian, openSUSE Tumbleweed,
SLES, ...) switched shell for 'nobody' user from /bin/bash (or /bin/sh)
to /usr/sbin/nologin. That effectively disables using 'sudo', 'su', 'sg':
ima_conditionals 1 TINFO: verify measuring user files when requested via uid
sudo: Account expired or PAM config lacks an "account" section for sudo, contact your system administrator
sudo: a password is required
Signed-off-by: Petr Vorel <pvorel@suse.cz>
---
Changes v1->v2:
* Use tst_sudo instead of sudo and sg.
.../integrity/ima/tests/ima_conditionals.sh | 13 ++++++-------
.../integrity/ima/tests/ima_measurements.sh | 11 ++---------
2 files changed, 8 insertions(+), 16 deletions(-)
diff --git a/testcases/kernel/security/integrity/ima/tests/ima_conditionals.sh b/testcases/kernel/security/integrity/ima/tests/ima_conditionals.sh
index ba19176039..e290dcdaaa 100755
--- a/testcases/kernel/security/integrity/ima/tests/ima_conditionals.sh
+++ b/testcases/kernel/security/integrity/ima/tests/ima_conditionals.sh
@@ -9,7 +9,7 @@
# gid and fgroup options test kernel commit 40224c41661b ("ima: add gid
# support") from v5.16.
-TST_NEEDS_CMDS="cat chgrp chown id sg sudo"
+TST_NEEDS_CMDS="cat chgrp chown"
TST_SETUP="setup"
TST_CNT=1
@@ -27,8 +27,8 @@ verify_measurement()
local test_file="$PWD/test.txt"
local cmd="cat $test_file > /dev/null"
- local value="$(id -u $user)"
- [ "$request" = 'gid' -o "$request" = 'fgroup' ] && value="$(id -g $user)"
+ local value="$TST_USR_UID"
+ [ "$request" = 'gid' -o "$request" = 'fgroup' ] && value="$TST_USR_GID"
# needs to be checked each run (not in setup)
require_policy_writable
@@ -41,15 +41,14 @@ verify_measurement()
case "$request" in
fgroup)
- chgrp $user $test_file
+ chgrp $TST_USR_GID $test_file
sh -c "$cmd"
;;
fowner)
- chown $user $test_file
+ chown $TST_USR_UID $test_file
sh -c "$cmd"
;;
- gid) sg $user "sh -c '$cmd'";;
- uid) sudo -n -u $user sh -c "$cmd";;
+ gid|uid) tst_sudo sh -c "$cmd";;
*) tst_brk TBROK "Invalid res type '$1'";;
esac
diff --git a/testcases/kernel/security/integrity/ima/tests/ima_measurements.sh b/testcases/kernel/security/integrity/ima/tests/ima_measurements.sh
index 60350f3926..30bfe3e629 100755
--- a/testcases/kernel/security/integrity/ima/tests/ima_measurements.sh
+++ b/testcases/kernel/security/integrity/ima/tests/ima_measurements.sh
@@ -68,30 +68,23 @@ test2()
test3()
{
- local user="nobody"
local dir="$PWD/user"
local file="$dir/test.txt"
local cmd="grep $file $ASCII_MEASUREMENTS"
# Default policy does not measure user files
tst_res TINFO "verify not measuring user files"
- tst_check_cmds sudo || return
if [ "$IMA_MISSING_POLICY_CONTENT" = 1 ]; then
tst_res TCONF "test requires specific policy, try load it with LTP_IMA_LOAD_POLICY=1"
return
fi
- if ! id $user >/dev/null 2>/dev/null; then
- tst_res TCONF "missing system user $user (wrong installation)"
- return
- fi
-
[ -d "$dir" ] || mkdir -m 0700 $dir
- chown $user $dir
+ chown $TST_USR_UID $dir
cd $dir
# need to read file to get updated $ASCII_MEASUREMENTS
- sudo -n -u $user sh -c "echo $(cat /proc/uptime) user file > $file; cat $file > /dev/null"
+ tst_sudo sh -c "echo $(cat /proc/uptime) user file > $file; cat $file > /dev/null"
cd ..
if ! tst_rod "$cmd" 2> /dev/null; then
--
2.51.0
^ permalink raw reply related
* [PATCH v2 4/4] ima_conditionals.sh: Split test by request
From: Petr Vorel @ 2025-11-21 15:21 UTC (permalink / raw)
To: ltp
Cc: Petr Vorel, Mimi Zohar, linux-integrity, selinux, Cyril Hrubis,
Jan Stancek, Li Wang
In-Reply-To: <20251121152111.10419-1-pvorel@suse.cz>
This helps to run all testcases on systems without CONFIG_IMA_WRITE_POLICY=y
(disabled by default in mainline, therefore disabled for some distros,
e.g. openSUSE Tumbleweed), if SUT reboots.
Signed-off-by: Petr Vorel <pvorel@suse.cz>
---
The same as in v1.
runtest/ima | 5 +-
.../integrity/ima/tests/ima_conditionals.sh | 67 ++++++++++++-------
2 files changed, 46 insertions(+), 26 deletions(-)
diff --git a/runtest/ima b/runtest/ima
index 01942eefa3..c8d0c6801e 100644
--- a/runtest/ima
+++ b/runtest/ima
@@ -6,5 +6,8 @@ ima_violations ima_violations.sh
ima_keys ima_keys.sh
ima_kexec ima_kexec.sh
ima_selinux ima_selinux.sh
-ima_conditionals ima_conditionals.sh
+ima_conditionals_uid ima_conditionals.sh -r uid
+ima_conditionals_fowner ima_conditionals.sh -r fowner
+ima_conditionals_gid ima_conditionals.sh -r gid
+ima_conditionals_fgroup ima_conditionals.sh -r fgroup
evm_overlay evm_overlay.sh
diff --git a/testcases/kernel/security/integrity/ima/tests/ima_conditionals.sh b/testcases/kernel/security/integrity/ima/tests/ima_conditionals.sh
index e290dcdaaa..8eed0b6a9d 100755
--- a/testcases/kernel/security/integrity/ima/tests/ima_conditionals.sh
+++ b/testcases/kernel/security/integrity/ima/tests/ima_conditionals.sh
@@ -11,35 +11,66 @@
TST_NEEDS_CMDS="cat chgrp chown"
TST_SETUP="setup"
-TST_CNT=1
+TST_OPTS="r:"
+TST_USAGE="usage"
+TST_PARSE_ARGS="parse_args"
+REQUEST="uid"
+
+parse_args()
+{
+ REQUEST="$2"
+}
+
+usage()
+{
+ cat << EOF
+usage: $0 [-r <uid|fowner|gid|fgroup>]
+
+OPTIONS
+-r Specify the request to be measured. One of:
+ uid, fowner, gid, fgroup
+ Default: uid
+EOF
+}
setup()
{
+ case "$REQUEST" in
+ fgroup|fowner|gid|uid)
+ tst_res TINFO "request '$REQUEST'"
+ ;;
+ *) tst_brk TBROK "Invalid -r '$REQUEST', use: -r <uid|fowner|gid|fgroup>";;
+ esac
+
if check_need_signed_policy; then
tst_brk TCONF "policy have to be signed"
fi
}
-verify_measurement()
+test()
{
+ # needs to be checked each run (not in setup)
+ require_policy_writable
+
local request="$1"
- local user="nobody"
local test_file="$PWD/test.txt"
local cmd="cat $test_file > /dev/null"
-
local value="$TST_USR_UID"
- [ "$request" = 'gid' -o "$request" = 'fgroup' ] && value="$TST_USR_GID"
- # needs to be checked each run (not in setup)
- require_policy_writable
+ if [ "$REQUEST" = 'gid' -o "$REQUEST" = 'fgroup' ]; then
+ if tst_kvcmp -lt 5.16; then
+ tst_brk TCONF "gid and fgroup options require kernel 5.16 or newer"
+ fi
+ value="$TST_USR_GID"
+ fi
ROD rm -f $test_file
- tst_res TINFO "verify measuring user files when requested via $request"
- ROD echo "measure $request=$value" \> $IMA_POLICY
- ROD echo "$(cat /proc/uptime) $request test" \> $test_file
+ tst_res TINFO "verify measuring user files when requested via $REQUEST"
+ ROD echo "measure $REQUEST=$value" \> $IMA_POLICY
+ ROD echo "$(cat /proc/uptime) $REQUEST test" \> $test_file
- case "$request" in
+ case "$REQUEST" in
fgroup)
chgrp $TST_USR_GID $test_file
sh -c "$cmd"
@@ -49,24 +80,10 @@ verify_measurement()
sh -c "$cmd"
;;
gid|uid) tst_sudo sh -c "$cmd";;
- *) tst_brk TBROK "Invalid res type '$1'";;
esac
ima_check $test_file
}
-test1()
-{
- verify_measurement uid
- verify_measurement fowner
-
- if tst_kvcmp -lt 5.16; then
- tst_brk TCONF "gid and fgroup options require kernel 5.16 or newer"
- fi
-
- verify_measurement gid
- verify_measurement fgroup
-}
-
. ima_setup.sh
tst_run
--
2.51.0
^ permalink raw reply related
* Re: [PATCH -next] ima: Handle error code returned by ima_filter_rule_match()
From: Mimi Zohar @ 2025-11-21 15:38 UTC (permalink / raw)
To: Zhao Yipeng, roberto.sassu, dmitry.kasatkin, eric.snowberg
Cc: lujialin4, linux-integrity, linux-security-module, linux-kernel
In-Reply-To: <20251120071805.1604864-1-zhaoyipeng5@huawei.com>
On Thu, 2025-11-20 at 15:18 +0800, Zhao Yipeng wrote:
> In ima_match_rules(), if ima_filter_rule_match() returns -ENOENT due to
> the rule being NULL, the function incorrectly skips the 'if (!rc)' check
> and sets 'result = true'. The LSM rule is considered a match, causing
> extra files to be measured by IMA.
>
> This issue can be reproduced in the following scenario:
> After unloading the SELinux policy module via 'semodule -d', if an IMA
> measurement is triggered before ima_lsm_rules is updated,
> in ima_match_rules(), the first call to ima_filter_rule_match() returns
> -ESTALE. This causes the code to enter the 'if (rc == -ESTALE &&
> !rule_reinitialized)' block, perform ima_lsm_copy_rule() and retry. In
> ima_lsm_copy_rule(), since the SELinux module has been removed, the rule
> becomes NULL, and the second call to ima_filter_rule_match() returns
> -ENOENT. This bypasses the 'if (!rc)' check and results in a false match.
>
> Call trace:
> selinux_audit_rule_match+0x310/0x3b8
> security_audit_rule_match+0x60/0xa0
> ima_match_rules+0x2e4/0x4a0
> ima_match_policy+0x9c/0x1e8
> ima_get_action+0x48/0x60
> process_measurement+0xf8/0xa98
> ima_bprm_check+0x98/0xd8
> security_bprm_check+0x5c/0x78
> search_binary_handler+0x6c/0x318
> exec_binprm+0x58/0x1b8
> bprm_execve+0xb8/0x130
> do_execveat_common.isra.0+0x1a8/0x258
> __arm64_sys_execve+0x48/0x68
> invoke_syscall+0x50/0x128
> el0_svc_common.constprop.0+0xc8/0xf0
> do_el0_svc+0x24/0x38
> el0_svc+0x44/0x200
> el0t_64_sync_handler+0x100/0x130
> el0t_64_sync+0x3c8/0x3d0
>
> Fix this by changing 'if (!rc)' to 'if (rc <= 0)' to ensure that error
> codes like -ENOENT do not bypass the check and accidentally result in a
> successful match.
>
> Fixes: 4af4662fa4a9d ("integrity: IMA policy")
> Signed-off-by: Zhao Yipeng <zhaoyipeng5@huawei.com>
Thank you. The patch is now queued in next-integrity.
Mimi
^ permalink raw reply
* Re: [RFC v1 0/1] Implement IMA Event Log Trimming
From: Anirudh Venkataramanan @ 2025-11-21 19:13 UTC (permalink / raw)
To: Roberto Sassu, linux-integrity
Cc: Mimi Zohar, Roberto Sassu, Dmitry Kasatkin, Eric Snowberg,
Paul Moore, James Morris, Serge E . Hallyn, linux-security-module,
Steven Chen, Gregory Lumen, Lakshmi Ramasubramanian,
Sush Shringarputale
In-Reply-To: <7722dff4e68ef5fb7f39bd732a8a77422bad5549.camel@huaweicloud.com>
On 11/20/2025 3:02 AM, Roberto Sassu wrote:
> On Wed, 2025-11-19 at 13:33 -0800, Anirudh Venkataramanan wrote:
>> ==========================================================================
>>> 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.
>
> Hi Anirudh
Hi Roberto,
Thanks for the feedback! Few questions below.
>
> I will rephrase this paragraph, to be sure that I understood it
> correctly.
>
> You are proposing a method to trim the measurement list and, at the
> same time, to keep the measurement list verifiable after trimming. The
> way you would like to achieve that is to keep the verification state in
> the kernel in the form of PCR values.
>
> Those values mean what verifiers have already verified. Thus, for the
> next verification attempt, verifiers take the current PCR values as
> starting values, replay the truncated IMA measurement list, and again
> you match with the current PCR values and you trim until that point.
>
> So the benefit of this proposal is that you keep the verification of
> the IMA measurement list self-contained by using the last verification
> state (PCR starting value) and the truncated IMA measurement list as
> the inputs of your verification.
Your understanding as described above is correct.
>
> Let me reiterate on the trusted computing principles IMA relies on for
> providing the evidence about a system's integrity.
>
> Unless you are at the beginning of the measurement chain, where the
> Root of Trust for Measurement (RTM) is trusted by assumption, the
> measurements done by a component can be trusted because that component
> was already measured by the previous component in the boot chain,
> before it had any chance to corrupt the system.
>
> In the context of IMA, IMA can be trusted to make new measurements
> because it measures every file before those files could cause any harm
> to the system. So, potentially IMA and the kernel can be corrupted by
> any file.
>
> What you are proposing would not work, because you are placing trust in
> an input (the PCR starting value) that can be manipulated at any time
> by a corrupted kernel, before you had the chance to detect such
> corruption.
If starting PCR values can be corrupted, the IMA measurements list can
also be corrupted, right?
More generally, what integrity guarantees can be provided (if any) if
the kernel itself is corrupted?
>
> Let me describe a scenario where I could take advantage of such
> weakness. After the first measurement list trim, I perform an attack on
> the system such that it corrupts the kernel. IMA added a new entry in
> the measurement list, which would reveal the attack.
>
> But, since I have control of the kernel, I conveniently update the PCR
> starting value to replay the new measurement entry, and remove the
> measurement entry from the measurement list.
>
> Now, from the perspective of the user space verifiers everything is
> fine, the truncated IMA measurement list is clean, no attack, and the
> current PCR values match by replaying the new PCR starting value with
> the remaining of the IMA measurement list.
Wouldn't the verifier detect the attack when it sees that its
recalculated PCR values don't match up to the PCR digest in the TPM quote?
>
> So, in my opinion the kernel should just offer the ability to trim the
> measurement list, and a remote verifier should be responsible to verify
> the measurement list, without relying on anything from the system being
> evaluated.
>
> Sure, the remote verifier can verify just the trimmed IMA measurement
> list, but the remote verifier must solely rely on state information
> maintained internally.
>
> Roberto
>
>> 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
>>
>
^ permalink raw reply
* Re: [RFC v1 0/1] Implement IMA Event Log Trimming
From: Anirudh Venkataramanan @ 2025-11-21 19:53 UTC (permalink / raw)
To: Mimi Zohar, linux-integrity
Cc: Roberto Sassu, Dmitry Kasatkin, Eric Snowberg, Paul Moore,
James Morris, Serge E . Hallyn, linux-security-module,
Steven Chen, Gregory Lumen, Lakshmi Ramasubramanian,
Sush Shringarputale
In-Reply-To: <629289c119a1a71d8d7a1208ec3676e006d4d527.camel@linux.ibm.com>
On 11/20/2025 2:58 PM, Mimi Zohar wrote:
> On Wed, 2025-11-19 at 13:33 -0800, Anirudh Venkataramanan wrote:
>>
>>
>> 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.
>
> Depending on the IMA policy, the IMA measurement list may contain integrity
> violations, such as "ToM/ToU" (Time of Measurement/Time of Use) or "open-
> writer". Either the userspace supplied PCR values will not match any measurement
> record or the PCR values will be "fixed" to match the well known violation hash
> value extended into the TPM. Depending on how the userspace PCR values will
> subsequently be used, saving the "fixed" PCR values could result in whitewashing
> the integrity of the measurement list.
>
Yes, we account for this. IMA documentation [1] notes that:
"An all zeros hash indicates a measurement log violation. IMA is
invalidating an entry. Trust in entries after that are up to the end
user. If the Template Data Hash is all zeros, an all ones digest is
extended."
A userspace verifier could be designed with a user option like
"--ignore-violations". This would extend a digest of all ones in the
event replay process and arrive at the same per-event PCR values that
the TPM originally did. The trimming logic in the kernel would do the
same thing.
By "whitewashing", you mean that violations will also get trimmed? Given
that trust in entries post violation is up to the user, is this a
problem? The IMA log itself can still be saved by userspace for further
analysis, auditing, etc. The point of trimming is to get it out of the
kernel memory.
Thanks!
Ani
[1]
https://ima-doc.readthedocs.io/en/latest/event-log-format.html#template-data-hash
^ permalink raw reply
* Re: [PATCH] KEYS: encrypted: Use pr_fmt()
From: Jarkko Sakkinen @ 2025-11-21 20:10 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: <83C83079-0354-4642-A980-DBC7AE572A53@linux.dev>
On Wed, Nov 19, 2025 at 03:45:02PM +0100, Thorsten Blum wrote:
> 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 ..."?
I think e.g., "Rewrite the definition of ..." describes better what
you're doing.
>
> >> "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
>
BR, Jarkko
^ permalink raw reply
* Re: [PATCH 15/44] drivers/char/tpm: use min() instead of min_t()
From: Jarkko Sakkinen @ 2025-11-21 20:11 UTC (permalink / raw)
To: david.laight.linux; +Cc: linux-kernel, linux-integrity, Peter Huewe
In-Reply-To: <20251119224140.8616-16-david.laight.linux@gmail.com>
On Wed, Nov 19, 2025 at 10:41:11PM +0000, david.laight.linux@gmail.com wrote:
> From: David Laight <david.laight.linux@gmail.com>
>
> min_t(int, a, b) casts an 'long' to 'int'.
> Use min(a, b) instead as it promotes any 'int' to 'long'
> and so cannot discard significant bits.
>
> In this case the 'long' value is small enough that the result is ok.
>
> Detected by an extra check added to min_t().
>
> Signed-off-by: David Laight <david.laight.linux@gmail.com>
> ---
> drivers/char/tpm/tpm1-cmd.c | 2 +-
> drivers/char/tpm/tpm_tis_core.c | 4 ++--
> 2 files changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/char/tpm/tpm1-cmd.c b/drivers/char/tpm/tpm1-cmd.c
> index cf64c7385105..11088bda4e68 100644
> --- a/drivers/char/tpm/tpm1-cmd.c
> +++ b/drivers/char/tpm/tpm1-cmd.c
> @@ -530,7 +530,7 @@ struct tpm1_get_random_out {
> int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
> {
> struct tpm1_get_random_out *out;
> - u32 num_bytes = min_t(u32, max, TPM_MAX_RNG_DATA);
> + u32 num_bytes = min(max, TPM_MAX_RNG_DATA);
> struct tpm_buf buf;
> u32 total = 0;
> int retries = 5;
> diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c
> index 8954a8660ffc..2676e3a241b5 100644
> --- a/drivers/char/tpm/tpm_tis_core.c
> +++ b/drivers/char/tpm/tpm_tis_core.c
> @@ -310,7 +310,7 @@ static int get_burstcount(struct tpm_chip *chip)
> return -EBUSY;
> }
>
> -static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
> +static int recv_data(struct tpm_chip *chip, u8 *buf, u32 count)
> {
> struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
> int size = 0, burstcnt, rc;
> @@ -453,7 +453,7 @@ static int tpm_tis_send_data(struct tpm_chip *chip, const u8 *buf, size_t len)
> rc = burstcnt;
> goto out_err;
> }
> - burstcnt = min_t(int, burstcnt, len - count - 1);
> + burstcnt = min(burstcnt, len - count - 1);
> rc = tpm_tis_write_bytes(priv, TPM_DATA_FIFO(priv->locality),
> burstcnt, buf + count);
> if (rc < 0)
> --
> 2.39.5
>
Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>
BR, Jarkko
^ permalink raw reply
* [PATCH] selftests: tpm2: Fix ill defined assertions
From: Maurice Hieronymus @ 2025-11-23 11:18 UTC (permalink / raw)
To: peterhuewe, jarkko
Cc: linux-integrity, linux-kselftest, linux-kernel,
Maurice Hieronymus
Remove parentheses around assert statements in Python. With parentheses,
assert always evaluates to True, making the checks ineffective.
Signed-off-by: Maurice Hieronymus <mhi@mailbox.org>
---
tools/testing/selftests/tpm2/tpm2.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/tools/testing/selftests/tpm2/tpm2.py b/tools/testing/selftests/tpm2/tpm2.py
index bba8cb54548e..3d130c30bc7c 100644
--- a/tools/testing/selftests/tpm2/tpm2.py
+++ b/tools/testing/selftests/tpm2/tpm2.py
@@ -437,7 +437,7 @@ class Client:
def extend_pcr(self, i, dig, bank_alg = TPM2_ALG_SHA1):
ds = get_digest_size(bank_alg)
- assert(ds == len(dig))
+ assert ds == len(dig)
auth_cmd = AuthCommand()
@@ -589,7 +589,7 @@ class Client:
def seal(self, parent_key, data, auth_value, policy_dig,
name_alg = TPM2_ALG_SHA1):
ds = get_digest_size(name_alg)
- assert(not policy_dig or ds == len(policy_dig))
+ assert not policy_dig or ds == len(policy_dig)
attributes = 0
if not policy_dig:
base-commit: 821e6e2a328bb907d40f8d1141d8b6c079aa7340
--
2.50.1
^ permalink raw reply related
* Re: [PATCH v3 0/9] module: Introduce hash-based integrity checking
From: Sebastian Andrzej Siewior @ 2025-11-23 17:05 UTC (permalink / raw)
To: Thomas Weißschuh
Cc: James Bottomley, 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: <20251119154834.A-tQsLzh@linutronix.de>
On 2025-11-19 16:48:34 [+0100], Sebastian Andrzej Siewior wrote:
> 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.
The following PoC creates a merkle tree from a set files ending with .ko
within the specified directory. It will write a .hash files containing
the required hash for each file for its validation. The root hash is
saved as "hash_root" and "hash_root.h" in the directory.
The Debian kernel shipps 4256 modules:
| $ time ./compute_hashes mods_deb
| Files 4256 levels: 13 root hash: 97f8f439d63938ed74f48ec46dbd75c2b5e5b49f012a414e89b6f0e0f06efe84
|
| real 0m0,732s
| user 0m0,304s
| sys 0m0,427s
This computes the hashes for all the modules it found in the mods_deb
folder.
The kernel needs the root hash (for sha256 32 bytes) and the depth of
the tree (4 bytes). That are 36 bytes regardless of the number of
modules that are built.
In this case, the attached hash for each module is 420 bytes. This is 4
bytes (position in the tree) + 13 (depth) * 32.
The verification process requires 13 hash operation to hash through the
tree and verify against the root hash.
For convience, the following PoC can also be found at
https://git.kernel.org/pub/scm/linux/kernel/git/bigeasy/mtree-hashed-mods.git/
which also includes a small testsuite.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000000000..e4a35c15f0a94
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,7 @@
+CC := gcc
+CFLAGS := -O2 -g -Wall
+LDLIBS := -lcrypto
+
+all: compute_hashes mk-files verify_hash
+test: compute_hashes mk-files verify_hash
+ ./verify_test.sh
diff --git a/compute_hashes.c b/compute_hashes.c
new file mode 100644
index 0000000000000..da61b214137b8
--- /dev/null
+++ b/compute_hashes.c
@@ -0,0 +1,407 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Compute hashes for individual files and build a merkle tree.
+ *
+ * Author: Sebastian Andrzej Siewior <sebastian@breakpoint.cc>
+ *
+ */
+#define _GNU_SOURCE 1
+#include <ftw.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+#include <openssl/evp.h>
+
+#include "helpers.h"
+
+struct file_entry {
+ char *name;
+ size_t fsize;
+ unsigned int pos;
+ unsigned char hash[EVP_MAX_MD_SIZE];
+};
+
+static struct file_entry *fh_list;
+static size_t num_files;
+
+struct leaf_hash {
+ unsigned char hash[EVP_MAX_MD_SIZE];
+};
+
+struct mtree {
+ struct leaf_hash **l;
+ unsigned int *entries;
+ unsigned int levels;
+};
+
+static unsigned int get_pow2(unsigned int val)
+{
+ return 31 - __builtin_clz(val);
+}
+
+static unsigned int roundup_pow2(unsigned int val)
+{
+ return 1 << (get_pow2(val - 1) + 1);
+}
+
+static unsigned int log2_roundup(unsigned int val)
+{
+ return get_pow2(roundup_pow2(val));
+}
+
+static int str_endswith(const char *s, const char *suffix)
+{
+ size_t ls, lf;
+
+ ls = strlen(s);
+ lf = strlen(suffix);
+
+ if (ls <= lf)
+ return -1;
+ return strcmp(s + ls - lf, suffix);
+}
+
+static void __print_hash(unsigned char *h)
+{
+ int i;
+
+ for (i = 0; i < hash_size; i++)
+ printf("%02x", h[i]);
+}
+
+static void print_hash(unsigned char *h)
+{
+ __print_hash(h);
+ printf("\n");
+}
+
+static int hash_file(struct file_entry *fe)
+{
+ void *mem;
+ int fd;
+
+ fd = open(fe->name, O_RDONLY);
+ if (fd < 0) {
+ printf("Failed to open %s: %m\n", fe->name);
+ exit(1);
+ }
+
+ mem = mmap(NULL, fe->fsize, PROT_READ, MAP_SHARED, fd, 0);
+ close(fd);
+
+ if (mem == MAP_FAILED) {
+ printf("Failed to mmap %s: %m\n", fe->name);
+ exit(1);
+ }
+
+ hash_data(mem, fe->pos, fe->fsize, fe->hash);
+
+ munmap(mem, fe->fsize);
+ return 0;
+}
+
+static int add_files_cb(const char *fpath, const struct stat *sb, int tflag,
+ struct FTW *ftwbuf)
+{
+ if (tflag != FTW_F)
+ return 0;
+
+ if (str_endswith(fpath, ".ko"))
+ return 0;
+
+ fh_list = xrealloc(fh_list, (num_files + 1) * sizeof (struct file_entry));
+
+ fh_list[num_files].name = strdup(fpath);
+ if (!fh_list[num_files].name) {
+ printf("Failed to allocate memory\n");
+ exit(1);
+ }
+
+ fh_list[num_files].fsize = sb->st_size;
+
+ num_files++;
+ return 0;
+}
+
+static int cmp_file_entry(const void *p1, const void *p2)
+{
+ const struct file_entry *f1, *f2;
+
+ f1 = p1;
+ f2 = p2;
+
+ return strcmp(f1->name, f2->name);
+}
+
+static struct mtree *build_merkle(struct file_entry *fh, size_t num)
+{
+ unsigned int i, le;
+ struct mtree *mt;
+
+ mt = xmalloc(sizeof(struct mtree));
+ mt->levels = log2_roundup(num);
+ mt->l = xcalloc(sizeof(struct leaf_hash *), mt->levels);
+
+ mt->entries = xcalloc(sizeof(unsigned int), mt->levels);
+ le = num / 2;
+ if (num & 1)
+ le++;
+ mt->entries[0] = le;
+ mt->l[0] = xcalloc(sizeof(struct leaf_hash), le);
+
+ /* First level of pairs */
+ for (i = 0; i < num; i+= 2) {
+ if (i == num - 1) {
+ /* Odd number of files, no pair. Hash with itself */
+ hash_entry(fh[i].hash, fh[i].hash, mt->l[0][i/2].hash);
+ } else {
+ hash_entry(fh[i].hash, fh[i + 1].hash, mt->l[0][i/2].hash);
+ }
+ }
+ for (i = 1; i < mt->levels; i++) {
+ int n;
+ int odd = 0;
+
+ if (le & 1) {
+ le++;
+ odd++;
+ }
+
+ mt->entries[i] = le / 2;
+ mt->l[i] = xcalloc(sizeof(struct leaf_hash), le);
+
+ for (n = 0; n < le; n += 2) {
+ if (n == le - 2 && odd) {
+ /* Odd number of pairs, no pair. Hash with itself */
+ hash_entry(mt->l[i - 1][n].hash, mt->l[i - 1][n].hash,
+ mt->l[i][n/2].hash);
+ } else {
+ hash_entry(mt->l[i - 1][n].hash, mt->l[i - 1][n +1].hash,
+ mt->l[i][n/2].hash);
+ }
+ }
+ le = mt->entries[i];
+ }
+ return mt;
+}
+
+static void free_mtree(struct mtree *mt)
+{
+ int i;
+
+ for (i = 0; i < mt->levels; i++)
+ free(mt->l[i]);
+
+ free(mt->l);
+ free(mt->entries);
+ free(mt);
+}
+
+static void write_be_int(int fd, unsigned int v)
+{
+ unsigned int be_val = host_to_be32(v);
+
+ if (write(fd, &be_val, sizeof(be_val)) != sizeof(be_val)) {
+ printf("Failed writting to file: %m\n");
+ exit(1);
+ }
+}
+
+static void write_hash(int fd, const void *h)
+{
+ ssize_t wr;
+
+ wr = write(fd, h, hash_size);
+ if (wr != hash_size) {
+ printf("Failed writting to file: %m\n");
+ exit(1);
+ }
+}
+
+static void build_proof(struct mtree *mt, unsigned int n, int fd)
+{
+ unsigned char cur[EVP_MAX_MD_SIZE];
+ unsigned char tmp[EVP_MAX_MD_SIZE];
+ struct file_entry *fe, *fe_sib;
+ unsigned int i;
+
+ fe = &fh_list[n];
+
+ if ((n & 1) == 0) {
+ /* No pair, hash with itself */
+ if (n + 1 == num_files)
+ fe_sib = fe;
+ else
+ fe_sib = &fh_list[n + 1];
+ } else {
+ fe_sib = &fh_list[n - 1];
+ }
+ /* First comes the node position into the file */
+ write_be_int(fd, n);
+
+ if ((n & 1) == 0)
+ hash_entry(fe->hash, fe_sib->hash, cur);
+ else
+ hash_entry(fe_sib->hash, fe->hash, cur);
+
+ /* Next is the sibling hash, followed by hashes in the tree */
+ write_hash(fd, fe_sib->hash);
+
+ for (i = 0; i < mt->levels - 1; i++) {
+ n >>= 1;
+ if ((n & 1) == 0) {
+ void *h;
+
+ /* No pair, hash with itself */
+ if (n + 1 == mt->entries[i])
+ h = cur;
+ else
+ h = mt->l[i][n + 1].hash;
+
+ hash_entry(cur, h, tmp);
+ write_hash(fd, h);
+ } else {
+ hash_entry(mt->l[i][n - 1].hash, cur, tmp);
+ write_hash(fd, mt->l[i][n - 1].hash);
+ }
+ memcpy(cur, tmp, hash_size);
+ }
+
+ /* After all that, the end hash should match the root hash */
+ if (memcmp(cur, mt->l[mt->levels - 1][0].hash, hash_size))
+ printf("MISS-MATCH\n");
+}
+
+static void write_merkle_root(struct mtree *mt, const char *fp)
+{
+ char buf[1024];
+ int fd;
+
+ if (snprintf(buf, sizeof(buf), "%s/hash_root", fp) >= sizeof(buf)) {
+ printf("Root dir too long\n");
+ exit(1);
+ }
+ fd = open(buf, O_WRONLY | O_CREAT | O_TRUNC, DEF_F_PERM);
+ if (fd < 0) {
+ printf("Failed to create %s: %m\n", buf);
+ exit(1);
+ }
+
+ write_be_int(fd, mt->levels);
+ write_hash(fd, mt->l[mt->levels - 1][0].hash);
+ close(fd);
+ printf("Files %ld levels: %d root hash: ", num_files, mt->levels);
+ print_hash(mt->l[mt->levels - 1][0].hash);
+}
+
+static void write_merkle_root_h(struct mtree *mt, const char *fp)
+{
+ char buf[1024];
+ unsigned int i;
+ unsigned char *h;
+ FILE *f;
+
+ if (snprintf(buf, sizeof(buf), "%s/hash_root.h", fp) >= sizeof(buf)) {
+ printf("Root dir too long\n");
+ exit(1);
+ }
+ f = fopen(buf, "w");
+ if (!f) {
+ printf("Failed to create %s: %m\n", buf);
+ exit(1);
+ }
+ h = mt->l[mt->levels - 1][0].hash;
+
+ fprintf(f, "#ifndef __HASH_ROOT_TREE_H__\n");
+ fprintf(f, "#define __HASH_ROOT_TREE_H__\n\n");
+ fprintf(f, "unsigned int hashed_mods_levels = %u;\n", mt->levels);
+ fprintf(f, "unsigned char hashed_mods_root[%d] = {", hash_size);
+ for (i = 0; i < hash_size; i++) {
+ char *space = "";
+
+ if (!(i % 8))
+ fprintf(f, "\n\t");
+
+ if ((i + 1) % 8)
+ space = " ";
+
+ fprintf(f, "0x%02x,%s", h[i], space);
+ }
+ fprintf(f, "\n};\n#endif\n");
+ fclose(f);
+}
+
+int main(int argc, char *argv[])
+{
+ const EVP_MD *hash_evp;
+ char *fp;
+ struct mtree *mt;
+ int i;
+
+ ctx = EVP_MD_CTX_new();
+ if (!ctx)
+ goto err_ossl;
+
+ if (argc != 2) {
+ printf("%s: folder\n", argv[0]);
+ return 1;
+ }
+ fp = argv[1];
+
+ hash_evp = EVP_sha256();
+ hash_size = EVP_MD_get_size(hash_evp);
+ if (hash_size <= 0)
+ goto err_ossl;
+
+ if (EVP_DigestInit_ex(ctx, hash_evp, NULL) != 1)
+ goto err_ossl;
+
+ nftw(fp, add_files_cb, 64, 0);
+
+ qsort(fh_list, num_files, sizeof(struct file_entry), cmp_file_entry);
+
+ for (i = 0; i < num_files; i++) {
+ fh_list[i].pos = i;
+ hash_file(&fh_list[i]);
+ }
+
+ mt = build_merkle(fh_list, num_files);
+ write_merkle_root(mt, fp);
+ write_merkle_root_h(mt, fp);
+ for (i = 0; i < num_files; i++) {
+ char signame[1024];
+ int fd;
+ int ret;
+
+ ret = snprintf(signame, sizeof(signame), "%s.hash", fh_list[i].name);
+ if (ret >= sizeof(signame)) {
+ printf("path + name too long\n");
+ return 1;
+ }
+ fd = open(signame, O_WRONLY | O_CREAT | O_TRUNC, DEF_F_PERM);
+ if (fd < 0) {
+ printf("Can't create %s: %m\n", signame);
+ return 1;
+ }
+ build_proof(mt, i, fd);
+ close(fd);
+ }
+
+ free_mtree(mt);
+ for (i = 0; i < num_files; i++)
+ free(fh_list[i].name);
+ free(fh_list);
+
+ EVP_MD_CTX_free(ctx);
+ return 0;
+
+err_ossl:
+ printf("libssl operation failed\n");
+ return 1;
+}
diff --git a/helpers.h b/helpers.h
new file mode 100644
index 0000000000000..f52ad3543f890
--- /dev/null
+++ b/helpers.h
@@ -0,0 +1,109 @@
+#ifndef __HELPERS_H__
+#define __HELPERS_H__
+
+static EVP_MD_CTX *ctx;
+static int hash_size;
+
+#define DEF_F_PERM (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) /* 0644*/
+#define DEF_D_PERM (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) /* 0755*/
+
+static unsigned int host_to_be32(unsigned int v)
+{
+#if __BYTE_ORDER__ == __LITTLE_ENDIAN
+ return __builtin_bswap32(v);
+#elif __BYTE_ORDER__ == __BIG_ENDIAN
+ return v;
+#else
+#error Missing endian define
+#endif
+}
+
+static inline void *xcalloc(size_t n, size_t size)
+{
+ void *p;
+
+ p = calloc(n, size);
+ if (p)
+ return p;
+ printf("Memory allocation failed\n");
+ exit(1);
+}
+
+static void *xmalloc(size_t size)
+{
+ void *p;
+
+ p = malloc(size);
+ if (p)
+ return p;
+ printf("Memory allocation failed\n");
+ exit(1);
+}
+
+static inline void *xrealloc(void *oldp, size_t size)
+{
+ void *p;
+
+ p = realloc(oldp, size);
+ if (p)
+ return p;
+ printf("Memory allocation failed\n");
+ exit(1);
+}
+
+static void hash_data(void *p, unsigned int pos, size_t size, void *ret_hash)
+{
+ unsigned char magic = 0x01;
+ unsigned int pos_be;
+
+ pos_be = host_to_be32(pos);
+ if (EVP_DigestInit_ex(ctx, NULL, NULL) != 1)
+ goto err;
+
+ if (EVP_DigestUpdate(ctx, &magic, sizeof(magic)) != 1)
+ goto err;
+
+ if (EVP_DigestUpdate(ctx, &pos_be, sizeof(pos_be)) != 1)
+ goto err;
+
+ if (EVP_DigestUpdate(ctx, p, size) != 1)
+ goto err;
+
+ if (EVP_DigestFinal_ex(ctx, ret_hash, NULL) != 1)
+ goto err;
+
+ return;
+
+err:
+ printf("libssl operation failed\n");
+ exit(1);
+}
+static void hash_entry(void *left, void *right, void *ret_hash)
+{
+ unsigned char magic = 0x02;
+
+ if (EVP_DigestInit_ex(ctx, NULL, NULL) != 1)
+ goto err;
+
+ if (EVP_DigestUpdate(ctx, &magic, sizeof(magic)) != 1)
+ goto err;
+
+ if (EVP_DigestUpdate(ctx, left, hash_size) != 1)
+ goto err;
+
+ if (EVP_DigestUpdate(ctx, right, hash_size) != 1)
+ goto err;
+
+ if (EVP_DigestFinal_ex(ctx, ret_hash, NULL) != 1)
+ goto err;
+
+ return;
+
+err:
+ printf("libssl operation failed\n");
+ exit(1);
+}
+
+
+
+#endif
diff --git a/verify_hash.c b/verify_hash.c
new file mode 100644
index 0000000000000..0a842f27f1ebc
--- /dev/null
+++ b/verify_hash.c
@@ -0,0 +1,206 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Verify a file against and its hash against a merkle tree hash.
+ *
+ * Author: Sebastian Andrzej Siewior <sebastian@breakpoint.cc>
+ *
+ */
+#define _GNU_SOURCE 1
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+#include <openssl/evp.h>
+
+#include "helpers.h"
+
+struct hash_root {
+ unsigned int level;
+ unsigned char hash[EVP_MAX_MD_SIZE];
+};
+
+struct verify_sig {
+ unsigned int pos;
+ char hash_sigs[];
+};
+
+static int hash_file(const char *f, unsigned char *hash, unsigned int pos)
+{
+ struct stat sb;
+ int fd, ret;
+ void *mem;
+
+ fd = open(f, O_RDONLY);
+ if (fd < 0) {
+ printf("Failed to open %s: %m\n", f);
+ exit(1);
+ }
+
+ ret = fstat(fd, &sb);
+ if (ret) {
+ printf("stat failed %m\n");
+ exit(1);
+ }
+
+ mem = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
+ close(fd);
+
+ if (mem == MAP_FAILED) {
+ printf("Failed to mmap file: %m\n");
+ exit(1);
+ }
+
+ hash_data(mem, pos, sb.st_size, hash);
+
+ munmap(mem, sb.st_size);
+ return 0;
+}
+
+static void verify_hash(struct hash_root *hr, struct verify_sig *vs, unsigned char *cur,
+ const char *fn)
+{
+ unsigned char tmp[EVP_MAX_MD_SIZE];
+ unsigned sig_ofs = 0;
+ unsigned int i, n;
+
+ n = vs->pos;
+ if ((n & 1) == 0)
+ hash_entry(cur, &vs->hash_sigs[sig_ofs], tmp);
+ else
+ hash_entry(&vs->hash_sigs[sig_ofs], cur, tmp);
+
+ memcpy(cur, tmp, hash_size);
+ sig_ofs += hash_size;
+ for (i = 0; i < hr->level - 1; i++) {
+ n >>= 1;
+ if ((n & 1) == 0) {
+ hash_entry(cur, &vs->hash_sigs[sig_ofs], tmp);
+ } else {
+ hash_entry(&vs->hash_sigs[sig_ofs], cur, tmp);
+ }
+ memcpy(cur, tmp, hash_size);
+ sig_ofs += hash_size;
+ }
+
+ if (!memcmp(cur, hr->hash, hash_size)) {
+ exit(0);
+ } else {
+ printf("MISS-MATCH on %s\n", fn);
+ exit(1);
+ }
+}
+
+static void read_be_int(int fd, unsigned int *val)
+{
+ unsigned int val_be;
+
+ if (read(fd, &val_be, sizeof(val_be)) != sizeof(val_be)) {
+ printf("Can't read from file\n");
+ exit(1);
+ }
+ *val = host_to_be32(val_be);
+}
+
+struct hash_root *read_root_hash(const char *f)
+{
+ int fd;
+ struct hash_root *hr;
+
+ hr = xmalloc(sizeof(*hr));
+ fd = open(f, O_RDONLY);
+ if (fd < 0) {
+ printf("Can't open %s: %m\n", f);
+ exit(1);
+ }
+ read_be_int(fd, &hr->level);
+ if (read(fd, hr->hash, hash_size) != hash_size) {
+ printf("Can't read complete hash (%u): %m\n",
+ hash_size);
+ exit(1);
+ }
+ close(fd);
+ return hr;
+}
+
+static void load_hash_sig(const char *f, struct verify_sig *verify_sig,
+ unsigned int sig_num)
+{
+ ssize_t total_hash_size;
+ struct stat sb;
+ char buf[1024];
+ int fd;
+ int ret;
+
+ total_hash_size = sig_num * hash_size;
+
+ ret = snprintf(buf, sizeof(buf), "%s.hash", f);
+ if (ret >= sizeof(buf)) {
+ printf("Too long\n");
+ exit(1);
+ }
+ fd = open(buf, O_RDONLY);
+ if (fd < 0) {
+ printf("Failed to open %s\n", buf);
+ exit(1);
+ }
+ read_be_int(fd, &verify_sig->pos);
+
+ ret = fstat(fd, &sb);
+ if (ret < 0) {
+ printf("Failed to stat %s: %m\n", f);
+ exit(1);
+ }
+
+ if (sb.st_size != total_hash_size + 4) {
+ printf("Unexpected signature size: Expected %ld vs found %ld\n",
+ total_hash_size + 4, sb.st_size);
+ exit(1);
+ }
+ if (read(fd, verify_sig->hash_sigs, total_hash_size) != total_hash_size) {
+ printf("Failed to read the signature: %m\n");
+ exit(1);
+ }
+ close(fd);
+}
+
+int main(int argc, char *argv[])
+{
+ struct hash_root *hash_root;
+ struct verify_sig *vsig;
+ unsigned char fhash[EVP_MAX_MD_SIZE];
+ const EVP_MD *hash_evp;
+
+ ctx = EVP_MD_CTX_new();
+ if (!ctx)
+ goto err;
+
+ if (argc != 3) {
+ printf("%s: hash_root module\n", argv[0]);
+ return 1;
+ }
+
+ hash_evp = EVP_sha256();
+ hash_size = EVP_MD_get_size(hash_evp);
+ if (hash_size <= 0)
+ goto err;
+
+ if (EVP_DigestInit_ex(ctx, hash_evp, NULL) != 1)
+ goto err;
+
+ hash_root = read_root_hash(argv[1]);
+ vsig = xmalloc(sizeof(struct verify_sig) + hash_root->level * hash_size);
+
+ load_hash_sig(argv[2], vsig, hash_root->level);
+ hash_file(argv[2], fhash, vsig->pos);
+ verify_hash(hash_root, vsig, fhash, argv[2]);
+
+ EVP_MD_CTX_free(ctx);
+ return 0;
+err:
+ printf("libssl operation failed\n");
+ return 1;
+}
--
2.51.0
Sebastian
^ permalink raw reply related
* Re: [PATCH v3 7/9] module: Move lockdown check into generic module loader
From: Sebastian Andrzej Siewior @ 2025-11-23 17:10 UTC (permalink / raw)
To: Paul Moore
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: <CAHC9VhTuf1u4B3uybZxdojcmz5sFG+_JHUCC=C0N=9gFDmurHg@mail.gmail.com>
On 2025-11-19 14:55:47 [-0500], Paul Moore wrote:
> 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.
Okay. So if it is just me and everyone is well aware then okay.
Sebastian
^ permalink raw reply
* Re: [PATCH v3 0/9] module: Introduce hash-based integrity checking
From: Thomas Weißschuh @ 2025-11-24 9:41 UTC (permalink / raw)
To: Sebastian Andrzej Siewior
Cc: James Bottomley, 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: <20251123170502.Ai5Ig66Z@breakpoint.cc>
Hi Sebastian,
On 2025-11-23 18:05:02+0100, Sebastian Andrzej Siewior wrote:
> On 2025-11-19 16:48:34 [+0100], Sebastian Andrzej Siewior wrote:
> > 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.
>
> The following PoC creates a merkle tree from a set files ending with .ko
> within the specified directory. It will write a .hash files containing
> the required hash for each file for its validation. The root hash is
> saved as "hash_root" and "hash_root.h" in the directory.
Thanks a lot!
> The Debian kernel shipps 4256 modules:
>
> | $ time ./compute_hashes mods_deb
> | Files 4256 levels: 13 root hash: 97f8f439d63938ed74f48ec46dbd75c2b5e5b49f012a414e89b6f0e0f06efe84
> |
> | real 0m0,732s
> | user 0m0,304s
> | sys 0m0,427s
>
> This computes the hashes for all the modules it found in the mods_deb
> folder.
> The kernel needs the root hash (for sha256 32 bytes) and the depth of
> the tree (4 bytes). That are 36 bytes regardless of the number of
> modules that are built.
> In this case, the attached hash for each module is 420 bytes. This is 4
> bytes (position in the tree) + 13 (depth) * 32.
> The verification process requires 13 hash operation to hash through the
> tree and verify against the root hash.
We'll need to store the proof together with the modules somewhere.
Regular module signatures are stored as PKCS#7 and appended to the module
file. If we can also encode the merkle proof as PKCS#7, the integration
into the existing infrastructure should be much easier.
It will require some changes to this series, but honestly the Merkle
tree aproach looks like the clear winner here.
> For convience, the following PoC can also be found at
> https://git.kernel.org/pub/scm/linux/kernel/git/bigeasy/mtree-hashed-mods.git/
>
> which also includes a small testsuite.
(...)
Thomas
^ permalink raw reply
* Re: [PATCH 00/44] Change a lot of min_t() that might mask high bits
From: Herbert Xu @ 2025-11-24 9:49 UTC (permalink / raw)
To: david.laight.linux
Cc: linux-kernel, Alan Stern, Alexander Viro, Alexei Starovoitov,
Andi Shyti, Andreas Dilger, Andrew Lunn, Andrew Morton,
Andrii Nakryiko, Andy Shevchenko, Ard Biesheuvel,
Arnaldo Carvalho de Melo, Bjorn Helgaas, Borislav Petkov,
Christian Brauner, Christian König, Christoph Hellwig,
Daniel Borkmann, Dan Williams, Dave Hansen, Dave Jiang,
David Ahern, David Hildenbrand, Davidlohr Bueso, David S. Miller,
Dennis Zhou, Eric Dumazet, Greg Kroah-Hartman, Ingo Molnar,
Jakub Kicinski, Jakub Sitnicki, James E.J. Bottomley,
Jarkko Sakkinen, Jason A. Donenfeld, Jens Axboe, Jiri Slaby,
Johannes Weiner, John Allen, Jonathan Cameron, Juergen Gross,
Kees Cook, KP Singh, Linus Walleij, Martin K. Petersen,
Matthew Wilcox (Oracle), Mika Westerberg, Mike Rapoport,
Miklos Szeredi, Namhyung Kim, Neal Cardwell, nic_swsd,
OGAWA Hirofumi, Olivia Mackall, Paolo Abeni, Paolo Bonzini,
Peter Huewe, Peter Zijlstra, Rafael J. Wysocki,
Sean Christopherson, Srinivas Kandagatla, Stefano Stabellini,
Steven Rostedt, Tejun Heo, Theodore Ts'o, Thomas Gleixner,
Tom Lendacky, Willem de Bruijn, x86, Yury Norov, amd-gfx, bpf,
cgroups, dri-devel, io-uring, kvm, linux-acpi, linux-block,
linux-crypto, linux-cxl, linux-efi, linux-ext4, linux-fsdevel,
linux-gpio, linux-i2c, linux-integrity, linux-mm, linux-nvme,
linux-pci, linux-perf-users, linux-scsi, linux-serial,
linux-trace-kernel, linux-usb, mptcp, netdev, usb-storage
In-Reply-To: <20251119224140.8616-1-david.laight.linux@gmail.com>
On Wed, Nov 19, 2025 at 10:40:56PM +0000, david.laight.linux@gmail.com wrote:
> From: David Laight <david.laight.linux@gmail.com>
>
> It in not uncommon for code to use min_t(uint, a, b) when one of a or b
> is 64bit and can have a value that is larger than 2^32;
> This is particularly prevelant with:
> uint_var = min_t(uint, uint_var, uint64_expression);
>
> Casts to u8 and u16 are very likely to discard significant bits.
>
> These can be detected at compile time by changing min_t(), for example:
> #define CHECK_SIZE(fn, type, val) \
> BUILD_BUG_ON_MSG(sizeof (val) > sizeof (type) && \
> !statically_true(((val) >> 8 * (sizeof (type) - 1)) < 256), \
> fn "() significant bits of '" #val "' may be discarded")
>
> #define min_t(type, x, y) ({ \
> CHECK_SIZE("min_t", type, x); \
> CHECK_SIZE("min_t", type, y); \
> __cmp_once(min, type, x, y); })
>
> (and similar changes to max_t() and clamp_t().)
>
> This shows up some real bugs, some unlikely bugs and some false positives.
> In most cases both arguments are unsigned type (just different ones)
> and min_t() can just be replaced by min().
>
> The patches are all independant and are most of the ones needed to
> get the x86-64 kernel I build to compile.
> I've not tried building an allyesconfig or allmodconfig kernel.
> I've also not included the patch to minmax.h itself.
>
> I've tried to put the patches that actually fix things first.
> The last one is 0009.
>
> I gave up on fixing sched/fair.c - it is too broken for a single patch!
> The patch for net/ipv4/tcp.c is also absent because do_tcp_getsockopt()
> needs multiple/larger changes to make it 'sane'.
>
> I've had to trim the 124 maintainers/lists that get_maintainer.pl finds
> from 124 to under 100 to be able to send the cover letter.
> The individual patches only go to the addresses found for the associated files.
> That reduces the number of emails to a less unsane number.
>
> David Laight (44):
> x86/asm/bitops: Change the return type of variable__ffs() to unsigned
> int
> ext4: Fix saturation of 64bit inode times for old filesystems
> perf: Fix branch stack callchain limit
> io_uring/net: Change some dubious min_t()
> ipc/msg: Fix saturation of percpu counts in msgctl_info()
> bpf: Verifier, remove some unusual uses of min_t() and max_t()
> net/core/flow_dissector: Fix cap of __skb_flow_dissect() return value.
> net: ethtool: Use min3() instead of nested min_t(u16,...)
> ipv6: __ip6_append_data() don't abuse max_t() casts
> x86/crypto: ctr_crypt() use min() instead of min_t()
> arch/x96/kvm: use min() instead of min_t()
> block: use min() instead of min_t()
> drivers/acpi: use min() instead of min_t()
> drivers/char/hw_random: use min3() instead of nested min_t()
> drivers/char/tpm: use min() instead of min_t()
> drivers/crypto/ccp: use min() instead of min_t()
> drivers/cxl: use min() instead of min_t()
> drivers/gpio: use min() instead of min_t()
> drivers/gpu/drm/amd: use min() instead of min_t()
> drivers/i2c/busses: use min() instead of min_t()
> drivers/net/ethernet/realtek: use min() instead of min_t()
> drivers/nvme: use min() instead of min_t()
> arch/x86/mm: use min() instead of min_t()
> drivers/nvmem: use min() instead of min_t()
> drivers/pci: use min() instead of min_t()
> drivers/scsi: use min() instead of min_t()
> drivers/tty/vt: use umin() instead of min_t(u16, ...) for row/col
> limits
> drivers/usb/storage: use min() instead of min_t()
> drivers/xen: use min() instead of min_t()
> fs: use min() or umin() instead of min_t()
> block: bvec.h: use min() instead of min_t()
> nodemask: use min() instead of min_t()
> ipc: use min() instead of min_t()
> bpf: use min() instead of min_t()
> bpf_trace: use min() instead of min_t()
> lib/bucket_locks: use min() instead of min_t()
> lib/crypto/mpi: use min() instead of min_t()
> lib/dynamic_queue_limits: use max() instead of max_t()
> mm: use min() instead of min_t()
> net: Don't pass bitfields to max_t()
> net/core: Change loop conditions so min() can be used
> net: use min() instead of min_t()
> net/netlink: Use umin() to avoid min_t(int, ...) discarding high bits
> net/mptcp: Change some dubious min_t(int, ...) to min()
>
> arch/x86/crypto/aesni-intel_glue.c | 3 +-
> arch/x86/include/asm/bitops.h | 18 +++++-------
> arch/x86/kvm/emulate.c | 3 +-
> arch/x86/kvm/lapic.c | 2 +-
> arch/x86/kvm/mmu/mmu.c | 2 +-
> arch/x86/mm/pat/set_memory.c | 12 ++++----
> block/blk-iocost.c | 6 ++--
> block/blk-settings.c | 2 +-
> block/partitions/efi.c | 3 +-
> drivers/acpi/property.c | 2 +-
> drivers/char/hw_random/core.c | 2 +-
> drivers/char/tpm/tpm1-cmd.c | 2 +-
> drivers/char/tpm/tpm_tis_core.c | 4 +--
> drivers/crypto/ccp/ccp-dev.c | 2 +-
> drivers/cxl/core/mbox.c | 2 +-
> drivers/gpio/gpiolib-acpi-core.c | 2 +-
> .../gpu/drm/amd/amdgpu/amdgpu_doorbell_mgr.c | 4 +--
> drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 2 +-
> .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 +-
> drivers/i2c/busses/i2c-designware-master.c | 2 +-
> drivers/net/ethernet/realtek/r8169_main.c | 3 +-
> drivers/nvme/host/pci.c | 3 +-
> drivers/nvme/host/zns.c | 3 +-
> drivers/nvmem/core.c | 2 +-
> drivers/pci/probe.c | 3 +-
> drivers/scsi/hosts.c | 2 +-
> drivers/tty/vt/selection.c | 9 +++---
> drivers/usb/storage/protocol.c | 3 +-
> drivers/xen/grant-table.c | 2 +-
> fs/buffer.c | 2 +-
> fs/exec.c | 2 +-
> fs/ext4/ext4.h | 2 +-
> fs/ext4/mballoc.c | 3 +-
> fs/ext4/resize.c | 2 +-
> fs/ext4/super.c | 2 +-
> fs/fat/dir.c | 4 +--
> fs/fat/file.c | 3 +-
> fs/fuse/dev.c | 2 +-
> fs/fuse/file.c | 8 ++---
> fs/splice.c | 2 +-
> include/linux/bvec.h | 3 +-
> include/linux/nodemask.h | 9 +++---
> include/linux/perf_event.h | 2 +-
> include/net/tcp_ecn.h | 5 ++--
> io_uring/net.c | 6 ++--
> ipc/mqueue.c | 4 +--
> ipc/msg.c | 6 ++--
> kernel/bpf/core.c | 4 +--
> kernel/bpf/log.c | 2 +-
> kernel/bpf/verifier.c | 29 +++++++------------
> kernel/trace/bpf_trace.c | 2 +-
> lib/bucket_locks.c | 2 +-
> lib/crypto/mpi/mpicoder.c | 2 +-
> lib/dynamic_queue_limits.c | 2 +-
> mm/gup.c | 4 +--
> mm/memblock.c | 2 +-
> mm/memory.c | 2 +-
> mm/percpu.c | 2 +-
> mm/truncate.c | 3 +-
> mm/vmscan.c | 2 +-
> net/core/datagram.c | 6 ++--
> net/core/flow_dissector.c | 7 ++---
> net/core/net-sysfs.c | 3 +-
> net/core/skmsg.c | 4 +--
> net/ethtool/cmis_cdb.c | 7 ++---
> net/ipv4/fib_trie.c | 2 +-
> net/ipv4/tcp_input.c | 4 +--
> net/ipv4/tcp_output.c | 5 ++--
> net/ipv4/tcp_timer.c | 4 +--
> net/ipv6/addrconf.c | 8 ++---
> net/ipv6/ip6_output.c | 7 +++--
> net/ipv6/ndisc.c | 5 ++--
> net/mptcp/protocol.c | 8 ++---
> net/netlink/genetlink.c | 9 +++---
> net/packet/af_packet.c | 2 +-
> net/unix/af_unix.c | 4 +--
> 76 files changed, 141 insertions(+), 176 deletions(-)
Patches 10,14,16,37 applied. Thanks.
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* Re: [RFC v1 0/1] Implement IMA Event Log Trimming
From: Roberto Sassu @ 2025-11-24 10:01 UTC (permalink / raw)
To: Anirudh Venkataramanan, linux-integrity
Cc: Mimi Zohar, Roberto Sassu, Dmitry Kasatkin, Eric Snowberg,
Paul Moore, James Morris, Serge E . Hallyn, linux-security-module,
Steven Chen, Gregory Lumen, Lakshmi Ramasubramanian,
Sush Shringarputale
In-Reply-To: <a77e9609-f6bd-4e6d-88be-5422f780b496@linux.microsoft.com>
On Fri, 2025-11-21 at 11:13 -0800, Anirudh Venkataramanan wrote:
> On 11/20/2025 3:02 AM, Roberto Sassu wrote:
> > On Wed, 2025-11-19 at 13:33 -0800, Anirudh Venkataramanan wrote:
> > > ==========================================================================
> > > > 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.
> >
> > Hi Anirudh
>
> Hi Roberto,
>
> Thanks for the feedback! Few questions below.
>
> >
> > I will rephrase this paragraph, to be sure that I understood it
> > correctly.
> >
> > You are proposing a method to trim the measurement list and, at the
> > same time, to keep the measurement list verifiable after trimming. The
> > way you would like to achieve that is to keep the verification state in
> > the kernel in the form of PCR values.
> >
> > Those values mean what verifiers have already verified. Thus, for the
> > next verification attempt, verifiers take the current PCR values as
> > starting values, replay the truncated IMA measurement list, and again
> > you match with the current PCR values and you trim until that point.
> >
> > So the benefit of this proposal is that you keep the verification of
> > the IMA measurement list self-contained by using the last verification
> > state (PCR starting value) and the truncated IMA measurement list as
> > the inputs of your verification.
>
> Your understanding as described above is correct.
>
> >
> > Let me reiterate on the trusted computing principles IMA relies on for
> > providing the evidence about a system's integrity.
> >
> > Unless you are at the beginning of the measurement chain, where the
> > Root of Trust for Measurement (RTM) is trusted by assumption, the
> > measurements done by a component can be trusted because that component
> > was already measured by the previous component in the boot chain,
> > before it had any chance to corrupt the system.
> >
> > In the context of IMA, IMA can be trusted to make new measurements
> > because it measures every file before those files could cause any harm
> > to the system. So, potentially IMA and the kernel can be corrupted by
> > any file.
> >
> > What you are proposing would not work, because you are placing trust in
> > an input (the PCR starting value) that can be manipulated at any time
> > by a corrupted kernel, before you had the chance to detect such
> > corruption.
>
> If starting PCR values can be corrupted, the IMA measurements list can
> also be corrupted, right?
Yes, my point was that there could be a malicious update of the PCR
starting value, so that the IMA measurements list with omitted entries
looks not corrupted.
> More generally, what integrity guarantees can be provided (if any) if
> the kernel itself is corrupted?
None. This is exactly the point: measuring the files before they get
accessed is the only way to provide reliable measurements. After that,
we assume that the operation can corrupt both the user space processes
and the kernel itself (the threat model takes into consideration only
regular files).
But if that happened, replaying the IMA measurements list will reveal
the attack at that point, and the remote verifier can conclude that any
measurement after that cannot be trusted.
Your solution is storing the verification state in the kernel, and make
remote verifiers rely on it for resuming their verification. But,
because the kernel can get potentially corrupted by every measurement,
the verification state can also get potentially corrupted by every
measurement, thus cannot be trusted.
The only way to make the verification of measurements list snapshots
work is that the verification state is stored outside the system to
evaluate (which can be assumed to be trusted), so that you are sure
that the system is not advancing the PCR starting value by itself.
> > Let me describe a scenario where I could take advantage of such
> > weakness. After the first measurement list trim, I perform an attack on
> > the system such that it corrupts the kernel. IMA added a new entry in
> > the measurement list, which would reveal the attack.
> >
> > But, since I have control of the kernel, I conveniently update the PCR
> > starting value to replay the new measurement entry, and remove the
> > measurement entry from the measurement list.
> >
> > Now, from the perspective of the user space verifiers everything is
> > fine, the truncated IMA measurement list is clean, no attack, and the
> > current PCR values match by replaying the new PCR starting value with
> > the remaining of the IMA measurement list.
>
> Wouldn't the verifier detect the attack when it sees that its
> recalculated PCR values don't match up to the PCR digest in the TPM quote?
I think not, because the system replayed the entries it wants to omit
by itself. If the remote verifier is trusting the PCR starting value
from the system, the remote verifier will replay the remaining
measurement entries and will obtain the PCR current values.
The same will happen if someone in the system just did a regular trim
without the remote attestation agent noticing it. Unless the agent
stored which was the last PCR starting value it took, it would not
notice.
But, again, if you rely on the remote attestation agent to maintain the
verification state locally in the system, you are assuming that the
agent will not be corrupted, which is a much stronger assumption than
just letting the agent pass data to the remote verifier (which instead
can be trusted to detect the PCR mismatch).
So, yes, the point of trimming is to just get the IMA measurements list
out of the kernel memory. I'm not opposing to trim N entries instead of
the entire IMA measurements list, as long as: (1) the PCR matching is
done in user space and is done only for convenience (can be totally
untrusted); (2) the verification state is stored in the remote verifier
(outside the system evaluated), and latter detects the PCR mismatch.
Roberto
> > So, in my opinion the kernel should just offer the ability to trim the
> > measurement list, and a remote verifier should be responsible to verify
> > the measurement list, without relying on anything from the system being
> > evaluated.
> >
> > Sure, the remote verifier can verify just the trimmed IMA measurement
> > list, but the remote verifier must solely rely on state information
> > maintained internally.
> >
> > Roberto
> >
> > > 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
> > >
> >
>
^ permalink raw reply
* Re: [PATCHv2 1/2] kernel/kexec: Change the prototype of kimage_map_segment()
From: Andrew Morton @ 2025-11-24 22:16 UTC (permalink / raw)
To: Pingfan Liu
Cc: kexec, linux-integrity, Baoquan He, Mimi Zohar, Roberto Sassu,
Alexander Graf, Steven Chen, stable
In-Reply-To: <20251106065904.10772-1-piliu@redhat.com>
On Thu, 6 Nov 2025 14:59:03 +0800 Pingfan Liu <piliu@redhat.com> wrote:
> The kexec segment index will be required to extract the corresponding
> information for that segment in kimage_map_segment(). Additionally,
> kexec_segment already holds the kexec relocation destination address and
> size. Therefore, the prototype of kimage_map_segment() can be changed.
Could we please have some reviewer input on thee two patches?
Thanks.
(Pingfan, please cc linux-kernel on patches - it's where people go to
find emails on lists which they aren't suscribed to)
(akpm goes off and subscribes to kexec@)
> Fixes: 07d24902977e ("kexec: enable CMA based contiguous allocation")
> Signed-off-by: Pingfan Liu <piliu@redhat.com>
> Cc: Andrew Morton <akpm@linux-foundation.org>
> Cc: Baoquan He <bhe@redhat.com>
> Cc: Mimi Zohar <zohar@linux.ibm.com>
> Cc: Roberto Sassu <roberto.sassu@huawei.com>
> Cc: Alexander Graf <graf@amazon.com>
> Cc: Steven Chen <chenste@linux.microsoft.com>
> Cc: <stable@vger.kernel.org>
> To: kexec@lists.infradead.org
> To: linux-integrity@vger.kernel.org
> ---
> include/linux/kexec.h | 4 ++--
> kernel/kexec_core.c | 9 ++++++---
> security/integrity/ima/ima_kexec.c | 4 +---
> 3 files changed, 9 insertions(+), 8 deletions(-)
>
> diff --git a/include/linux/kexec.h b/include/linux/kexec.h
> index ff7e231b0485..8a22bc9b8c6c 100644
> --- a/include/linux/kexec.h
> +++ b/include/linux/kexec.h
> @@ -530,7 +530,7 @@ extern bool kexec_file_dbg_print;
> #define kexec_dprintk(fmt, arg...) \
> do { if (kexec_file_dbg_print) pr_info(fmt, ##arg); } while (0)
>
> -extern void *kimage_map_segment(struct kimage *image, unsigned long addr, unsigned long size);
> +extern void *kimage_map_segment(struct kimage *image, int idx);
> extern void kimage_unmap_segment(void *buffer);
> #else /* !CONFIG_KEXEC_CORE */
> struct pt_regs;
> @@ -540,7 +540,7 @@ static inline void __crash_kexec(struct pt_regs *regs) { }
> static inline void crash_kexec(struct pt_regs *regs) { }
> static inline int kexec_should_crash(struct task_struct *p) { return 0; }
> static inline int kexec_crash_loaded(void) { return 0; }
> -static inline void *kimage_map_segment(struct kimage *image, unsigned long addr, unsigned long size)
> +static inline void *kimage_map_segment(struct kimage *image, int idx)
> { return NULL; }
> static inline void kimage_unmap_segment(void *buffer) { }
> #define kexec_in_progress false
> diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c
> index fa00b239c5d9..9a1966207041 100644
> --- a/kernel/kexec_core.c
> +++ b/kernel/kexec_core.c
> @@ -960,17 +960,20 @@ int kimage_load_segment(struct kimage *image, int idx)
> return result;
> }
>
> -void *kimage_map_segment(struct kimage *image,
> - unsigned long addr, unsigned long size)
> +void *kimage_map_segment(struct kimage *image, int idx)
> {
> + unsigned long addr, size, eaddr;
> unsigned long src_page_addr, dest_page_addr = 0;
> - unsigned long eaddr = addr + size;
> kimage_entry_t *ptr, entry;
> struct page **src_pages;
> unsigned int npages;
> void *vaddr = NULL;
> int i;
>
> + addr = image->segment[idx].mem;
> + size = image->segment[idx].memsz;
> + eaddr = addr + size;
> +
> /*
> * Collect the source pages and map them in a contiguous VA range.
> */
> diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c
> index 7362f68f2d8b..5beb69edd12f 100644
> --- a/security/integrity/ima/ima_kexec.c
> +++ b/security/integrity/ima/ima_kexec.c
> @@ -250,9 +250,7 @@ void ima_kexec_post_load(struct kimage *image)
> if (!image->ima_buffer_addr)
> return;
>
> - ima_kexec_buffer = kimage_map_segment(image,
> - image->ima_buffer_addr,
> - image->ima_buffer_size);
> + ima_kexec_buffer = kimage_map_segment(image, image->ima_segment_index);
> if (!ima_kexec_buffer) {
> pr_err("Could not map measurements buffer.\n");
> return;
> --
> 2.49.0
^ permalink raw reply
* [PATCH 1/1] tpm_crb: Fix a spelling mistake
From: Chu Guangqing @ 2025-11-25 2:30 UTC (permalink / raw)
To: peterhuewe, jarkko, jgg; +Cc: linux-integrity, linux-kernel, Chu Guangqing
The spelling of the word "requrest" is incorrect; it should be "request".
Signed-off-by: Chu Guangqing <chuguangqing@inspur.com>
---
drivers/char/tpm/tpm_crb.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c
index c75a531cfb98..e094c517b96e 100644
--- a/drivers/char/tpm/tpm_crb.c
+++ b/drivers/char/tpm/tpm_crb.c
@@ -412,7 +412,7 @@ static int crb_do_acpi_start(struct tpm_chip *chip)
#ifdef CONFIG_ARM64
/*
* This is a TPM Command Response Buffer start method that invokes a
- * Secure Monitor Call to requrest the firmware to execute or cancel
+ * Secure Monitor Call to request the firmware to execute or cancel
* a TPM 2.0 command.
*/
static int tpm_crb_smc_start(struct device *dev, unsigned long func_id)
--
2.43.7
^ permalink raw reply related
* Re: [PATCHv2 1/2] kernel/kexec: Change the prototype of kimage_map_segment()
From: Pingfan Liu @ 2025-11-25 4:10 UTC (permalink / raw)
To: Andrew Morton
Cc: kexec, linux-integrity, Baoquan He, Mimi Zohar, Roberto Sassu,
Alexander Graf, Steven Chen, stable
In-Reply-To: <20251124141620.eaef984836fe2edc7acf9179@linux-foundation.org>
On Tue, Nov 25, 2025 at 6:16 AM Andrew Morton <akpm@linux-foundation.org> wrote:
>
> On Thu, 6 Nov 2025 14:59:03 +0800 Pingfan Liu <piliu@redhat.com> wrote:
>
> > The kexec segment index will be required to extract the corresponding
> > information for that segment in kimage_map_segment(). Additionally,
> > kexec_segment already holds the kexec relocation destination address and
> > size. Therefore, the prototype of kimage_map_segment() can be changed.
>
> Could we please have some reviewer input on thee two patches?
>
> Thanks.
>
> (Pingfan, please cc linux-kernel on patches - it's where people go to
> find emails on lists which they aren't suscribed to)
>
OK, I will cc linux-kernel for the future kexec patches
For this series, it can also be found on
https://lore.kernel.org/linux-integrity/20251106065904.10772-1-piliu@redhat.com/
Thanks,
Pingfan
> (akpm goes off and subscribes to kexec@)
>
> > Fixes: 07d24902977e ("kexec: enable CMA based contiguous allocation")
> > Signed-off-by: Pingfan Liu <piliu@redhat.com>
> > Cc: Andrew Morton <akpm@linux-foundation.org>
> > Cc: Baoquan He <bhe@redhat.com>
> > Cc: Mimi Zohar <zohar@linux.ibm.com>
> > Cc: Roberto Sassu <roberto.sassu@huawei.com>
> > Cc: Alexander Graf <graf@amazon.com>
> > Cc: Steven Chen <chenste@linux.microsoft.com>
> > Cc: <stable@vger.kernel.org>
> > To: kexec@lists.infradead.org
> > To: linux-integrity@vger.kernel.org
> > ---
> > include/linux/kexec.h | 4 ++--
> > kernel/kexec_core.c | 9 ++++++---
> > security/integrity/ima/ima_kexec.c | 4 +---
> > 3 files changed, 9 insertions(+), 8 deletions(-)
> >
> > diff --git a/include/linux/kexec.h b/include/linux/kexec.h
> > index ff7e231b0485..8a22bc9b8c6c 100644
> > --- a/include/linux/kexec.h
> > +++ b/include/linux/kexec.h
> > @@ -530,7 +530,7 @@ extern bool kexec_file_dbg_print;
> > #define kexec_dprintk(fmt, arg...) \
> > do { if (kexec_file_dbg_print) pr_info(fmt, ##arg); } while (0)
> >
> > -extern void *kimage_map_segment(struct kimage *image, unsigned long addr, unsigned long size);
> > +extern void *kimage_map_segment(struct kimage *image, int idx);
> > extern void kimage_unmap_segment(void *buffer);
> > #else /* !CONFIG_KEXEC_CORE */
> > struct pt_regs;
> > @@ -540,7 +540,7 @@ static inline void __crash_kexec(struct pt_regs *regs) { }
> > static inline void crash_kexec(struct pt_regs *regs) { }
> > static inline int kexec_should_crash(struct task_struct *p) { return 0; }
> > static inline int kexec_crash_loaded(void) { return 0; }
> > -static inline void *kimage_map_segment(struct kimage *image, unsigned long addr, unsigned long size)
> > +static inline void *kimage_map_segment(struct kimage *image, int idx)
> > { return NULL; }
> > static inline void kimage_unmap_segment(void *buffer) { }
> > #define kexec_in_progress false
> > diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c
> > index fa00b239c5d9..9a1966207041 100644
> > --- a/kernel/kexec_core.c
> > +++ b/kernel/kexec_core.c
> > @@ -960,17 +960,20 @@ int kimage_load_segment(struct kimage *image, int idx)
> > return result;
> > }
> >
> > -void *kimage_map_segment(struct kimage *image,
> > - unsigned long addr, unsigned long size)
> > +void *kimage_map_segment(struct kimage *image, int idx)
> > {
> > + unsigned long addr, size, eaddr;
> > unsigned long src_page_addr, dest_page_addr = 0;
> > - unsigned long eaddr = addr + size;
> > kimage_entry_t *ptr, entry;
> > struct page **src_pages;
> > unsigned int npages;
> > void *vaddr = NULL;
> > int i;
> >
> > + addr = image->segment[idx].mem;
> > + size = image->segment[idx].memsz;
> > + eaddr = addr + size;
> > +
> > /*
> > * Collect the source pages and map them in a contiguous VA range.
> > */
> > diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c
> > index 7362f68f2d8b..5beb69edd12f 100644
> > --- a/security/integrity/ima/ima_kexec.c
> > +++ b/security/integrity/ima/ima_kexec.c
> > @@ -250,9 +250,7 @@ void ima_kexec_post_load(struct kimage *image)
> > if (!image->ima_buffer_addr)
> > return;
> >
> > - ima_kexec_buffer = kimage_map_segment(image,
> > - image->ima_buffer_addr,
> > - image->ima_buffer_size);
> > + ima_kexec_buffer = kimage_map_segment(image, image->ima_segment_index);
> > if (!ima_kexec_buffer) {
> > pr_err("Could not map measurements buffer.\n");
> > return;
> > --
> > 2.49.0
>
^ 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