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