© Jiewen Yao and Vincent Zimmer 2020
J. Yao, V. ZimmerBuilding Secure Firmwarehttps://doi.org/10.1007/978-1-4842-6106-4_11

11. Configuration

Jiewen Yao1  and Vincent Zimmer2
(1)
Shanghai, China
(2)
Issaquah, WA, USA
 

User-configurable data can be used to control the firmware behavior with the same firmware code. The configuration data is designed to be updatable and mutated by the end user, whereas the firmware code is typically only editable by the platform manufacturer. As such, the protection of configuration data is different from the protection of the firmware code.

A UEFI variable is a way to store the UEFI firmware configuration. Let’s take UEFI variables as an example to describe the different protection mechanisms. These mechanisms can be used for alternate implementation choices to implement the firmware configuration data.

UEFI Variables

According to the UEFI specification, UEFI variables are intended to store the data that is passed between the UEFI components, such as components from the platform manufacturer, UEFI applications, or UEFI OS loaders. The classic CIA (confidentiality, integrity, availability) security attributes should be considered properties of UEFI variables. The adversaries attacking UEFI variables can be categorized as software attackers and hardware attackers. Software attack can be performed via calling UEFI SetVariable/GetVariable API and using code to directly read/write the area where the variables are stored or cached, and hardware attack can be performed via powering off the system during variable update or using a flash programmer to read/write the flash region where the variables are stored. See Table 11-1 for the UEFI variable protection mechanisms. We will describe them one by one.
Table 11-1

UEFI Variable Protection Mechanisms

Mechanism

Resist Software Attack

Resist Hardware Attack

Integrity protection

Variable authentication

Trusted Execution Environment

Variable Lock

Variable Sanity Check

Variable with RPMB

Variable with RPMC

Variable with TPM storage

Availability protection

Variable quota management

Flash wear-out protection

Variable atomicity

Fault-tolerant write (FTW)

Confidentiality protection

User Key Encrypted Variable

Platform Key Encrypted Variable

User Key Encrypted Variable

Integrity Protection

Variable Authentication

The purpose of variable authentication is to ensure the entity that calls the SetVariable() API to update the UEFI variable has the authority to update the variable. According to the UEFI specification, the caller needs to provide the updated variable with the signed certificate in order to update an authenticated variable.

There are three kinds of authenticated variable formats:
  1. 1)

    Count-based authenticated variable, if the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute is set (this is deprecated)

     
  2. 2)

    Time-based authenticated variable, if the EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set (currently used)

     
  3. 3)

    Extensible authenticated variable (time based or nonce based), if the EFI_VARIABLE_ENHANCED_AUTHENTICATED_WRITE_ACCESS attribute is set (new)

     
When a user calls the SetVariable() API, the authenticated variable input data format is used. There is a timestamp or a nonce associated with the authentication descriptor. For the certificate type field, only PKCS7 is accepted for a time-based authenticated variable or extensible authenticated variable. The certificate is DER-encoded PKCS#7 version 1.5 SignedData. The most important fields are the signer’s DER-encoded X.509 certificate, SHA256 hash of the metadata (VariableName, VariableGuid, Attributes), second descriptor (timestamp or nonce), optional additional nonce, optional additional certificate, and new variable data content. The descriptor is an extensible structure to identify a unique X.509 cert associated with a given variable. It could be a timestamp or a nonce value. The Authenticated Variable driver will check the authentication descriptor before updating the variable content. Figures 11-1 and 11-2 show the format of a time-based auth variable input and a nonce-based authenticated variable input. (* means the field is optional.)
../images/488723_1_En_11_Chapter/488723_1_En_11_Fig1_HTML.png
Figure 11-1

Authenticated Variable Input Format (Time Based)

../images/488723_1_En_11_Chapter/488723_1_En_11_Fig2_HTML.png
Figure 11-2

Authenticated Variable Input Format (Nonce Based)

As we discussed in Chapter 4, the secure boot–related keys, such as PK, KEK, db/dbx, and so on, are authenticated variables. When the system firmware is created, these keys might not be provisioned. According to the UEFI specification, the system is in setup mode when a PK is NOT enrolled, whereas the system is in user mode when a PK is enrolled. The secure boot feature can only be enabled in user mode. See Figure 11-3.
../images/488723_1_En_11_Chapter/488723_1_En_11_Fig3_HTML.png
Figure 11-3

UEFI Secure Boot Setup Mode vs. User Mode

In the UEFI 2.5 specification, two additional modes were added – deployed mode and audit mode (see Figure 11-4). Audit mode is an extension for setup mode. Audit mode enables programmatic discovery of signature list combinations that successfully authenticate installed EFI images without the risk of rendering a system unbootable. Chosen signature list configurations can be tested to ensure the system will continue to boot after the system is transitioned out of audit mode. After transitioning to audit mode, signature enforcement is disabled such that all images are initialized and enhanced Image Execution Information Table (IEIT) logging is performed including recursive validation for multi-signed images.
../images/488723_1_En_11_Chapter/488723_1_En_11_Fig4_HTML.jpg
Figure 11-4

UEFI2.5 Secure Boot Modes (Source: UEFI Specification)

Deployed mode is an extension for user mode. Deployed mode is the most secure mode. By design, both user mode and audit mode support unauthenticated transitions to Deployed Mode. However, to move from deployed mode to any other mode requires a secure platform-specific method, or deleting the PK, which is authenticated.

Updating the secure boot keys (PK, KEK, db/dbx, etc.) requires signing verification. However, it prevents the end user from updating the secure boot keys because the end user does not have the PK or KEK. As such, EDK II introduced two special secure boot modes (see Figure 11-5):
  1. 1)

    Standard secure boot mode: The default mode to follow the UEFI specification

     
  2. 2)
    Custom secure boot mode: Allows more flexibility as specified in the following:
    • PK variable update need NOT be signed by an old PK.

    • KEK variable update need NOT be signed by a PK.

    • Image signature database (db/dbx), timestamp database (dbt), and recovery database (dbr) update need NOT be signed by PK or KEK.

     
../images/488723_1_En_11_Chapter/488723_1_En_11_Fig5_HTML.png
Figure 11-5

Standard Secure Boot Mode vs. Custom Secure Boot Mode

The switch between standard mode and custom mode needs user physical presence, as we discussed in Chapter 10. There must be a platform-specific way to detect if a physical user is present in order to perform such an action.

In order to update the PK or KEK, the following authentication flow is used. First, if the system is in CustomMode with UserPhysicalPresent, no authentication is needed. Second, if the system is in setup mode, no authentication is needed with the PK. Third, if the system is in user mode, authentication with the PK is performed. Last, if the system is in setup mode to enroll the PK, authentication with this payload is performed. See Figure 11-6.
../images/488723_1_En_11_Chapter/488723_1_En_11_Fig6_HTML.png
Figure 11-6

Variable Authentication Flow – ProcessVarWithPk

In order to update the image signature database (db/dbx), timestamp database (dbt), or recovery database (dbr), the system will invoke ProcessVarWithPk at first. If this routine fails, the system will invoke ProcessVarWithKek. First, if the system is in CustomMode with UserPhysicalPresent, no authentication is needed. Second, if the system is in setup mode, no authentication is needed. Last, authentication with KEK is performed. See Figure 11-7.
../images/488723_1_En_11_Chapter/488723_1_En_11_Fig7_HTML.png
Figure 11-7

