Intel Boot Guard

So some innocent post on the coreboot mailing list managed to make some waves.

The problem they try to solve…

Intel Boot Guard is the latest effort in a long series by Intel and others to allow computers to provide some reliable information about the state a computer is in. They're working on int since at least 2003, with projects and trade groups named Palladium, TCPA, and now TCG, and some of them faced scrutiny in the past already because the freedom of computing was deemed under attack (partly realistic, but with some hyperbole). The scheme they developed ultimately requires having a chip in system that keeps track of the system state and is able to keep secrets from the main CPU until it proves that the system is in a safe state, called TPM (short for Trusted Platform Module). From the beginning the TPM was designed as a passive component: Some other part of the system needs to update the TPM's view of the platform, the TPM is not able to lock down any component in the system except access to its own memory. The TPM consists of some way to keep track of the system state, some non-volatile memory (for the "secrets"), a way to bind secrets to system states, and it also provides some cryptographic operations - among them: creating RSA keypairs, and working with them. One major design issue is where the trust is rooted in: The first verification of signatures happens by code on the CPU, so if you are able to intercept that and replace it with your own, it's trivial to emulate a "properly" booted system (by just sending the right values to the TPM). Moving that issue ever earlier in the boot process, the last frontier is eventually the bootblock, the part of the firmware that contains the first instructions executed by the CPU: Since it comes first, it verifies the part that comes after it, which again verifies its successor, and so on. Analogous to a proof by induction, the entire system state remains well-known as long as the first component tests the next component, and every other component does likewise. But if you can't trust the bootblock to send a truthful state into the TPM, you have already lost. Enter Boot Guard: It allows the hardware vendor to lock down the boot block so the machine only starts if the code stored there matches a key they wrote into the computer.

… and its very own problems

The main grief with this approach is that this key can't be rewritten once it is in. So when the hardware vendor (say Lenovo) sets this key, they are the only ones that can provide firmware to the machine, even if the owner of the machine wants something else. In combination with the complexity of UEFI, which commonly includes a network stack (and thus the capability to communicate with the world) and the ability to load and execute code (eg. through the net), some people are uncomfortable with that prospect. Others just want the ability to replace all code on a system, including firmware, as a matter of principle - and since they own their machines, I find it really hard to argue that they shouldn't be able to.

There's more to it: Verified Boot vs. Measured Boot

But this isn't the whole story to Intel's Boot Guard. The option of installing a key is what Intel refers to as "Verified Boot". It's described in some short words on their product brief for these CPUs. That document also talks about another mode, "Measured Boot". In this mode, Boot Guard creates a hash over the bootblock and sends it off to the TPM. The value is stored in one of TPM's plenty registers, and in particular in a register that isn't writable by code running on the CPU (there's some circuitry to make sure of that). This is supposed to prevent replay attacks in which it would be possible to fake a certain Boot Guard state if it's ever possible for an attacker to disable Boot Guard altogether.

User friendly security, powered by Boot Guard

