clevis
clevis copied to clipboard
disable dangerous Clevis TPM pin retrieval in recovery mode
Since Clevis utilizes the TPM auto-unlock in recovery mode the same way it does in a regular bootup, this creates a vulnerability where someone with physical access could bypass the OS login screen and instead boot into recovery, where Clevis utilizes TPM to unlock the encrypted volume, and the user can simply select "Root" in the recovery menu and gain root access.
Is there a way to instruct Clevis not to run during recovery mode?

Clevis auto-unlocks the disk using the TPM pin..

select "root"

root access obtained without having to know an encryption passphrase or login password

I confirm the issue (I originally reported it).
Can you try with {"pcr_ids": "0,1,2,3,5,7,8,9"}?
confirmed that a different PCR config actually fixes this.
we needed to add in PCR4 {"pcr_ids": "0,1,2,4"} to safeguard against different changes in boot manager states.
I think this is a good thing to add to the readme.md (I can make a PR if we think that's a sufficient route forward), so that users relying on TPM pins aren't caught flat-footed with their PCR configs.
Huge thanks to getting us pointed in the right direction, @savchenko !
@cole-seph-work , perhaps consider 5, 7 and 8 as well?
P.S. You might find this useful: https://github.com/savchenko/debian/wiki/tpm2-@-libvirt,-Clevis
thanks @savchenko , after some more digging, it seems that {"pcr_ids": "0,1,8"} fit our use case better. ID's 5 and 7 didn't seem to be quite what we were looking for in our case. This configuration seems to undo the vulnerability in the body of this issue but also doesn't trigger a tpm lockout in cases where users upgrade Ubuntu or their kernel version. PCR ID 4 seems to successfully address the original issue but it does trigger a tpm lockout when users upgrade Ubuntu or their kernel versions.
summary of fix: I needed to change PCR ID's to include PCR ID "8"
The reading you've linked is excellent and helps to understand this platform more.
@savchenko after using a machine for some time with the increased number of PCR ID's (in this case, either 0,1,8 or 0,1,4), I've found that both of these combinations can still trigger unexpected lockouts, depending on what updates are shipped with Linux/Ubuntu. For this reason, I am still requesting that there be a way to completely disable TPM unlocking when in recovery mode.
I'm happy to test/contribute for this issue. If you could point me to where in the repo I might want to get started, that would be awesome
0,1,4
What's the machine spec and can you reproduce this reliably? Ping @sergio-correia re. contribution.
0,1,4 is rather benign combination, are you booting with CSM disabled?
This occurs across several different Lenovo models (X1, P1) running Ubuntu 20.04 LTS with TPM 2.0 enabled with Clevis. CSM is disabled on these machines. We can reliably reproduce this as often as we want.
The reason for the PCR ID's being rather benign is that I am trying to limit the amount of lockouts that occur due to unexpected state changes (keep things feeling stable), but again, just don't want the TPM to unlock the volume in recovery
Hold on. Why not to set password on GRUB?
If you set a GRUB2 password you are now prompted for a GRUB password at every bootup, which yes, resolves this vulnerability, but isn't a worthwhile solution since you are right back to having to enter two different passwords at bootup (GRUB and login, vs recovery key and login). In this case, the encryption key is going to be the stronger safeguard anyway. GRUB2 passwords also do not appear to be very automate-able at-scale.
I've also looked at modifying the recovery menu root selection file to require a password, but I'm hesitant to rely on this never changing long-term, since Ubuntu/Linux could easily push an update that overwrites it. This would also be a weaker safeguard than full disk encryption. It would resolve this issue but leave a weak backdoor, in my opinion.
Which is why I keep coming back to changing Clevis itself as the best long-term solution.
@sergio-correia 👋 if we wanted to look at contributing to clevis in order to disable it from auto-unlocking volumes during recovery boot, can you point us in the right direction? (Which files or any background necessary) ?
@sergio-correia wave if we wanted to look at contributing to clevis in order to disable it from auto-unlocking volumes during recovery boot, can you point us in the right direction? (Which files or any background necessary) ?
Probably we can check for specific params in /proc/cmdline (maybe single and/or recovery?) and exit in those cases, in those scripts under initramfs-tools/scripts. @dannf: would you have some insights here?
A user can edit the GRUB command line, or bypass GRUB altogether. If you enable a TPM pin, it seems like you're just taking the risk that an attacker will not have physical access.
@dannf, thanks for your thoughts. While I understand your perspective for a single-user use-case of Clevis, I think larger organizations are always going to want the benefit of storing keys in something like a TPM, if possible, rather than hoping employees will manage their own recovery pins/keys securely. To me, if you flip the situation and ask yourself: "Why would you want clevis to unlock an encrypted volume in recovery mode?", I personally at least can't think of many strong answers there. I understand the fix might basically just be adding levels of obfuscation, but that still seems like a more secure approach than leaving this unaddressed.
I should be clear that I've never used TPM-based disk encryption, so I don't really understand the guarantees. Recovery mode is enabled by a kernel command line argument (single). It appears that the TPM is able to seal the kernel command line arguments. If this is in use, and single is found, shouldn't that prevent decryption?
Just to be sure, I went back and tried extending PCR ID's 13, 14, and 12, both in combinations and by themselves (in addition to the other minimal PCR ID's we've already extended). These combinations still allowed for the TPM to unlock the volume during recovery. I can add that there are some PCR's that can be extended so that booting into recovery does always cause a lockout, but it seems these ID's carry unintended consequences that extend beyond just causing a lockout when a user boots into recovery, which is unwanted and causes disruptions to users.
PCR ID 8 appears to store the kernel command line hash (per https://wiki.archlinux.org/title/Trusted_Platform_Module). I tried sealing some data to that hash:
$ echo secret > PT
$ cat /proc/cmdline
BOOT_IMAGE=/boot/vmlinuz-5.13.0-19-generic root=LABEL=cloudimg-rootfs ro console=tty1 console=ttyS0
$ sudo clevis encrypt tpm2 '{"pcr_bank":"sha1","pcr_ids":"8"}' < PT > JWE
$ sudo clevis decrypt < JWE
secret
After rebooting, and leaving the kernel command line args the same, I was able to continue to decrypt:
$ cat /proc/cmdline
BOOT_IMAGE=/boot/vmlinuz-5.13.0-19-generic root=LABEL=cloudimg-rootfs ro console=tty1 console=ttyS0
$ sudo clevis decrypt < JWE
secret
I then rebooted and added foo to the kernel command line arguments via the GRUB menu and retried:
$ cat /proc/cmdline
BOOT_IMAGE=/boot/vmlinuz-5.13.0-19-generic root=LABEL=cloudimg-rootfs ro console=tty1 console=ttyS0 foo
$ sudo clevis decrypt < JWE
WARNING:esys:src/tss2-esys/api/Esys_Unseal.c:295:Esys_Unseal_Finish() Received TPM Error
ERROR:esys:src/tss2-esys/api/Esys_Unseal.c:98:Esys_Unseal() Esys Finish ErrorCode (0x0000099d)
ERROR: Esys_Unseal(0x99D) - tpm:session(1):a policy check failed
ERROR: Unable to run tpm2_unseal
Unsealing jwk from TPM failed!
This should hold for recovery mode, because recovery mode has a different kernel command line:
ubuntu@ubuntu:~$ cat /proc/cmdline
BOOT_IMAGE=/boot/vmlinuz-5.13.0-19-generic root=LABEL=cloudimg-rootfs ro console=tty1 console=ttyS0 recovery nomodeset
ubuntu@ubuntu:~$ sudo clevis decrypt < JWE
WARNING:esys:src/tss2-esys/api/Esys_Unseal.c:295:Esys_Unseal_Finish() Received TPM Error
ERROR:esys:src/tss2-esys/api/Esys_Unseal.c:98:Esys_Unseal() Esys Finish ErrorCode (0x0000099d)
ERROR: Esys_Unseal(0x99D) - tpm:session(1):a policy check failed
ERROR: Unable to run tpm2_unseal
Unsealing jwk from TPM failed!
If it's not, I wonder if something is going wrong with seeding PCR ID 8.
PCR ID 8 appears to store the kernel command line hash (per https://wiki.archlinux.org/title/Trusted_Platform_Module).
This should hold for recovery mode, because recovery mode has a different kernel command line:
If it's not, I wonder if something is going wrong with seeding PCR ID 8.
Won't that also mean, though, that each upgraded kernel release will fail to unlock the first time it's booted? Each kernel has a unique command line (as it contains the release string), and IIUC you can't pre-seal to the new command line immediately after install, because at that point the system is still running under the old kernel and its corresponding unique command line.
Thanks for doing that research, @dannf.
@ferdnyc , I believe your theory is correct. So, we had extended PCR ID 8 in order to resolve this original issue. This was fine until a new kernel release shipped and was installed on devices, at which point, we had many lockouts to deal with. So we resolved this initial "recovery" issue only to create an entirely new issue for ourselves.
This is why I'm stating that in my opinion, this problem should be dealt with in the Clevis code itself, rather than extending PCR ID's for a more sensitive TPM lockout.
Because even if you are running Clevis on a personal machine with TPM PCR ID 8 extended, I'd argue that these lockouts may deter users from running important security updates that are bundled with kernel upgrades, as users may begin to associate that "Every time I run updates, I get locked out. So I won't run updates right now." etc. etc.
@ferdnyc @cole-seph-work I do agree that upgrading kernels with measured boot is not a smooth story - I'm not sure what work is being done in that area. But if you're unable to guarantee a secure boot chain through to the kernel command line, I fail to see what clevis can do to prevent volume unlocking. Is obfuscation/security-by-obscurity (as implied in https://github.com/latchset/clevis/issues/331#issuecomment-950229426) really what you're after? If so, I think it does it disservice to users to give the impression of security where none exists.
This was interesting reading.
I think @dannf is correct, you should use the correct PCR for this [ probably as suggested PCR ID 8 ]
To prevent breakage on kernel upgrades etc, you implement something that replays the TPM event log for the registers and works what the new registers would be based on a new executable or new kernel commandline hash.
There is a project which does that here: https://github.com/grawity/tpm_futurepcr
However, you would probably then need a feature in clevis to bind against user provided PCR values. That bit is probably pretty straight forward to implement, according tot he README in the tpm_futurepcr project.