On 12/11/2025 1:56 AM, Roberto Sassu wrote:
On Wed, 2025-12-10 at 11:12 -0800, Gregory Lumen wrote:
Roberto,

The proposed approach appears to be workable. However, if our primary goal
here is to enable UM to free kernel memory consumed by the IMA log with an
absolute minimum of kernel functionality/change, then I would argue that
the proposed Stage-then-delete approach still represents unnecessary
complexity when compared to a trim-to-N solution. Specifically:

- Any functional benefit offered through the introduction of a staged
measurement list could be equally achieved in UM with a trim-to-N solution
coupled with the proposed ima_measure_users counter for access locking.
Ok, let's quantify the complexity of each solution. Let's assume that
the IMA measurements list has M entries and you want to trim at N < M.

Staging:

1st. trim at N

(kernel)
1. list lock (write side) -> list replace (swap the heads) -> list unlock
2. read M -> file (file contains 0..M)
3. for each 0..M -> delete entry

(user)
1. for each 0..N in file -> replay PCR
2. trim at N (keep N + 1..M)


2nd. trim at O

(kernel)
1. list lock -> list replace (swap the heads) -> list unlock
2. read P -> file (file contains N + 1..P)
3. for each M + 1..P -> delete entry

(user)
1. for each N + 1..O in file -> replay PCR
2. trim at O (keep O + 1..P)



Trimming:

1st. trim at N

(kernel)
1. list lock (read side) -> for each 0..M -> read in file (file now contains 0..M) 
-> list unlock

(user)
1. for each 0..N -> replay PCR
2. discard N + 1..M

(kernel)

1. list lock (write side) -> for each 0..N -> trim -> list unlock


2nd. trim at O

(kernel)
1. list lock (read side) -> for each N + 1..P -> read in file (file now contains N 
+ 1..P) -> list unlock

(user)
1. for each N + 1..O -> replay PCR
2. discard O + 1..P

(kernel)

1. list lock (write side) -> for each N + 1..O -> trim -> list unlock


You can try to optimize it a bit by prematurely ending the reading
before M and P, and by replaying the PCR on a partial buffer.


But still:

I just swap list heads in the hot path (still need to do the same for
the hash table, postponed to later), and do the free later once there
is no contention with new measurements.

In your case you are taking the lock and walking the list two times,
once as a reader and once as a writer, and discarding measurements in
user space that you already have.

I think your solution is more complex.
This is not the case, please check the released version 2 of trim N entries patch as bellow:

[PATCH v2 0/1] Trim N entries of IMA event logs
<https://lore.kernel.org/linux-integrity/[email protected]/T/#t>


The following are the steps for trim N solution:
    User space reads list without lock
    User space decides to trim N entries and send command to kernel
    Kernel will lock the list use the same or less time as staged solution use

All work done.


- There exists a potential UM measurement-loss race condition introduced
by the staging functionality that would not exist with a trim-to-N
approach. (Occurs if a kexec call occurs after a UM agent has staged
measurements for deletion, but has not completed copying them to
userspace). This could be avoided by persisting staged measurements across
kexec calls at the cost of making the proposed change larger.
The solution is to coordinate the staging with kexec in user space.


Roberto



Reply via email to