On Tue, Jun 16, 2026 at 04:50:37AM +0100, Daniel Golle wrote: > Hi Jarkko, > Hi James, > > first of all, sorry for hijacking a thread from 2 years ago. > > On Thu, Nov 14, 2024 at 12:34:30AM +0200, Jarkko Sakkinen wrote: > > On Wed Nov 13, 2024 at 8:12 PM EET, James Bottomley wrote: > > > > I think we might have to expect the NULL name to change on actual > > > > hibernation because unlike suspend to ram it does power off the TPM. > > > > > > I checked the code: we're coming in on the correct path to renew the > > > null seed after hibernation, so it should all work. The problem seems > > > to be that your TPM itself is doing something invalid because the name > > > we calculate for the primary key doesn't match what your TPM says it > > > should be. Absent some form of attack or bus integrity problem, that > > > shouldn't ever happen, so I'm even more curious to know why it worked > > > in 6.11.5 and before and whether current upstream works. > > > > > > I haven't found it yet, but I think the every 10s signature is because > > > the hibernation path is trying to restart the TPM device and won't take > > > no for an answer. > > > > My fix returned the behavior how it was before my earlier fix in this > > corner case (i.e. disable TPM). The issue has gone unnoticed before > > since it has emitted only a single klog entry. > > > > On suspend this has not happened to me so obvious deduction is that > > hibernate resets the null seed. > > > > Hibernate needs an addition a fix to disable bus encryption from kernel > > command-line completely, i.e. tpm.disable_integrity following the > > convention from my earlier fix [1]. > > I'd like to offer a way it might be resolvable with the null key after > all, without provisioning a persistent NV key -- by changing the > question from "re-derive the null primary and compare" to "inherit the > trust the resume has already established". > > Resume-from-hibernation is a TPM Restart (Shutdown(STATE) -> > Startup(CLEAR)), i.e. a firmware cold-init of the (f)TPM, after which > the boot/initramfs kernel establishes a fresh, genuine null primary. > In the common configuration (FDE with the resume/swap device inside > a TPM-sealed LUKS2 container) that same TPM has, moments earlier and > *before* the hibernation image is restored, cryptographically attested > itself by unsealing the resume device. A substituted or interposed TPM > cannot produce that unseal. > > So rather than letting the resumed kernel re-derive the null name, > find a mismatch and disable the chip, the boot kernel's > freshly-established and unseal-validated null primary could be > inherited by the resumed image. The existing null-seed TOFU model is > preserved; nothing new is provisioned. > > The gate is the unseal, and the adversary case shows why it is the > right gate: > > Malice swaps (or interposes on) the TPM while the machine is > hibernated, then leaves. Alice powers on. The initramfs attempts the > TPM unseal of the resume device; with a foreign TPM it fails, so > systemd-cryptsetup falls back to the passphrase, which Alice -- > seeing a prompt -- types. The disk opens and the system resumes. > > If trust were re-established here, Alice would have personally vouched > for Malice's TPM. But the unseal *failed*, so under this scheme > nothing is inherited and the chip stays fail-closed exactly as today. > The passphrase proves a human is present; it never proves the TPM is > the genuine one. > Hence: unseal succeeded -> inherit the validated null primary; > passphrase fallback -> trust is lost, stay disabled. > > This keeps the property the null-seed design wants -- an in-session > reset is not on the hibernate-restore path and is still caught -- > while removing the false positive only where the platform has already > re-attested the TPM. > > The hard parts, and where I'd value direction: > > - systemd-cryptsetup would need to signal "the resume device was > unsealed by the TPM this boot" (vs. the passphrase fallback). > This is per-resume runtime state; a static command-line parameter > (and obviously build-time config as well) cannot represent it. > > - the validated null primary has to cross the boot -> resumed memory > discontinuity (the initramfs kernel's state is overwritten by the > restored image). Boot and image kernel are the same binary, so > patching chip->null_key_name in the restored image is mechanically > possible; a small reserved/nosave hand-off area may be cleaner. > I don't know the hibernate path well enough to say which is right. > > It is admittedly cross-subsystem (tpm + pm/hibernate + > systemd/cryptsetup), which is presumably why it hasn't been done. > Compared with the persistent NV-key route > (tpm.integrity_key=<handle>): that avoids the carry-across but needs > the key provisioned and managed, and a persistent key's name no longer > changes on a genuine reset, so the implicit reset detection has to be > reconstructed. The null-key-inherit approach keeps the existing model > and defers "is this the same TPM?" to the unseal that has already > happened. > > Does this seem viable, or is there a reason the unseal-as-attestation > gate does not hold that I'm missing? > > (For motivation: on a firmware TPM -- Intel PTT here -- there is no > external bus to interpose, so the protection has no benefit on this > class of hardware at all, yet the legitimate hibernation power-cycle > still trips the disable. For fTPMs specifically, not enabling the > feature is arguably the better answer; but for discrete TPMs that > hibernate, a real solution seems a good idea if doable.)
I think this has at least changed since 2024: bootc container type of deployment is where you can realistically configure hibernate, and use it in a real application. > > > Cheers > > > Daniel BR, Jarkko