Variable Authentication Flow – ProcessVarWithKek

Other authenticated variables (other than those secure boot related) do not require the PK/KEK verification. The verification flow is different. First, if the variable requires physical presence, but the user is not physically present, the update request is rejected. Second, if the variable is a time-based authenticated variable, authentication with time and the creator’s key is performed. Last, if an old variable has an AUTHENTICATED attribute which does not patch the current one, the update request is rejected. Or it means no authentication is needed. See Figure 11-8.
../images/488723_1_En_11_Chapter/488723_1_En_11_Fig8_HTML.png
Figure 11-8

Variable Authentication Flow – ProcessVariable

Trusted Execution Environment

Similar to firmware image signing verification, the variable authentication and update requires a trusted execution environment. That achieves the non-bypassability of the capability.

The UEFI or OS runtime is not a trusted execution environment. For X86 systems, system management mode (SMM) is used for the implementation of the variable authentication services. The UEFI runtime service SetVariable puts the variable data and signature into an SMM communication buffer and triggers an SMI. Then the SetVariableHandler is invoked. It copies the communication buffer data into SMM and then processes the variable by performing the authentication and update. See Figure 11-9.
../images/488723_1_En_11_Chapter/488723_1_En_11_Fig9_HTML.png
Figure 11-9

TEE-Based Auth Variable Update

Variable Lock

In addition to user configuration variables, the system may need to record the current platform data at runtime. For example, it can include the memory initialization training data. Memory training is time-consuming, and the training data is the same across a warm reset or S3 resume. As such, there is no need to train the memory again. We may save the training data to the non-volatile storage and restore the configuration directly after a warm reset or during a S3 resume.

How can we can make sure the configuration data is not modified by another entity? The easiest way is just to lock the variable and make it unchangeable at some point in time.

EDK II implements the EDKII_VARIABLE_LOCK_PROTOCOL to support marking some variables READ ONLY, by adopting the following rules:
  • Before the EndOfDxe event, the EDKII_VARIABLE_LOCK_PROTOCOL.RequestToLock() API is used to submit a Variable Lock request.

  • This lock request itself is volatile. That means RequestToLock() must be called each boot.

  • After the EndOfDxe event, the RequestToLock() API is closed.

Variable Lock policy rules are as follows:
  • Before the EndOfDxe event, Variable Lock does not take effect because only the OEM BIOS code is executed and trusted.

  • After the EndOfDxe event, Variable Lock takes effect in the DXE or OS runtime phase because the third-party code is not trusted. A locked variable cannot be deleted or updated. A locked variable cannot be created if it has not existed before.

  • Variable Lock does not have any effect in SMM because SMM is constructed by the OEM BIOS and there is no non-platform code in SMM. Inside SMM, the variable can still be updated.

A full summary is shown in Figure 11-10.
../images/488723_1_En_11_Chapter/488723_1_En_11_Fig10_HTML.png
Figure 11-10

Variable Features in Each Phase

RO means read-only.

RW means read/write.

RWC means read/write, with reclaim feature.

RWL means read/write, with lock feature.

The UEFI specification also defined other attributes such as RUNTIME (RT). Variables with the RT attribute are not accessible after the Exit Boot Service event.

Variable Sanity Check

A platform may define a setup variable that can be used by the UEFI Human Interface Infrastructure (HII) so that users can control the platform settings by updating a setup User Interface (UI). For example, a user can configure a SATA controller to be in IDE mode or AHCI mode or RAID mode. A setup variable field SataMode is used. 1 means IDE mode, 5 means AHCI mode, and 6 means RAID mode. Other values, such as 0, 2, 3, 4, or 7, are considered as invalid input.

The problem is that there is no way to check if some variable fields are valid and reject invalid variable updates. In the preceding example, when the code calls SetVariable() to update a setup variable, we hope the variable driver can check SataMode to see if the setting is valid (1, 5, or 6) and reject the variable update if the setting is invalid.

In order to resolve this problem, EDK II introduced “Variable Check” – the capability of checking variable contents based on a predefined policy.

In order to check a variable, a driver can register a SetVariable check handler to define properties for a specific variable:
  • Attributes: UEFI-defined variable attributes (BS, RT, NV, etc.)

  • Property: Non–UEFI-defined variable attributes (READ_ONLY)

  • MinSize: The minimum size of the variable data

  • MaxSize: The maximum size of the variable data

A system can have multiple variable checkers. Two examples of checkers are a UEFI Human Interface Infrastructure (HII)–based checker and a UEFI Platform Initialization (PI) Platform Configuration Database (PCD)–based checker:
  1. 1)

    HII-based checker

     

The UEFI specification’s HII section defines HII opcodes that allow the setting UI to be linked with UEFI variable storage. Some other setup options go through the HII_CONFIG_ACCESS_PROTOCOL. They could link to a variable or some other storages. If a variable is associated with a setup option, we can use data in HII IFR opcode to check the legal configuration of variable content. For example, the variable mapped to the ONE_OF_OP, NUMERIC_OP, ORDERED_LIST_OP, or CHECKBOX_OP must be in a predefined range.

In order to achieve preceding checks, the VarCheckHii handler needs to get HII data from two sources:
  • Static HII data: HII data built inside of the firmware volume. The EDK II build tool generates HII information into an FFS raw section (see Figure 11-11) or a UEFI-specific PE/COFF resource. The typical usage is setup configuration data. The information can be retrieved even if some special setup data is not installed into the HII database due to the current hardware configuration.

../images/488723_1_En_11_Chapter/488723_1_En_11_Fig11_HTML.png
Figure 11-11

HII Build Time Info

  • Dynamic HII data: HII data exposed by the HII_DATABASE_PROTOCOL. This is the UEFI-defined way to get HII data from the HII database. The platform code or third-party option ROM may construct HII data dynamically from C code. All HII data is exposed by the HII_DATABASE_PROTOCOL.

Figure 11-12 shows the VarCheckHii process during system boot. During initialization, VarCheckHiiGen() collects HII information from the FV and HII_DATABASE_PROTOCOL and generates VarCheckHiiBin – a compact data structure to store the ONE_OF, NUMERIC, and CHECKBOX information. During runtime, SetVariableCheckHandlerHii() refers to VarCheckHiiBin to check if the variable content is legal. If variable attributes are different, data size is different, or the content does not satisfy the HII question, the variable content is treated as illegal, and EFI_SECURITY_VIOLATION is returned to the SetVariable() call to reject the variable update.
../images/488723_1_En_11_Chapter/488723_1_En_11_Fig12_HTML.png
Figure 11-12

Variable Check HII

The EDK II VarCheckHii handler just uses a simple policy for ONE_OF, NUMERIC, and CHECKBOX opcodes because they are the most popular questions used for platform setup. A known limitation is that the inconsistent error checking opcodes are not supported, because evaluating these opcodes would require IFR expression parser support or reading other variable storage or buffer storage. The implementation might be too complicated.
  1. 2)

    PCD-based checker

     
