Sunday, September 8, 2013

End of summer '13

The unusually warm summer proved a bit confusing to the psyche. The return of the Pacific Northwest rain of late brings me back to normalcy.

I haven't blogged in a while, but I must recommend and continue to be impressed by he writing of Tim Lewis at http://uefi.blogspot.com/. Really good stuff. I have appreciated the opportunity to work with Tim over the last decade or so and I am in continual awe of his intelligence and prolific output.

Let's begin with something of a meta-blog as an introduction today. I sometimes censor my content for fear of being read as an advocate of a specific technology, or detractor of another. Sometimes 'is' versus 'ought' gets confused in such writings, namely the difference between describing a technology and evangelizing the same. I felt alone in this tension until listening to Violet Blue and her description of today's confusion around 'information' versus 'advocacy' with the tech culture. The talk 'Hackers As A High-Risk Population [29c3]' https://www.youtube.com/watch?v=zq-bloM4Cmo elaborates on this point, among others.

Of course, I surely have subconscious confirmation bias based upon areas with which I'm more familiar, but information comprises the intent of the following.

Enough of the caveats, let's talk about architecture versus implementation.

In the world of central processing units and hardware, we often refer to the distinction as 'architecture' versus 'micro-architecture.' The former describes the public description of the instruction set architecture (ISA), memory model, protection modes, and other modalities of the hardware that provide the consistency against which compiler writers, application developers and system software engineers can base their software development. For Intel, these details are codified in the Software Developer Manual (SDM) http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html. The micro-architecture, on the other hand, provides details on 'how' the architecture is implemented given adherence to the architecture as an outward constraint, but compounded with additional constraints of design inventiveness, power envelopes, transistor budgets, design invention, and schedule constraints, among others. It is in the world of micro-architecture where techniques like in-order versus out-of-order, additional functional units, bus width, number of ports to the memory and register file, micro-coded versus hardwired, and other techniques come into play.

That's for the world of CPU's and hardware. Correspondingly, the world of software defines the demarcation as 'interface' versus 'implementation.' The former include the POSX API's, Win32, the UEFI Boot Services, and to even stretch the metaphor a bit, network wire protocols. For the latter, implements include the Linux kernel, Microsoft Windows, the edk2 development project, and the venerable BSD TCP/IP network stack. The line is not always clear initially, and some implementations become a de facto implementation, such as the Microsoft DOS binary executable. The same holds true for the original PC/AT, where the public description http://bitsavers.trailing-edge.com/pdf/ibm/pc/at/1502494_PC_AT_Technical_Reference_Mar84.pdf of the hardware and software 'implementation' became the 'architecture' foundation, now referred to nostalgically or disparagingly as 'legacy', of the PC ecosystem.

Let's get into some details on where the architecture and implementation come together with respect to host firmware. From a most generic taxonomy, there are two phases of execution. The first is a 'platform initialization' and the second is a 'boot loader' phase. The former phase entails initialization of the system board hardware and passing control to the boot loader phase.

All of these processes of booting entail passing control from one domain of execution into another. These can include system boards that need boot firmware to launch a shrink wrap OS or a vertically integrated embedded system wherein the firmware producer and the OS producer are the same entity. There are often different instances in the market depending upon the requirements of the business entities.

For the first phase, here is a quick chart mapping two well-known boot firmware technologies found on Intel Architecture.

Platform InitilizationcorebootUEFI PI

Reset vector Boot block SEC

Memory init ROM stage PEI

I/O init RAM stage DXE

Boot loader phase Payload BDS

Of the boot loader phases using coreboot payloads, these can include U-Boot as an implementation with SeaBIOS and a direct kernel load as alternate 'hand-offs' of control. Those hand-offs of control can include the Advanced Configuration and Power Interface (ACPI) http://www.acpi.info or the flattened device tree (FDT) evolved from open firmware IEEE 1275 http://www.openfirmware.org/1275/. For the boot loader phase of the UEFI PI, the most well known embodiment is the Unified Extensible Firmware Interface (UEFI) presently at revision 2.4 http://www.uefi.org.

The story is not so straightforward, though. Coreboot can have edk2-style firmware as a payload, such as found in the 'PIANO' project, or 'Payload using Tiano.' Recall that "Tiano" was Intel's original code-name for what became the Intel (R) Framework and EFI, then UEFI PI and UEFI reference implementation. You can still find reference to 'Tiano' on the edk2 project http://sourceforge.net/apps/mediawiki/tianocore/index.php?title=EDK2, too. Correspondingly, the Boot Device Selection (BDS) driver in a edk2-based PI implementation can do a direct Linux kernel load and publish a FDT, as found in ARM Ltd's (R) adaptation of edk2 in https://svn.code.sf.net/p/edk2/code/trunk/edk2/EmbeddedPkg/.

The point of FDT/ACPI is to expose non-discoverable resources to the operating system. And the point of U-Boot/UEFI is to assist in loading the operating system kernel via the local NV store, disk, or network and passing control to the same. We discuss some of the uses of UEFI/PI for embedded at http://linuxgizmos.com/using-uefi-in-embedded-and-mobile-devices/, too.

Recall my mention of Intel Architecture above. In general, UEFI has processor bindings to 32-bit or IA32 and 64-bit Intel Architecture, or 'x64' as known in the UEFI spec. The latter has been alternately called x86-64, AMD64, EM64T, and Intel64. UEFI also supports Intel(R) Itanium and both 32-bit and 64-bit ARM ISA. The latter 2 are Aarch32 and Aarch64, resp. Beyond that, there have been ports to other architectures not covered by the UEFI specification, such as 32-bit MIPS http://sourceforge.net/projects/efi-mips/.

Correspondingly, the coreboot tip has IA32 support and recently has added 32-bit ARM. In the past, PowerPC support was also found in this project.

