Reproducible builds

Recently we made sure that every build of PC Engines' firmware is built in a reproducible manner. This short post shows what exactly does it mean and why this should be important to firmware developers.

What?

A build process is reproducible if it produces exactly the same image every time it is built. This means that it cannot:

  • include the time of compilation in resulting image or application
  • use data obtained from build environment, like a host or user name
  • use random input data
  • point to any non-static points in a source tree (e.g. head of a branch)

Why?

As firmware images for apu platforms were delivered in the form of binary images, users would like to have a way of confirming whether those images are what they are expected to be. The easiest way is to build an image from the source and compare its hash with the hash of the pre-built binary.

Reproducibility is also important in most security features, where one stage of a firmware calculates a checksum of the next one. The new stage starts only if the checksum has a value known to the current stage.

The image read from a platform can also be compared to known images. It makes it possible to check whether platform firmware was tampered with.

How?

Both the time of compilation and environment variables were used a long time ago by coreboot. These “features” were still present in the legacy releases up to v4.0.23 - the time of compilation was dropped earlier, but domain, host and user name were still being saved. Note that they were not actually used in the code, just saved in a config file in the firmware image. coreboot is built with coreboot-sdk Docker image. The hostname was different with every build because it is randomly assigned every time a container is started. This problem was not present in the mainline releases - new coreboot code was already reproducible.

We discovered that it was not the only issue - images still had different checksums with every build. The next step was to find which part of CBFS changes. It was iPXE, because of this line. This variable can be overwritten when executing make.

After that, all consecutive builds resulted in identical images, but these were not reproducible yet. Some payloads were still built from the master branch, so the image would be different as soon as new commits appear. The last change left to do was to use stable commits in all payloads used.

All mentioned changes can be found in pull requests: 241, 242, 269 and 270.

Summary

From now on, the coreboot images for PC Engines by 3mdeb will be built in a reproducible manner. It means that a couple of years from now it should still be possible to build the versions released recently.

If you think we can help in improving the security of your firmware or you looking for someone who can boost your product by leveraging advanced features of used hardware platform, feel free to book a call with us or drop us email to contact<at>3mdeb<dot>com. If you are interested in similar content feel free to sign up for our newsletter


Krystian Hebel
Firmware Engineer interested mostly in things deliberately omitted from documentation. Thinks C is high-level language, can write something in Verilog but doesn't know how to read it yet.