EDK II PCDs are mapped to a UEFI variable if it is instantiated using the PcdDynamicHii access type. The EDK II PCD implementation also supports defining a set of valid configurations for a specific PCD in a DEC file, for example:
  • @ValidList: Variable data must be in the list.

  • @ValidRange: Variable data must be in the range.

Therefore, we have a way to check if the PCD-mapped variable is legal.

The EDK II build tool generates the information, and the information may be encoded in binary form in an FFS raw section. See Figure 11-13. During initialization, LocateVarCheckPcdBin () gets the VarCheckPcdBin binary from the FFS raw section. During runtime, SetVariableCheckHandlerPcd() refers to VarCheckPcdBin to check if the variable contents are legal. If variable attributes are different, variable size is too small, or the content does not satisfy the valid list or valid range for the PCD, then the variable content is treated as illegal, and the EFI_SECURITY_VIOLATION status code is returned.
../images/488723_1_En_11_Chapter/488723_1_En_11_Fig13_HTML.png
Figure 11-13

Variable Check PCD

PCDs include the offset in the variable but not the variable’s size. We can only check if a variable is too small, but we cannot determine if a variable is too large. This is a known limitation of VarCheckPcd.

The EDK II VarCheckPcd handler uses a simple policy for @ValidList and @ValidRange. A known limitation is that PCD’s @Expression validity check is unsupported, since this needs expression parser support. The implementation might be too complicated.

The variable checker only checks the variable format in SetVariable() API. It does not check variable format in GetVariable() API, assuming that if variable data is checked on Set, it must be correct on Get.

This assumption is true if our adversary is a software attacker, but it is not true for the hardware attacker, which we will discuss in the following section.

Variable with Replay Protected Memory Block (RPMB)

Some storage devices support Replay Protected Memory Block (RPMB) capability, such as those conforming to the Non-Volatile Memory Express (NVMe), Embedded Multimedia Card (eMMC), or Universal Flash Storage (UFS) specifications. In such devices, there is a special partition named the RPMB partition. Writing to the RPMB partition requires special hardware authentication. Reading from a RPMB partition returns the signature of the data for authentication.

Two key elements are involved in RPMB:
  • A RPMB key only known by the device and the host Trusted Execution Environment (TEE) for write protection.

  • A monotonic counter to resist replay attack

The variable implementation may use the RPMB partition (see Figure 11-14). In the manufacturing phase, each device has a unique RPMB key generated, and that key is programmed into the device’s one-time programmable (OTP) area. The RPMB key is only known by the host TEE.
../images/488723_1_En_11_Chapter/488723_1_En_11_Fig14_HTML.png
Figure 11-14

Variable with RPMB

When writing, the host TEE needs to read the device monotonic counter, calculate the hash-based message authentication code – HMAC(RPMB key, data || monotonic counter) – and send data, monotonic counter, and HMAC to the device. The device will check if the monotonic counter is the same as the current one. If they are the same, then the device will verify the HMAC value. Only after the HMAC verification passes the device writes the data into the RPMB area and increases the monotonic counter.

When reading, the host TEE generates a random value and sends the read request to the device. The device reads out the data, calculates the HMAC(RPMB key, data || random value), and sends the data, random value, and HMAC to the host. After the host gets the data, the host will check whether the random value is the same as the current one. If they are the same, then the host will verify the HMAC value. Only after the HMAC verification passes the host can then make sure the data is from the real RPMB device.

One RPMB-capable device may have multiple RPMB partitions. Each RPMB partition can only have one owner. If we save UEFI variables into a RPMB partition, the BIOS is the owner for this partition. The SMM and Management Engine (ME) can be used as a TEE. In the manufacturing phase, the ME can generate a unique RPMB key and provision it to the RPMB device. During runtime, the SMM variable driver can get the RPMB key from the ME and get the monotonic counter from the RPMB device. When a UEFI runtime service is used to set a new variable, it sends a request to the SMM variable driver. The SMM variable driver then calculates the HMAC and sends both data and HMAC to the RPMB device. Then the RPMB device verifies the HMAC and writes the data onto the RPMB storage area.

The hardware attack to the variable won’t succeed since the attacker does not know the RPMB key. As such, they cannot create a HMAC for the new variable data.

The replay attack can also be mitigated based upon the fact that the HMAC includes a monotonic counter. Writing old data will be rejected because the counter in the old HMAC does not match the current one.

Variable with Replay Protected Monotonic Counter (RPMC)

RPMB requires special storage devices. If a system does not have such a RPMB-capable device but only has a traditional SSD and SPI flash, then the enhanced SPI flash with Replay Protected Monotonic Counter (RPMC) capability can be used.

The RPMC device has a monotonic counter. A unique RPMC key is required to increment the monotonic counter. In the manufacturing phase, each RPMC device has a unique RPMC key generated and programmed into the device’s one-time programmable (OTP) area. The RPMC key is only known by the host TEE. As such, the host TEE can increment the monotonic counter with the MAC-based authentication.

RPMC SPI devices have no flash write authentication capability. The host TEE can access the RPMC-capable SPI device like a normal SPI device. The value of the RPMC SPI device that it provides a monotonic counter which can help to resist the replay attack.

The variable implementation may leverage the RPMC counter and a platform key in the ME (see Figure 11-15). In the manufacturing phase, the ME can generate a unique RPMC root key and provision the key into the RPMC device. During system initialization, the ME can generate a random RPMC HMAC key and program the RPMC HMAC key to the RPMC device via the UpdateHmacKey() command with HMAC(RPMC root key, new HMAC key data).
../images/488723_1_En_11_Chapter/488723_1_En_11_Fig15_HTML.png
Figure 11-15

Variable with RPMC

During runtime, the SMM variable driver can get the platform key from the ME for variable data MAC and get the RPMC HMAC key from the ME to increment the monotonic counter of the RPMC device. The SMM variable driver also gets the monotonic counter from the RPMC device. When the SMM variable driver gets a request to update a variable, it uses the platform key and the monotonic counter to create a HMAC for the variable region – HMAC(platform key, Variable1 || Variable2 || … || VariableN || Monotonic Counter), with VariableX = Name || Guid || Attributes || DataSize || Data. Then the SMM variable driver saves both the data and the HMAC to the flash device. This HMAC is saved as the variable metadata. Because the HMAC is calculated with the platform key, the attacker cannot tamper with the HMAC. Finally, the SMM variable driver sends the IncrementCounter() command to the RPMC device with HMAC(RPMC Hmac Key, monotonic counter). On the next boot, the variable driver reads all of the variable data and the metadata. The variable driver calculates the HMAC with the platform key, all variable data, and the monotonic counter. Then the variable driver compares the calculated HMAC with the variable metadata. If they are the same, then the variable region is good. Otherwise, the variable region has been updated by an unauthorized entity. After such a mismatch is found, the recovery process is triggered.

Hardware writes to the variable region will succeed. However, this attack will be detected on the next boot based upon the variable’s metadata and based upon the fact that the attacker does not have the platform key and cannot create the valid HMAC. Once the attack is detected, the system firmware must trigger the variable recovery process. The firmware settings for recovery have been discussed in Chapter 5.