U-Boot has an even broader CPU support set since for certain CPU and platform architecture, the hand-off to the "Boot Loader Phase" can be done by opaque firmware and hardware in the platform. In other words, the "reset vector", "memory init," and "I/O init" happen in the 'hardware' and do not require UEFI PI or coreboot style processing.

So in the spirit of 'information' versus 'advocacy,' you can see that the different facets of the solutions above can map to alternate deployment needs. For a shrink-wrap OS that wants a guarantee of system board behavior into the "boot loader phase," the industry standard ACPI+UEFI couplet has some merit. For defacto standards like the kernel load protocol of Linux, FDT+U-Boot or FDT+UEFI may suffice.

And the distinction between architecture and implementation rears its head again with respect to security. As noted as recently as Blackhat this year by Yuriy Bulygin, et al. http://www.blackhat.com/us-13/speakers/Yuriy-Bulygin.html in their presentation http://c7zero.info/stuff/Windows8SecureBoot_Bulygin-Furtak-Bazhniuk_BHUSA2013.pdf, any flaws in implementation of the architecture can allow for bypassing of the controls for which the architecture was intended to enforce. In this case, the policy objects and implementation of UEFI Secure Boot represented the implementation artifacts that failed to successfully refine the architecture to the code in the system board storage. This is an example of the classic assurance consideration and reads into the firmware design space. Security is not alone. Performance, manageability ease-of-use, size, and other metrics can be impacted by the refinement process of a high level architecture to code.

As a final thought, I will be at the Intel Developer Forum next week talking about "UEFI Secure Boot and Linux" https://intel.activeevents.com/sf13/connect/sessionDetail.ww?SESSION_ID=1064. This talk reads on many of the themes treated in this blog around building an implementation of an architectural feature, specifically the administration of policy objects for features like UEFI Secure Boot. For this talk, the architecture of UEFI Secure Boot can be found in Chapter 26 of the UEFI 2.4 specification. This has our familiar friends the Platform Key (PK), Key Exchange Key (KEK) and the allow/disallowed list of the db/dbx. These authenticated variables and how they inform the policy-based load of 3rd party UEFI images is well defined in that document. What is absent from the document is how a security administrator (e.g., security_admin_r) or end user manages the UEFI Secure Boot behavior. This gap stems from the absence of manageability interfaces to a given platform in the UEFI Specification, among other things.

So in order to appreciate UEFI Secure Boot as an end user, the description and implementation of the feature in chapter 26 is necessary but not sufficient. Even for assessing the overall integrity goals of the feature, you need to assess the end-to-end solution, such as shown below in one embodiment.

End-to-end platform integrity

As you can see from above, the underlying UEFI PI implementation must guarantee its provenance, such as through NIST 800-147 http://csrc.nist.gov/publications/nistpubs/800-147/NIST-SP800-147-April2011.pdf specified updates. Another means by which to effect the same would be a load-time verification of the UEFI PI code from the 'hardware' block that I will discuss at IDF. Finally, SUSE will discuss some options to support the "OS Secure Boot." Note that the UEFI specification only reads on the center of the diagram, and even for this portion, it does not describe how to manage the PK, KEK, and DB/DBX other than through cryptographically signed updates of the same by the private key owner.

For the latter key management, a end user who is a kernel hacker may manage the key store directly via physically present interaction with the firmware setup screens and load his/her own keys. A consumer, on the other hand, just wants it 'to work' with live CD's and other shrink-wrap binary images from different OS vendors without any administrative changes. In the former two cases, the 'owner' and 'user' are typically one in the same. A corporate IT, on the other hand, only wants the IT staff to manage and change these options since the 'user' or knowledge worker of a client machine is distinct from the 'owner', who is typically the knowledge worker's employer. And the IT staff simple acts as an agent of the owner and the owner's elevated privileges.

On the subject of assurance, many people use UEFI variables for storing PI-specific content. The problem with that scheme is that after the signalling of EFI_END_OF_DXE_EVENT_GUID from volume 2 of the UEFI PI spec at www.uefi.org (aka "Exit PM_AUTH" from http://www.intel.com/content/dam/doc/white-paper/uefi-pi-tcg-firmware-white-paper.pdf or "Exit Mfgr Auth" from http://www.uefi.org/sites/default/files/resources/Intel-UEFI-ThreatModel.pdf) and/or when BDS does a connect on the driver load list and the UEFI boot variables, 3rd party UEFI content will run. Even in the case of UEFI Secure Boot, you know the provenance of code but not if the UEFI loader or OS runtime will attack the platform. Given that case, the PI-only variables should be prohibited from change by the 3rd party UEFI drivers, applications and operating system runtime. One way to do this protection is to use the edk2 variable lock protocol (EDKII_VARIABLE_LOCK_PROTOCOL) http://permalink.gmane.org/gmane.comp.bios.tianocore.scm/842. Note that this API is in the edk2 project but not prefixed with "PI" or "EFI" since it does not exist in the industry standard specification. This API allows for downgrading a variable to read-only (RO) from read-write (RW) prior to running third party code. It also covers a gap in the UEFI and PI specifications wherein the SetVariable API in chapter 7 of the UEFI specification does not read on creation of RO variables; the main UEFI specification only describes the need for a set of RO variables to exist. How the underlying PI-based code creates these RO UEFI variables was left as an exercise for implementations. The EDKII_VARIABLE_LOCK_PROTOCOL provides one 'answer' to that exercise.

So what have we seen in this blog?

1) Explanation of technology without marketing for same

2) Many examples of architecture versus implementation

3) For boot firmware, there are many different architecture and implementation

4) Take due care in traversing from architecture to implementation

5) Take a systems view of a solution beyond a given technology's architecture and implementation