On Fri, 19 Aug 2022 at 09:41, Heinrich Schuchardt <heinrich.schuchardt@xxxxxxxxxxxxx> wrote: > > On 8/19/22 09:07, Ard Biesheuvel wrote: > > On Fri, 19 Aug 2022 at 09:01, Heinrich Schuchardt > > <heinrich.schuchardt@xxxxxxxxxxxxx> wrote: > >> > >> On 8/19/22 08:52, Ard Biesheuvel wrote: > >>> On Fri, 19 Aug 2022 at 07:29, Heinrich Schuchardt > >>> <heinrich.schuchardt@xxxxxxxxxxxxx> wrote: > >>>> > >>>> > >>>> > >>>> On 8/18/22 19:10, Ard Biesheuvel wrote: ... > >>>>> What we could do is define a vendor GUID for the decompressed kernel, > >>>>> and create a device path for it. That way, you can grab the > >>>>> loaded_image of the parent to obtain this information. > >>>>> > >>>>> What did you have in mind as a use case? > >>>> > >>>> The device-path could be used in the kernel log. > >>>> > >>>> It can be used to find the device or folder with initrd where we use > >>>> initrd= on the command line. > >>>> > >>>> You could use the device path to access the original file, e.g. to read > >>>> additional information. > >>>> > >>>> For all use cases you would want to have the original device path. > >>>> > >>> > >>> What we could do is: > >>> > >>> - define a device path in the decompressor, e.g., > >>> > >>> <original device path>/Offset(<start>, <end>)/VendorMedia(xxx-xxx-xxx, > >>> <compression type>) > >>> > >>> where start, end and compression type describe the compressed payload > >>> inside the decompressor executable. (The compression type could be > >>> omitted, or could be a separate node.) > >>> > >>> - install the LoadFile2 protocol and the device path protocol onto a > >>> handle, and move the decompression logic into the LoadFile2 > >>> implementation > > Why would you create a LoadFile2 implementation if the decompressor is > the only user? In this case I think an internal function call is more > adequate. > You argued that you would want to access the original file, no? When using the SourceBuffer argument to LoadImage(), the original data is gone. When you pass a LoadFile2 protocol, you can use the device path to reload the data (compressed or uncompressed) as needed. > A LoadFile2 protocol would make sense if the compressed image contains > both a compressed kernel and the initrd and you wanted to provide the > initrd via the LoadFile2 protocol. > The initrd loading is a completely separate issue, and the fact that we might use LoadFile2 for both is just a coincidence. > For Iot use cases it would make sense to have a standalone process which > you can use to: > > * compress a kernel > * create a binary containing > * * a prepended decompressor binary > * * the compressed kernel > * * an optional initrd > * * an optional device-tree > * sign the complete file > > At runtime the decompressor would: > > * decompress the kernel > * create a LoadFile2 protocol for the initrd > * call the firmware to fix-up the device-tree > * install the fixed-up device-tree > * invoke the EFI stub of the kernel > > This way we could have one binary where all relevant components are > inside a single signed image. > The only generic and portable way to move data into memory and execute it as code is using LoadImage/StartImage. Everything else is a hack, and hacks are notoriously non-portable between architectures and firmware implementations. This means the 'inner' executable *must* be invoked using LoadImage/StartImage, which implies it must be signed if secure boot is enabled. Fixing up the device tree is tied to specific architectures, and the notion that the OS should be involved in poking the firmware at the right time to fix it up is also highly arch dependent. Which means it does not belong in a generic EFI decompressor either. What you are describing is essentially the systemd-stub, which also omits LoadImage/StartImage, which means it has to parse the PE/COFF image, load the sections, apply the relocations, etc etc, all of which it surely got correct right off the bat ... The reason I am so adamant about this is that we are digging ourselves into a hole here, and the more instances we add of this pattern, the more difficult it is to reason about it, and to fix it when things break. Shim should not need to exist, but we all know it has to. But ideally, it would only hook LoadImage/StartImage to interpose its own implementations, leaving subsequent stages none the wiser. I personally find it very disappointing that distro GRUB cannot work without shim even if the distro's signing key is in db - this is a missed opportunity imo. But if we repeat this pattern at every level above it, (i.e., open code PE app launch to avoid using LoadImage/StartImage), reasoning about secure boot and measured boot becomes very difficult, and every stage needs to invoke the TCG protocols directly etc etc