Hi folks,

As some of you may know, I've been working on a way to add
verification directly into CBFS (as opposed to the current vboot that
can only verify images as a whole) for a while (I have presented at
OSFC 2019: https://www.youtube.com/watch?v=Hs_EhewBgtM and published a
general design document:
https://osfc.io/uploads/talk/paper/47/The_future_of_firmware_verification_in_coreboot.pdf).
As part of this work I have been very careful to keep all these
changes fully backwards-compatible so that existing payloads with
their own CBFS implementations will continue to work.

I have now come across a fundamental problem that I cannot solve
without introducing a small backwards-incompatible change: the CBFS
"stage" format that is used to store the code for coreboot stages
(e.g. romstage, ramstage) consists of a small "stage header"
containing things like load address and size in front of the actual
binary code. From the point of view of the generic CBFS structure,
both that header and the code are part of the "file data" (and not the
generic CBFS "file header" that contains things like the file name or
generic CBFS attributes).

This creates a tough chicken-and-egg problem when verifying pre-RAM
stages, because (for platforms that actually load pre-RAM stages and
don't execute in-place, like Arm platforms running from SRAM) the
stage needs to be directly loaded into the final location it should
execute out of, but the load address containing that location is in
the stage header. My verification design works on whole files, so the
stage header cannot be trusted before the whole file was loaded and
hashed. But I can't load it without information from the stage header,
and there's generally not enough scratch space in these pre-RAM
environments to first load it somewhere else and then copy it over to
its final destination after verification.

My solution to this problem is to move the stage header out of the
file data into a CBFS attribute that is stored in the generic CBFS
file header. File headers are verified separately so they can already
be trusted by the time the file data needs to be loaded. I think this
is arguably a somewhat cleaner approach anyway (the concept of CBFS
attributes just didn't exist yet when the stage format was originally
designed, so it wasn't written that way to start with), but of course
these new stages will be incompatible to the old ones. I believe this
is okay because the "stage" format is generally only used for parts of
coreboot itself (e.g. romstage, ramstage), whereas the payload and
other binaries the payload may want to chain-load should be using the
"simple ELF" (SELF) format anyway. Since coreboot is always built as a
whole, when you're gonna build the new version all your stages will be
in the new format and all code that loads them will know how to load
the new format, so you should be fine. Tying this into a payload build
system that is not aware of these changes should be okay because that
payload shouldn't try to add extra files using the "stage" format, and
shouldn't try to load any stages (if it wants to chain-load things it
should be using the SELF format with cbfstool add-payload, not
add-stage).

But this file format has remained untouched for the whole 10+ years
CBFS existed, so I thought I should ask before I do it. If you know
any payloads that do use the "stage" format for files outside of
coreboot itself and that couldn't adapt to this change for some
reason, or have any other concerns about unexpected problems this
could be causing you, please let me know here or on the CL:
https://review.coreboot.org/46484

Note that for cbfstool, this will also mean that newer versions of
cbfstool will only support the new format. I think this should also be
okay because coreboot is built as a whole, i.e. all your stages are
added with a cbfstool version that was built from the same code base
version as the coreboot code trying to load these stages. But it does
mean that if you have an old version of cbfstool stashed away
somewhere and try to use it to cbfstool print -v or cbfstool extract a
new coreboot image, it won't be able to show load address or entry
point for the new stages or convert them back into an ELF file on
extraction (or vice versa for new versions of cbfstool on old images).
So if you do a lot of after-the-fact cbfstool manipulation on
different versions of coreboot images (which is probably only done by
people trying to debug something?), you may need to keep two cbfstool
versions to switch back-and-forth between for a while. It would be
possible to make the new cbfstool version support both formats for
reading/extracting but that's a bunch of extra work that I hope I can
avoid unless people really feel like this is gonna be a widespread
problem.

Also note that I'm not planning to touch the SELF (payload) format
(which also has a header in the "file data" part) -- I will keep that
as it is because I think it's much more likely that external payloads
are using it for their own purposes that I don't want to break. It's
also not necessary because SELFs are mostly just used in post-RAM
environments and the SELF loader code already requires it (on
non-memory-mapped platforms) to be loaded to a separate scratch buffer
before copying the individual pieces to where they need to go. When we
have that buffer anyway, it's easy to verify the whole file in there
before examining the header.
_______________________________________________
coreboot mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to