linux/Documentation/speculation.txt
<<
>>
Prefs
   1This document explains potential effects of speculation, and how undesirable
   2effects can be mitigated portably using common APIs.
   3
   4===========
   5Speculation
   6===========
   7
   8To improve performance and minimize average latencies, many contemporary CPUs
   9employ speculative execution techniques such as branch prediction, performing
  10work which may be discarded at a later stage.
  11
  12Typically speculative execution cannot be observed from architectural state,
  13such as the contents of registers. However, in some cases it is possible to
  14observe its impact on microarchitectural state, such as the presence or
  15absence of data in caches. Such state may form side-channels which can be
  16observed to extract secret information.
  17
  18For example, in the presence of branch prediction, it is possible for bounds
  19checks to be ignored by code which is speculatively executed. Consider the
  20following code:
  21
  22        int load_array(int *array, unsigned int index)
  23        {
  24                if (index >= MAX_ARRAY_ELEMS)
  25                        return 0;
  26                else
  27                        return array[index];
  28        }
  29
  30Which, on arm64, may be compiled to an assembly sequence such as:
  31
  32        CMP     <index>, #MAX_ARRAY_ELEMS
  33        B.LT    less
  34        MOV     <returnval>, #0
  35        RET
  36  less:
  37        LDR     <returnval>, [<array>, <index>]
  38        RET
  39
  40It is possible that a CPU mis-predicts the conditional branch, and
  41speculatively loads array[index], even if index >= MAX_ARRAY_ELEMS. This
  42value will subsequently be discarded, but the speculated load may affect
  43microarchitectural state which can be subsequently measured.
  44
  45More complex sequences involving multiple dependent memory accesses may
  46result in sensitive information being leaked. Consider the following
  47code, building on the prior example:
  48
  49        int load_dependent_arrays(int *arr1, int *arr2, int index)
  50        {
  51                int val1, val2,
  52
  53                val1 = load_array(arr1, index);
  54                val2 = load_array(arr2, val1);
  55
  56                return val2;
  57        }
  58
  59Under speculation, the first call to load_array() may return the value
  60of an out-of-bounds address, while the second call will influence
  61microarchitectural state dependent on this value. This may provide an
  62arbitrary read primitive.
  63
  64====================================
  65Mitigating speculation side-channels
  66====================================
  67
  68The kernel provides a generic API to ensure that bounds checks are
  69respected even under speculation. Architectures which are affected by
  70speculation-based side-channels are expected to implement these
  71primitives.
  72
  73The array_index_nospec() helper in <linux/nospec.h> can be used to
  74prevent information from being leaked via side-channels.
  75
  76A call to array_index_nospec(index, size) returns a sanitized index
  77value that is bounded to [0, size) even under cpu speculation
  78conditions.
  79
  80This can be used to protect the earlier load_array() example:
  81
  82        int load_array(int *array, unsigned int index)
  83        {
  84                if (index >= MAX_ARRAY_ELEMS)
  85                        return 0;
  86                else {
  87                        index = array_index_nospec(index, MAX_ARRAY_ELEMS);
  88                        return array[index];
  89                }
  90        }
  91