On 02/07/2018 09:18 AM, Laszlo Ersek wrote:
On 02/07/18 14:51, Stefan Berger wrote:
On 01/10/2018 08:22 AM, Laszlo Ersek wrote:
On 01/09/18 20:02, Stefan Berger wrote:
Another twist is that Intel's EDK2 also implements this but the data structure layout is different and they use SMM + SMIs etc.
As I described in my investigation linked from https://bugzilla.tianocore.org/show_bug.cgi?id=594#c5, we should not include the Tcg2Smm driver in OVMF, for TPM enablement -- at least for the short & mid terms.
What does the Tcg2Smm driver do? In section (2f), I described that the driver installs two tables, "TPM2" and an "SSDT".
The TPM2 table from this driver is unneeded, since QEMU generates its own TPM2 table, which describes the TPM device's access method -- TIS+Cancel (method 6).
The SSDT from the driver is again unneeded. It provides (via the _DSM method) an ACPI-level API that the OS can use, for talking to the TPM device. An implementation detail of this ACPI method is that it raises an SMI, for entering the firmware at an elevated privilege level (= in SMM). Then, the actual TPM hardware manipulation, or even the TPM *software emulation*, is performed by the firmware, in SMM.
This approach is totally ill-suited for the QEMU virtualization stack. For starters, none of the firmware code exist -- as open source anyway -- that would actually handle such ACPI->SMM requests. Second, I'm sure we don't want to debug TPM software emulation running in SMM guest firmware, rather than an actual QEMU device model.
Once we have a real device model, accessed via IO ports and/or MMIO locations, perhaps in combination with request/response buffers allocated in guest RAM, the SMI/SMM implementation detail falls away completely. Our TPM emulation would attain its "privileged / protected" status simply by existing in the hypervisor (QEMU).
Regarding the SMI/SMM: I think it will be needed for the TPM Physical Presence interface where ACPI gets a code from the user that it sends to the firmware and the firmware acts upon next reboot. SMM stores this code in a UEFI variable (EDK2) to protect it from modules executed by UEFI. I was trying to use a memory area (PPI memory device) for storing this code but it would not give the same protection for UEFI compared to the variable. I suppose the reason is that UEFI can execute (untrusted) code that could manipulate this memory area and cause unwanted changes to the TPM upon reboot by for example writing a code for clearing the TPM. How 'safe' would the BIOS be or any path from the BIOS until the OS kernel takes over? Can untrusted code be executed by something like a BIOS module (vgabios.bin and the like) and mess with that memory area? A grub module?
Yes, this is a correct assessment in my view. SMM provides protection to platform firmware modules not only against the OS, but also against 3rd party firmware components, such as boot loaders, various UEFI applications, UEFI device drivers (loaded from disk or PCI card option ROM BARs), and such.
SMRAM and the writeable pflash chip are two pieces of emulated hardware whose (write) access is restricted to code executing in SMM.
This does not necessarily imply that QEMU should generate SMI-triggering AML methods for the guest. Instead, the sensitive writeable register block of the TPM chip that you added could be restricted to code executing in SMM, similarly to pflash:
... On the other hand, I do realize this would take custom SMM code, which is even worse than reusing the SMM variable service code.
Sigh, I *utterly* hate this. I maintain from my earlier email that generating ACPI for this in QEMU is ill-suited. Minimally, the TPM2 table will conflict between edk2 and QEMU. edk2 will be *both* missing code that's going to be necessary for the QEMU/OVMF use case, *and* it will contain code that either conflicts with or is not dynamic enough for the QEMU/OVMF use case.
One other complication is the memory area that EDK2 requires for exchanging of data ('that code' for example) between ACPI and SMM. It's hard coded to 0xFFFF 0000. However, with SeaBIOS I cannot use this memory and there's this comment here: 'src/fw/shadow.c:// On the emulators, the bios at 0xf0000 is also at 0xffff0000'.
So the point is SMM is needed for UEFI. QEMU would need to provide the ACPI code for it, which is basically a translation of the ACPI from EDK2 so that this could work.
To support SeaBIOS as well, we would have to be able to distinguish a BIOS from the UEFI on the QEMU level so that we could produce different ACPI
Yes and no,
(no SMI and different OperationRegion than 0xFFFF 0000 for SeaBIOS),
"yes" with regard to the SMM difference, "no" with regard to the operation region. We have an ACPI linker/loader command that makes the firmware basically just allocate memory, and we have two other ACPI linker/loader commands that (a) patch the allocation address into other ACPI artifacts, (b) return the allocation address to QEMU (for device emulation purposes), if necessary.
I thought about allowing the firmware to configure the memory region to use for the PPI interface. UEFI would say 0xFFFF 0000, SeaBIOS would choose some other area (0xFEF4 5000). Does the ACPI patcher handle this case or does the address patching have to be set up while building the tables in QEMU? If latter, then we would have to know in QEMU whether it's going to be BIOS or UEFI as firmware. I have tried a lot of things in the recent past, but I forgot whether this type of patching is possible.
*if* on a system with a BIOS the memory area can be considered to be safe (like that EDK2 variable). Otherwise I am afraid it's better to not support it in SeaBIOS and provide all necessary early TPM 2 operations via user interaction with the menu only.
FWIW, to my knowledge, the RH boot loader team is only interested in TPM for UEFI.
Does Windows utilize TPM PPI when booted on a traditional BIOS computer?
Not sure. Linux for sure doesn't care whether there's a BIOS or UEFI running underneath.
I think your analysis is correct, about SMM. Previously I missed that specifically the Physical Presence operations needed protection.
My operating knowledge about the TPM had been that
Components measure stuff into PCRs, and if any untrusted agent messes with those measurements, for example by directly writing to the PCRs, then the TPM will simply not unseal its secrets, hence such tampering is self-defeating for those agents.
While this might be correct (I hope it is correct!), the *PPI* part of TPM appears entirely different. In fact I don't have the slightest idea *why* PPI is lumped together with the TPM.
The physical presence interface allows *automation of TPM operations and changing the TPM's state* (such as clearing all keys) that are typically only possible via interaction with the TPM menu in the firmware. Think of it as some TPM operations that can only run successfully while the system runs the firmware. Once the firmware has given control to the next stage (bootloader, kernel) these operations are not possible anymore since the firmware has execute some TPM commands that put the TPM into a state so it wouldn't allow those operations anymore.
Can you explain in more detail what the PPI operations are, and why they need protection, from what agents exactly? What is the purported lifecycle of such PPI operations?
With the clearing of the TPM one would loose all keys associated with the TPM. So you don't want some software module to be able to set such a 'code', reset the machine, and the user looses all keys on the way. The control has to be strongly with the admin. Also, to prevent fumbling with the variables, UEFI seems to make the variable read-only.
I am wondering whether a malicious UEFI module could be written that patches the ACPI tables and does what it wants when it comes to these early TPM operations, rather than what the admin wants. Its ACPI code would just enter SMM and instruct to clear the TPM upon reboot whenever invoked. If that's possible then we may have 'only' moved the problem from the secured UEFI variable to patching ACPI code, which is more work of course. (We need signed ACPI tables...)