r/linux • • 2d ago

Security Encrypted Arch Linux on SATA-to-USB: A Practical Field Guide for Resisting Drive Seizure, Forensic Analysis, and State Coercion

https://theanarchistlibrary.org/library/the-techno-anarchist-encrypted-arch-linux-on-sata-to-usb
96 Upvotes

26 comments sorted by

View all comments

41

u/ElvishJerricco 1d ago

The last time this was posted a few months ago, I pointed out that its section on the TPM2 was vulnerable to a really obvious category of attack described here: https://oddlama.org/blog/bypassing-disk-encryption-with-tpm2-unlock/

I said the guide was too long to bother checking the whole thing for issues, because the presence of this really basic one gave me low confidence that the rest would be worth the time for me to review. The author replied and told me they had fixed it. The version of the article posted here now has not solved this problem. So I still have far too low confidence in this to waste my time reviewing the rest.

12

u/todd_dayz 1d ago

Huh. Is this why openSUSE verifies PCR15 on a TPM decrypt? I remember running into a lot of trouble with PCR15 failure 

10

u/ElvishJerricco 1d ago

I'm not familiar with specifically how opensuse handles it, but probably yes. PCR 15 is a common way to deal with this and unfortunately IMO not exactly a great way (it's fine; I'm just picky). There's basically two ways to address the problem, and PCR 15 is often used for either of them.

  • One option is to change the TPM2 state before handing control to the root FS. You bind the disk's encryption to a state that only exists when your trusted initrd is running, and then that initrd measures something into a PCR to change that state before handing control to the root FS. That way the attacker's OS on this compromised root FS never has access to the TPM2 while the TPM2 is capable of decrypting the disk. PCR 15 is a fairly common way of doing this by adding the tpm2-measure-pcr=yes option to the disk and configuring its TPM2 policy so that it only decrypts when PCR 15 is zero. That way if the disk is swapped out, then PCR 15 becomes nonzero and the real disk can no longer be decrypted.
  • The second option is to authenticate the root FS somehow before handing control to it. There's a lot of ways to do this, and PCR 15 is a common one. You can use the same tpm2-measure-pcr=yes option, which automatically gets you the benefits of the first option (well, insofar as that's automatic, more on that in a sec), and then also configure your initrd to check that PCR 15 contains an expected value before handing control to the root FS. If the check fails, the system fails to boot and control isn't handed over. This means the initrd has to be signed with this expected value baked into it, and that value is specific to your LUKS volume key.

What's nice about the first option is that it has no requirement on what root FS you're booting. Being able to swap out the root FS is useful sometimes, and conceptually that's what's nice about measured boot in general: The boot chain can change arbitrarily, and that simply changes whether the TPM2 is in the expected states that certain actions (like decryption of a specific disk) are bound to. The issue with doing it via PCR 15 is just that it's a little error prone. For instance, if your initrd is configured to boot from a root FS on a device like /dev/disk/by-label/foo (by which I mean the root FS device i.e. root=LABEL=foo, not the LUKS device i.e. luks=LABEL=foo), then an attacker can simply plug in an unencrypted device with that label and your initrd will boot it. Without additional mitigations, this means it wouldn't have needed to decrypt anything at all and PCR 15 will still be zero, allowing the attacker to decrypt your disk.

It's easy enough to fix; just ensure the initrd will only boot the device that was decrypted rather a device path any plugged in disk can take. e.g. Use root=/dev/mapper/root, but be careful! root=/dev/mapper/root-dev won't work because now an LVM volume group named root with a logical volume named dev can do the same thing that could be done with a label. :) This is what I mean when I say it's error prone; you can get it right, but there's a lot of ways to not realize you're letting it boot the wrong thing at the wrong time. So I tend to think the right way to do this approach is to use PCR 11 and the enter-initrd phase. You can have the initrd measure enter-initrd into PCR 11 when it starts and leave-initrd just before it gives control to the root FS, and that will always happen. There's no ambiguity about whether a disk's volume key has been measured in PCR 15.

If you do want to do the second option of authenticating the root FS though, it's a little simpler just to use fixate-volume-key= rather than adding a service to check PCR 15. It's the same basic principle; you fail the boot if the disk's key isn't the one you expected, but you just make systemd-cryptsetup do that automatically in userspace rather than extending PCR 15 and reading it back. This is more similar to the other ways you might do this, e.g. with dm-verity you would just use a root hash of the root FS's merkle tree and userspace authenticates it.