Since the TPM is able to bind data it stores to those registers, it's possible to verify the system state against a key stored in the TPM that is bound against a known good state: In the factory, have the TPM create a keypair, and bind it against the bootblock that is installed. Export the public part of the key (the TPM won't relinquish the private one, so this operation is safe). When trying to assert if the system is still in a good state, encrypt a random value (nonce) with the public key, and send it to the system to test. If it can decrypt the value and send it back, the state is known, and everything is fine. This could be a measure for Windows to employ on a Domain login, to assert that the system wasn't tampered with. Or the Windows Account / Store / Update so it can report suspect events (you already have to register the machine with Microsoft when using Windows, so let's use it for something user-friendly). Or bind the encryption key for the disk against that state, so the data is only readable in that computer with that firmware. (Since TPM crypto is so slow, this is somewhat more involved, but conceptually that's what can be done with it) A user wanting to install their own firmware (including bootblock), will face loss of access to an encrypted disk that is bound to the bootblock in this way, and to a Domain that does this verification. From a security perspective, both are desirable. But they can use Boot Guard with their own TPM state, and encrypt the disk with their own secret stored within that chip. With "Verified Mode", overwriting the firmware just transforms their computer into a nice, expensive, dead brick.

So what went wrong?

The issue isn't that Intel added Boot Guard to their platform. It's that Intel provides the Verified Boot mode. Had they not done that, the effort would be universally lauded as a technology that improves the security of their users (and without ripping holes in their security fabric like Intel TXT did). But as is, as Matthew Garrett states, "vendors are forced to choose between security and freedom". And that's an exercise most vendors routinely fail to do properly. So Intel, please: Protect the vendors from themselves, and your users from the vendors between yourself and your users, and do the right thing. Drop Verified Boot in future chipsets, and discourage vendors from using it now.

coreboot report of May 2012

Let's see if I can keep up with this monthly report of what happened in the project.

Changes in the repository

New boards

Gigabyte MA785GM-US2H was already committed, but not hooked up properly.

"blobs" repository

We provide a new repository for binary components and hooked it up in the build. So far it provides binaries for the Intel Sandybridge and Ivybridge platform, as well as the AMD Geode VSA binary that used to be distributed by Marc Jones.

The latter could be replaced by source in the main repository as soon as someone takes the time to port the VSA source (also part of the repository) from MASM assembly to some syntax compatible with our build system.

For VSA, the build system was slightly extended so its cbfs-files mechanism can be used to add coreboot stages.

SeaBIOS mirror

We mirror the SeaBIOS repository on review.coreboot.org. This isn't meant for patch submissions to SeaBIOS, but it provides a more robust source for the repository when using the build method that automatically integrates SeaBIOS in coreboot when behind firewalls.

Sandybridge support

Google provided various commits to improve their initial contributed code for Sandybridge and Ivybridge chipsets and boards.

Simplify using a driver for multiple PCI IDs

Instead of defining a device structure for a larger number of devices (eg. multiple revisions of the same device), extend them so they can optionally cover a set of devices.

static const struct pci_driver pch_sata_ahci_driver __pci_driver = {
   .ops    = &sata_ops,
   .vendor = PCI_VENDOR_ID_INTEL,
   .device = 0x1c02,
};
static const struct pci_driver pch_sata_mobile_ahci_driver __pci_driver = {
   .ops    = &sata_ops,
   .vendor = PCI_VENDOR_ID_INTEL,
   .device = 0x1c03,
};

becomes

static const struct pci_driver pch_sata_driver __pci_driver = {
    .ops    = &sata_ops,
    .vendor = PCI_VENDOR_ID_INTEL,
    .devices = { 0x1c02, 0x1c03 },
};

Remove Kconfig options

Stefan dropped CONFIG_MAX_PHYSICAL_CPUS on non-AMD boards. This Kconfig option is only used on AMD boards, but should eventually be removed there, too.

Fixed long time bug in Intel microcode update code

We used to have a couple of issues with cpuid in the past. It's an opcode that modifies a whole lot of registers, and we didn't always teach gcc about all of them.

The latest victim is Intel microcode updates - or rather, one of the earlier ones, since the code was broken since 2004. It only triggered bugs in later code if the compiler tried to reuse values in clobbered registers, and was rather elusive.

roda/rk886ex: Expose VGA devices

This one is interesting as it explains some of the less well documented properties in coreboot, devices in devicetree.cb:

As a rule of thumb, all devices should be listed (and not commented out) that are on-board. While coreboot can find them on its own, it only marks devices as "on mainboard" that are explicitely mentioned - among other things, the VGABIOS execution system uses that to determine the VGABIOS location, but we also run set_subsystem only on onboard hardware.

Console output

There were improvements to console output: The ACPI generation code can print PSS table entries as it generates them. The CBFS code prints more helpful debug output now. * MTRR debug output is more useful now.

Preprocessor mangling

Some preprocessor idioms were unified. CONFIG_FOO==1 became CONFIG_FOO, CONFIG_FOO==0 became !CONFIG_FOO.

We also added the config_enabled macro recently introduced with Linux. It works both for the preprocessor and inside code, and will allow us to eventually reduce the amount of changes we carry around in our version of Kconfig.

i915tool

Ron committed his research project, a set of Coccinelle scripts to convert Linux KMS code to code that can eventually be run from coreboot, as VGABIOS replacement.

AMD unification

Various aspects of AMD code were unified into generic code: FADT table generation for sb800, cbtypes.h was copied across AMD southbridge drivers,

Add SPI flash driver for Intel chipsets

After AMD added a tiny (and highly specialized) SPI driver for sb800, we now also have support to write to SPI flash on Intel chipsets. Like with AMD, it's used to store configuration data that is required on wakeup-from-S3.

GSoC USB: Conclusion

Now that GSoC is coming to an end, I prepared the patches and pushed the code upstream.

r5691 contains the work done until today, which is what I’ll post as my final result to GSoC, too. Work won’t end on it however, so expect more patches in the future.

OHCI

OHCI works – except for interrupt transfers, which are mostly used (in boot environments at least) for keyboards.

xHCI

That one is more complicated than the other controllers combined, and while I made a couple of stupid mistakes that held me up for longer than I wanted, there are aspects in xHCI that make the bootstrap of the driver harder than I’d like it to be.

Once you got the command and event channels set up, it seems that xHCI provides a neat interface for getting all kinds of status information out of it. The only problem is that setting up these channels seems to be more complicated than the entire bring up of UHCI – at least, that’s where I’m stuck right now.

I’ll get back to it, but I hope that a couple of days of doing something else will help me to finally see the problem.

Conclusion

Doing both drivers was ambitious. While I didn’t have the burden of creating the stack design, and learning USB in the first place, like I had in 2007 (when I worked on UHCI for GSoC), it’s still two specifications to understand, two way of communication between the controller and the host system, and finally two drivers to write.

It was fun, but I’ll be more conservative in choosing my project, and estimating the required effort, next time. It’s much easier (and also more satisfying) to add some tasks when the job is done early than to remove them – especially when you get to strip milestones because the hardware is acting up.

GSoC USB: xHCI part 1

I started implementing the xHCI driver. The first obstacle was to overcome a weird lack of configuration of the card (it’s a PCIe device) by coreboot. First I suspected that something went wrong because it uses a 64bit memory BAR, but then it was just a disabled PCIe bus in the devicetree.cb.

Thanks to Stefan for working out that issue.

However, the last days weren’t wasted, as I read the xHCI spec again and again, to build a mental image of how things interact in that standard.

Now I’m chugging along with implementing the data structures in C that xHCI requires (many more than in the older USB HCI specs)

GSoC USB: mid-term report

I stopped doing weekly reports at some point, for a very simple reason: I had few to report, except maybe my frustration that I couldn’t find the bugs in my OHCI driver that prevented some (but not all) devices from working.

So I spent the last weeks tracking down these issues and reading specs and more specs. Both OHCI and xHCI – the latter because it’s part two of my project, and because I was close to giving up OHCI for now and working on xHCI first. It’s an independent task, so that could have been done easily.

Today, I managed to hunt down the bug. It was a simple fix once I found out what’s up. While this uncovered more problems, I can move forward again.

To prevent me from hanging 4 weeks on the next bug, I’ll start on xHCI nonetheless, while doing OHCI on the sideline. Most of OHCI is done, and I guess I can start pushing code upstream soon – just one feature (interrupt transfers, so keyboards work) and a couple of cleanups are missing.

GSoC USB: first successful transfer

Just got this:
FILO version 0.6.0 () Fri Jun 11 13:38:04 GMT 2010
00:03.2 0223:1166.2 EHCI controller
Not supported.
00:03.1 0223:1166.1 OHCI controller
00:03.0 0223:1166.0 OHCI controller
fullspeed device
device 0x3606:0x0151 is USB 2.0 (MSC)
it uses SCSI transparent command set
it uses Bulk-Only Transport protocol
using endpoint 82 as in, 1 as out
has 1 luns
Waiting for device to become ready... ok.
spin up. OK.
Reading capacity of mass storage device.
has 256000 blocks sized 512b
boot:

For this to work, the OHCI root hub must work (to find the USB device), control transfers must work (setup the address, get some general information about it, like “SCSI”, “Bulk-Only”, endpoints, and LUNs), and bulk transfers must work (“256000 blocks of 512b” is got through SCSI/MMC2 commands via bulk)

There’s still quite some work left, as this only works on selected USB devices (more timing resilient than the others?) and errors are neither detected nor handled so far.

Once this is stable and survives all my USB gear, I have to implement interrupt transfers (mostly for keyboards) and my first part of GSoC, OHCI, is done. :-)

USB development for this year’s GSoC

After starting the USB stack in libpayload in the Google Summer of Code of 2007, I’m back this year to implement some more drivers. So far, we support UHCI Controllers – that is, USB1.x on Via and Intel chipsets.

There are also patches to support OHCI which are under GPL licensing As libpayload ist BSD-licensed, this make it unsuitable for inclusion. So this year I’ll do a clean implementation of OHCI to get this matter settled.

With this, all USB1.x controllers except for some very rare pre-standard controllers will be supported. This also includes USB2 boards, which means all current mainboards out there, as USB2 simply requires “companion controllers” (which are usually OHCI or UHCI) for USB1 modes.

After this is done, I’ll start on USB3 support. USB3 is still relatively new, but there are two reasons to start working on it:

  1. USB3 will be more popular in the next years, so doing it now ensures that we have one issue less to care about.
  2. Unlike with USB2, xHCI (the host controller standard for USB3) doesn’t use the companion concept, but requires the controller to support USB1 to USB3 itself. This means that old drivers (for UHCI, OHCI or EHCI) won’t find any controller to work with on such boards.

Implementing OHCI and xHCI ensures that all current boards as well as those of the near future will be supportable by libpayload and its users.