Fit images and EFI_LOAD_FILE2_PROTOCOL

François Ozog francois.ozog at linaro.org
Tue Oct 6 14:04:15 CEST 2020


As always, Ard made a good point, and I feel compelled to top post and
restate stuff.

Here is the supporting deck:
https://docs.google.com/presentation/d/1JK00su6e7vt8lRfwSt2C9EuuzwcBHLyoLRRrdcYfVWY/edit?usp=sharing

We have two boot flows under consideration (not saying others are bad, just
to say they are on focus):
A.1 typical distro (slide 2): <EFI firmware/ACPI> --> <shim> --> <grub> -->
Linux; Linux is here defined as the tuple {vmlinuz}, vmlinuz is verified
through EFI mechanism by either efi firmware or shim,  ACPI tables are
verified by firmware, initrd is not verified
A.2 typical embedded (slide 3): <firmware/DT> -> Linux ; Linux is here
defined as the tuple {vmlinuz, initrd, dtb} that is folded into a FIT and
are verified via signature, it avoid errors/attacks about mixing
vmlinuz/initrd/dtb.

We want EBBR "equivalent" flows (Equivalent meaning with the same level of
security and accepting the weaknesses).
B.1 typical distro (slide 4): <EFI firmware/DT> --> <shim> --> <grub> -->
Linux
B.2 typical embedded (slide 5): <EFI firmware/DT> -> Linux

For B.1 to be equivalent to A.1, we need the DT to be authenticated (ACPI
is embedded in the firmware in A.1).
For B2. to be equivalent to A.2, we  need the DT and initrd to be
authenticated

_____________
We can first validate this point: let's check whether we want to do this
(regardless of the implementation details, focusing on the intention).



On the implementation side, last call we discussed Trusting DT and we ended
up talking about trusting initrd too (probably because B.2 in the back of
our minds, without being explicit about this).

After giving some additional thoughts, it sounds like a good approach is to
"lead by example": let's implement what we think are the "archetype" flows
for Qemu and maintain it over time. We would make all changes we think are
good in all relevant projects (tfa, op-tee, u-boot, devicetree, linux
kernel, qemu...). Being an "archetype" flow does not prevent systems to be
EBBR compliant, we just have reference flows.

_____________
We can validate this second point: are we in agreement that leading by an
end-to-end example on a platform, rather by technology layers (trusting DT
PoC was in that spirit) ?



What are the implementation details of B.1 and B.2?

B.1
To trust DT the proposal is to make its use closer to ACPI: this is a
platform attribute that is verified by firmware and handed over to OS.
To achieve that:
- we create a platform repo in devicetree.org, add the Qemu-bsa DT (coming
from current Linux kernel ), and maintain it over time. We shall ensure
forward/backward compatibility of relevant Linux drivers.
- the resulting DTB is compiled and integrated by the platform vendor in
its TF-A FIP at NT_FW_CONFIG section.
- at boot time, TF-A verifies DTB, pass it to U-Boot, U-Boot passes that
DTB to the shim as a config table and boot flow continues; the platform DTB
can be overridden by grub (without any verification, that can be seen as a
weaker than ACPI case); the Linux EFI-STUB uses EFI_LOAD_FILE2 protocol to
get the initrd (unverified). Linux command line dtb= is disabled

B.2
To trust DT the proposal is to make its use closer to ACPI: this is a
platform attribute that is verified by firmware and handed over to OS.
To trust the initrd the proposal is to leverage the same concept as A.2:
create a tuple with {vmlinuz, initrd, dtb}
To achieve that:
- we create a platform repo in devicetree.org, add the Qemu-bsa DT (coming
from current Linux kernel ), and maintain it over time. We shall ensure
forward/backward compatibility of relevant Linux drivers.
- the resulting DTB is compiled and integrated by the platform vendor in
its TF-A FIP at NT_FW_CONFIG section.
- the platform vendor creates a FIT with the desired tuple
- an EFI application is actually "booting" that FIT verifying both the
initrd and the replacement DTB
- at boot time, TF-A verifies DTB, pass it to U-Boot, U-Boot passes that
DTB to the EFI application as a config table; The EFI application hooks the
EFI BS (much like the SHIM does) so that EFI_LOAD_FILE2 of initrd goes to
the FIT (uefi_merge_fs idea in the slide 5); vmlinuz is verified launched
via UEFI mechanism, Linux EFI stub gets the initrd with EFI_LOAD_PROTOCOL2
which happens to be transparently redirected to the FIT (so the initrd is
validated as in A.2).

