Hi Matt, On Tue, 29 Mar 2022 at 19:41, Matthew Garrett <mjg59@xxxxxxxxxxxxx> wrote: > > We're still trying to come to a conclusion about the most maintainable > approach to getting DRTM implementations like Intel TXT working on UEFI > platforms under Linux. I'm going to try to summarise the situation here > - I'm not an expert, so details may be inaccurate, but I think this is > the rough shape of things. > > Under normal circumstances on UEFI platforms, the bootloader (or system > firmware directly) load the kernel and execute code in the boot stub. > This boot stub code interacts with the firmware in various ways, > including working around some platform-specific issues and doing things > like copying the TPM event log into memory that can be used by the > kernel proper. While it remains technically possible to boot the kernel > on x86 UEFI platforms by jumping directly to the kernel entry point and > skipping the boot stub, this risks disabling certain functionality and > leaving the kernel in a slightly unexpected state. The contract that > exists between the UEFI stub and the kernel is not meaningfully > documented - portions are carried out by updating the contents of the > bootparams struct on x86 or devicetree on ARM, but other information is > conveyed via UEFI configuration tables, the boot stub may modify the > contents of certain UEFI variables, and some of this is implicit in > the form of hardware state. > > The Trenchboot project is attempting to implement DRTM under Linux. > Traditional measured boot takes the form of a static root of trust - > each component in the boot chain is measured by the previous component > before being executed, and each measures what it considers to be > security relevant configuration and behavioural state. Modifying any > component will change the measurements, even if the end result is > equivalent. Dynamic Root of Trust Measurement aims to provide more > useful measurements by performing a measurement at a specific point in > time - as a result, DRTM cares only about what the state *is*, not what > happened before then. > > There's a bunch of complexity involved in this that's vendor specific, > but the short version is that a launch environment is set up and a > specific CPU instruction executed that triggers a secure launch event. > The Trenchboot code consists of patches to bootloaders to support > setting up this environment, and patches to the kernel to provide > support for the "Secure Launch" kernel that handles DRTM before handing > control off to the kernel proper, skipping the UEFI boot stub. > > Since this skips the UEFI boot stub, it's then the responsibility of the > bootloader to implement the functionality of the boot stub. This is made > difficult due to the absence of an express contract between the boot > stub and the rest of the kernel - our assumption has been that the code > is the contract, and this is free to change arbitrarily since both the > producer and the consumer of the information can be updated > simultaneously and can't get out of sync. That seems to leave us with > two options: > > 1) Formalise the contract between the boot stub and the kernel, making > it easier for other boot loaders to implement the contract. This has the > downside that even within the scope of the contract we may end up with > divergent behaviour, and also new functionality in the kernel may not be > available without the bootloader also being updated. > > 2) Modify the boot stub such that it can be provided with a callback, > and instead of jumping to the kernel it can jump to the callback. The > boot flow would then involve the boot loader setting up the launch > environment, calling the boot stub code, and then performing the DRTM > event. This avoids requiring an explicit contract (the boot stub would > remain part of the kernel image and would be updated in lockstep). > > One complexity for both approaches is that the secure launch environment > needs to be aware of all security-critical state in the system. The > firmware nominally exposes that information for everything it's aware > of that's security-critical, but the boot stub may have performed > security-critical actions or exposed security-critical state that the > firmware is unaware of. The secure launch code from Trenchboot has to be > aware of this in order to ensure it's measured. > > If there's a contract, then in theory this would be embodied in the > contract and when the contract is updated the secure launch code could > also be updated. If there's no contract, every change to the boot stub > would need to be examined and the secure launch code updated if > necessary. > > While the secure launch code is currently out of tree, the goal is for > it to be integrated into the kernel tree. My feeling is that it's > going to be easier to manage this if everything is in tree - ie, all the > EFI setup code that does anything security-critical is either in the > firmware (and so the firmware takes responsibility for exposing it) or > is in the Linux tree (and so we take responsibility for updating the > secure launch code whenever something relevant changes in the boot > stub). But this requires support from the EFI maintainers in terms of > not merging things until we've established whether updates are required > to the secure launch code. The alternative is effectively the same, > except it would require updating the contract instead. > > But, as mentioned, that's just my feeling - I know that Daniel feels > that the contract approach is preferable. So: > > 1) From an EFI maintainer perspective, is making the contract between > the boot stub and the kernel explicit viable? > No. The direction of travel has been to define EFI boot only in terms of the handover from the loader to the stub. What happens next is up to the architecture, and is deliberately not specified, because it is considered to be internal Linux ABI. We've deviated from this once for Xen on ARM, but this means we have already painted ourselves into a corner when it comes the way we use DT internally at the handover point between stub and kernel proper, and I am not eager to repeat that. Locking down the stub-to-kernel protocol for all architectures is not the way to go. > 2) If so, is it desirable? > > 3) If either (1) or (2) is "no", is it reasonable to ensure that all > potentially security-critical state or configuration changes to the > boot stub are reviewed by DRTM people to verify whether the secure > launch code needs to be updated to match? Wouldn't it be better for the secure launch kernel to boot the EFI entrypoint directly? As it happens, I just completed a PoC last week for a minimal implementation of EFI (in Rust) that only carries the pieces that the EFI stub needs to boot Linux. It is currently just a proof of concept that only works on QEMU/arm64, but it should not be too hard to adapt it for x86 and for booting a kernel that has already been loaded to memory. [0] https://github.com/ardbiesheuvel/efilite