System Management Mode Speculative Execution Attacks

We have discovered a new application of speculative execution attacks, bypassing hardware-based memory protections. Vulnerabilities affecting speculative execution of modern processor architectures were first discovered in 2017 by Jann Horn of Google Project Zero and other security researchers. This class of vulnerabilities allows local unprivileged attackers to expose the contents of protected memory by exploiting the microarchitectural capabilities of modern out-of-order CPUs such as caching, instruction pipeline or speculative execution. We expanded on this method to gain access to the highly privileged System Management Mode (SMM) memory.

Impact

Because SMM generally has privileged access to physical memory, including memory isolated from operating systems, our research demonstrates that Spectre-based attacks can reveal other secrets in memory (eg. hypervisor, operating system, or application). Thus far, the Spectre and Meltdown vulnerabilities were demonstrated to affect software, such as operating systems, hypervisors or even applications within protected SGX enclaves. However, the effect on firmware has not previously been shown. While there are many different kinds of firmware present in every system, we wanted to investigate host processor firmware first. The processor executes the main system firmware, often referred to as BIOS or UEFI, when the system boots. Much of this firmware only runs at boot time; however, there is also a portion that runs in parallel with the OS in a special x86 mode known as System Management Mode (SMM). This runtime part of firmware (often referred to as SMI Handler) has long been of interest to security researchers and a target for advanced attackers, since this code has high privileges and operates outside the view of other software including the OS and any security applications.

Intel CPUs use a memory protection mechanism known as a range register to protect sensitive contents of memory regions such as SMM memory, including against cache poisoning attacks. Specifically, SMM memory on Intel CPUs is protected by a special type of range registers known as System Management Range Register (SMRR). This blog post describes a modification of speculative execution attacks that can expose the contents of memory protected with this hardware-based range register protection mechanism. The proof-of-concept exploit demonstrated here leverages a modification of Spectre variant 1 (bounds check bypass) to bypass SMRR protection of SMM memory. While we used Spectre variant 1 in our research, it is likely that a similar modification of Spectre variant 2 would be similarly effective.

These enhanced Spectre attacks allow an unprivileged attacker to read the contents of memory, including memory that should be protected by the range registers, such as SMM memory. This can expose SMM code and data that was intended to be confidential, revealing other SMM vulnerabilities as well as secrets stored in SMM. Additionally, since we demonstrate that the speculative memory access occurs from the context of SMM, this could be used to reveal other secrets in memory as well.

Bounds Check Bypass in SMM

Overview

Many people have now heard of the Meltdown and Spectre attacks leveraging speculative execution side channels. In this research, we will focus on Spectre, which has been described in two variants:

  • Bounds Check Bypass, a.k.a. Spectre variant 1 (CVE-2017-5753)
  • Branch Target Injection, a.k.a. Spectre variant 2 (CVE-2017-5715)

Spectre variant 1 (CVE-2017-5753) allows an unprivileged attacker to exploit privileged code, which correctly checks the size of a buffer located in privileged memory without any software vulnerability. Normally, correctly implemented bounds checking would prevent an attacker from gaining out-of-bounds access to the privileged buffer. However, by using Spectre variant 1, instructions causing an out-of-bounds access would still be executed speculatively by the CPU if they reside on the predicted path behind the indirect conditional branch instruction. When the CPU rolls back changes caused by the speculatively executed “out of bounds access” instructions after the target address of the indirect branch has been resolved from memory, the attacker can observe side effects in CPU caches, which allows the attacker to recover data read from privileged memory.

First experiment

In our experiments we used a PoC of the Spectre1 exploit, which is publicly available from GitHub. First, we ported this PoC to a kernel driver and confirmed that out-of-bounds access over speculative execution was working from the kernel privilege level. We were then able to run our experiment from the kernel privilege level against protected memory. The kernel-level PoC exploit provides access to different hardware interfaces, which gives attackers better control over the system hardware and access to different hardware interfaces such as physical memory, IO, PCI, and MMIO interfaces. It also provides access to interfaces at a higher privilege level, such as software SMI.