The replay attack can also be mitigated based upon the fact that the HMAC includes a monotonic counter. Writing the same old data will be rejected because the counter in the old HMAC does not match the current one. Also, the attacker cannot send the command to increment the RPMC monotonic counter, based upon the fact that the attacker does not have the RPMC root key and RPMC HMAC key.

Compared with RPMB, the RPMC solution is more difficult to implement because the SMM variable driver needs to calculate a metadata variable to store the MAC for the variable region and also needs increment the monotonic counter. The advantage of the RPMC solution is that there is no flash device dependency – the SPI device can be used. The difference between RPMC-based SPI flash solution and RPMB-based NVMe/eMMC/UFS flash storage solution is in Table 11-2.
Table 11-2

Variable with RPMB vs. RPMC

Property

RPMB

RPMC

Flash device

NVMe/eMMC/UFS.

SPI.

Monotonic counter

Stored in the RPMB device.

Counter increased for every write.

Stored in the RPMC device.

Counter increased for every write.

Secret key

RPMB key:

One time non-volatile.

Provisioned into RPMB during manufacture.

Host TEE gets the key from the ME during runtime.

RPMC root key:

One time non-volatile.

Provisioned into RPMC during manufacture.

RPMC HMAC key:

Generated during boot time.

Host TEE gets the key from the ME during runtime.

Platform key:

One time non-volatile.

Host TEE gets the key from the ME during runtime.

Content storage

In RPMB device.

In SPI flash device.

Security property

Integrity, confidentiality, availability.

Integrity.

Protection (write authentication)

Done by the RPMB device.

Write MAC is calculated by the host TEE and verified by RPMB.

No. RPMC SPI flash does not have capability for write authentication.

MAC is calculated by the host TEE and stored on the flash device.

Detection (read verification)

Done by the host TEE.

Read MAC is calculated by the RPMB device and verified by the host TEE.

Done by the host TEE.

MAC is calculated by the host TEE at write operation and verified once during initialization in next boot.

Recovery

Not required.

Required, if the hardware modification is detected on the next boot.

Variable with TPM Storage

Besides the flash device, the TPM non-volatile storage may be used to hold the variable data (see Figure 11-16). Because the TPM chip is tamper proof, the simple hardware attacker may not modify the data in TPM directly. However, the limitation is that because of the TPM non-volatile storage size, we are not able to write very big non-volatile data into TPM.
../images/488723_1_En_11_Chapter/488723_1_En_11_Fig16_HTML.png
Figure 11-16

Variable with TPM NV Storage

The alternative is to record a hash of the variable data. As such, the unauthorized modification can be detected later if the attacker updated the variable region directly.

The TPM NV storage can be used to save UEFI variable data. It can also be used to save UEFI variable–independent data. As such, the caller needs to use the TPM interface to access the variable data, instead of the UEFI interface. If the TPM NV storage stores the hash, the variable data can be in the UEFI variable or other storage such as the file system, as long as the caller knows where to get the data.

The TPM non-volatile storage can be an NV index or a sealed object.

We have discussed sealing usage in Chapter 7. Here are the steps of sealed object usage. The VariableData is sealed to be a TPM object by the TPM2_Create command with AuthPolicyHash. The output is the public area (outPublic) and the encrypted sensitive area (outPrivate). The PCR value may be used as AuthPolicy. The outPublic and outPrivate are saved in UEFI NV. The outPublic and outPrivate can be used to unseal to the VariableData by the TPM2_Load and TPM2_Unseal commands.

The TPM NV index variable should be defined before it is used. A TPM NV variable must have an index, and index-specific authorization policies, which can be used to authorize reading and writing to the TPM NV. The policy includes a password/key, PCR value, locality value, read/write lock, and so on. These policies can be defined by the TPM2 Enhanced Authorization (EA) commands in a policy session. For a policy session, some commands require checking something at execution time. For example, TPM2_PolicyCounterTimer checks the TPMS_TIME_INFO structure, TPM2_PolicyLocality checks the locality information, TPM2_PolicyPCR checks the PCR value, and TPM2_PolicyPassword checks the password value. TPM2 provides a more flexible policy control via EA, which can be used to create the policy AND or policy OR. For example, one object may be accessed when the PCR value matches and the locality value matches. Another object may be accessed when the PCR value matches or the password value matches. We can store the VariableData into TPM NV with EA command PolicySession for access control. Table 11-3 shows the TPM storage usage. Besides integrity, the TPM storage solution can also provide confidentiality.
Table 11-3

Variable with TPM Storage

Property

TPM NV Index

(Data)

TPM NV Index

(Hash)

TPM Sealed Object

(Data)

TPM Sealed Object

(Hash)

TPM access control

The TPM NV index has flexible attributes, such as read lock, write lock, write once, and increment-only.

The TPM NV can use policy session for access control, such as PCRs, locality, and user password.

The sealed object is bound to TPM PCRs.

Security property

Integrity, confidentiality, availability.

Integrity.

Integrity, confidentiality.

Integrity.

Use case

Intel ACM/SGX secure version number (SVN).

coreboot firmware version number.

Intel TXT Launch Control Policy (LCP) – policy hash.

Windows BitLocker key.

 

Availability Protection

Variable Quota Management

Any system resource is limited, including variable storage. A typical platform may allocate around a 128K~256K region for variable storage. Sometimes the variable region may be full, and SetVariable() returns OUT_OF_RESOURCE. It might happen when a QA engineer runs a test in the UEFI shell or a hacker tries to attack the system in the OS. How do we handle that?

Most modern OSs (Linux and Windows) have disk quota management to set a limit for disk storage for a special user or group, give notification if the disk is nearly full, and let the user clean up. In EDK II, we enabled a similar mechanism for variable quota management.
  • EDK II defines a set of variable size–related PCDs:

  • PcdFlashNvStorageVariableSize: The whole variable storage region size on flash

  • PcdMaxVariableSize: The maximum size of a single non–HwErr-type variable

  • PcdMaxAuthVariableSize: The maximum size of a single authenticated variable

  • PcdMaxHardwareErrorVariableSize: The maximum size of a single hardware error record variable

  • PcdVariableStoreSize: The size of a volatile buffer

  • PcdHwErrStorageSize: The size of reserved HwErr variable space

  • PcdBoottimeReservedNvVariableSpaceSize: The size of NV variable space reserved at UEFI boot time

  • PcdMaxUserNvVariableSpaceSize: The size of maximum user NV variable space

The last three PCDs are used for quota management (see Figure 11-17).
../images/488723_1_En_11_Chapter/488723_1_En_11_Fig17_HTML.png
Figure 11-17

Variable Quota Allocation

PcdHwErrStorageSize indicates the space reserved for the UEFI hardware error logging variable only.

PcdBoottimeReservedNvVariableSpaceSize indicates the space reserved for UEFI boot time. Even if a malicious code writes into the variable space until out of resource state at OS runtime, the BIOS can still write a new variable at boot time.