_____________
Identifying the right flow is the third point to decide on. I hope we can
achieve this result on the October 14th call. If we agree on the first two
points, the mail thread shall be such that we find consensus on how to
implement the intention, the above description and slide 4/5 in the deck
being just starting points. We can go in an entire direction.




On Tue, 6 Oct 2020 at 12:38, Grant Likely <grant.likely at arm.com> wrote:

>
>
> On 06/10/2020 05:35, Heinrich Schuchardt wrote:
> > Am 6. Oktober 2020 00:37:58 MESZ schrieb Grant Likely <
> grant.likely at arm.com>:
> >>
> >>
> >> On 03/10/2020 09:51, Heinrich Schuchardt wrote:
> >>> Hello Ilias, hello Christian,
> >>>
> >>> with commit ec80b4735a59 ("efi_loader: Implement FileLoad2 for
> >> initramfs
> >>> loading") Ilias provided the possibility to specify a device path
> >>> (CONFIG_EFI_INITRD_FILESPEC) from which an initial RAM disk can be
> >>> served via the EFI_FILE_LOAD2_PROTOCOL.
> >>>
> >>> Ard extended the Linux EFI stub to allow loading the initial RAM disk
> >>> via the EFI_FILE_LOAD2_PROTOCOL with the utmost priority.
> >>>
> >>> With commit ecc7fdaa9ef1 ("bootm: Add a bootm command for type
> >>> IH_OS_EFI") Cristian enabled signed FIT images that contain a device
> >>> tree and a UEFI binary (enabled by CONFIG_BOOTM_EFI=y).
> >>>
> >>> In the DTE calls we have discussed that it is unfortunate that we do
> >> not
> >>> have a method to validate initial RAM images in the UEFI context.
> >>>
> >>> To me it would look like a good path forward to combine the two
> >> ideas:
> >>>
> >>> * Let the signed FIT image (of type IH_OS_EFI) contain a RAM disk
> >>> * Pass location and size to the UEFI subsystem and serve them via
> >>>     the EFI_FILE_LOAD2_PROTOCOL.
> >>>
> >>> We could also extend the bootefi command to be callable as
> >>>
> >>>      bootefi $kernel_addr_r $ramdisk_addr_r:$filesize $fdt_addr_r
> >>>
> >>> like the booti command to serve an initial RAM disk.
> >>>
> >>> What are your thoughts?
> >>
> >> Hi Heinrich,
> >>
> >> I've got concerns about this approach. Even though it uses the UEFI
> >> infrastructure, images deployed in this way are U-Boot specific and
> >> won't ever be applicable on EDK2 or other UEFI implementations.
> >>
> >> However there is another way to approach it which I think Francois
> >> touched on. If instead a UEFI stub was added to the FIT image, in the
> >> same way that the kernel has a UEFI stub, then the logic of decoding
> >> the
> >> FIT and choosing the correct DTB & initrd can be part of the image and
> >> it becomes applicable to any UEFI implementation. It would also address
> >>
> >> Ard's concern of loading the FIT into memory, and then copying due to
> >> the EFI_FILE_LOAD2 path. The FIT stub would already know the image is
> >> in
> >> RAM, that is is reserved correctly, and just pass the correct addresses
> >>
> >> to the kernel as part of the normal boot flow.
> >>
> >> Signing would also be taken care of because the whole FIT can be
> >> signed,
> >> and that signature would be checked when it gets loaded.
> >>
> >> Thoughts?
> >>
> >
> > The gain of a fit image in U-Boot used for calling the Linux kernel via
> the EFI stub vs calling the legacy entry point comes down to providing the
> EFI_RNG_PROTOCOL to be used for KASLR.
>
> I agree with that, but that is not my concern.
>
> My concern is that the FIT image format will only be supported by
> U-Boot. Other UEFI implementations do not implement it.
>
> On the other hand, adding a UEFI Stub to the FIT image format makes it a
> generic solution that can be used by any UEFI implementation. This would
> be separate from the linux kernel's UEFI stub, and should only deal with
> choosing the appropriate kernel/initrd/dtb from the FIT and then calling
> into the kernel's stub to actually boot the kernel.
>
> > For initrd a stub UEFI binary will work. But if you want to provide a
> kernel specific  dtb with the same stub binary it will require a new
> service for device-tree fixups.
>
> Devicetree fixups indeed needs to be solved. I would propose registering
> a new protocol for fixups. If the protocol is present, then stub can
> call it. If not, then the DTB from the fit should be used unmodified.
>
> g.
>


-- 
François-Frédéric Ozog | *Director Linaro Edge & Fog Computing Group*
T: +33.67221.6485
francois.ozog at linaro.org | Skype: ffozog


More information about the U-Boot mailing list