Next, we integrated the PoC exploit into CHIPSEC in order to quickly expand our tests. In our first experiment, we tried to read protected SMRAM memory. We mapped the physical addresses of SMRAM into the virtual address space and then used the SMRAM addresses as the target of our exploit.

This experimental attack scenario does not work against SMRAM, because the victim_function function is running at the kernel privilege level, which doesn’t have access to SMRAM, since it protected by SMRRs. In this experiment, a read memory transaction within the speculative execution flow doesn’t work. The hardware protection drops this type of read, and the contents of SMM are not exposed to a kernel-privileged attacker.

Example output:

[506147.777314] SPECTRE1
[506147.777319] SMRR BASE: 7e800000
[506147.777335] mapped va: ffffb6db80343000
[506147.777338] reading content directly:
[506147.777338] 0xFFFFFFFF
...
[506147.777356] 0xFFFFFFFF
[506147.777884] Reading 40 bytes by Spectre1:
[506147.777885] Reading at malicious_x = ffffb6dbbfcd1fa0...
[506147.778132] Success:
[506147.778133] 0x00=’?’ score=3
[506147.778135] Reading at malicious_x = ffffb6dbbfcd1fa1...
[506147.778234] Success:
[506147.778235] 0x00=’?’ score=3
[506147.778237] Reading at malicious_x = ffffb6dbbfcd1fa2...
[506147.778335] Success:
[506147.778336] 0x00=’?’ score=3
…

As we can see above, the contents of SMRAM are protected against this attack scenario.

Next, we enhanced the attack scenario. We tried to make SMRAM cacheable (set as Write-Back) over MTRRs and also set MSR_IA32_MTRR_DEF_TYPE to Write-Back as well. This enhancement didn’t help, and SMRAM was still not accessible, indicating that SMRR has a higher priority than MTRRs. But this experiment also gave us an idea about how Spectre1 works for different memory transactions. We learned:

  • Spectre1 works for uncacheable memory (checked over memory set to uncacheable over MTRRs).
  • Spectre1 doesn’t work for MMIO. We assumed this is because MMIO access is much slower than memory access.
  • Spectre1 from kernel mode, with a speculative execution flow running in kernel mode, doesn’t work for SMRAM. SMRR protection is preventing speculative memory access.

So, we needed to run a speculative flow within SMRAM, and this was our next step. By running this experiment, we would know whether range registers prevent speculative execution in a scenario when the attacker controls arguments passed to a victim_function in SMM from a Spectre1 exploit running in the kernel. Linux eBPF JIT it is definitely a practical attack scenario with these conditions. SMM doesn’t have any JIT in SMRAM, so attackers need to find vulnerable code within SMI handlers. Systems have firmware with many SMI handlers in SMRAM that are very likely to have vulnerable code.

Applying Spectre Variant 1 to SMM

We modified the attack scenario and developed a proof-of-concept that exploits the Bounds Check Bypass vulnerability and exposes arbitrary contents from SMRAM, bypassing SMRR protection.

The theory behind this modified attack against SMM is roughly as follows:

  1. An OS-level exploit invokes an SMI, which will cause the CPU to transition to SMM and execute SMI handler firmware.
  2. The SMI handler accesses elements of an array residing in SMRAM (not accessible to OS kernel or user-mode applications).
  3. Before accessing, the SMI handler validates the index of an element to be accessed against the length of the array, because the index is untrusted, supplied by less privileged mode (e.g., the OS).
  4. The check translates into a conditional branch executed by the CPU. The CPU starts resolving the target address of the indirect branch.
  5. While the CPU is waiting for the branch target to be resolved, it uses branch prediction mechanisms to “predict” the target address while it’s still not available in order to execute the next SMI handler instructions (which are executed “speculatively”).
  6. The SMM instructions executed speculatively may load the value of an “element” outside of bounds of the array using the untrusted index value. This points to some location inside SMRAM, which the attacker wants to expose.
  7. The data is then loaded from memory and cached by the CPU in the data cache at locations that are outside of SMRAM (in OS accessible memory) but depend on this [secret] SMRAM value.
  8. The OS-level exploit can then measure the access time to these different non-SMRAM locations using one of the cache timing side-channel techniques (e.g., FLUSH+RELOAD).
  9. The time to access cache-lines in the data cache loaded based on secret SMRAM value will be smaller. This discloses information about the secret value stored in SMRAM to the less privileged OS mode regardless of SMRR protections.

