TrenchBoot / landing-zone

An open source implementation of an AMD-V Secure Loader.
GNU General Public License v2.0
23 stars 7 forks source link

Refactoring binary layout #32

Open dpsmith opened 4 years ago

dpsmith commented 4 years ago

Description

When the LZ was first created a rough layout of the binary was devised. As the code has evolved the layout has languished a bit and it needs to be revisited. An approach needs to be devised and implemented that ensures only static/predictable information is in the region measured by SKINIT instruction while providing a means for the bootloader to communicate setup details to the LZ.

Tasks

krystian-hebel commented 4 years ago

My notes on the subject below. Opinions are welcome.


List of constant fields, can/should/must be measured:

The hashes of LZ also have to be included somewhere to be included in the event log. While they are constant, they cannot be located in the measured part or the hashes would change, obviously.

List of data passed by bootloader:

I also had an idea about some kind of "I know it is not secure, but I really want to boot it nonetheless" switch that would clear R_INIT and do STGI in the LZ. The former one is done in the LZ already, but it should be kernel's responsibility.


The size of kernel boot protocol data passed by the bootloader depends on the given protocol. It may get bigger for the new protocols implemented. For that reason, and to keep additions to the LZ boot protocol relatively painless, a structure similar to Multiboot2 boot information may be created by a bootloader, located in the unmeasured part of SLB.

The contents of data provided by a bootloader should be measured, as it controls the flow of the LZ. Should we use PCR18 or leave that one for kernel's measurements and use a different one for this?


It seems that much of the precious space is wasted by alignment of structures. Right now, all page-aligned structures are located at the end of measured part of LZ, as a consequence of this the bootloader data is also page-aligned. This gives at least 4K bytes used for a structure that is just over a hundred bytes long.

To improve this situation, we can move all page-aligned data to the very beginning of SLB and just fix up the first 4 bytes (used by SKINIT) in code. If the first page would be the Device Table for the IOMMU, the SL length field would overlay a part of the Page Table Root Pointer which is not used for a simple "block everything" IOMMU configuration. We can leave that field unmodified and read it later from the kernel, if necessary (e.g. in order to get access to the TPM Event Log), so only the SL entry point offset must be overwritten, which is no longer useful.

The downside of that approach is that we cannot put too many other fields into the SLB header, so the rest of the constant data listed above must be located in another structure. We can use next 16 bits of the Page Table Root Pointer to hold the pointer to that structure.