PcdMaxUserNvVariableSpaceSize indicates the maximum space that can be used for a user NV variable. The EDK II variable driver divides variables into two groups: system variables and user variables. The following types of variables will be regarded as a system variable after EndOfDxe:
  • UEFI-defined variables (gEfiGlobalVariableGuid and gEfiImageSecurityDatabaseGuid variables at least), for example, L“ConIn”, L“ConOut”, L“db”, and L“dbx”

  • Variables managed by the variable driver internally, for example, L“CustomMode” and L“VendorKeysNv”

  • Variables that need to be locked and MUST be set by the Variable Lock protocol, for example, L“PhysicalPresenceFlags”

  • Important variables during platform boot – their properties SHOULD be set by the VarCheck protocol – for example, L“MemoryOverwriteRequestControl”, L“MemoryOverwriteRequestControlLock”, and platform setup variable for system configuration

If a variable is not a system variable, it is a user variable.

System variables can be authenticated variables or non-auth variables. User variables can also be authenticated variables or non-auth variables.

The reason the EDK II variable driver supports a limit for user NV variables is that the variable driver wants to make sure there is enough space for system variables. System variables are critical for system boot. User variables are less important.

When the quota limitation is hit, the EDK II variable driver needs to record the error. Then a platform owner may take action to recover the system to a good state.

This error information is recorded in the L“VarErrorFlag” variable. The EDK II variable driver uses 1 byte to record the error. 0xFF means no error. 0xEF means system variable out of space. 0xFE means user variable out of space. If the system gets a 0xEE later, it means both system variable and user variable are out of space.

On the next boot, if a platform detects L“VarErrorFlag” is in an error state, it may use a platform-specific way to clean up some unused variables. The system variables can be handled differently than user variables. The possible implementation could be
  • System variable out of space: Enter Setup to let the user load default settings; or force clear the variable region and treat as a first boot.

  • User variable out of space: Prompt a setup page and list all user variables to let the user select which user variables to be deleted or just delete all user variables.

Flash Wear-Out Protection

The SPI is a NOR flash device. In order to change a bit from 1 to 0, the code can send a WRITE command to the device to update 1 byte. However, in order to change a bit from 0 to 1, the code must send an ERASE command to the device to erase a 4 KiB or 64 KiB block to all 1s and then send a write command to update 1 byte. Ideally, the user is free to set configuration at any time. However, the SPI flash device has the ERASE limitation. When the number of flash ERASE actions reaches the limit, the flash is no longer usable.

The variable driver takes this into account on the variable storage design. The variable exists in a special variable firmware volume (FV). The variable FV can be identified by gEfiSystemNvDataFvGuid in the File System GUID field of the FV header. The Authenticated Variable can be identified by gEfiAuthenticatedVariableGuid in the GUID field of the variable store header. 0x5A in the Format field of a variable store header means this region is formatted. 0xFE in the State field of the variable store header means healthy. Figure 11-18 shows the variable storage format and the individual variable formats.
../images/488723_1_En_11_Chapter/488723_1_En_11_Fig18_HTML.png
Figure 11-18

Variable Storage Format

Each individual variable is saved after the variable storage header. 0x55AA in StartId of a variable header means there is a new variable storage. 0x3F in the State field means it is a valid variable added. 0x3D in the State field means it is deleted. In some rare case, system reset during variable update, a 0x7F in the State field means only the header is valid and no real variable data written. 0x3E in the State field means this variable is in delete transition.

The State field is extremely useful on variable updates. Figure 11-19 shows the variable update flow:
  1. 1)

    The old variable state is marked as InDeleted.

     
  2. 2)

    The new variable full header is added with state unchanged (0xFF).

     
  3. 3)

    The new variable state is changed to Header Valid state.

     
  4. 4)

    New variable full data is added.

     
  5. 5)

    The new variable state is changed to Added.

     
  6. 6)

    The old variable state is marked as deleted.

     
../images/488723_1_En_11_Chapter/488723_1_En_11_Fig19_HTML.png
Figure 11-19

Variable Update Flow

From the preceding variable update flow, when a variable is updated, it is actually not UPDATED in the original place, but marked as DELETED in the original place and then ADDED in a new place. If a user updates the variable several times, the non-volatile storage will have many DELETED variables which are useless but occupy storage space.

In this case, there is a mechanism called reclaim to reorganize the variable region (see Figure 11-20). Reclaim removes the DELETED variables to save space. Reclaim is triggered in the following conditions:
  1. 1)

    When updating a variable or adding a new variable and there is not enough free space

     
  2. 2)

    On exiting the OEM phase (EndOfDxe event) and there is not enough remaining free space

     
  3. 3)

    On initialization and the variable storage free space is not all 0xFF (there must be something wrong)

     
../images/488723_1_En_11_Chapter/488723_1_En_11_Fig20_HTML.png
Figure 11-20

Variable Reclaim

Ideally the variable reclaim should not happen frequently. However, the malicious attacker may manipulate a variable update service in a dramatic way and trigger variable reclaim again and again. Then the flash ERASE command is sent again and again, and finally that action causes the flash device to become broken.

To prevent this from happening, the ERASE command shall be only allowed at boot time within the OEM manufacture code . The ERASE command should be disabled at runtime. Only flash write is allowed to support a limited number of configurations. As such, the attacker has to boot the system again and again to perform the wear-out attack. Because the system reboot needs time, this can reduce the risk of flash wear-out.

Variable Atomicity

As we discussed how to update variable in the preceding section, only 1-byte write from bit 1 to bit 0 can be atomic for the NOR flash device from the hardware perspective. This state is designed to maintain atomicity of individual variables from the software perspective. Each variable exists in ALL-or-NONE state. A partial variable is not allowed. See Figure 11-19.

Fault-Tolerant Write

Individual variable atomicity is maintained by the variable update flow. However, during variable reclaim, the flash block will be erased and written again. In that period of time, if there is a power loss or system shutdown due to a user mistake, the variable firmware volume will be partially destroyed. That means if a variable crosses a flash block, it might be partially correct. The atomicity is broken in this scenario, which is not acceptable.

Fault-tolerant write (FTW) is designed to handle this situation. The EDK II FTW driver is not included in the variable driver. It is a standalone driver to provide the capability of fault-tolerant write. Every flash update driver can consume the FTW protocol API to update the flash part in a safe manner.

The following is a high-level picture of the fault-tolerant write flash layout. An FTW driver requires two flash parts:
  1. 1)

    FTW working block: This is a block to record a write action. It is the record block, not the data block.

     
  2. 2)

    FTW spare block: This is a real data block to save the data. It must be bigger than the size of the block required to perform the update. In this case, it must be bigger than the variable region.

     
In the FTW working block, the FTW driver puts a data structure to record the write request and write status. Figure 11-21 shows the fault-tolerant write flash layout.
../images/488723_1_En_11_Chapter/488723_1_En_11_Fig21_HTML.png
Figure 11-21

Fault-Tolerant Write Flash Layout

The signature field of the WORKING_BLOCK_HEADER is used to identify if it is the FTW working block. After the header, there will be multiple WriteQueueEntry’s. Each WriteQueueEntry has one WRITE_HEADER and one or more WRITE_RECORDs. The number of WRITE_RECORDs is recorded as the NumberOfWrites fields of the WRITE_HEADER. The most important fields are the Complete field of the WRITE_HEADER, the SpareComplete, and the DestinationComplete of the WRITE_RECORD. Those fields record the status of writes and guarantee the fault tolerance.