Bypassing System Management Range Registers

Based on the attack scenario above, we ran the following experiment:

  1. We found a conditional branch validating the index into an array in one of the SMI handlers. This index should be the one controlled by the OS-level attacker.
  2. For the sake of a proof-of-concept, it is possible to inject the “vulnerable” function, as in the following example victim_function. The goal of this experiment was to demonstrate the impact of original Spectre attacks on memory protections like range registers.
  3. We triggered the vulnerable code in the SMI handler (by calling SW SMI or other SMM interfaces) with out-of-bounds array access, which caused speculative execution and the loading of data from an arbitrary SMRAM location to the data cache.
  4. We recovered the SMRAM data by measuring access time to different non-SMRAM locations in the data cache using one of the cache timing side-channel techniques.

As a result of running the above experiment, we’ve successfully recovered data that was stored in SMRAM and protected by SMRR. This proof-of-concept exploit is a modified Spectre variant 1 PoC exploit running with kernel-mode privileges.

Example of vulnerable SMI code:

struct arrays {
    UINT64 array1_size;
    UINT8 unused1[64];
    UINT8 array1[160];
    UINT8 unused2[64];
    UINT8 array2[256 * 512];
};

CHAR8 * secret = "SMM. The Magic Words are ...";

UINT8 temp = 0; /* Used so compiler won’t optimize out victim_function() */

__declspec(noinline) VOID victim_function(UINT64 x, struct arrays *arrays_ptr) {
    if (x array1_size) {
        temp &= arrays_ptr->array2[arrays_ptr->array1[x] * 512];
    }
}

Example of the output from the kernel driver for the recovery of 6 bytes of a secret string:

[63186.685023] [SPECTRE1] Arg: 7e8264c0 
[63186.685034] [SPECTRE1] allocate_arrays() pa_array1: 2cec0048 
[63186.685037] [SPECTRE1] allocate_arrays() va_array1: ffff8e086cec0048 
[63186.685046] [SPECTRE1] address of va_addr: ffff8e086cec0000 
[63186.685049] [SPECTRE1] phys address of arrays: 2cec0000 
[63186.685050] [SPECTRE1] address of secret: 7e8264c0 
[63186.685051] [SPECTRE1] value of malicious_x: 51966478 
[63186.685109] Reading 6 bytes from SMM: 
[63186.685110] Reading at malicious_x = 0000000051966478... 
[63187.533644] Success: [63187.533646] 0x00=’?’ score=1 
[63187.533647] Reading at malicious_x = 0000000051966479... 
[63187.886660] Success: [63187.886661] 0x00=’?’ score=1 
[63187.886662] Reading at malicious_x = 000000005196647a... 
[63189.017075] Success: [63189.017077] 0x00=’?’ score=12 
[63189.017077] (second best: 0x4D score=5) 
[63189.017078] Reading at malicious_x = 000000005196647b... 
[63192.551132] Unclear: [63192.551133] 0x00=’?’ score=44 
[63192.551133] (second best: 0x2E score=27) 
[63192.551134] Reading at malicious_x = 000000005196647c... 
[63193.116332] Success: [63193.116333] 0x00=’?’ score=4 
[63193.116334] (second best: 0x20 score=1) 
[63193.116335] Reading at malicious_x = 000000005196647d... 
[63193.328231] Success: [63193.328232] 0x00=’?’ score=1

We recovered 3 bytes: 0x4D 0x2E 0x20 which is ‘M. ‘ the third, fourth, and fifth symbols from the secret string. This exploit doesn’t cause any stability problems and can be executed multiple times to recover the entire contents of memory protected by the SMRR.

