On Tue, 2025-03-18 at 16:55 +0100, Nicolai Stange wrote: > Mimi Zohar <zohar@xxxxxxxxxxxxx> writes: > > > On Tue, 2025-03-18 at 11:26 +0100, Nicolai Stange wrote: > > > Mimi Zohar <zohar@xxxxxxxxxxxxx> writes: > > > > > > > On Thu, 2025-03-13 at 18:33 +0100, Nicolai Stange wrote: > > > > > Normally IMA would extend a template hash of each bank's associated > > > > > algorithm into a PCR. However, if a bank's hash algorithm is unavailable > > > > > to the kernel at IMA init time, it would fallback to extending padded > > > > > SHA1 hashes instead. > > > > > > > > > > That is, if e.g. SHA-256 was missing at IMA init, it would extend padded > > > > > SHA1 template hashes into a PCR's SHA-256 bank. > > > > > > > > > > The ima_measurement command (marked as experimental) from ima-evm-utils > > > > > would accordingly try both variants when attempting to verify a measurement > > > > > list against PCRs. keylime OTOH doesn't seem to -- it expects the template > > > > > hash type to match the PCR bank algorithm. I would argue that for the > > > > > latter case, the fallback scheme could potentially cause hard to debug > > > > > verification failures. > > > > > > > > > > There's another problem with the fallback scheme: right now, SHA-1 > > > > > availability is a hard requirement for IMA, and it would be good for a > > > > > number of reasons to get rid of that. However, if SHA-1 is not available to > > > > > the kernel, it can hardly provide padded SHA-1 template hashes for PCR > > > > > banks with unsupported algos. > > > > > > > > > > There are several more or less reasonable alternatives possible, among > > > > > them are: > > > > > a.) Instead of padded SHA-1, use padded/truncated ima_hash template > > > > > hashes. > > > > > b.) Record every event as a violation, i.e. extend unsupported banks > > > > > with 0xffs. > > > > > c.) Don't extend unsupported banks at all. > > > > > d.) Invalidate unsupported banks only once (e.g. with 0xffs) at first > > > > > use. > > > > > > > > > > a.) would make verification from tools like ima_measurement nearly > > > > > impossible, as it would have to guess or somehow determine ima_hash. > > > > > b.) would still put an significant and unnecessary burden on tools like > > > > > ima_measurement, because it would then have to exercise three > > > > > possible variants on the measurement list: > > > > > - the template hash matches the bank algorithm, > > > > > - the template hash is padded SHA-1, > > > > > - the template hash is all-ones. > > > > > c.) is a security risk, because the bank would validate an empty > > > > > measurement list. > > > > > > > > > > AFAICS, d.) is the best option to proceed, as it allows for determining > > > > > from the PCR bank value in O(1) whether the bank had been maintained by > > > > > IMA or not and also, it would not validate any measurement list (except > > > > > one with a single violation entry at the head). > > > > > > > > > > Hi Mimi, > > > > > > > What a pleasure reviewing your patch set. Nicely organized. Well written patch > > > > descriptions. > > > > > > thank you :) > > > > > > > Currently with the SHA1 hash algorithm, whether it is being extended into the > > > > TPM or not, the measurement list is complete. Relying on the ima_hash in the > > > > current kernel and the subsequent kexec'ed kernel should be fine, assuming if > > > > they're different hash algorithms both TPM banks are enabled. Otherwise, the > > > > measurement lists will be incomplete. > > > > > > Yes. However with your comment I'm now realizing there's an issue if the > > > set of supported hash algorithms differs between the previous and the > > > next, kexeced kernel -- something I admittedly hadn't thought of before. > > > > > > The current behavior as implemented in this RFC is that an unsupported > > > PCR bank would get invalidated *once* upon first use, i.e. extended once > > > with e.g. all 0xFEs. (Note that the actual patch implements invalidation > > > with all 0xFFs, for the choice of the exact invalidation value see > > > below). The idea is that > > > a.) tools could easily recognize this by comparing the PCR bank value > > > against constant HASH(00 .. 00 | fe ... fe) > > > b.) and they would fail to verify any non-trivial event log against such > > > a PCR bank if they did not do that comparison ahead. > > > > > > In order to implement this invalidate-once logic, there's that > > > ima_extended_pcrs_mask you asked about in reply to [3/7], the > > > preparatory patch for [4/7] ("ima: track the set of PCRs ever > > > extended"). As the set of PCRs ever to be found in any policy rule > > > cannot be predicted, their unsupported banks cannot get invalidated once > > > at __init. Hence this inalidate-at-first-extend logic, which needs that > > > tracking of PCRs ever extended as maintained in ima_extended_pcrs_mask. > > > > > > Upon kexec, the current patchset attempts to restore the > > > ima_extended_pcrs_mask from the previous kernel by walking through the > > > measurement list, setting a bit for each PCR found in any event. > > > > > > Now consider the following: > > > - some hash algorithm is supported by the initially booted kernel, > > > - but not in the subsequently kexeced one. > > > > > > The initially booted kernel would not invalidate the given hash > > > algorithm's bank for any PCR, and the kexeced one would neither, because > > > it would restore the ima_extended_pcrs_mask from the initially booted > > > one. However, the kexeced kernel would also not extend any further > > > events into the now unsupported PCR banks then. That means that these > > > PCR banks would happily verify a measurement list truncated to the point > > > before the kexec, which is of course bad. > > > > > > > > > I can see two ways around this: > > > a.) Give up on the invalidate-once scheme, unconditionally invalidate > > > unsupported banks (with 0xfe .. fe) for every new measurement list > > > entry. > > > > > > b.) Make the kexeced kernel to read back PCR banks it doesn't support > > > from the TPM at __init and see if they had been invalidated by the > > > previous kernel. Set the bit in ima_extended_pcrs_mask *only* if so. > > > That is, invalidate unsupported and not yet invalidated PCR banks > > > upon first use. > > > > > > Also, make it read PCR banks it does support and refrain from > > > further extending any found to have been invalidated before (for all > > > PCRs mentioned in the measurement list). That is, leave previously > > > invalidated PCR banks alone. > > > > > > Going with a.) would mean that verifiers would not be able to recognize > > > in O(1) anymore that some bank was unsupported and had not been > > > maintained by the kernel. It would still be possible to figure in linear > > > time whether neither of the kernels in a kexec chain covered by a single > > > measurement list did support a given PCR bank hash. > > > > > > For implementing b.), one would have to store a table of precomputed > > > HASH(00 .. 00 | fe .. fe) values for every recognized hash possible in > > > .rodata for comparison purposes, i.e. for every entry in > > > tpm2_hash_map[5] at least -- after all, the whole point is to deal with > > > hashes for which no implementation is available to the kernel, so these > > > values cannot get computed dynamically at runtime. > > > > > > With that, if the initially booted kernel did not support some hash > > > algorithm, it would be recognizable by verifiers in O(1) time. > > > > > > If the initially booted kernel did support a given hash, but a > > > subsequent kernel in the kexec chain would not, the PCR would get > > > invalidated by the latter. This sitatuation cannot be detected at all > > > (with reasonable effort) from the final PCR hash bank value alone and > > > verification against it would fail then. Perhaps it's noteworthy that > > > this is true with any possible scheme, including the currently > > > implemented one extending with padded SHA1 into unsupported banks. > > > > > > > > > I think that the decision about what to do now boils down to whether > > > there's any value in verifiers being able to tell that a PCR bank had > > > been unsupported and not been maintained rather than to simply fail its > > > verification if attempted. > > > > > > If it is not important, or linear time + the additional implementation > > > complexity burden at the verifier side is acceptable, the much simpler > > > a.) would do. > > > > > > Otherwise I could give implementing b.) a try and see how bad the > > > resulting code would get. > > > > > > What do you think? > > > > Let me try to summarize 'b'. The initial unsupported hash algorithms would > > continue to be unsupported in subsequent kexec's. However this does not address > > the case where the initial kernel image supported a hash algorithm, but the > > subsequent kexec'ed image does not. The TPM bank has already been extended with > > other values. In this case, like the original violation the attestation service > > would not verify. If I'm understanding it correctly, 'b' is thus a partial > > solution. > > Yes, that all matches exactly what I was trying to say. FWIW, I might be > way too naive, but I would expect two categories of existing verifier > behaviors: > - "Real" ones like keylime or so, which are being asked to verify > against a single specific bank and the result is either yes or no with > no inbetween. In particular, these wouldn't fallback to checking > whether something else like padded SHA1s would perhaps verify. > - The ones more in the development/debugging/testsuite realm, which > would attempt to verify against all banks and fail (the test?) if any > does not verify. These would try harder to avoid false negatives by > testing for the alternatives like padded SHA1s as well. I suppose > ima-evm-utils' ima_measurement would qualify as such one. > > For the first class, simply invalidating the unsupported PCR banks > somehow, i.e. option a.), is good enough. For the second kind however, > the question is whether something like b.) would be helpful and the > additional complexity on the kernel side warranted. But agreed, it's a > partial and best-effort solution. If one kexecs into a kernel with a > proper subset of supported TPM bank hashes, it wouldnt't work. Refer to comment on "Replacing the "Kconfig select". > > > My concern with 'b' is the ability to read the multiple TPM bank PCRs so early > > during kernel initialization. Will it succeed? If it does succeed, will it > > introduce initialization delays? > > As the boot aggregate gets extended already at that point in time > (IIRC), I'd expect that reading the PCRs would probably succeed as > well. For the delays imposed on the kexec restore path -- I can't tell > unfortunately. But I would only do it on kexec restore if the > measurement list is non-empty anyway, so systems not having IMA enabled > or ones which wouldn't kexec are not affected. Ok > > > > FYI, because the IMA Kconfig selects SHA1, we're guaranteed that SHA1 exists in > > the kernel and the subsequent kexec'ed kernel. For this reason we're guaranteed > > that the measurement list is complete. The simplest solution, not necessarily > > the best, would be to punt the problem for the time being by replacing the > > "select" with a different hash algorithm. > > Yes, that would work as well. IIUC, it would mean that we would > e.g. extend truncated SHA-256 template hashes into a SHA-1 bank, right? > However, since no existing tool like 'ima_measurement' is expecting > that, and would fail a verification then, I'm currently struggling to > see the advantage over just doing a.) and invalidating the PCR banks > with a fixed value right away? Replacing the "Kconfig select" has more to do with having at least one guaranteed complete measurement list. I'm fine with extending a TPM bank with an unknown kernel hash algorithm violation (either option a or b). > > > > > This patch set introduces a new definition of integrity violation. Previously it > > > > was limited to open-writers and ToMToU integrity violations. Now it could also > > > > mean no kernel hash algorithm available. Unfortunately some attestation > > > > services simply ignore integrity violations. > > > > > > Yeah, there's indeed an ambiguity. I think the right thing to do is to > > > make measurement lists unverifiable against unsupported banks and would > > > propose to use 0xfe ... fe for the associated invalidations instead of > > > the 0xff .. ff used for violation events already. > > > > I just realized that unlike the existing open-writers/ToMToU violations, by > > definition the new unsupported bank violation would not be included in the > > measurement list, but just extended into the TPM. > > That's true, but when invalidating unsupported banks with a single ff > ... ff, one could successfully verify a measurement list having only a > single violation entry against an invalidated bank AFAICS. I think it > would be more robust to use a different constant for the invalidation. Agreed. thanks, Mimi > > > > > > > So implement d.). As it potentially breaks existing userspace, i.e. > > > > > the current implementation of ima_measurement, put it behind a Kconfig > > > > > option, "IMA_COMPAT_FALLBACK_TPM_EXTEND". If set to "y", the original > > > > > behavior of extending with padded SHA-1 is retained. Otherwise the new > > > > > scheme to invalidate unsupported PCR banks once upon their first extension > > > > > from IMA is implemented instead. As ima_measurement is marked as > > > > > experimental and I find it unlikely that other existing tools depend on > > > > > the padded SHA-1 fallback scheme, make the IMA_COMPAT_FALLBACK_TPM_EXTEND > > > > > Kconfig option default to "n". > > > > > > > > > > For IMA_COMPAT_FALLBACK_TPM_EXTEND=n, > > > > > - make ima_calc_field_array_hash() to fill the digests corresponding to > > > > > banks with unsupported hash algorithms with 0xffs, > > > > > - make ima_pcr_extend() to extend these into the unsupported PCR banks only > > > > > upon the PCR's first usage, skip them on subsequent updates and > > > > > - let ima_init_ima_crypto() help it with that by populating the new > > > > > ima_unsupported_tpm_banks_mask with one bit set for each bank with > > > > > an unavailable hash algorithm at init. > > > > > > > > > > [1] https://github.com/linux-integrity/ima-evm-utils > > > > > > > > > > Signed-off-by: Nicolai Stange <nstange@xxxxxxx> > > > > > --- > > > > > >