Now, let’s see how FTW->Write() works. Figure 11-22 shows the detailed steps:
  1. 1)

    Step 1: When FTW->Write() is invoked, this API will record the request in the FTW working block.

     
  2. 2)

    Step 2: This API finds SpareBuf on the FTW spare flash area and backs it up to memory.

     
  3. 3)

    Step 3: This API writes NewData to the FTW spare block, instead of the variable FV.

     
  4. 4)

    Step 4: After that, it sets the SpareComplete flag in the FTW working block.

     
  5. 5)

    Step 5. This API writes NewData from the FTW spare block to the variable FV.

     
  6. 6)

    Step 6: After that, it sets the DestinationComplete flag in the FTW working block.

     
  7. 7)

    Step 7: If it is the last WRITE_RECORD associated with WRITE_HEADER, this API sets the Complete flag in WRITE_HEADER.

     
  8. 8)

    Step 8: SpareBuf is restored in the FTW spare block. Then FTW->Write() finishes.

     
Step 5 is the most important step, and we want to make sure it is fault tolerant. If system reset occurs during step 5, then the SpareComplete flag is set, but the DestinationComplete flag is not set. On the next boot, the FTW driver will detect this situation and try to perform recovery. The data is inside of the FTW spare block, and all the LBA/size information is in the FTW working block. As such, the corrupted variable region will be recovered on the next boot.
../images/488723_1_En_11_Chapter/488723_1_En_11_Fig22_HTML.png
Figure 11-22(1)

FTW Steps 1 and 2

../images/488723_1_En_11_Chapter/488723_1_En_11_Fig23_HTML.png
Figure 11-22(2)

FTW Steps 3 and 4

../images/488723_1_En_11_Chapter/488723_1_En_11_Fig24_HTML.png
Figure 11-22(3)

FTW Steps 5 and 6

../images/488723_1_En_11_Chapter/488723_1_En_11_Fig25_HTML.png
Figure 11-22(4)

FTW Steps 7 and 8

Confidentiality Protection

The UEFI specification defines the variable interface for authenticated variables, which provides integrity protection against a software attacker. However, there might be some variable usage that requires the confidentiality protection, such as a WIFI pre-shared key (PSK) in the preboot phase to support further reconnection, a Bluetooth pairing key information for reconnection, and a storage volume key to decrypt the disk. A platform firmware may choose a different authority – a user or a platform hardware entity based upon the use case.

User Key Encrypted Variable

If a user is required to provide the authorization for the variable access, the variable data is bound to a user. If another person takes the machine, they cannot decrypt the variable content. The data migration is easy. If a user copies the data to another machine, they can still access the same data. The only disadvantage is that the physical user must be present to perform the user authentication.

We have discussed the three types of user authentication in Chapter 10: 1) what the user knows, such as password; 2) what the user has, such as hardware token; and 3) what the user is, such as biometrics. Take the user password as an example. In this case, the password itself can be used as a root key to derive the encryption key. Then the encryption key can be used to encrypt or decrypt the variable data.

Platform Key Encrypted Variable

If a platform is required to provide the authorization for the variable access, the variable data is bound to a platform. It is different from the user binding. If another person takes the machine, they may get the decrypted content because the platform authority has zero knowledge on which user is using the machine. If data migration is needed, the user must use the old platform authority to decrypt the data, copy data to a new machine, and use the new platform authority to encrypt the data.

In practice, there could be different platform authorities. For example, the Trusted Platform Module (TPM) Platform Configuration Register (PCR) could be used to seal the variable data or the key to encrypt the variable data. The sealed object is saved in the TPM non-volatile storage. When the firmware wants to get the variable, it just sends an unseal command to the TPM device. It is the TPM hardware that checks and returns the data if the PCR policy matches. We have discussed this in Chapter 7 and previous sections – variable with TPM storage.

The other example is to use a platform key (see Figure 11-23). During the manufacturing phase, each platform can generate a unique platform key and save the key to a secure coprocessor, such as Intel Converged Security and Management Engine (CSME). The platform system firmware can get the platform key at initialization time and save the key in the trusted execution environment. Then this platform key can be used to encrypt and decrypt the variable data.
../images/488723_1_En_11_Chapter/488723_1_En_11_Fig26_HTML.png
Figure 11-23

Variable Encryption

The platform key–based encryption might not able to resist the software attacker because an attacker may just write a software program to call the GetVariable service to ascertain the decrypted data. If this is a threat, the solution needs to use another mechanism to prevent the GetVariable service from being invoked.

The user authority and the platform authority can be combined together to provide more security. For example, a solution can use the TPM NV index to save the variable data with the policy PCR (platform authority) and policy password (user authority). If the PCR matches and the user provides the correct password, only then the variable can be decrypted.

Table 11-4 shows the difference between the user authority and platform authority.
Table 11-4

Authority of the Confidential Variable

Property

User

Platform

Authentication mechanism

User authentication, such as what a user knows, what a user has, and what a user is.

Platform property, such as

TPM Platform Configuration Register (PCR) and platform key – from a secure coprocessor.

Binding

Bind to a user.

If another person takes the machine, they cannot decrypt the variable content.

Bind to a platform.

If another person takes the machine, they may get the decrypted content.

User interaction

Required.

Not required.

Data Migration

Easy.

Hard.

Adversary

Software attack, hardware attack

Hardware attack

Example

User inputs password as encryption key.

Management Engine provides the RPMB key.

CSME provides the variable encryption key.

TPM PCR seals the variable encryption key.

It is possible that we can use a user password or a platform PCR to seal the data encryption key directly. However, a better way is to use a key encryption key (KEK) to protect the encryption key and only bind the KEK to the user or the platform (see Figure 11-24). The data encryption key might be backed up to another source, such as a USB key device, just in case that the user forgets the password or the platform PCRs are changed.
../images/488723_1_En_11_Chapter/488723_1_En_11_Fig27_HTML.jpg
Figure 11-24

Key Encryption Key

The key from the user or the platform can also be used as the root key to create a key hierarchy (see Figure 11-25). The root key can be used to encrypt the subkey. It is the subkey that encrypts the final secret variable data. The subkey can be created by the user and saved into the NV storage area. The subkey can also be derived from the root key automatically by using a key deviation function such as the HMAC-based key deviation function (HKDF), for example:

VarEncKey = HKDF_Expand (SHA256, RootKey, VarName||VarGuid||Attributes||“VAR_ENC_KEY”)
../images/488723_1_En_11_Chapter/488723_1_En_11_Fig28_HTML.png
Figure 11-25

Key Hierarchy

The encrypted variable data is only on the flash region. For performance considerations, the variable data may save a copy of the decrypted variable data in the memory as a cache to support GetVariable() API. In this case, we need other technologies to resist the hardware attack to the system memory, such as Total Memory Encryption (TME).

Attack and Mitigation

Now, let’s take a look at some real use cases for the attack against UEFI variables and mitigation.

Malformed Input

The authenticated variable requires the signature verification. The attacker may construct a malformed variable input data, such as no signing data or bad signing data. The signing verification code should reject the no signing data as well as the bad signing data.

Bypass the Protection: TOC/TOU Attack

Similar to the image signing verification, the variable authentication and update must happen in a trusted execution environment, such as SMM. Both authentication and update must be in one SMI handler.