For all our experiments we used a Supermicro X9SPU-F server with:

  • Intel® Core™ i3-3220 CPU (Ivy Bridge)
  • Ubuntu 16.04.3 LTS

The system has a modified BIOS with an SMI handler that contains the code pattern (index-based array size validation) from the original Spectre variant 1 exploit to confirm that these types of speculative cache loads can be exploited to read secrets from SMRAM if this code pattern is found inside an SMI.

It should be noted that the code pattern does not contain a software vulnerability and is a common way to ensure that the index in the array is outside of the array bounds, i.e., a security check. Also, we used spectre-meltdown-checker to check if system is vulnerable for Spectre1. According to this tool:

CVE-2017-5753 [bounds check bypass] aka 'Spectre Variant 1'
…
> STATUS: NOT VULNERABLE (Mitigation: OSB (observable speculation barrier, Intel v6))
…

Spectre1 is mitigated only by software patches and not a microcode update. However, for the sake of our experiment, we updated the test system with the latest microcode update available from the Intel website. It is an Intel i3-3220 CPU (model 58 stepping 9) with microcode patch version 0x1f. According to Intel’s Microcode Revision Guidance, this was the latest microcode version available for this system.

Future Research

We tested the PoC only against System Management Range Registers (SMRR), but it’s likely that a similar attack would work against memory relying on other hardware-based range register protection mechanisms.

Because the vulnerability is triggered by executing the privileged code after a transition into the privileged mode, any protection mechanism used to protect memory accessible from the privileged mode (SMM in our example) but inaccessible to an unprivileged mode (OS kernel in our example) does not prevent leaking the contents of memory via the speculative execution side-channel. We demonstrated how this attack can bypass protection based on range registers; however, we believe other mechanisms are equally affected.

While we have only confirmed that the Spectre variant 1 attack would work against SMM, Branch Target Injection (Spectre variant 2) should also be effective as long as branch prediction history is not invalidated when transitioning to privileged mode, such as SMM.

Mitigation

We began working with Intel on this in March. They recommended that the same software guidance to mitigate Spectre variant 1 should also be applied to SMM. The analysis released by Intel recommends using LFENCE instructions to mitigate Spectre variant 1. This should also apply to the firmware developed by system manufacturers or independent BIOS vendors. However, while it’s relatively straightforward to update the OS and applications to mitigate exposure to this attack, redesigning and updating the firmware adds significant complexity. Moreover, many organizations do not apply the latest firmware updates, which often require visiting the manufacturer’s website in order to download and manually install them.

Hardware vendors have also introduced mitigations to the other Spectre attacks. For example, Intel introduced Indirect Branch Restricted Speculation (IBRS) to mitigate Spectre variant 2 attacks. According to the Speculative Execution Side Channel Mitigations document released by Intel, in processors that include basic support of IBRS (even without enabling by software) “software executed before a system management interrupt (SMI) cannot control the predicted targets of indirect branches executed in system-management mode (SMM) after the SMI.”

Another mitigation strategy is for firmware to limit the access that SMM has to memory. Most firmware will map physical memory into the page table used by SMM. However, the latest version of Tianocore uses techniques described in A Tour Beyond BIOS – Memory Protection in UEFI BIOS to only map the necessary portions of memory. This should greatly reduce the impact. However, most current systems are probably based on an older version of Tianocore. Firmware developers should consider back-porting this feature to protect users from this and other SMM vulnerabilities.

Conclusion

Our research showed that Spectre variant 1 speculative execution side-channel attacks are applicable across range register protection boundaries and can be used to exfiltrate data protected by range registers. In our example, we demonstrated this attack scenario against x86 System Management Mode (SMM) and exfiltrated data from System Management RAM protected by the CPU hardware. This expands the impact of Spectre vulnerabilities. Rather than just revealing secrets from another victim process, our analysis reveals that attackers can leverage SMM’s access to physical memory and steal secrets from other processes, hypervisors, or even firmware. Intel has indicated that existing mitigation guidance would be effective, and the PSIRT team has provided helpful responses to our communications about this issue.