My issue:
Encrypted a partition with LUKS, added the appropriate entry to /etc/crypttab so that systemd would generate a unit file for it, and used systemd-cryptenroll with tpm2-device=auto to enroll it for auto unlock with the default TPM PCR 7. On boot, volume would not unlock, with the following in the journal:
systemd-cryptsetup[1144]: Set cipher aes, mode xts-plain64, key size 512 bits for device /dev/sda1.
systemd-cryptsetup[1144]: Automatically discovered security TPM2 token unlocks volume.
systemd-cryptsetup[1144]: WARNING:esys:src/tss2-esys/api/Esys_Unseal.c:295:Esys_Unseal_Finish() Received TPM Error
systemd-cryptsetup[1144]: ERROR:esys:src/tss2-esys/api/Esys_Unseal.c:98:Esys_Unseal() Esys Finish ErrorCode (0x00000128)
systemd-cryptsetup[1144]: Failed to unseal HMAC key in TPM: tpm:error(2.0): PCR have changed since checked
systemd[1]: systemd-cryptsetup@whatever.service: Main process exited, code=exited, status=1/FAILURE
Github issue (filed against systemd 251.4):
Failed to unseal HMAC key in TPM: tpm:error(2.0): PCR have changed since checked
Github PR (adopted into system 253):
cryptsetup: retry TPM2 unseal operation if it fails with TPM2_RC_PCR_CHANGED
Ubuntu bug report requesting it to be backported:
Intermittent problem accessing TPM during 22.04 boot
My first attempt was to adopt the logic from the PR onto the current systemd-249.11 that comes with Ubuntu 22.04. That did not work, probably can't work. I tried. Repeated attempts to retry TPM operations just lead to more errors.
I noticed that after OS startup, although the systemd-cryptsetup units had failed, I could manually start the service with systemctl start systemd-cryptsetup@whatever.service. I decided a better effort would be to have systemd-cryptsetup-generator craft the unit files in a way that caused them to retry.
Disclaimer: I've never made a custom Debian package before
Install dependencies for building packages:
sudo apt install build-essential devscripts quilt checkinstall
Make a directory to hold the resulting packages:
mkdir crypt-fix && cd crypt-fix
Download latest systemd sources into subdirectory and switch to it:
apt-get source systemd
cd systemd-249.11
Create patch file from cryptsetup-restart.patch attached to this gist. And append the name of the patch to the series file:
cat > debian/patches/cryptsetup-restart.patch <<EOF
{{ contents }}
EOF
echo "cryptsetup-restart.patch" >> debian/patches/series
Use quilt to apply the patch:
quilt push
quilt refresh
Set environment variables with your information:
export DEBEMAIL="<bnabholz@gmail.com>"
export DEBFULLNAME="Brad Nabholz"
Use debchange (dch) to add non-maintainer release notes:
dch -n "systemd-cryptsetup unit files should auto retry"
debchange will increment the version from (at the time of this writing) 249.11-0ubuntu3.12 to 249.11-0ubuntu3.13.
Finally use debuild to build the new packages, which will be in the parent folder (crypt-fix):
debuild -us -uc
The arguments -us and -uc skip signing of the source package and changes file, as indicated in man dpkg-buildpackage.
Now there are 21 .deb packages in crypt-fix:
libnss-myhostname_249.11-0ubuntu3.13_amd64.deb
libnss-mymachines_249.11-0ubuntu3.13_amd64.deb
libnss-resolve_249.11-0ubuntu3.13_amd64.deb
libnss-systemd_249.11-0ubuntu3.13_amd64.deb
libpam-systemd_249.11-0ubuntu3.13_amd64.deb
libsystemd0_249.11-0ubuntu3.13_amd64.deb
libsystemd-dev_249.11-0ubuntu3.13_amd64.deb
libudev1_249.11-0ubuntu3.13_amd64.deb
libudev-dev_249.11-0ubuntu3.13_amd64.deb
systemd_249.11-0ubuntu3.13_amd64.deb
systemd-container_249.11-0ubuntu3.13_amd64.deb
systemd-oomd_249.11-0ubuntu3.13_amd64.deb
systemd-repart_249.11-0ubuntu3.13_amd64.deb
systemd-sysv_249.11-0ubuntu3.13_amd64.deb
systemd-tests_249.11-0ubuntu3.13_amd64.deb
systemd-timesyncd_249.11-0ubuntu3.13_amd64.deb
udev_249.11-0ubuntu3.13_amd64.deb
On a default Ubuntu installation, the following packages are not installed:
systemd-coredump
systemd-journal-remote
systemd-standalone-sysusers
systemd-standalone-tmpfiles
Those can be removed:
rm *coredump* *journal* *standalone*
And the 17 remaining packages installed with:
sudo dpkg -i *.deb
Immediately after installation (but even before reboot) you can see the effect on the cryptsetup unit files, with the addition of StartLimitIntervalSec=20, StartLimitBurst=5, Restart=on-failure, and RestartSec=5:
cat /run/systemd/generator/systemd-cryptsetup@whatever.service
# Automatically generated by systemd-cryptsetup-generator
[Unit]
Description=Cryptography Setup for %I
Documentation=man:crypttab(5) man:systemd-cryptsetup-generator(8) man:systemd-cryptsetup@.service(8)
SourcePath=/etc/crypttab
DefaultDependencies=no
IgnoreOnIsolate=true
After=cryptsetup-pre.target systemd-udevd-kernel.socket
Before=blockdev@dev-mapper-%i.target
Wants=blockdev@dev-mapper-%i.target
StartLimitIntervalSec=20
StartLimitBurst=5
Conflicts=umount.target
BindsTo=dev-sda1.device
After=dev-sda1.device
Before=umount.target
[Service]
Type=oneshot
RemainAfterExit=yes
Restart=on-failure
RestartSec=5
TimeoutSec=0
KeyringMode=shared
OOMScoreAdjust=500
ExecStart=/lib/systemd/systemd-cryptsetup attach 'whatever' '/dev/sda1' 'none' 'nofail,tpm2-device=auto'
ExecStop=/lib/systemd/systemd-cryptsetup detach 'whatever'
Reboot the system. systemd-cryptsetup services should initially fail, then try again after 5 seconds, then succeed. The journal for the unit will look like this:
-- Boot 0123456789abcdef0123456789abcdef --
00:00:06 swerver systemd[1]: Starting Cryptography Setup for whatever...
00:00:06 swerver systemd-cryptsetup[1145]: Set cipher aes, mode xts-plain64, key size 512 bits for device /dev/sda1.
00:00:06 swerver systemd-cryptsetup[1145]: Automatically discovered security TPM2 token unlocks volume.
00:00:06 swerver systemd-cryptsetup[1145]: WARNING:esys:src/tss2-esys/api/Esys_Unseal.c:295:Esys_Unseal_Finish() Received TPM Error
00:00:06 swerver systemd-cryptsetup[1145]: ERROR:esys:src/tss2-esys/api/Esys_Unseal.c:98:Esys_Unseal() Esys Finish ErrorCode (0x00000128)
00:00:06 swerver systemd-cryptsetup[1145]: Failed to unseal HMAC key in TPM: tpm:error(2.0): PCR have changed since checked
00:00:07 swerver systemd[1]: systemd-cryptsetup@whatever.service: Main process exited, code=exited, status=1/FAILURE
00:00:07 swerver systemd[1]: systemd-cryptsetup@whatever.service: Failed with result 'exit-code'.
00:00:07 swerver systemd[1]: Failed to start Cryptography Setup for whatever.
00:00:12 swerver systemd[1]: systemd-cryptsetup@whatever.service: Scheduled restart job, restart counter is at 1.
00:00:12 swerver systemd[1]: Stopped Cryptography Setup for whatever.
00:00:12 swerver systemd[1]: Starting Cryptography Setup for whatever...
00:00:12 swerver systemd-cryptsetup[1227]: Set cipher aes, mode xts-plain64, key size 512 bits for device /dev/sda1.
00:00:12 swerver systemd-cryptsetup[1227]: Automatically discovered security TPM2 token unlocks volume.
00:00:13 swerver systemd[1]: Finished Cryptography Setup for whatever.
This will be good enough to get the encrypted volumes mapped for whatever else is needed, mounting through /etc/fstab, joining a volume group through LVM, etc.