Bypass the Protection: Authentication Disabled

When UEFI secure boot was introduced, some firmware used another read/write variable to control the secure boot on/off. As such, the attacker just needed to control this read/write variable to disable the secure boot feature to turn off all the signing verification. This is not a secure implementation. The secure boot disable capability must be a platform policy and require physical user presence. Also, this disable action must be recorded to a measurement log to provide the attestation that the platform configuration is NOT secure.

Bypass the Protection: Variable Lock Disabled

Ideally, the read-only variable should be locked in any possible boot path, such as normal boot, S3 resume, capsule update, and so on. If this read-only variable is not locked in a special boot path, then the attack may trigger this patch and modify the variable content.

Replay Attack: Software

The software replay attack means to save a valid variable input data and try to call it later. See Figure 11-26.
../images/488723_1_En_11_Chapter/488723_1_En_11_Fig29_HTML.png
Figure 11-26

Replay Attack – Software

In order to prevent the software replay attack, the UEFI authentication variable must be used. It could be a time-based auth variable or nonce-based auth variable. For the time-based auth variable, the new timestamp must be greater than the old one. As such, the signature is invalid because the timestamp is older. For the nonce-based auth variable, the new nonce data must be different from current nonce. As such, the signature is invalid because the nonce value is changed. See Figure 11-27.
../images/488723_1_En_11_Chapter/488723_1_En_11_Fig30_HTML.png
Figure 11-27

Replay Attack Prevention – Time-Based/Nonce-Based Auth Variable

Replay Attack: Hardware

The hardware replay attack means to save a valid copy of current variable configuration and restore the same configuration later via a flash programmer to update the flash content directly. See Figure 11-28.
../images/488723_1_En_11_Chapter/488723_1_En_11_Fig31_HTML.png
Figure 11-28

Replay Attack – Hardware

In order to prevent the hardware replay attack, the UEFI variable may use a hardware-based monotonic counter, such as RPMB or RPMC. For the RPMB-based variable, the flash data write will fail, because the old monotonic counter is smaller than the current RPMB device monotonic counter (see Figure 11-29). For the RPMC-based variable, the flash data write will succeed because of the absence of flash protection. But on the next boot, the attack will be detected. The MAC of the variable region is invalid because the monotonic counter in the RPMC device is different from the one involved in the MAC calculation (see Figure 11-30). Then the system firmware will trigger the recovery process.
../images/488723_1_En_11_Chapter/488723_1_En_11_Fig32_HTML.png
Figure 11-29

Replay Attack Prevention with RPMB

../images/488723_1_En_11_Chapter/488723_1_En_11_Fig33_HTML.png
Figure 11-30

Replay Attack Prevention with RPMC

Rollback Attack

In the preceding section, we know that the hardware replay attack can be detected with RPMC, with the consequence of variable recovery. This can be used as a special attack to roll back the current UEFI secure boot variable to the old manufacture version (see Figure 11-31). This is very dangerous for UEFI secure boot because the UEFI secure boot variable policy may be updated to add the latest image forbidden database (dbx). The recommendation is that the platform system firmware should update the manufacturer default forbidden database along with the current used forbidden database.
../images/488723_1_En_11_Chapter/488723_1_En_11_Fig34_HTML.png
Figure 11-31

Rollback Attack – RPMC-Based Variable

Flash Wear-Out Attack

We have discussed the flash wear-out protection in the previous section. The key is to lock the flash erase action after OEM platform manufacture code. Care must be taken that this lock must happen in any boot mode, such as normal boot, S4 resume, S3 resume, flash update, recovery, manufacturing mode, and so on.

Partial Update Attack

An attacker may power off the system during the variable data update. One possibility is that an individual variable is partially updated with the flash WRITE command. The other possibility is that the variable block region is partially updated with the flash ERASE command. The BIOS must have ways to detect both scenarios based upon the hardware limitation. If the hardware can guarantee the data updating at the block level, the detection mechanism shall be in the block-based mechanism, such as a Replay Protected Memory Block (RPMB) device. If the hardware can guarantee the data updating at the byte level, the detection mechanism shall be at the byte level, such as a Replay Protected Monotonic Counter (RPMC)–capable SPI device.

For the individual variable update, the variable atomicity must be guaranteed, which we have discussed in the previous section. Each variable exists in ALL-or-NONE state.

For the variable block region update, the fault-tolerant write must be used, which we have also discussed in the previous section. The variable region can be recovered on the next boot if the corruption is detected.

UEFI PI Firmware Volume

Besides UEFI variable, the configuration data can be saved to a UEFI PI firmware volume (FV). See Table 11-5 for the UEFI PI configuration FV protection mechanisms. If a key is used to verify the integrity of the configuration FV data in the update or boot, the key itself must be protected as well to resist the same attack. Otherwise, the attacker can modify the verification key to bypass the protection.
Table 11-5

UEFI PI Configuration FV Protection Mechanism

Mechanism

Resist Software Attack

Resist Hardware Attack

Integrity Protection

Flash region lock

Signed Update, such as UEFI signed capsule update.

Hardware root-of-trust based verification, such as Intel Boot Guard, Intel Platform Firmware Resilience

Availability Protection

Flash Wear-out Protection

Update Version Check

Fault Tolerant Write

Default/Golden Configuration Recovery

Confidentiality Protection

User-Key Encryption

Platform-Key Encryption

User-Key Encryption

UEFI PI PCD (Platform Configuration Data)

UEFI variables provide read/write configuration data support based upon a name/GUID pair. Besides UEFI variables, the UEFI Platform Initialization (PI) specification defines the Platform Configuration Database (PCD) concept to abstract the configuration data with a token ID. The PCD could be static data fixed at build time or dynamic data editable at runtime.

Static PCD:
  • PcdsFeatureFlag: This type of PCD only supports 1/0. The caller uses FeaturePcdGet() to retrieve the value. This type of PCD is mapped to be a MACRO so that a compiler optimization can remove the code scoped by “if(FALSE)”. It is not allowed to set as a PcdsFeatureFlag.

  • PcdsFixedAtBuild: This type of PCD can be mapped to a global variable if the caller uses PcdGet() or a MACRO if the caller uses FixedPcdGet(). As such, this type of PCD can be used in a data structure definition. It is not allowed to set as a PcdsFixedAtBuild.

  • PcdsPatchableInModule: This type of PCD is mapped to a global variable. It is allowed for use by both PcdGet and PcdSet. If PcdSet is called, it only changes the module-level PCD value instead of the system-level PCD value. Only the current module sees the PCD change. Other modules still see the original value.

