1Dealing with Untrusted Input in SMM 2=================================== 3 4Objective 5--------- 6Intel Security recently held a talk and published 7[slides](http://www.intelsecurity.com/advanced-threat-research/content/data/REConBrussels2017_BARing_the_system.pdf) 8on a vulnerability in SMM handlers on x86 systems. They provide examples 9on how both UEFI and coreboot are affected. 10 11Background 12---------- 13SMM, the System Management Mode, is a CPU mode that is configured by 14firmware and survives the system’s initialization phase. On certain 15events that mode can be triggered and executes code, suspending the 16current processing that is going on the CPU, no matter whether it’s 17in kernel or user space. 18 19In SMM, the CPU has access to memory dedicated to that mode (SMRAM) that 20is normally inaccessible, and typically some restrictions are lifted as 21well (eg. in some configurations, certain flash write protection registers 22are writable in SMM only). This makes SMM a target for attacks which 23seek to elevate a ring0 (kernel) exploit to something permanent. 24 25Overview 26-------- 27Intel Security showed several places in coreboot’s SMM handler (Slides 2832+) that could be manipulated into writing data at user-chosen addresses 29(SMRAM or otherwise), by modifying the BAR (Base Address Register) on 30certain devices. By picking the right addresses and the right events 31(and with them, mutators on the data at these addresses), it might 32be possible to change the SMM handler itself to call into regular RAM 33(where other code resides that then can work with elevated privileges). 34 35Their proposed mitigations (Slide 37) revolve around making sure 36that the BAR entries are reasonable, and point to a device instead of 37regular memory or SMRAM. They’re not very detailed on how this could 38be implemented, which is what this document discusses. 39 40Detailed Design 41--------------- 42The attack works because the SMM handler trusts the results of the 43`pci_read_config32(dev, reg)` function, even though the value read by that 44function can be modified in kernel mode. 45 46In the general case it’s not possible to keep the cached value from 47system initialization because there are legitimate modifications the 48kernel can do to these values, so the only remedy is to make sure that 49the value isn’t totally off. 50 51For applications where hardware changes are limited by design (eg. no 52user-modifiable PCIe slots) and where the running kernel is known, 53such as Chromebooks, further efforts include caching the BAR settings 54at initialization time and comparing later accesses to that. 55 56What "totally off" means is chipset specific because it requires 57knowledge of the memory map as seen by the memory controller: which 58addresses are routed to devices, which are handled by the memory 59controller itself? 60The proposal is that in SMM, the `pci_read_config` functions (which 61aren’t timing critical) _always_ validate the value read from a given 62set of registers (the BARs) and fail hard (ie. cold reset, potentially 63after logging the event) if they’re invalid (because that points to 64a severe kernel bug or an attack). 65The actual validation is done by a function implemented by the chipset code. 66 67Another validation that can be done is to make sure that the BAR has the 68appropriate bits set so it is enabled and points to memory (instead of 69IO space). 70 71In terms of implementation, this might look somewhat as follows. There 72are a bunch of blanks to fill in, in particular how to handle the actual 73config space access and there will be more registers that need to be 74checked for correctness, both official BARs (0-4) and per-chipset 75registers that need to be blacklisted in another chipset specific 76function: 77 78```c 79static inline __attribute__((always_inline)) 80uint32_t pci_read_config32[d](pci_devfn_t dev, unsigned int where) 81{ 82 uint32_t val = real_pci_read_config32(dev, where); 83 if (IS_ENABLED(__SMM__) && (where == PCI_BASE_ADDRESS_0) && 84 is_mmio_ptr(dev, where) && !is_address_in_mmio(val)) { 85 cold_reset(); 86 } 87 return val; 88} 89``` 90 91`is_address_in_mmio(addr)` would be a newly introduced function to be 92implemented by chipset drivers that returns true if the passed address 93points into whatever is considered valid MMIO space. 94`is_mmio_ptr(dev, where)` returns true for PCI config space registers that 95point to BARs (allowing custom overrides because sometimes additional 96registers are used to point to addresses). 97 98For this function what is considered a legal address needs to be 99documented, in accordance with the chipset design. (For example: AMD 100K8 has a bunch of registers that define strictly which addresses are 101"MMIO") 102 103### Fully insured (aka “paranoid”) mode 104For systems with more control over the hardware and kernel (such as 105Chromebooks), it may be possible to set up the BARs in a way that the 106kernel isn’t compelled to rewrite them, and store these values for 107later comparison. 108 109This avoids attacks such as setting the BAR to point to another device’s 110MMIO region which the above method can’t catch. Such a configuration 111would be “illegal”, but depending on the evaluation order of BARs 112in the chipset, this might effectively only disable the device used for 113the attack, while still fooling the SMM handler. 114 115Since this method isn’t generalizable, it has to be an optional 116compile-time feature. 117 118Caveats 119------- 120This capability might need to be hidden behind a Kconfig flag 121because we won’t be able to provide functional implementations of 122`is_address_in_mmio()` for every chipset supported by coreboot from the 123start. 124 125Security Considerations 126----------------------- 127The actual exploitability of the issue is unknown, but fixing it serves 128as defense in depth, similar to the 129[Memory Sinkhole mitigation](https://review.coreboot.org/#/c/11519/) for 130older Intel chipsets. 131 132Testing Plan 133------------ 134Manual testing can be conducted easily by creating a small payload that 135provokes the reaction. It should test all conditions that enable the 136address test (ie. the different BAR offsets if used by SMM handlers). 137