[PATCH v2 00/19] prevent bounds-check bypass via speculative execution
From: Dan Williams
Date: Thu Jan 11 2018 - 20:01:20 EST
Changes since v1 [1]:
* fixup the ifence definition to use alternative_2 per recent AMD
changes in tip/x86/pti (Tom)
* drop 'nospec_ptr' (Linus, Mark)
* rename 'nospec_array_ptr' to 'array_ptr' (Alexei)
* rename 'nospec_barrier' to 'ifence' (Peter, Ingo)
* clean up occasions of 'variable assignment in if()' (Sergei, Stephen)
* make 'array_ptr' use a mask instead of an architectural ifence by
default (Linus, Alexei)
* provide a command line and compile-time opt-in to the ifence
mechanism, if an architecture provides 'ifence_array_ptr'.
* provide an optimized mask generation helper, 'array_ptr_mask', for
x86 (Linus)
* move 'get_user' hardening from '__range_not_ok' to '__uaccess_begin'
(Linus)
* drop "Thermal/int340x: prevent bounds-check..." since userspace does
not have arbitrary control over the 'trip' index (Srinivas)
* update the changelog of "net: mpls: prevent bounds-check..." and keep
it in the series to continue the debate about Spectre hygiene patches.
(Eric).
* record a reviewed-by from Laurent on "[media] uvcvideo: prevent
bounds-check..."
* update the cover letter
[1]: https://lwn.net/Articles/743376/
---
Quoting Mark's original RFC:
"Recently, Google Project Zero discovered several classes of attack
against speculative execution. One of these, known as variant-1, allows
explicit bounds checks to be bypassed under speculation, providing an
arbitrary read gadget. Further details can be found on the GPZ blog [2]
and the Documentation patch in this series."
This series incorporates Mark Rutland's latest ARM changes and adds
the x86 specific implementation of 'ifence_array_ptr'. That ifence
based approach is provided as an opt-in fallback, but the default
mitigation, '__array_ptr', uses a 'mask' approach that removes
conditional branches instructions, and otherwise aims to redirect
speculation to use a NULL pointer rather than a user controlled value.
The mask is generated by the following from Alexei, and Linus:
mask = ~(long)(_i | (_s - 1 - _i)) >> (BITS_PER_LONG - 1);
...and Linus provided an optimized mask generation helper for x86:
asm ("cmpq %1,%2; sbbq %0,%0;"
:"=r" (mask)
:"r"(sz),"r" (idx)
:"cc");
The 'array_ptr' mechanism can be switched between 'mask' and 'ifence'
via the spectre_v1={mask,ifence} command line option, and the
compile-time default is set by selecting either CONFIG_SPECTRE1_MASK or
CONFIG_SPECTRE1_IFENCE.
The 'array_ptr' infrastructure is the primary focus this patch set. The
individual patches that perform 'array_ptr' conversions are a point in
time (i.e. earlier kernel, early analysis tooling, x86 only etc...)
start at finding some of these gadgets.
Another consideration for reviewing these patches is the 'hygiene'
argument. When a patch refers to hygiene it is concerned with stopping
speculation on an unconstrained or insufficiently constrained pointer
value under userspace control. That by itself is not sufficient for
attack (per current understanding) [3], but it is a necessary
pre-condition. So 'hygiene' refers to cleaning up those suspect
pointers regardless of whether they are usable as a gadget.
These patches are also be available via the 'nospec-v2' git branch
here:
git://git.kernel.org/pub/scm/linux/kernel/git/djbw/linux nospec-v2
Note that the BPF fix for Spectre variant1 is merged in the bpf.git
tree [4], and is not included in this branch.
[2]: https://googleprojectzero.blogspot.co.uk/2018/01/reading-privileged-memory-with-side.html
[3]: https://spectreattack.com/spectre.pdf
[4]: https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf.git/commit/?id=b2157399cc98
---
Dan Williams (16):
x86: implement ifence()
x86: implement ifence_array_ptr() and array_ptr_mask()
asm-generic/barrier: mask speculative execution flows
x86: introduce __uaccess_begin_nospec and ASM_IFENCE
x86: use __uaccess_begin_nospec and ASM_IFENCE in get_user paths
ipv6: prevent bounds-check bypass via speculative execution
ipv4: prevent bounds-check bypass via speculative execution
vfs, fdtable: prevent bounds-check bypass via speculative execution
userns: prevent bounds-check bypass via speculative execution
udf: prevent bounds-check bypass via speculative execution
[media] uvcvideo: prevent bounds-check bypass via speculative execution
carl9170: prevent bounds-check bypass via speculative execution
p54: prevent bounds-check bypass via speculative execution
qla2xxx: prevent bounds-check bypass via speculative execution
cw1200: prevent bounds-check bypass via speculative execution
net: mpls: prevent bounds-check bypass via speculative execution
Mark Rutland (3):
Documentation: document array_ptr
arm64: implement ifence_array_ptr()
arm: implement ifence_array_ptr()
Documentation/speculation.txt | 142 ++++++++++++++++++++++++++++++
arch/arm/Kconfig | 1
arch/arm/include/asm/barrier.h | 24 +++++
arch/arm64/Kconfig | 1
arch/arm64/include/asm/barrier.h | 24 +++++
arch/x86/Kconfig | 3 +
arch/x86/include/asm/barrier.h | 46 ++++++++++
arch/x86/include/asm/msr.h | 3 -
arch/x86/include/asm/smap.h | 4 +
arch/x86/include/asm/uaccess.h | 16 +++
arch/x86/include/asm/uaccess_32.h | 6 +
arch/x86/include/asm/uaccess_64.h | 12 +--
arch/x86/lib/copy_user_64.S | 3 +
arch/x86/lib/usercopy_32.c | 8 +-
drivers/media/usb/uvc/uvc_v4l2.c | 9 +-
drivers/net/wireless/ath/carl9170/main.c | 7 +
drivers/net/wireless/intersil/p54/main.c | 9 +-
drivers/net/wireless/st/cw1200/sta.c | 11 +-
drivers/net/wireless/st/cw1200/wsm.h | 4 -
drivers/scsi/qla2xxx/qla_mr.c | 17 ++--
fs/udf/misc.c | 40 +++++---
include/linux/fdtable.h | 7 +
include/linux/nospec.h | 71 +++++++++++++++
kernel/Kconfig.nospec | 31 +++++++
kernel/Makefile | 1
kernel/nospec.c | 52 +++++++++++
kernel/user_namespace.c | 11 +-
lib/Kconfig | 3 +
net/ipv4/raw.c | 10 +-
net/ipv6/raw.c | 10 +-
net/mpls/af_mpls.c | 12 +--
31 files changed, 521 insertions(+), 77 deletions(-)
create mode 100644 Documentation/speculation.txt
create mode 100644 include/linux/nospec.h
create mode 100644 kernel/Kconfig.nospec
create mode 100644 kernel/nospec.c