Turtles All the Way Down: Firmware and bootloaders.

26 February 2014

After rethinking this post a little, I feel a need to caveat things: In a previous post in this series I mentioned the possibility of using an open source System On A Chip because it would simplify the construction process somewhat. I've been doing some more research and I'm not certain that all SoC's (if that is the direction a project like this would go in) require system firmware of the sort we're about to discuss. The Broadcom BCM2835 mentioned earlier, for example, has firmware on board that is sufficient to initialize the hardware and then try to load the OS from an SD card, and that's about it. It doesn't seem to use anything even vaguely PC-like insofar as the early stages of the boot process are concerned. So, let's cover this ground because it may be necessary, and if it isn't it would be handy to have some knowledge of a few open source projects that don't get enough attention. If it's not necessary, then we'll figure out what is when the time comes.

Moving up the stack, now we need core code - a set of instructions that the computer loads into memory and executes to bootstrap the rest of the system, starting with initializing a basic set of peripherals and activating the boot loader. PCs have a BIOS, which you've probably encountered when playing around with your machine's configuration. Apple computers use something different that does much the same thing called UEFI (Unified Extensible Firmware Interface). Sun servers used OpenFirmware for this purpose, which is incidentally open source and bears a BSD license. Examples given, we need something that does the same job that we have transparency into the inner workings of.
We may as well check out Coreboot, a GPL'd open source firmware that aims to boot rapidly and handle errors in an intelligent manner. Coreboot tries to be portable to every common platform we're likely to run into, including x86, x86-64, and ARM architectures. While doing some digging I was surprised to discover that, except for 12 instructions in platform-native assembly language the entire codebase is written in ANSI C, which is about as standard as code gets (and is deliberate because the project wants to facilitate code auditing as one of its stated goals). It is also interesting to note that a number of mainboard vendors have helped work on the codebase. Make code run on your product, people buy your product more. Who knew? Coreboot can load and initiate any ELF executable at boot time and can provide PC-standard BIOS services if necessary, both of which may be useful features insofar as this project is concerned.

OpenBIOS is another such project which is also designed to be portable across as many common platforms as possible. It consists of several modules which are indiginous to one or more platforms:

  • OpenFirmware for x86, PowerPC, and ARM which does not require a boot loader and can also directly execute ELF binaries.

  • SmartFirmware, which is written entirely in C and seems designed to make it easier to write drivers for PCI expansion cards.
  • OpenBOOT, which was designed for the sun4v architecture.
  • OpenBIOS, which implements a boot ROM.
  • SLim Open Firmware, which provides only what is necessary to kickstart a Linux kernel or a hypervisor.
Most of the OpenBIOS modules rely on lower level code to initialize the hardware, like Coreboot, so if we're careful we can assemble a pretty slim stack of code to bring the trusted open computer to life. Depending upon the architecture the project goes with a different selecction of OpenBIOS modules will be necessary. For the purpose of our discussion this will probably be either OpenFirmware or SmartFirmware given the open source CPUs or SoC's available at this time. The firmware will have to be cross-compiled on another system, which means that we'll need to start figuring out a trusted software development toolchain. I plan on addressing this in more detail in a later post, but for now I will only get the obligatory post-Snowden infosec drinking game mention of Ken Thompson's Trusting Trust paper out of the way (Cheers!). For bonus points, I will link to Dr. David A. Wheeler's dissertation Fully Countering Trusted Trust Through Diverse Double Compiling, which documents a practical technique for detecting Trusting Trust-backdoored software development toolchains (Cheers!). Please read it. Until the post in this series where I talk about it, assume that we've carried out the process and feel reasonably certain that we have a toolchain which cross-compiles for our trusted and open computing platform that will not generate binaries with hidden backdoors in them (including copies of itself). The bootstrap process for the cross-compilation toolchain will take a considerable period of time but once it's done, it's done. Make backup copies of the binaries to read-only media and lock them away for later. Then the project will probably need a boot loader, which will pull the operating system kernel into RAM and start executing it. If you've built a Linux box or two you're probably familiar with GRUB, which many distributions use as their default bootloader. GRUB2 is the only version of the codebase which is still under active development. It's config files are also baroque and most reliably edited with a third-party graphical app. I don't know how you feel about this, but needing to install a desktop environment and an extra app just to edit a freaking boot loader's configuration files really gets under my skin. However, if you're comfortable editing the GRUB2 config files, more power to you. You're a better lifeform than I. Moving along to other options LILO is one of the oldest open source bootloaders out there that is still under development. It has a fairly easy to understand and modify configuration file format so it's pretty non-expert friendly. While this seems like a burned-out system admin crabbing for the sake of doing so (and I won't claim that I'm not a burned-out sysadmin), there are advantages to things having simple configuration files. For the threat model we're speculating under (relatively) simpler is better because it means less confusion and a lower chance of setting things up in an insecure manner. Misconfigurations and bugs often hide in situations of extreme complexity and the more complexity we can eliminate the better for us in the long run. I don't know what platforms LILO is known to work on other than x86 and x86-64, they're the only two places I've used it. There are slightly different versions of LILO out there, like SILO for Sparc but I have no first-hand experience with them and will defer to those who have to comment. Barebox is a fairly new bootloader which is aimed at embedded systems, not too unlike the system we're discussing. It is specifically available for platforms like ARM, MIPS, and Nios (which was designed for FPGA use) and has a list of boards that it already works on. Syslinux is the name of a collection of bootloaders which all do pretty much the same thing just under different circumstances.
  • SYSLINUX is used for booting from NTFS and FAT file systems.
  • ISOLINUX is used on optical disks for booting from ISO-9660 file systems.
  • PXELINUX is used to boot from a server on a local network. This is nice but probably not useful inside of our threat model because it means trusting another machine on the network to serve our trusted machine boot code, and an attacker serving malicious PXEboot code could compromise the project.
  • EXTLINUX does the same thing as SYSLINUX but from EXT2, 3, 4 or BTRFS file systems on non-volatile storage.
  • MEMDISK is used to boot older operating systems. We're trying to get away from older OSes (like DOS), so we needn't concern ourselves with this one, either.
It would be worth keeping in mind that Syslinux also includes an environment for writing custom modules. This may or may not be useful in the future for, say, verifying cryptographic signatures on certain aspects of the boot process to determine if they've been tampered with or not. Das U-Boot is yet another open source bootloader, only this one was designed with embedded systems in mind and so has been ported to multiple architecures, from PowerPC to ARM. The codebase of Das U-boot was designed so that it's easy to add new boards if the implementation warrants it. The README file lists everything that U-Boot will boot, and it's by far not a short list. Das U-Boot can also boot from lots of storage devices that most systems can't, such as PCMCIA cards, CompactFlash cards, network boot servers, and probably other stuff. It can also be flashed into a boot ROM, which means that it might be of use to this project if a SoC implementation is used. Now the more-speculative-than-usual bit of this post. With one exception (the distro of Linux which runs on the LatticeMico32 that uses Das U-Boot), I don't know which, if any of these boot loaders have been ported to any of our potential open source hardware platforms. Doing so might be a fairly easy task to accomplish, or it could be a long and drawn out process that few would be willing to undertake. I don't know, having not tried yet. However, if building one's own computers from the ground up becomes a popular thing to do, this might change in a hurry. At the very least, one of the more portable bootloaders (like Das U-Boot) might find itself with many more functioning platforms. Time will tell. --- This work by The Doctor [412/724/301/703][ZS] is published under a Creative Commons By Attribution / Noncommercial / Share Alike v3.0 License.