[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <d7418d0afa696b8da67e4f25fd0dc1b9d6fd908f.camel@huaweicloud.com>
Date: Thu, 11 Dec 2025 10:56:22 +0100
From: Roberto Sassu <roberto.sassu@...weicloud.com>
To: Gregory Lumen <gregorylumen@...ux.microsoft.com>
Cc: corbet@....net, zohar@...ux.ibm.com, dmitry.kasatkin@...il.com,
eric.snowberg@...cle.com, paul@...l-moore.com, jmorris@...ei.org,
serge@...lyn.com, linux-doc@...r.kernel.org, linux-kernel@...r.kernel.org,
linux-integrity@...r.kernel.org, linux-security-module@...r.kernel.org,
chenste@...ux.microsoft.com, nramas@...ux.microsoft.com, Roberto Sassu
<roberto.sassu@...wei.com>
Subject: Re: [RFC][PATCH] ima: Add support for staging measurements for
deletion
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.
> - 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
Powered by blists - more mailing lists