Dynamic PCD:
  • PcdsDynamicDefault: PcdsDynamicDefault is mapped to a PPI or protocol. It is allowed for both PcdGet and PcdSet. PcdSet changes the system-level PCD value immediately. This type of PCD value is volatile. The changed value will not be saved on the next boot.

  • PcdsDynamicHii: PcdsDynamicHii is mapped to a UEFI variable. It is non-volatile. As such, the changed value can be saved on the next boot. However, the tricky thing is that this PCD value depends on the readiness of the UEFI variable services. If PcdGet is called before UEFI variable services are ready, the default PCD value will be returned instead of the updated PCD value. We suggest that the platform owner be very careful of this trap. If DXE PcdGet is required before the UEFI variable services are ready, we suggest that the platform define the PCD with the access type of PcdsDynamicDefault and then use the value returned by GetVariable in the PEI phase. A nonsecure bootrelated variable can be set in this PCD’s value.

  • PcdsDynamicVpd: PcdsDynamicVpd is used to map configuration data to a static flash region so that a tool can modify the values after the flash image is generated. This is used by a BIOS that needs to support binary configuration after build. Intel Firmware Support Package (FSP) is an example that uses PcdsDynamicVpd. The dynamic VPD can also be map to a configuration FV and updated via UEFI signed capsule.

  • PcdsDynamicEx: PcdsDynamicEx supports external modules for binary build. If a UEFI module (DXE driver or PEIM) is not built with the system firmware, the dynamic PCD must be declared as PcdsDynamicEx. If a platform wants to include this binary EFI module, the binary module INF must be included in the DSC file. As such, the PCD database will include the external PCDs declared in this binary module. This is important since the PCD database only includes PCDs that are used by a module.

Special PCD concepts:
  • SkuIds: SkuIds allow the building of one UEFI firmware image that boots on multiple boards with a different configuration in each board. It can support multiple board configurations generated at build time and then support runtime selection to make one configuration active.

  • DefaultStores: DefaultStores is a special usage of PCD (gEfiMdeModulePkgTokenSpaceGuid.PcdSetNvStoreDefaultId). The use case of DefaultStores is to create different default stores in different boot modes, such as standard boot mode, manufacturing boot mode, or safe boot mode. The configuration data is set to (gEfiMdeModulePkgTokenSpaceGuid.PcdNvStoreDefaultValueBuffer). All those default stores are configured at build time and selected at runtime according to the boot mode. The default store PCD can be consumed by the HII database to support a BIOS setup “load default” operation.

Static (FeatureFlag or FixedAtBuild) PCD is built in the code. The PcdsDynamicDefault is implemented as a standard PPI or protocol in memory. They have no attack surface. From a security perspective, the only potential attack surface is PcdsDynamicVpd and PcdsDynamicHii.

VPD is used to provide the static configuration data in a flash region. Because the data is not runtime updatable, it is similar to the firmware code. As such, signing-based verification can be used for the VPD region.

Dynamic HII PCDs can be mapped to the UEFI variables. All the protection mechanisms for UEFI variables can also be used for dynamic HII PCDs.

Summary

In this chapter, we discussed firmware configuration. We use UEFI variables as an example. In the next chapter, we will discuss the non-host firmware.

References

Conference, Journal, and Paper

[P-1] Jiewen Yao, Vincent Zimmer, Star Zeng, “A Tour Beyond BIOS Implementing UEFI Authenticated Variables in SMM with EDK II,” Intel Whitepaper, https://github.com/tianocore-docs/Docs/raw/master/White_Papers/A_Tour_Beyond_BIOS_Implementing_UEFI_Authenticated_Variables_in_SMM_with_EDKII_V2.pdf

[P-2] Yuriy Bulygin, Andrew Furtak, Oleksandr Bazhaniuk, John Loucaides, Corey Kallenberg, Xeno Kovah, John Butterworth, Sam Cornwell, “All your boot are belong to us,” in CanSecWest 2014, available at https://cansecwest.com/slides/2014/AllYourBoot_csw14-mitre-final.pdf, and www.c7zero.info/stuff/AllYourBoot_csw14-intel-final.pdf

[P-3] Yuriy Bulygin, Andrew Furtak, Oleksandr Bazhaniuk, “A Tale of One Software Bypass of Windows 8 Secure Boot,” in BlackHat US 2013, available at www.c7zero.info/stuff/Windows8SecureBoot_Bulygin-Furtak-Bazhniuk_BHUSA2013.pdf

[P-4] Yuriy Bulygin, John Loucaides, Andrew Furtak, Oleksandr Bazhaniuk, Alexander Matrosov, “Summary of Attacks Against BIOS and Secure Boot,” in DEF CON 22, available at www.c7zero.info/stuff/DEFCON22-BIOSAttacks.pdf

[P-5] Yoongu Kim, Ross Daly, Jeremie Kim, Chris Fallin, Ji Hye Lee, Donghyuk Lee, Chris Wilkerson, Konrad Lai, Onur Mutlu, “Flipping Bits in Memory Without Accessing Them: An Experimental Study of DRAM Disturbance Errors,” in IEEE 2014, available at http://users.ece.cmu.edu/~yoonguk/papers/kim-isca14.pdf

[P-6] Mark Seaborn, Thomas Dullien, “Exploiting the DRAM rowhammer bug to gain kernel privileges,” in project zero 2015, available at https://googleprojectzero.blogspot.com/2015/03/exploiting-dram-rowhammer-bug-to-gain.html

[P-7] Anil Kurmus, Nikolas Ioannou, Matthias Neugschwandtner, Nikolaos Papandreou, Thomas Parnell, “From random block corruption to privilege escalation: A filesystem attack vector for rowhammer-like attacks,” in USENIX 2017, available at www.usenix.org/system/files/conference/woot17/woot17-paper-kurmus.pdf

Specification and Guideline

[S-1] NVM Express Org, “NVM Express Specification,” 2019, available at https://nvmexpress.org/resources/specifications/

[S-2] JEDEC Org, “Universal Flash Storage,” 2018, available at www.jedec.org/standards-documents/focus/flash/universal-flash-storage-ufs

[S-3] JEDEC Org, “e-MMC,” 2019, available at www.jedec.org/standards-documents/technology-focus-areas/flash-memory-ssds-ufs-emmc/e-mmc

[S-4] Intel, “Serial Flash Hardening Product External Architecture Specification,” 2013, available at www.intel.com/content/www/us/en/support/articles/000020984/software/chipset-software.html

[S-5] Trusted Computing Group, “Trusted Platform Module Library,” 2016, available at https://trustedcomputinggroup.org/resource/tpm-library-specification/

[S-6] UEFI Organization, “UEFI Specification,” 2019, available at www.uefi.org/

[S-7] UEFI Organization, “UEFI Platform Initialization Specification,” 2019, available at www.uefi.org/

[S-8] Intel, “Intel TXT Software Development Guide,” 2017, available at

www.intel.com/content/www/us/en/software-developers/intel-txt-software-development-guide.html

[S-9] IETF, “RFC 5869 – HMAC-based Extract-and-Expand Key Derivation Function (HKDF),” 2010, available at https://tools.ietf.org/html/rfc5869

Web

[W-1] Chromium TPM usage, www.chromium.org/developers/design-documents/tpm-usage

[W-2] BitLocker Drive Encryption Overview, https://docs.microsoft.com/en-us/windows/security/information-protection/bitlocker/bitlocker-device-encryption-overview-windows-10

[W-3] eCryptfs: An Enterprise-class Encrypted Filesystem for Linux, www.kernel.org/doc/ols/2005/ols2005v1-pages-209-226.pdf

[W-4] Windows Quota, https://docs.microsoft.com/en-us/windows-server/storage/fsrm/quota-management

[W-5] Linux Disk Quota, https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/storage_administration_guide/ch-disk-quotas