On 02/13/18 21:29, Stefan Berger wrote: > On 02/13/2018 02:59 PM, Laszlo Ersek wrote: >> On 02/13/18 20:37, Kevin O'Connor wrote: >>> On Tue, Feb 13, 2018 at 05:16:49PM +0100, Laszlo Ersek wrote: >>>> On 02/12/18 21:49, Stefan Berger wrote: >>>>> On 02/12/2018 03:46 PM, Kevin O'Connor wrote: >>>>>> I'm not sure I fully understand the goals of the PPI interface. >>>>>> Here's what I understand so far: >>>>>> >>>>>> The TPM specs define some actions that are considered privileged. An >>>>>> example of this would be disabling the TPM itself. In order to >>>>>> prevent an attacker from performing these actions without >>>>>> authorization, the TPM specs define a mechanism to assert "physical >>>>>> presence" before the privileged action can be done. They do this by >>>>>> having the firmware present a menu during early boot that permits >>>>>> these privileged operations, and then the firmware locks the TPM chip >>>>>> so the actions can no longer be done by any software that runs after >>>>>> the firmware. Thus "physical presence" is asserted by demonstrating >>>>>> one has console access to the machine during early boot. >>>>>> >>>>>> The PPI spec implements a work around for this - presumably some >>>>>> found >>>>>> the enforcement mechanism too onerous. It allows the OS to provide a >>>>>> request code to the firmware, and on the next boot the firmware will >>>>>> take the requested action before it locks the chip. Thus allowing >>>>>> the >>>>>> OS to indirectly perform the privileged action even after the chip >>>>>> has >>>>>> been locked. Thus, the PPI system seems to be an "elaborate hack" to >>>>>> allow users to circumvent the physical presence mechanism (if they >>>>>> choose to). >>>>> Correct. >>>>>> Here's what I understand the proposed implementation involves: >>>>>> >>>>>> 1 - in addition to emulating the TPM device itself, QEMU will also >>>>>> introduce a virtual memory device with 0x400 bytes. >>>>> Correct. >>>>>> 2 - on first boot the firmware (seabios and uefi) will populate the >>>>>> memory region created in step 1. In particular it will fill an >>>>>> array with the list of request codes it supports. (Each >>>>>> request >>>>>> is an 8bit value, the array has 256 entries.) >>>>> Correct. Each firmware would fill out the 256 byte array depending on >>>>> what it supports. The 8 bit values are basically flags and so on. >>>>>> 3 - QEMU will produce AML code implementing the standard PPI ACPI >>>>>> interface. This AML code will take the request, find the table >>>>>> produced in step 1, compare it to the list of accepted requests >>>>>> produced in step 2, and then place the 8bit request in another >>>>>> qemu virtual memory device (at 0xFFFF0000 or 0xFED45000). >>>>> Correct. >>>>> >>>>> Now EDK2 wants to store the code in a UEFI variable in NVRAM. We >>>>> therefore would need to trigger an SMI. In SeaBIOS we wouldn't have to >>>>> do this. >>>>> >>>>>> 4 - the OS will signal a reboot, qemu will do its normal reboot >>>>>> logic, >>>>>> and the firmware will be run again. >>>>>> >>>>>> 5 - the firmware will extract the code written in stage 3, and if the >>>>>> tpm device has been configured to accept PPI codes from the >>>>>> OS, it >>>>>> will invoke the requested action. >>>>> SeaBIOS would look into memory to find the code. EDK2 will read the >>>>> code >>>>> from a UEFI variable. >>>>> >>>>>> Did I understand the above correctly? >>>>> I think so. With the fine differences between SeaBIOS and EDK2 >>>>> pointed out. >>>> Here's what I suggest: >>>> >>>> Please everyone continue working on this, according to Kevin's & >>>> Stefan's description, but focus on QEMU and SeaBIOS *only*. Ignore edk2 >>>> for now. >>> If this were targetted at SeaBIOS, I'd look for a simpler >>> QEMU/firmware interface. Something like: >>> >>> A - QEMU produces AML code implementing the standard PPI ACPI >>> interface that generates a request code and stores it in the >>> device memory of an existing device (eg, writable fw_cfg or an >>> extension field in the existing emulated TPM device). > > ACPI code writing into fw_cfg sounds difficult. > I initially had PPI SeaBIOS code write into the TPM TIS device's memory > into some custom addresses. I'd consider this a hack. Now we have that > virtual memory device with those 0x400 bytes... > > In these 0x400 bytes we have 256 bytes that are used for configuration > flags describing the supported opcode as you previously described. This > array allows us to decouple the firmware implementation from the ACPI > code and we need not hard code what is supported in the firmware inside > the ACPI code (which would be difficult to do anyway since in QEMU we > would not what firmware will be started and what PPI opcodes are > support) and the ppi sysfs entries in Linux for example show exactly > those PPI opcodes that are supported. The firmware needs to set those > flags and the firmware knows what it supports. > > I hope we can settle that this device is the right path. > >>> >>> B - after a reboot the firmware extracts the PPI request code >>> (produced in step A) and performs the requested action (if the TPM >>> is configured to accept OS generated codes). >>> >>> That is, skip steps 1 and 2 from the original proposal. >> I think A/B can work fine, as long as >> - the firmware can somehow dynamically recognize the device / "register >> block" that the request codes have to be pulled from, and > > I experimented with what Igor had suggested with the fw_cfg file > callback and so on. > >> - QEMU is free to move the device or register block around, from release >> to release, without disturbing migration. > > I think we should basically limit the firmware to writing two addresses > into this fw_cfg file: > - SeaBIOS: write back the same address that QEMU suggested in the file > (currently 0xfed4 5000) > - EDK2: write back 0xffff 0000 Given that I intend to rip the SecurityPkg ASL code out of OVMF's solution for this, I don't think that the address 0xffff_0000 has any relevance for OVMF. If the QEMU x86 MMIO space generally has a suitable gap at 0xfed4_5000 (and I do think it has, even considering pflash & LAPIC), then just put the register block there.
As long as Igor agrees. :) Another question just occurred to me. If the guest OS queues some PPI operations, and then the VM is powered down fully (instead of a reboot), then we're at liberty to forget the queued PPI ops, right? Thanks Laszlo > > No other address would be accepted by QEMU since presumably QEMU knows > where otherwise address collisions can occur.