2017-06-17 01:32:43 +08:00
|
|
|
//===- X86_64.cpp ---------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Linker
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "InputFiles.h"
|
|
|
|
#include "Symbols.h"
|
|
|
|
#include "SyntheticSections.h"
|
|
|
|
#include "Target.h"
|
[lld] unified COFF and ELF error handling on new Common/ErrorHandler
Summary:
The COFF linker and the ELF linker have long had similar but separate
Error.h and Error.cpp files to implement error handling. This change
introduces new error handling code in Common/ErrorHandler.h, changes the
COFF and ELF linkers to use it, and removes the old, separate
implementations.
Reviewers: ruiu
Reviewed By: ruiu
Subscribers: smeenai, jyknight, emaste, sdardis, nemanjai, nhaehnle, mgorny, javed.absar, kbarton, fedor.sergeev, llvm-commits
Differential Revision: https://reviews.llvm.org/D39259
llvm-svn: 316624
2017-10-26 06:28:38 +08:00
|
|
|
#include "lld/Common/ErrorHandler.h"
|
2017-06-17 01:32:43 +08:00
|
|
|
#include "llvm/Object/ELF.h"
|
|
|
|
#include "llvm/Support/Endian.h"
|
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
using namespace llvm::object;
|
|
|
|
using namespace llvm::support::endian;
|
|
|
|
using namespace llvm::ELF;
|
|
|
|
using namespace lld;
|
|
|
|
using namespace lld::elf;
|
|
|
|
|
|
|
|
namespace {
|
Introduce the "retpoline" x86 mitigation technique for variant #2 of the speculative execution vulnerabilities disclosed today, specifically identified by CVE-2017-5715, "Branch Target Injection", and is one of the two halves to Spectre..
Summary:
First, we need to explain the core of the vulnerability. Note that this
is a very incomplete description, please see the Project Zero blog post
for details:
https://googleprojectzero.blogspot.com/2018/01/reading-privileged-memory-with-side.html
The basis for branch target injection is to direct speculative execution
of the processor to some "gadget" of executable code by poisoning the
prediction of indirect branches with the address of that gadget. The
gadget in turn contains an operation that provides a side channel for
reading data. Most commonly, this will look like a load of secret data
followed by a branch on the loaded value and then a load of some
predictable cache line. The attacker then uses timing of the processors
cache to determine which direction the branch took *in the speculative
execution*, and in turn what one bit of the loaded value was. Due to the
nature of these timing side channels and the branch predictor on Intel
processors, this allows an attacker to leak data only accessible to
a privileged domain (like the kernel) back into an unprivileged domain.
The goal is simple: avoid generating code which contains an indirect
branch that could have its prediction poisoned by an attacker. In many
cases, the compiler can simply use directed conditional branches and
a small search tree. LLVM already has support for lowering switches in
this way and the first step of this patch is to disable jump-table
lowering of switches and introduce a pass to rewrite explicit indirectbr
sequences into a switch over integers.
However, there is no fully general alternative to indirect calls. We
introduce a new construct we call a "retpoline" to implement indirect
calls in a non-speculatable way. It can be thought of loosely as
a trampoline for indirect calls which uses the RET instruction on x86.
Further, we arrange for a specific call->ret sequence which ensures the
processor predicts the return to go to a controlled, known location. The
retpoline then "smashes" the return address pushed onto the stack by the
call with the desired target of the original indirect call. The result
is a predicted return to the next instruction after a call (which can be
used to trap speculative execution within an infinite loop) and an
actual indirect branch to an arbitrary address.
On 64-bit x86 ABIs, this is especially easily done in the compiler by
using a guaranteed scratch register to pass the target into this device.
For 32-bit ABIs there isn't a guaranteed scratch register and so several
different retpoline variants are introduced to use a scratch register if
one is available in the calling convention and to otherwise use direct
stack push/pop sequences to pass the target address.
This "retpoline" mitigation is fully described in the following blog
post: https://support.google.com/faqs/answer/7625886
We also support a target feature that disables emission of the retpoline
thunk by the compiler to allow for custom thunks if users want them.
These are particularly useful in environments like kernels that
routinely do hot-patching on boot and want to hot-patch their thunk to
different code sequences. They can write this custom thunk and use
`-mretpoline-external-thunk` *in addition* to `-mretpoline`. In this
case, on x86-64 thu thunk names must be:
```
__llvm_external_retpoline_r11
```
or on 32-bit:
```
__llvm_external_retpoline_eax
__llvm_external_retpoline_ecx
__llvm_external_retpoline_edx
__llvm_external_retpoline_push
```
And the target of the retpoline is passed in the named register, or in
the case of the `push` suffix on the top of the stack via a `pushl`
instruction.
There is one other important source of indirect branches in x86 ELF
binaries: the PLT. These patches also include support for LLD to
generate PLT entries that perform a retpoline-style indirection.
The only other indirect branches remaining that we are aware of are from
precompiled runtimes (such as crt0.o and similar). The ones we have
found are not really attackable, and so we have not focused on them
here, but eventually these runtimes should also be replicated for
retpoline-ed configurations for completeness.
For kernels or other freestanding or fully static executables, the
compiler switch `-mretpoline` is sufficient to fully mitigate this
particular attack. For dynamic executables, you must compile *all*
libraries with `-mretpoline` and additionally link the dynamic
executable and all shared libraries with LLD and pass `-z retpolineplt`
(or use similar functionality from some other linker). We strongly
recommend also using `-z now` as non-lazy binding allows the
retpoline-mitigated PLT to be substantially smaller.
When manually apply similar transformations to `-mretpoline` to the
Linux kernel we observed very small performance hits to applications
running typical workloads, and relatively minor hits (approximately 2%)
even for extremely syscall-heavy applications. This is largely due to
the small number of indirect branches that occur in performance
sensitive paths of the kernel.
When using these patches on statically linked applications, especially
C++ applications, you should expect to see a much more dramatic
performance hit. For microbenchmarks that are switch, indirect-, or
virtual-call heavy we have seen overheads ranging from 10% to 50%.
However, real-world workloads exhibit substantially lower performance
impact. Notably, techniques such as PGO and ThinLTO dramatically reduce
the impact of hot indirect calls (by speculatively promoting them to
direct calls) and allow optimized search trees to be used to lower
switches. If you need to deploy these techniques in C++ applications, we
*strongly* recommend that you ensure all hot call targets are statically
linked (avoiding PLT indirection) and use both PGO and ThinLTO. Well
tuned servers using all of these techniques saw 5% - 10% overhead from
the use of retpoline.
We will add detailed documentation covering these components in
subsequent patches, but wanted to make the core functionality available
as soon as possible. Happy for more code review, but we'd really like to
get these patches landed and backported ASAP for obvious reasons. We're
planning to backport this to both 6.0 and 5.0 release streams and get
a 5.0 release with just this cherry picked ASAP for distros and vendors.
This patch is the work of a number of people over the past month: Eric, Reid,
Rui, and myself. I'm mailing it out as a single commit due to the time
sensitive nature of landing this and the need to backport it. Huge thanks to
everyone who helped out here, and everyone at Intel who helped out in
discussions about how to craft this. Also, credit goes to Paul Turner (at
Google, but not an LLVM contributor) for much of the underlying retpoline
design.
Reviewers: echristo, rnk, ruiu, craig.topper, DavidKreitzer
Subscribers: sanjoy, emaste, mcrosier, mgorny, mehdi_amini, hiraditya, llvm-commits
Differential Revision: https://reviews.llvm.org/D41723
llvm-svn: 323155
2018-01-23 06:05:25 +08:00
|
|
|
template <class ELFT> class X86_64 : public TargetInfo {
|
2017-06-17 01:32:43 +08:00
|
|
|
public:
|
|
|
|
X86_64();
|
2017-11-04 05:21:47 +08:00
|
|
|
RelExpr getRelExpr(RelType Type, const Symbol &S,
|
2017-06-17 01:32:43 +08:00
|
|
|
const uint8_t *Loc) const override;
|
2018-04-05 20:07:20 +08:00
|
|
|
RelType getDynRel(RelType Type) const override;
|
2017-06-17 01:32:43 +08:00
|
|
|
void writeGotPltHeader(uint8_t *Buf) const override;
|
2017-11-04 05:21:47 +08:00
|
|
|
void writeGotPlt(uint8_t *Buf, const Symbol &S) const override;
|
2017-06-17 01:32:43 +08:00
|
|
|
void writePltHeader(uint8_t *Buf) const override;
|
|
|
|
void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
|
|
|
|
int32_t Index, unsigned RelOff) const override;
|
2017-10-12 06:49:24 +08:00
|
|
|
void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
|
2017-06-17 01:32:43 +08:00
|
|
|
|
2017-10-12 06:49:24 +08:00
|
|
|
RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data,
|
2017-06-17 01:32:43 +08:00
|
|
|
RelExpr Expr) const override;
|
|
|
|
void relaxGot(uint8_t *Loc, uint64_t Val) const override;
|
2017-10-12 06:49:24 +08:00
|
|
|
void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
|
|
|
|
void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
|
|
|
|
void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
|
|
|
|
void relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
|
2017-06-17 01:32:43 +08:00
|
|
|
|
|
|
|
private:
|
|
|
|
void relaxGotNoPic(uint8_t *Loc, uint64_t Val, uint8_t Op,
|
|
|
|
uint8_t ModRm) const;
|
|
|
|
};
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
template <class ELFT> X86_64<ELFT>::X86_64() {
|
|
|
|
CopyRel = R_X86_64_COPY;
|
|
|
|
GotRel = R_X86_64_GLOB_DAT;
|
|
|
|
PltRel = R_X86_64_JUMP_SLOT;
|
|
|
|
RelativeRel = R_X86_64_RELATIVE;
|
|
|
|
IRelativeRel = R_X86_64_IRELATIVE;
|
|
|
|
TlsGotRel = R_X86_64_TPOFF64;
|
|
|
|
TlsModuleIndexRel = R_X86_64_DTPMOD64;
|
|
|
|
TlsOffsetRel = R_X86_64_DTPOFF64;
|
|
|
|
GotEntrySize = 8;
|
|
|
|
GotPltEntrySize = 8;
|
|
|
|
PltEntrySize = 16;
|
|
|
|
PltHeaderSize = 16;
|
|
|
|
TlsGdRelaxSkip = 2;
|
2017-06-27 03:45:53 +08:00
|
|
|
TrapInstr = 0xcccccccc; // 0xcc = INT3
|
2017-06-17 01:32:43 +08:00
|
|
|
|
|
|
|
// Align to the large page size (known as a superpage or huge page).
|
|
|
|
// FreeBSD automatically promotes large, superpage-aligned allocations.
|
|
|
|
DefaultImageBase = 0x200000;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class ELFT>
|
2017-11-04 05:21:47 +08:00
|
|
|
RelExpr X86_64<ELFT>::getRelExpr(RelType Type, const Symbol &S,
|
2017-06-17 01:32:43 +08:00
|
|
|
const uint8_t *Loc) const {
|
|
|
|
switch (Type) {
|
|
|
|
case R_X86_64_8:
|
|
|
|
case R_X86_64_16:
|
|
|
|
case R_X86_64_32:
|
|
|
|
case R_X86_64_32S:
|
|
|
|
case R_X86_64_64:
|
|
|
|
case R_X86_64_DTPOFF32:
|
|
|
|
case R_X86_64_DTPOFF64:
|
|
|
|
return R_ABS;
|
|
|
|
case R_X86_64_TPOFF32:
|
|
|
|
return R_TLS;
|
|
|
|
case R_X86_64_TLSLD:
|
|
|
|
return R_TLSLD_PC;
|
|
|
|
case R_X86_64_TLSGD:
|
|
|
|
return R_TLSGD_PC;
|
|
|
|
case R_X86_64_SIZE32:
|
|
|
|
case R_X86_64_SIZE64:
|
|
|
|
return R_SIZE;
|
|
|
|
case R_X86_64_PLT32:
|
|
|
|
return R_PLT_PC;
|
|
|
|
case R_X86_64_PC32:
|
|
|
|
case R_X86_64_PC64:
|
|
|
|
return R_PC;
|
|
|
|
case R_X86_64_GOT32:
|
|
|
|
case R_X86_64_GOT64:
|
|
|
|
return R_GOT_FROM_END;
|
|
|
|
case R_X86_64_GOTPCREL:
|
|
|
|
case R_X86_64_GOTPCRELX:
|
|
|
|
case R_X86_64_REX_GOTPCRELX:
|
|
|
|
case R_X86_64_GOTTPOFF:
|
|
|
|
return R_GOT_PC;
|
|
|
|
case R_X86_64_NONE:
|
|
|
|
return R_NONE;
|
|
|
|
default:
|
2017-10-12 11:14:06 +08:00
|
|
|
return R_INVALID;
|
2017-06-17 01:32:43 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class ELFT> void X86_64<ELFT>::writeGotPltHeader(uint8_t *Buf) const {
|
|
|
|
// The first entry holds the value of _DYNAMIC. It is not clear why that is
|
|
|
|
// required, but it is documented in the psabi and the glibc dynamic linker
|
|
|
|
// seems to use it (note that this is relevant for linking ld.so, not any
|
|
|
|
// other program).
|
|
|
|
write64le(Buf, InX::Dynamic->getVA());
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class ELFT>
|
2017-11-04 05:21:47 +08:00
|
|
|
void X86_64<ELFT>::writeGotPlt(uint8_t *Buf, const Symbol &S) const {
|
2017-08-31 18:14:10 +08:00
|
|
|
// See comments in X86::writeGotPlt.
|
2017-06-17 01:32:43 +08:00
|
|
|
write32le(Buf, S.getPltVA() + 6);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class ELFT> void X86_64<ELFT>::writePltHeader(uint8_t *Buf) const {
|
|
|
|
const uint8_t PltData[] = {
|
2017-12-27 14:54:18 +08:00
|
|
|
0xff, 0x35, 0, 0, 0, 0, // pushq GOTPLT+8(%rip)
|
|
|
|
0xff, 0x25, 0, 0, 0, 0, // jmp *GOTPLT+16(%rip)
|
|
|
|
0x0f, 0x1f, 0x40, 0x00, // nop
|
2017-06-17 01:32:43 +08:00
|
|
|
};
|
|
|
|
memcpy(Buf, PltData, sizeof(PltData));
|
|
|
|
uint64_t GotPlt = InX::GotPlt->getVA();
|
|
|
|
uint64_t Plt = InX::Plt->getVA();
|
|
|
|
write32le(Buf + 2, GotPlt - Plt + 2); // GOTPLT+8
|
|
|
|
write32le(Buf + 8, GotPlt - Plt + 4); // GOTPLT+16
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class ELFT>
|
|
|
|
void X86_64<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
|
|
|
|
uint64_t PltEntryAddr, int32_t Index,
|
|
|
|
unsigned RelOff) const {
|
|
|
|
const uint8_t Inst[] = {
|
2017-12-27 14:54:18 +08:00
|
|
|
0xff, 0x25, 0, 0, 0, 0, // jmpq *got(%rip)
|
|
|
|
0x68, 0, 0, 0, 0, // pushq <relocation index>
|
|
|
|
0xe9, 0, 0, 0, 0, // jmpq plt[0]
|
2017-06-17 01:32:43 +08:00
|
|
|
};
|
|
|
|
memcpy(Buf, Inst, sizeof(Inst));
|
|
|
|
|
|
|
|
write32le(Buf + 2, GotPltEntryAddr - PltEntryAddr - 6);
|
|
|
|
write32le(Buf + 7, Index);
|
2018-03-15 01:41:34 +08:00
|
|
|
write32le(Buf + 12, -getPltEntryOffset(Index) - 16);
|
2017-06-17 01:32:43 +08:00
|
|
|
}
|
|
|
|
|
2018-04-05 20:07:20 +08:00
|
|
|
template <class ELFT> RelType X86_64<ELFT>::getDynRel(RelType Type) const {
|
|
|
|
if (Type == R_X86_64_64 || Type == R_X86_64_PC64 || Type == R_X86_64_SIZE32 ||
|
|
|
|
Type == R_X86_64_SIZE64)
|
|
|
|
return Type;
|
|
|
|
return R_X86_64_NONE;
|
2017-06-17 01:32:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class ELFT>
|
2017-10-12 06:49:24 +08:00
|
|
|
void X86_64<ELFT>::relaxTlsGdToLe(uint8_t *Loc, RelType Type,
|
2017-06-17 01:32:43 +08:00
|
|
|
uint64_t Val) const {
|
|
|
|
// Convert
|
|
|
|
// .byte 0x66
|
|
|
|
// leaq x@tlsgd(%rip), %rdi
|
|
|
|
// .word 0x6666
|
|
|
|
// rex64
|
|
|
|
// call __tls_get_addr@plt
|
|
|
|
// to
|
|
|
|
// mov %fs:0x0,%rax
|
|
|
|
// lea x@tpoff,%rax
|
|
|
|
const uint8_t Inst[] = {
|
|
|
|
0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0x0,%rax
|
2017-12-27 14:54:18 +08:00
|
|
|
0x48, 0x8d, 0x80, 0, 0, 0, 0, // lea x@tpoff,%rax
|
2017-06-17 01:32:43 +08:00
|
|
|
};
|
|
|
|
memcpy(Loc - 4, Inst, sizeof(Inst));
|
|
|
|
|
|
|
|
// The original code used a pc relative relocation and so we have to
|
|
|
|
// compensate for the -4 in had in the addend.
|
|
|
|
write32le(Loc + 8, Val + 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class ELFT>
|
2017-10-12 06:49:24 +08:00
|
|
|
void X86_64<ELFT>::relaxTlsGdToIe(uint8_t *Loc, RelType Type,
|
2017-06-17 01:32:43 +08:00
|
|
|
uint64_t Val) const {
|
|
|
|
// Convert
|
|
|
|
// .byte 0x66
|
|
|
|
// leaq x@tlsgd(%rip), %rdi
|
|
|
|
// .word 0x6666
|
|
|
|
// rex64
|
|
|
|
// call __tls_get_addr@plt
|
|
|
|
// to
|
|
|
|
// mov %fs:0x0,%rax
|
|
|
|
// addq x@tpoff,%rax
|
|
|
|
const uint8_t Inst[] = {
|
|
|
|
0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0x0,%rax
|
2017-12-27 14:54:18 +08:00
|
|
|
0x48, 0x03, 0x05, 0, 0, 0, 0, // addq x@tpoff,%rax
|
2017-06-17 01:32:43 +08:00
|
|
|
};
|
|
|
|
memcpy(Loc - 4, Inst, sizeof(Inst));
|
|
|
|
|
|
|
|
// Both code sequences are PC relatives, but since we are moving the constant
|
|
|
|
// forward by 8 bytes we have to subtract the value by 8.
|
|
|
|
write32le(Loc + 8, Val - 8);
|
|
|
|
}
|
|
|
|
|
|
|
|
// In some conditions, R_X86_64_GOTTPOFF relocation can be optimized to
|
|
|
|
// R_X86_64_TPOFF32 so that it does not use GOT.
|
|
|
|
template <class ELFT>
|
2017-10-12 06:49:24 +08:00
|
|
|
void X86_64<ELFT>::relaxTlsIeToLe(uint8_t *Loc, RelType Type,
|
2017-06-17 01:32:43 +08:00
|
|
|
uint64_t Val) const {
|
|
|
|
uint8_t *Inst = Loc - 3;
|
|
|
|
uint8_t Reg = Loc[-1] >> 3;
|
|
|
|
uint8_t *RegSlot = Loc - 1;
|
|
|
|
|
|
|
|
// Note that ADD with RSP or R12 is converted to ADD instead of LEA
|
|
|
|
// because LEA with these registers needs 4 bytes to encode and thus
|
|
|
|
// wouldn't fit the space.
|
|
|
|
|
|
|
|
if (memcmp(Inst, "\x48\x03\x25", 3) == 0) {
|
|
|
|
// "addq foo@gottpoff(%rip),%rsp" -> "addq $foo,%rsp"
|
|
|
|
memcpy(Inst, "\x48\x81\xc4", 3);
|
|
|
|
} else if (memcmp(Inst, "\x4c\x03\x25", 3) == 0) {
|
|
|
|
// "addq foo@gottpoff(%rip),%r12" -> "addq $foo,%r12"
|
|
|
|
memcpy(Inst, "\x49\x81\xc4", 3);
|
|
|
|
} else if (memcmp(Inst, "\x4c\x03", 2) == 0) {
|
|
|
|
// "addq foo@gottpoff(%rip),%r[8-15]" -> "leaq foo(%r[8-15]),%r[8-15]"
|
|
|
|
memcpy(Inst, "\x4d\x8d", 2);
|
|
|
|
*RegSlot = 0x80 | (Reg << 3) | Reg;
|
|
|
|
} else if (memcmp(Inst, "\x48\x03", 2) == 0) {
|
|
|
|
// "addq foo@gottpoff(%rip),%reg -> "leaq foo(%reg),%reg"
|
|
|
|
memcpy(Inst, "\x48\x8d", 2);
|
|
|
|
*RegSlot = 0x80 | (Reg << 3) | Reg;
|
|
|
|
} else if (memcmp(Inst, "\x4c\x8b", 2) == 0) {
|
|
|
|
// "movq foo@gottpoff(%rip),%r[8-15]" -> "movq $foo,%r[8-15]"
|
|
|
|
memcpy(Inst, "\x49\xc7", 2);
|
|
|
|
*RegSlot = 0xc0 | Reg;
|
|
|
|
} else if (memcmp(Inst, "\x48\x8b", 2) == 0) {
|
|
|
|
// "movq foo@gottpoff(%rip),%reg" -> "movq $foo,%reg"
|
|
|
|
memcpy(Inst, "\x48\xc7", 2);
|
|
|
|
*RegSlot = 0xc0 | Reg;
|
|
|
|
} else {
|
|
|
|
error(getErrorLocation(Loc - 3) +
|
|
|
|
"R_X86_64_GOTTPOFF must be used in MOVQ or ADDQ instructions only");
|
|
|
|
}
|
|
|
|
|
|
|
|
// The original code used a PC relative relocation.
|
|
|
|
// Need to compensate for the -4 it had in the addend.
|
|
|
|
write32le(Loc, Val + 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class ELFT>
|
2017-10-12 06:49:24 +08:00
|
|
|
void X86_64<ELFT>::relaxTlsLdToLe(uint8_t *Loc, RelType Type,
|
2017-06-17 01:32:43 +08:00
|
|
|
uint64_t Val) const {
|
|
|
|
// Convert
|
|
|
|
// leaq bar@tlsld(%rip), %rdi
|
|
|
|
// callq __tls_get_addr@PLT
|
|
|
|
// leaq bar@dtpoff(%rax), %rcx
|
|
|
|
// to
|
|
|
|
// .word 0x6666
|
|
|
|
// .byte 0x66
|
|
|
|
// mov %fs:0,%rax
|
|
|
|
// leaq bar@tpoff(%rax), %rcx
|
|
|
|
if (Type == R_X86_64_DTPOFF64) {
|
|
|
|
write64le(Loc, Val);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (Type == R_X86_64_DTPOFF32) {
|
|
|
|
write32le(Loc, Val);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const uint8_t Inst[] = {
|
2017-12-27 14:54:18 +08:00
|
|
|
0x66, 0x66, // .word 0x6666
|
|
|
|
0x66, // .byte 0x66
|
|
|
|
0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0,%rax
|
2017-06-17 01:32:43 +08:00
|
|
|
};
|
|
|
|
memcpy(Loc - 3, Inst, sizeof(Inst));
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class ELFT>
|
2017-10-12 06:49:24 +08:00
|
|
|
void X86_64<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
|
2017-06-17 01:32:43 +08:00
|
|
|
switch (Type) {
|
|
|
|
case R_X86_64_8:
|
2018-03-30 06:40:52 +08:00
|
|
|
checkUInt(Loc, Val, 8, Type);
|
2017-06-17 01:32:43 +08:00
|
|
|
*Loc = Val;
|
|
|
|
break;
|
|
|
|
case R_X86_64_16:
|
2018-03-30 06:40:52 +08:00
|
|
|
checkUInt(Loc, Val, 16, Type);
|
2017-06-17 01:32:43 +08:00
|
|
|
write16le(Loc, Val);
|
|
|
|
break;
|
|
|
|
case R_X86_64_32:
|
2018-03-30 06:40:52 +08:00
|
|
|
checkUInt(Loc, Val, 32, Type);
|
2017-06-17 01:32:43 +08:00
|
|
|
write32le(Loc, Val);
|
|
|
|
break;
|
|
|
|
case R_X86_64_32S:
|
|
|
|
case R_X86_64_TPOFF32:
|
|
|
|
case R_X86_64_GOT32:
|
|
|
|
case R_X86_64_GOTPCREL:
|
|
|
|
case R_X86_64_GOTPCRELX:
|
|
|
|
case R_X86_64_REX_GOTPCRELX:
|
|
|
|
case R_X86_64_PC32:
|
|
|
|
case R_X86_64_GOTTPOFF:
|
|
|
|
case R_X86_64_PLT32:
|
|
|
|
case R_X86_64_TLSGD:
|
|
|
|
case R_X86_64_TLSLD:
|
|
|
|
case R_X86_64_DTPOFF32:
|
|
|
|
case R_X86_64_SIZE32:
|
2018-03-30 06:40:52 +08:00
|
|
|
checkInt(Loc, Val, 32, Type);
|
2017-06-17 01:32:43 +08:00
|
|
|
write32le(Loc, Val);
|
|
|
|
break;
|
|
|
|
case R_X86_64_64:
|
|
|
|
case R_X86_64_DTPOFF64:
|
|
|
|
case R_X86_64_GLOB_DAT:
|
|
|
|
case R_X86_64_PC64:
|
|
|
|
case R_X86_64_SIZE64:
|
|
|
|
case R_X86_64_GOT64:
|
|
|
|
write64le(Loc, Val);
|
|
|
|
break;
|
|
|
|
default:
|
2017-10-12 11:14:06 +08:00
|
|
|
error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
|
2017-06-17 01:32:43 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class ELFT>
|
2017-10-12 06:49:24 +08:00
|
|
|
RelExpr X86_64<ELFT>::adjustRelaxExpr(RelType Type, const uint8_t *Data,
|
2017-06-17 01:32:43 +08:00
|
|
|
RelExpr RelExpr) const {
|
|
|
|
if (Type != R_X86_64_GOTPCRELX && Type != R_X86_64_REX_GOTPCRELX)
|
|
|
|
return RelExpr;
|
|
|
|
const uint8_t Op = Data[-2];
|
|
|
|
const uint8_t ModRm = Data[-1];
|
|
|
|
|
|
|
|
// FIXME: When PIC is disabled and foo is defined locally in the
|
|
|
|
// lower 32 bit address space, memory operand in mov can be converted into
|
|
|
|
// immediate operand. Otherwise, mov must be changed to lea. We support only
|
|
|
|
// latter relaxation at this moment.
|
|
|
|
if (Op == 0x8b)
|
|
|
|
return R_RELAX_GOT_PC;
|
|
|
|
|
|
|
|
// Relax call and jmp.
|
|
|
|
if (Op == 0xff && (ModRm == 0x15 || ModRm == 0x25))
|
|
|
|
return R_RELAX_GOT_PC;
|
|
|
|
|
|
|
|
// Relaxation of test, adc, add, and, cmp, or, sbb, sub, xor.
|
|
|
|
// If PIC then no relaxation is available.
|
|
|
|
// We also don't relax test/binop instructions without REX byte,
|
|
|
|
// they are 32bit operations and not common to have.
|
|
|
|
assert(Type == R_X86_64_REX_GOTPCRELX);
|
|
|
|
return Config->Pic ? RelExpr : R_RELAX_GOT_PC_NOPIC;
|
|
|
|
}
|
|
|
|
|
|
|
|
// A subset of relaxations can only be applied for no-PIC. This method
|
|
|
|
// handles such relaxations. Instructions encoding information was taken from:
|
|
|
|
// "Intel 64 and IA-32 Architectures Software Developer's Manual V2"
|
|
|
|
// (http://www.intel.com/content/dam/www/public/us/en/documents/manuals/
|
|
|
|
// 64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf)
|
|
|
|
template <class ELFT>
|
|
|
|
void X86_64<ELFT>::relaxGotNoPic(uint8_t *Loc, uint64_t Val, uint8_t Op,
|
|
|
|
uint8_t ModRm) const {
|
|
|
|
const uint8_t Rex = Loc[-3];
|
|
|
|
// Convert "test %reg, foo@GOTPCREL(%rip)" to "test $foo, %reg".
|
|
|
|
if (Op == 0x85) {
|
|
|
|
// See "TEST-Logical Compare" (4-428 Vol. 2B),
|
|
|
|
// TEST r/m64, r64 uses "full" ModR / M byte (no opcode extension).
|
|
|
|
|
|
|
|
// ModR/M byte has form XX YYY ZZZ, where
|
|
|
|
// YYY is MODRM.reg(register 2), ZZZ is MODRM.rm(register 1).
|
|
|
|
// XX has different meanings:
|
|
|
|
// 00: The operand's memory address is in reg1.
|
|
|
|
// 01: The operand's memory address is reg1 + a byte-sized displacement.
|
|
|
|
// 10: The operand's memory address is reg1 + a word-sized displacement.
|
|
|
|
// 11: The operand is reg1 itself.
|
|
|
|
// If an instruction requires only one operand, the unused reg2 field
|
|
|
|
// holds extra opcode bits rather than a register code
|
|
|
|
// 0xC0 == 11 000 000 binary.
|
|
|
|
// 0x38 == 00 111 000 binary.
|
|
|
|
// We transfer reg2 to reg1 here as operand.
|
|
|
|
// See "2.1.3 ModR/M and SIB Bytes" (Vol. 2A 2-3).
|
|
|
|
Loc[-1] = 0xc0 | (ModRm & 0x38) >> 3; // ModR/M byte.
|
|
|
|
|
|
|
|
// Change opcode from TEST r/m64, r64 to TEST r/m64, imm32
|
|
|
|
// See "TEST-Logical Compare" (4-428 Vol. 2B).
|
|
|
|
Loc[-2] = 0xf7;
|
|
|
|
|
|
|
|
// Move R bit to the B bit in REX byte.
|
|
|
|
// REX byte is encoded as 0100WRXB, where
|
|
|
|
// 0100 is 4bit fixed pattern.
|
|
|
|
// REX.W When 1, a 64-bit operand size is used. Otherwise, when 0, the
|
|
|
|
// default operand size is used (which is 32-bit for most but not all
|
|
|
|
// instructions).
|
|
|
|
// REX.R This 1-bit value is an extension to the MODRM.reg field.
|
|
|
|
// REX.X This 1-bit value is an extension to the SIB.index field.
|
|
|
|
// REX.B This 1-bit value is an extension to the MODRM.rm field or the
|
|
|
|
// SIB.base field.
|
|
|
|
// See "2.2.1.2 More on REX Prefix Fields " (2-8 Vol. 2A).
|
|
|
|
Loc[-3] = (Rex & ~0x4) | (Rex & 0x4) >> 2;
|
|
|
|
write32le(Loc, Val);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we are here then we need to relax the adc, add, and, cmp, or, sbb, sub
|
|
|
|
// or xor operations.
|
|
|
|
|
|
|
|
// Convert "binop foo@GOTPCREL(%rip), %reg" to "binop $foo, %reg".
|
|
|
|
// Logic is close to one for test instruction above, but we also
|
|
|
|
// write opcode extension here, see below for details.
|
|
|
|
Loc[-1] = 0xc0 | (ModRm & 0x38) >> 3 | (Op & 0x3c); // ModR/M byte.
|
|
|
|
|
|
|
|
// Primary opcode is 0x81, opcode extension is one of:
|
|
|
|
// 000b = ADD, 001b is OR, 010b is ADC, 011b is SBB,
|
|
|
|
// 100b is AND, 101b is SUB, 110b is XOR, 111b is CMP.
|
|
|
|
// This value was wrote to MODRM.reg in a line above.
|
|
|
|
// See "3.2 INSTRUCTIONS (A-M)" (Vol. 2A 3-15),
|
|
|
|
// "INSTRUCTION SET REFERENCE, N-Z" (Vol. 2B 4-1) for
|
|
|
|
// descriptions about each operation.
|
|
|
|
Loc[-2] = 0x81;
|
|
|
|
Loc[-3] = (Rex & ~0x4) | (Rex & 0x4) >> 2;
|
|
|
|
write32le(Loc, Val);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class ELFT>
|
|
|
|
void X86_64<ELFT>::relaxGot(uint8_t *Loc, uint64_t Val) const {
|
|
|
|
const uint8_t Op = Loc[-2];
|
|
|
|
const uint8_t ModRm = Loc[-1];
|
|
|
|
|
|
|
|
// Convert "mov foo@GOTPCREL(%rip),%reg" to "lea foo(%rip),%reg".
|
|
|
|
if (Op == 0x8b) {
|
|
|
|
Loc[-2] = 0x8d;
|
|
|
|
write32le(Loc, Val);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Op != 0xff) {
|
|
|
|
// We are relaxing a rip relative to an absolute, so compensate
|
|
|
|
// for the old -4 addend.
|
|
|
|
assert(!Config->Pic);
|
|
|
|
relaxGotNoPic(Loc, Val + 4, Op, ModRm);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convert call/jmp instructions.
|
|
|
|
if (ModRm == 0x15) {
|
|
|
|
// ABI says we can convert "call *foo@GOTPCREL(%rip)" to "nop; call foo".
|
|
|
|
// Instead we convert to "addr32 call foo" where addr32 is an instruction
|
|
|
|
// prefix. That makes result expression to be a single instruction.
|
|
|
|
Loc[-2] = 0x67; // addr32 prefix
|
|
|
|
Loc[-1] = 0xe8; // call
|
|
|
|
write32le(Loc, Val);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convert "jmp *foo@GOTPCREL(%rip)" to "jmp foo; nop".
|
|
|
|
// jmp doesn't return, so it is fine to use nop here, it is just a stub.
|
|
|
|
assert(ModRm == 0x25);
|
|
|
|
Loc[-2] = 0xe9; // jmp
|
|
|
|
Loc[3] = 0x90; // nop
|
|
|
|
write32le(Loc - 1, Val + 1);
|
|
|
|
}
|
|
|
|
|
Introduce the "retpoline" x86 mitigation technique for variant #2 of the speculative execution vulnerabilities disclosed today, specifically identified by CVE-2017-5715, "Branch Target Injection", and is one of the two halves to Spectre..
Summary:
First, we need to explain the core of the vulnerability. Note that this
is a very incomplete description, please see the Project Zero blog post
for details:
https://googleprojectzero.blogspot.com/2018/01/reading-privileged-memory-with-side.html
The basis for branch target injection is to direct speculative execution
of the processor to some "gadget" of executable code by poisoning the
prediction of indirect branches with the address of that gadget. The
gadget in turn contains an operation that provides a side channel for
reading data. Most commonly, this will look like a load of secret data
followed by a branch on the loaded value and then a load of some
predictable cache line. The attacker then uses timing of the processors
cache to determine which direction the branch took *in the speculative
execution*, and in turn what one bit of the loaded value was. Due to the
nature of these timing side channels and the branch predictor on Intel
processors, this allows an attacker to leak data only accessible to
a privileged domain (like the kernel) back into an unprivileged domain.
The goal is simple: avoid generating code which contains an indirect
branch that could have its prediction poisoned by an attacker. In many
cases, the compiler can simply use directed conditional branches and
a small search tree. LLVM already has support for lowering switches in
this way and the first step of this patch is to disable jump-table
lowering of switches and introduce a pass to rewrite explicit indirectbr
sequences into a switch over integers.
However, there is no fully general alternative to indirect calls. We
introduce a new construct we call a "retpoline" to implement indirect
calls in a non-speculatable way. It can be thought of loosely as
a trampoline for indirect calls which uses the RET instruction on x86.
Further, we arrange for a specific call->ret sequence which ensures the
processor predicts the return to go to a controlled, known location. The
retpoline then "smashes" the return address pushed onto the stack by the
call with the desired target of the original indirect call. The result
is a predicted return to the next instruction after a call (which can be
used to trap speculative execution within an infinite loop) and an
actual indirect branch to an arbitrary address.
On 64-bit x86 ABIs, this is especially easily done in the compiler by
using a guaranteed scratch register to pass the target into this device.
For 32-bit ABIs there isn't a guaranteed scratch register and so several
different retpoline variants are introduced to use a scratch register if
one is available in the calling convention and to otherwise use direct
stack push/pop sequences to pass the target address.
This "retpoline" mitigation is fully described in the following blog
post: https://support.google.com/faqs/answer/7625886
We also support a target feature that disables emission of the retpoline
thunk by the compiler to allow for custom thunks if users want them.
These are particularly useful in environments like kernels that
routinely do hot-patching on boot and want to hot-patch their thunk to
different code sequences. They can write this custom thunk and use
`-mretpoline-external-thunk` *in addition* to `-mretpoline`. In this
case, on x86-64 thu thunk names must be:
```
__llvm_external_retpoline_r11
```
or on 32-bit:
```
__llvm_external_retpoline_eax
__llvm_external_retpoline_ecx
__llvm_external_retpoline_edx
__llvm_external_retpoline_push
```
And the target of the retpoline is passed in the named register, or in
the case of the `push` suffix on the top of the stack via a `pushl`
instruction.
There is one other important source of indirect branches in x86 ELF
binaries: the PLT. These patches also include support for LLD to
generate PLT entries that perform a retpoline-style indirection.
The only other indirect branches remaining that we are aware of are from
precompiled runtimes (such as crt0.o and similar). The ones we have
found are not really attackable, and so we have not focused on them
here, but eventually these runtimes should also be replicated for
retpoline-ed configurations for completeness.
For kernels or other freestanding or fully static executables, the
compiler switch `-mretpoline` is sufficient to fully mitigate this
particular attack. For dynamic executables, you must compile *all*
libraries with `-mretpoline` and additionally link the dynamic
executable and all shared libraries with LLD and pass `-z retpolineplt`
(or use similar functionality from some other linker). We strongly
recommend also using `-z now` as non-lazy binding allows the
retpoline-mitigated PLT to be substantially smaller.
When manually apply similar transformations to `-mretpoline` to the
Linux kernel we observed very small performance hits to applications
running typical workloads, and relatively minor hits (approximately 2%)
even for extremely syscall-heavy applications. This is largely due to
the small number of indirect branches that occur in performance
sensitive paths of the kernel.
When using these patches on statically linked applications, especially
C++ applications, you should expect to see a much more dramatic
performance hit. For microbenchmarks that are switch, indirect-, or
virtual-call heavy we have seen overheads ranging from 10% to 50%.
However, real-world workloads exhibit substantially lower performance
impact. Notably, techniques such as PGO and ThinLTO dramatically reduce
the impact of hot indirect calls (by speculatively promoting them to
direct calls) and allow optimized search trees to be used to lower
switches. If you need to deploy these techniques in C++ applications, we
*strongly* recommend that you ensure all hot call targets are statically
linked (avoiding PLT indirection) and use both PGO and ThinLTO. Well
tuned servers using all of these techniques saw 5% - 10% overhead from
the use of retpoline.
We will add detailed documentation covering these components in
subsequent patches, but wanted to make the core functionality available
as soon as possible. Happy for more code review, but we'd really like to
get these patches landed and backported ASAP for obvious reasons. We're
planning to backport this to both 6.0 and 5.0 release streams and get
a 5.0 release with just this cherry picked ASAP for distros and vendors.
This patch is the work of a number of people over the past month: Eric, Reid,
Rui, and myself. I'm mailing it out as a single commit due to the time
sensitive nature of landing this and the need to backport it. Huge thanks to
everyone who helped out here, and everyone at Intel who helped out in
discussions about how to craft this. Also, credit goes to Paul Turner (at
Google, but not an LLVM contributor) for much of the underlying retpoline
design.
Reviewers: echristo, rnk, ruiu, craig.topper, DavidKreitzer
Subscribers: sanjoy, emaste, mcrosier, mgorny, mehdi_amini, hiraditya, llvm-commits
Differential Revision: https://reviews.llvm.org/D41723
llvm-svn: 323155
2018-01-23 06:05:25 +08:00
|
|
|
namespace {
|
|
|
|
template <class ELFT> class Retpoline : public X86_64<ELFT> {
|
|
|
|
public:
|
|
|
|
Retpoline();
|
|
|
|
void writeGotPlt(uint8_t *Buf, const Symbol &S) const override;
|
|
|
|
void writePltHeader(uint8_t *Buf) const override;
|
|
|
|
void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
|
|
|
|
int32_t Index, unsigned RelOff) const override;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <class ELFT> class RetpolineZNow : public X86_64<ELFT> {
|
|
|
|
public:
|
|
|
|
RetpolineZNow();
|
|
|
|
void writeGotPlt(uint8_t *Buf, const Symbol &S) const override {}
|
|
|
|
void writePltHeader(uint8_t *Buf) const override;
|
|
|
|
void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
|
|
|
|
int32_t Index, unsigned RelOff) const override;
|
|
|
|
};
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
template <class ELFT> Retpoline<ELFT>::Retpoline() {
|
|
|
|
TargetInfo::PltHeaderSize = 48;
|
|
|
|
TargetInfo::PltEntrySize = 32;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class ELFT>
|
|
|
|
void Retpoline<ELFT>::writeGotPlt(uint8_t *Buf, const Symbol &S) const {
|
|
|
|
write32le(Buf, S.getPltVA() + 17);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class ELFT> void Retpoline<ELFT>::writePltHeader(uint8_t *Buf) const {
|
|
|
|
const uint8_t Insn[] = {
|
|
|
|
0xff, 0x35, 0, 0, 0, 0, // 0: pushq GOTPLT+8(%rip)
|
|
|
|
0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // 6: mov GOTPLT+16(%rip), %r11
|
|
|
|
0xe8, 0x0e, 0x00, 0x00, 0x00, // d: callq next
|
|
|
|
0xf3, 0x90, // 12: loop: pause
|
|
|
|
0x0f, 0xae, 0xe8, // 14: lfence
|
|
|
|
0xeb, 0xf9, // 17: jmp loop
|
|
|
|
0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 19: int3; .align 16
|
|
|
|
0x4c, 0x89, 0x1c, 0x24, // 20: next: mov %r11, (%rsp)
|
|
|
|
0xc3, // 24: ret
|
2018-03-29 22:03:01 +08:00
|
|
|
0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 25: int3; padding
|
|
|
|
0xcc, 0xcc, 0xcc, 0xcc, // 2c: int3; padding
|
Introduce the "retpoline" x86 mitigation technique for variant #2 of the speculative execution vulnerabilities disclosed today, specifically identified by CVE-2017-5715, "Branch Target Injection", and is one of the two halves to Spectre..
Summary:
First, we need to explain the core of the vulnerability. Note that this
is a very incomplete description, please see the Project Zero blog post
for details:
https://googleprojectzero.blogspot.com/2018/01/reading-privileged-memory-with-side.html
The basis for branch target injection is to direct speculative execution
of the processor to some "gadget" of executable code by poisoning the
prediction of indirect branches with the address of that gadget. The
gadget in turn contains an operation that provides a side channel for
reading data. Most commonly, this will look like a load of secret data
followed by a branch on the loaded value and then a load of some
predictable cache line. The attacker then uses timing of the processors
cache to determine which direction the branch took *in the speculative
execution*, and in turn what one bit of the loaded value was. Due to the
nature of these timing side channels and the branch predictor on Intel
processors, this allows an attacker to leak data only accessible to
a privileged domain (like the kernel) back into an unprivileged domain.
The goal is simple: avoid generating code which contains an indirect
branch that could have its prediction poisoned by an attacker. In many
cases, the compiler can simply use directed conditional branches and
a small search tree. LLVM already has support for lowering switches in
this way and the first step of this patch is to disable jump-table
lowering of switches and introduce a pass to rewrite explicit indirectbr
sequences into a switch over integers.
However, there is no fully general alternative to indirect calls. We
introduce a new construct we call a "retpoline" to implement indirect
calls in a non-speculatable way. It can be thought of loosely as
a trampoline for indirect calls which uses the RET instruction on x86.
Further, we arrange for a specific call->ret sequence which ensures the
processor predicts the return to go to a controlled, known location. The
retpoline then "smashes" the return address pushed onto the stack by the
call with the desired target of the original indirect call. The result
is a predicted return to the next instruction after a call (which can be
used to trap speculative execution within an infinite loop) and an
actual indirect branch to an arbitrary address.
On 64-bit x86 ABIs, this is especially easily done in the compiler by
using a guaranteed scratch register to pass the target into this device.
For 32-bit ABIs there isn't a guaranteed scratch register and so several
different retpoline variants are introduced to use a scratch register if
one is available in the calling convention and to otherwise use direct
stack push/pop sequences to pass the target address.
This "retpoline" mitigation is fully described in the following blog
post: https://support.google.com/faqs/answer/7625886
We also support a target feature that disables emission of the retpoline
thunk by the compiler to allow for custom thunks if users want them.
These are particularly useful in environments like kernels that
routinely do hot-patching on boot and want to hot-patch their thunk to
different code sequences. They can write this custom thunk and use
`-mretpoline-external-thunk` *in addition* to `-mretpoline`. In this
case, on x86-64 thu thunk names must be:
```
__llvm_external_retpoline_r11
```
or on 32-bit:
```
__llvm_external_retpoline_eax
__llvm_external_retpoline_ecx
__llvm_external_retpoline_edx
__llvm_external_retpoline_push
```
And the target of the retpoline is passed in the named register, or in
the case of the `push` suffix on the top of the stack via a `pushl`
instruction.
There is one other important source of indirect branches in x86 ELF
binaries: the PLT. These patches also include support for LLD to
generate PLT entries that perform a retpoline-style indirection.
The only other indirect branches remaining that we are aware of are from
precompiled runtimes (such as crt0.o and similar). The ones we have
found are not really attackable, and so we have not focused on them
here, but eventually these runtimes should also be replicated for
retpoline-ed configurations for completeness.
For kernels or other freestanding or fully static executables, the
compiler switch `-mretpoline` is sufficient to fully mitigate this
particular attack. For dynamic executables, you must compile *all*
libraries with `-mretpoline` and additionally link the dynamic
executable and all shared libraries with LLD and pass `-z retpolineplt`
(or use similar functionality from some other linker). We strongly
recommend also using `-z now` as non-lazy binding allows the
retpoline-mitigated PLT to be substantially smaller.
When manually apply similar transformations to `-mretpoline` to the
Linux kernel we observed very small performance hits to applications
running typical workloads, and relatively minor hits (approximately 2%)
even for extremely syscall-heavy applications. This is largely due to
the small number of indirect branches that occur in performance
sensitive paths of the kernel.
When using these patches on statically linked applications, especially
C++ applications, you should expect to see a much more dramatic
performance hit. For microbenchmarks that are switch, indirect-, or
virtual-call heavy we have seen overheads ranging from 10% to 50%.
However, real-world workloads exhibit substantially lower performance
impact. Notably, techniques such as PGO and ThinLTO dramatically reduce
the impact of hot indirect calls (by speculatively promoting them to
direct calls) and allow optimized search trees to be used to lower
switches. If you need to deploy these techniques in C++ applications, we
*strongly* recommend that you ensure all hot call targets are statically
linked (avoiding PLT indirection) and use both PGO and ThinLTO. Well
tuned servers using all of these techniques saw 5% - 10% overhead from
the use of retpoline.
We will add detailed documentation covering these components in
subsequent patches, but wanted to make the core functionality available
as soon as possible. Happy for more code review, but we'd really like to
get these patches landed and backported ASAP for obvious reasons. We're
planning to backport this to both 6.0 and 5.0 release streams and get
a 5.0 release with just this cherry picked ASAP for distros and vendors.
This patch is the work of a number of people over the past month: Eric, Reid,
Rui, and myself. I'm mailing it out as a single commit due to the time
sensitive nature of landing this and the need to backport it. Huge thanks to
everyone who helped out here, and everyone at Intel who helped out in
discussions about how to craft this. Also, credit goes to Paul Turner (at
Google, but not an LLVM contributor) for much of the underlying retpoline
design.
Reviewers: echristo, rnk, ruiu, craig.topper, DavidKreitzer
Subscribers: sanjoy, emaste, mcrosier, mgorny, mehdi_amini, hiraditya, llvm-commits
Differential Revision: https://reviews.llvm.org/D41723
llvm-svn: 323155
2018-01-23 06:05:25 +08:00
|
|
|
};
|
|
|
|
memcpy(Buf, Insn, sizeof(Insn));
|
|
|
|
|
|
|
|
uint64_t GotPlt = InX::GotPlt->getVA();
|
|
|
|
uint64_t Plt = InX::Plt->getVA();
|
|
|
|
write32le(Buf + 2, GotPlt - Plt - 6 + 8);
|
|
|
|
write32le(Buf + 9, GotPlt - Plt - 13 + 16);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class ELFT>
|
|
|
|
void Retpoline<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
|
|
|
|
uint64_t PltEntryAddr, int32_t Index,
|
|
|
|
unsigned RelOff) const {
|
|
|
|
const uint8_t Insn[] = {
|
|
|
|
0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // 0: mov foo@GOTPLT(%rip), %r11
|
2018-03-29 22:03:01 +08:00
|
|
|
0xe8, 0, 0, 0, 0, // 7: callq plt+0x20
|
|
|
|
0xe9, 0, 0, 0, 0, // c: jmp plt+0x12
|
|
|
|
0x68, 0, 0, 0, 0, // 11: pushq <relocation index>
|
|
|
|
0xe9, 0, 0, 0, 0, // 16: jmp plt+0
|
|
|
|
0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 1b: int3; padding
|
Introduce the "retpoline" x86 mitigation technique for variant #2 of the speculative execution vulnerabilities disclosed today, specifically identified by CVE-2017-5715, "Branch Target Injection", and is one of the two halves to Spectre..
Summary:
First, we need to explain the core of the vulnerability. Note that this
is a very incomplete description, please see the Project Zero blog post
for details:
https://googleprojectzero.blogspot.com/2018/01/reading-privileged-memory-with-side.html
The basis for branch target injection is to direct speculative execution
of the processor to some "gadget" of executable code by poisoning the
prediction of indirect branches with the address of that gadget. The
gadget in turn contains an operation that provides a side channel for
reading data. Most commonly, this will look like a load of secret data
followed by a branch on the loaded value and then a load of some
predictable cache line. The attacker then uses timing of the processors
cache to determine which direction the branch took *in the speculative
execution*, and in turn what one bit of the loaded value was. Due to the
nature of these timing side channels and the branch predictor on Intel
processors, this allows an attacker to leak data only accessible to
a privileged domain (like the kernel) back into an unprivileged domain.
The goal is simple: avoid generating code which contains an indirect
branch that could have its prediction poisoned by an attacker. In many
cases, the compiler can simply use directed conditional branches and
a small search tree. LLVM already has support for lowering switches in
this way and the first step of this patch is to disable jump-table
lowering of switches and introduce a pass to rewrite explicit indirectbr
sequences into a switch over integers.
However, there is no fully general alternative to indirect calls. We
introduce a new construct we call a "retpoline" to implement indirect
calls in a non-speculatable way. It can be thought of loosely as
a trampoline for indirect calls which uses the RET instruction on x86.
Further, we arrange for a specific call->ret sequence which ensures the
processor predicts the return to go to a controlled, known location. The
retpoline then "smashes" the return address pushed onto the stack by the
call with the desired target of the original indirect call. The result
is a predicted return to the next instruction after a call (which can be
used to trap speculative execution within an infinite loop) and an
actual indirect branch to an arbitrary address.
On 64-bit x86 ABIs, this is especially easily done in the compiler by
using a guaranteed scratch register to pass the target into this device.
For 32-bit ABIs there isn't a guaranteed scratch register and so several
different retpoline variants are introduced to use a scratch register if
one is available in the calling convention and to otherwise use direct
stack push/pop sequences to pass the target address.
This "retpoline" mitigation is fully described in the following blog
post: https://support.google.com/faqs/answer/7625886
We also support a target feature that disables emission of the retpoline
thunk by the compiler to allow for custom thunks if users want them.
These are particularly useful in environments like kernels that
routinely do hot-patching on boot and want to hot-patch their thunk to
different code sequences. They can write this custom thunk and use
`-mretpoline-external-thunk` *in addition* to `-mretpoline`. In this
case, on x86-64 thu thunk names must be:
```
__llvm_external_retpoline_r11
```
or on 32-bit:
```
__llvm_external_retpoline_eax
__llvm_external_retpoline_ecx
__llvm_external_retpoline_edx
__llvm_external_retpoline_push
```
And the target of the retpoline is passed in the named register, or in
the case of the `push` suffix on the top of the stack via a `pushl`
instruction.
There is one other important source of indirect branches in x86 ELF
binaries: the PLT. These patches also include support for LLD to
generate PLT entries that perform a retpoline-style indirection.
The only other indirect branches remaining that we are aware of are from
precompiled runtimes (such as crt0.o and similar). The ones we have
found are not really attackable, and so we have not focused on them
here, but eventually these runtimes should also be replicated for
retpoline-ed configurations for completeness.
For kernels or other freestanding or fully static executables, the
compiler switch `-mretpoline` is sufficient to fully mitigate this
particular attack. For dynamic executables, you must compile *all*
libraries with `-mretpoline` and additionally link the dynamic
executable and all shared libraries with LLD and pass `-z retpolineplt`
(or use similar functionality from some other linker). We strongly
recommend also using `-z now` as non-lazy binding allows the
retpoline-mitigated PLT to be substantially smaller.
When manually apply similar transformations to `-mretpoline` to the
Linux kernel we observed very small performance hits to applications
running typical workloads, and relatively minor hits (approximately 2%)
even for extremely syscall-heavy applications. This is largely due to
the small number of indirect branches that occur in performance
sensitive paths of the kernel.
When using these patches on statically linked applications, especially
C++ applications, you should expect to see a much more dramatic
performance hit. For microbenchmarks that are switch, indirect-, or
virtual-call heavy we have seen overheads ranging from 10% to 50%.
However, real-world workloads exhibit substantially lower performance
impact. Notably, techniques such as PGO and ThinLTO dramatically reduce
the impact of hot indirect calls (by speculatively promoting them to
direct calls) and allow optimized search trees to be used to lower
switches. If you need to deploy these techniques in C++ applications, we
*strongly* recommend that you ensure all hot call targets are statically
linked (avoiding PLT indirection) and use both PGO and ThinLTO. Well
tuned servers using all of these techniques saw 5% - 10% overhead from
the use of retpoline.
We will add detailed documentation covering these components in
subsequent patches, but wanted to make the core functionality available
as soon as possible. Happy for more code review, but we'd really like to
get these patches landed and backported ASAP for obvious reasons. We're
planning to backport this to both 6.0 and 5.0 release streams and get
a 5.0 release with just this cherry picked ASAP for distros and vendors.
This patch is the work of a number of people over the past month: Eric, Reid,
Rui, and myself. I'm mailing it out as a single commit due to the time
sensitive nature of landing this and the need to backport it. Huge thanks to
everyone who helped out here, and everyone at Intel who helped out in
discussions about how to craft this. Also, credit goes to Paul Turner (at
Google, but not an LLVM contributor) for much of the underlying retpoline
design.
Reviewers: echristo, rnk, ruiu, craig.topper, DavidKreitzer
Subscribers: sanjoy, emaste, mcrosier, mgorny, mehdi_amini, hiraditya, llvm-commits
Differential Revision: https://reviews.llvm.org/D41723
llvm-svn: 323155
2018-01-23 06:05:25 +08:00
|
|
|
};
|
|
|
|
memcpy(Buf, Insn, sizeof(Insn));
|
|
|
|
|
2018-03-15 01:41:34 +08:00
|
|
|
uint64_t Off = TargetInfo::getPltEntryOffset(Index);
|
Introduce the "retpoline" x86 mitigation technique for variant #2 of the speculative execution vulnerabilities disclosed today, specifically identified by CVE-2017-5715, "Branch Target Injection", and is one of the two halves to Spectre..
Summary:
First, we need to explain the core of the vulnerability. Note that this
is a very incomplete description, please see the Project Zero blog post
for details:
https://googleprojectzero.blogspot.com/2018/01/reading-privileged-memory-with-side.html
The basis for branch target injection is to direct speculative execution
of the processor to some "gadget" of executable code by poisoning the
prediction of indirect branches with the address of that gadget. The
gadget in turn contains an operation that provides a side channel for
reading data. Most commonly, this will look like a load of secret data
followed by a branch on the loaded value and then a load of some
predictable cache line. The attacker then uses timing of the processors
cache to determine which direction the branch took *in the speculative
execution*, and in turn what one bit of the loaded value was. Due to the
nature of these timing side channels and the branch predictor on Intel
processors, this allows an attacker to leak data only accessible to
a privileged domain (like the kernel) back into an unprivileged domain.
The goal is simple: avoid generating code which contains an indirect
branch that could have its prediction poisoned by an attacker. In many
cases, the compiler can simply use directed conditional branches and
a small search tree. LLVM already has support for lowering switches in
this way and the first step of this patch is to disable jump-table
lowering of switches and introduce a pass to rewrite explicit indirectbr
sequences into a switch over integers.
However, there is no fully general alternative to indirect calls. We
introduce a new construct we call a "retpoline" to implement indirect
calls in a non-speculatable way. It can be thought of loosely as
a trampoline for indirect calls which uses the RET instruction on x86.
Further, we arrange for a specific call->ret sequence which ensures the
processor predicts the return to go to a controlled, known location. The
retpoline then "smashes" the return address pushed onto the stack by the
call with the desired target of the original indirect call. The result
is a predicted return to the next instruction after a call (which can be
used to trap speculative execution within an infinite loop) and an
actual indirect branch to an arbitrary address.
On 64-bit x86 ABIs, this is especially easily done in the compiler by
using a guaranteed scratch register to pass the target into this device.
For 32-bit ABIs there isn't a guaranteed scratch register and so several
different retpoline variants are introduced to use a scratch register if
one is available in the calling convention and to otherwise use direct
stack push/pop sequences to pass the target address.
This "retpoline" mitigation is fully described in the following blog
post: https://support.google.com/faqs/answer/7625886
We also support a target feature that disables emission of the retpoline
thunk by the compiler to allow for custom thunks if users want them.
These are particularly useful in environments like kernels that
routinely do hot-patching on boot and want to hot-patch their thunk to
different code sequences. They can write this custom thunk and use
`-mretpoline-external-thunk` *in addition* to `-mretpoline`. In this
case, on x86-64 thu thunk names must be:
```
__llvm_external_retpoline_r11
```
or on 32-bit:
```
__llvm_external_retpoline_eax
__llvm_external_retpoline_ecx
__llvm_external_retpoline_edx
__llvm_external_retpoline_push
```
And the target of the retpoline is passed in the named register, or in
the case of the `push` suffix on the top of the stack via a `pushl`
instruction.
There is one other important source of indirect branches in x86 ELF
binaries: the PLT. These patches also include support for LLD to
generate PLT entries that perform a retpoline-style indirection.
The only other indirect branches remaining that we are aware of are from
precompiled runtimes (such as crt0.o and similar). The ones we have
found are not really attackable, and so we have not focused on them
here, but eventually these runtimes should also be replicated for
retpoline-ed configurations for completeness.
For kernels or other freestanding or fully static executables, the
compiler switch `-mretpoline` is sufficient to fully mitigate this
particular attack. For dynamic executables, you must compile *all*
libraries with `-mretpoline` and additionally link the dynamic
executable and all shared libraries with LLD and pass `-z retpolineplt`
(or use similar functionality from some other linker). We strongly
recommend also using `-z now` as non-lazy binding allows the
retpoline-mitigated PLT to be substantially smaller.
When manually apply similar transformations to `-mretpoline` to the
Linux kernel we observed very small performance hits to applications
running typical workloads, and relatively minor hits (approximately 2%)
even for extremely syscall-heavy applications. This is largely due to
the small number of indirect branches that occur in performance
sensitive paths of the kernel.
When using these patches on statically linked applications, especially
C++ applications, you should expect to see a much more dramatic
performance hit. For microbenchmarks that are switch, indirect-, or
virtual-call heavy we have seen overheads ranging from 10% to 50%.
However, real-world workloads exhibit substantially lower performance
impact. Notably, techniques such as PGO and ThinLTO dramatically reduce
the impact of hot indirect calls (by speculatively promoting them to
direct calls) and allow optimized search trees to be used to lower
switches. If you need to deploy these techniques in C++ applications, we
*strongly* recommend that you ensure all hot call targets are statically
linked (avoiding PLT indirection) and use both PGO and ThinLTO. Well
tuned servers using all of these techniques saw 5% - 10% overhead from
the use of retpoline.
We will add detailed documentation covering these components in
subsequent patches, but wanted to make the core functionality available
as soon as possible. Happy for more code review, but we'd really like to
get these patches landed and backported ASAP for obvious reasons. We're
planning to backport this to both 6.0 and 5.0 release streams and get
a 5.0 release with just this cherry picked ASAP for distros and vendors.
This patch is the work of a number of people over the past month: Eric, Reid,
Rui, and myself. I'm mailing it out as a single commit due to the time
sensitive nature of landing this and the need to backport it. Huge thanks to
everyone who helped out here, and everyone at Intel who helped out in
discussions about how to craft this. Also, credit goes to Paul Turner (at
Google, but not an LLVM contributor) for much of the underlying retpoline
design.
Reviewers: echristo, rnk, ruiu, craig.topper, DavidKreitzer
Subscribers: sanjoy, emaste, mcrosier, mgorny, mehdi_amini, hiraditya, llvm-commits
Differential Revision: https://reviews.llvm.org/D41723
llvm-svn: 323155
2018-01-23 06:05:25 +08:00
|
|
|
|
|
|
|
write32le(Buf + 3, GotPltEntryAddr - PltEntryAddr - 7);
|
|
|
|
write32le(Buf + 8, -Off - 12 + 32);
|
|
|
|
write32le(Buf + 13, -Off - 17 + 18);
|
|
|
|
write32le(Buf + 18, Index);
|
|
|
|
write32le(Buf + 23, -Off - 27);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class ELFT> RetpolineZNow<ELFT>::RetpolineZNow() {
|
|
|
|
TargetInfo::PltHeaderSize = 32;
|
|
|
|
TargetInfo::PltEntrySize = 16;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class ELFT>
|
|
|
|
void RetpolineZNow<ELFT>::writePltHeader(uint8_t *Buf) const {
|
|
|
|
const uint8_t Insn[] = {
|
|
|
|
0xe8, 0x0b, 0x00, 0x00, 0x00, // 0: call next
|
|
|
|
0xf3, 0x90, // 5: loop: pause
|
|
|
|
0x0f, 0xae, 0xe8, // 7: lfence
|
|
|
|
0xeb, 0xf9, // a: jmp loop
|
|
|
|
0xcc, 0xcc, 0xcc, 0xcc, // c: int3; .align 16
|
|
|
|
0x4c, 0x89, 0x1c, 0x24, // 10: next: mov %r11, (%rsp)
|
|
|
|
0xc3, // 14: ret
|
2018-03-29 22:03:01 +08:00
|
|
|
0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 15: int3; padding
|
|
|
|
0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 1a: int3; padding
|
|
|
|
0xcc, // 1f: int3; padding
|
Introduce the "retpoline" x86 mitigation technique for variant #2 of the speculative execution vulnerabilities disclosed today, specifically identified by CVE-2017-5715, "Branch Target Injection", and is one of the two halves to Spectre..
Summary:
First, we need to explain the core of the vulnerability. Note that this
is a very incomplete description, please see the Project Zero blog post
for details:
https://googleprojectzero.blogspot.com/2018/01/reading-privileged-memory-with-side.html
The basis for branch target injection is to direct speculative execution
of the processor to some "gadget" of executable code by poisoning the
prediction of indirect branches with the address of that gadget. The
gadget in turn contains an operation that provides a side channel for
reading data. Most commonly, this will look like a load of secret data
followed by a branch on the loaded value and then a load of some
predictable cache line. The attacker then uses timing of the processors
cache to determine which direction the branch took *in the speculative
execution*, and in turn what one bit of the loaded value was. Due to the
nature of these timing side channels and the branch predictor on Intel
processors, this allows an attacker to leak data only accessible to
a privileged domain (like the kernel) back into an unprivileged domain.
The goal is simple: avoid generating code which contains an indirect
branch that could have its prediction poisoned by an attacker. In many
cases, the compiler can simply use directed conditional branches and
a small search tree. LLVM already has support for lowering switches in
this way and the first step of this patch is to disable jump-table
lowering of switches and introduce a pass to rewrite explicit indirectbr
sequences into a switch over integers.
However, there is no fully general alternative to indirect calls. We
introduce a new construct we call a "retpoline" to implement indirect
calls in a non-speculatable way. It can be thought of loosely as
a trampoline for indirect calls which uses the RET instruction on x86.
Further, we arrange for a specific call->ret sequence which ensures the
processor predicts the return to go to a controlled, known location. The
retpoline then "smashes" the return address pushed onto the stack by the
call with the desired target of the original indirect call. The result
is a predicted return to the next instruction after a call (which can be
used to trap speculative execution within an infinite loop) and an
actual indirect branch to an arbitrary address.
On 64-bit x86 ABIs, this is especially easily done in the compiler by
using a guaranteed scratch register to pass the target into this device.
For 32-bit ABIs there isn't a guaranteed scratch register and so several
different retpoline variants are introduced to use a scratch register if
one is available in the calling convention and to otherwise use direct
stack push/pop sequences to pass the target address.
This "retpoline" mitigation is fully described in the following blog
post: https://support.google.com/faqs/answer/7625886
We also support a target feature that disables emission of the retpoline
thunk by the compiler to allow for custom thunks if users want them.
These are particularly useful in environments like kernels that
routinely do hot-patching on boot and want to hot-patch their thunk to
different code sequences. They can write this custom thunk and use
`-mretpoline-external-thunk` *in addition* to `-mretpoline`. In this
case, on x86-64 thu thunk names must be:
```
__llvm_external_retpoline_r11
```
or on 32-bit:
```
__llvm_external_retpoline_eax
__llvm_external_retpoline_ecx
__llvm_external_retpoline_edx
__llvm_external_retpoline_push
```
And the target of the retpoline is passed in the named register, or in
the case of the `push` suffix on the top of the stack via a `pushl`
instruction.
There is one other important source of indirect branches in x86 ELF
binaries: the PLT. These patches also include support for LLD to
generate PLT entries that perform a retpoline-style indirection.
The only other indirect branches remaining that we are aware of are from
precompiled runtimes (such as crt0.o and similar). The ones we have
found are not really attackable, and so we have not focused on them
here, but eventually these runtimes should also be replicated for
retpoline-ed configurations for completeness.
For kernels or other freestanding or fully static executables, the
compiler switch `-mretpoline` is sufficient to fully mitigate this
particular attack. For dynamic executables, you must compile *all*
libraries with `-mretpoline` and additionally link the dynamic
executable and all shared libraries with LLD and pass `-z retpolineplt`
(or use similar functionality from some other linker). We strongly
recommend also using `-z now` as non-lazy binding allows the
retpoline-mitigated PLT to be substantially smaller.
When manually apply similar transformations to `-mretpoline` to the
Linux kernel we observed very small performance hits to applications
running typical workloads, and relatively minor hits (approximately 2%)
even for extremely syscall-heavy applications. This is largely due to
the small number of indirect branches that occur in performance
sensitive paths of the kernel.
When using these patches on statically linked applications, especially
C++ applications, you should expect to see a much more dramatic
performance hit. For microbenchmarks that are switch, indirect-, or
virtual-call heavy we have seen overheads ranging from 10% to 50%.
However, real-world workloads exhibit substantially lower performance
impact. Notably, techniques such as PGO and ThinLTO dramatically reduce
the impact of hot indirect calls (by speculatively promoting them to
direct calls) and allow optimized search trees to be used to lower
switches. If you need to deploy these techniques in C++ applications, we
*strongly* recommend that you ensure all hot call targets are statically
linked (avoiding PLT indirection) and use both PGO and ThinLTO. Well
tuned servers using all of these techniques saw 5% - 10% overhead from
the use of retpoline.
We will add detailed documentation covering these components in
subsequent patches, but wanted to make the core functionality available
as soon as possible. Happy for more code review, but we'd really like to
get these patches landed and backported ASAP for obvious reasons. We're
planning to backport this to both 6.0 and 5.0 release streams and get
a 5.0 release with just this cherry picked ASAP for distros and vendors.
This patch is the work of a number of people over the past month: Eric, Reid,
Rui, and myself. I'm mailing it out as a single commit due to the time
sensitive nature of landing this and the need to backport it. Huge thanks to
everyone who helped out here, and everyone at Intel who helped out in
discussions about how to craft this. Also, credit goes to Paul Turner (at
Google, but not an LLVM contributor) for much of the underlying retpoline
design.
Reviewers: echristo, rnk, ruiu, craig.topper, DavidKreitzer
Subscribers: sanjoy, emaste, mcrosier, mgorny, mehdi_amini, hiraditya, llvm-commits
Differential Revision: https://reviews.llvm.org/D41723
llvm-svn: 323155
2018-01-23 06:05:25 +08:00
|
|
|
};
|
|
|
|
memcpy(Buf, Insn, sizeof(Insn));
|
2017-06-17 04:15:03 +08:00
|
|
|
}
|
|
|
|
|
Introduce the "retpoline" x86 mitigation technique for variant #2 of the speculative execution vulnerabilities disclosed today, specifically identified by CVE-2017-5715, "Branch Target Injection", and is one of the two halves to Spectre..
Summary:
First, we need to explain the core of the vulnerability. Note that this
is a very incomplete description, please see the Project Zero blog post
for details:
https://googleprojectzero.blogspot.com/2018/01/reading-privileged-memory-with-side.html
The basis for branch target injection is to direct speculative execution
of the processor to some "gadget" of executable code by poisoning the
prediction of indirect branches with the address of that gadget. The
gadget in turn contains an operation that provides a side channel for
reading data. Most commonly, this will look like a load of secret data
followed by a branch on the loaded value and then a load of some
predictable cache line. The attacker then uses timing of the processors
cache to determine which direction the branch took *in the speculative
execution*, and in turn what one bit of the loaded value was. Due to the
nature of these timing side channels and the branch predictor on Intel
processors, this allows an attacker to leak data only accessible to
a privileged domain (like the kernel) back into an unprivileged domain.
The goal is simple: avoid generating code which contains an indirect
branch that could have its prediction poisoned by an attacker. In many
cases, the compiler can simply use directed conditional branches and
a small search tree. LLVM already has support for lowering switches in
this way and the first step of this patch is to disable jump-table
lowering of switches and introduce a pass to rewrite explicit indirectbr
sequences into a switch over integers.
However, there is no fully general alternative to indirect calls. We
introduce a new construct we call a "retpoline" to implement indirect
calls in a non-speculatable way. It can be thought of loosely as
a trampoline for indirect calls which uses the RET instruction on x86.
Further, we arrange for a specific call->ret sequence which ensures the
processor predicts the return to go to a controlled, known location. The
retpoline then "smashes" the return address pushed onto the stack by the
call with the desired target of the original indirect call. The result
is a predicted return to the next instruction after a call (which can be
used to trap speculative execution within an infinite loop) and an
actual indirect branch to an arbitrary address.
On 64-bit x86 ABIs, this is especially easily done in the compiler by
using a guaranteed scratch register to pass the target into this device.
For 32-bit ABIs there isn't a guaranteed scratch register and so several
different retpoline variants are introduced to use a scratch register if
one is available in the calling convention and to otherwise use direct
stack push/pop sequences to pass the target address.
This "retpoline" mitigation is fully described in the following blog
post: https://support.google.com/faqs/answer/7625886
We also support a target feature that disables emission of the retpoline
thunk by the compiler to allow for custom thunks if users want them.
These are particularly useful in environments like kernels that
routinely do hot-patching on boot and want to hot-patch their thunk to
different code sequences. They can write this custom thunk and use
`-mretpoline-external-thunk` *in addition* to `-mretpoline`. In this
case, on x86-64 thu thunk names must be:
```
__llvm_external_retpoline_r11
```
or on 32-bit:
```
__llvm_external_retpoline_eax
__llvm_external_retpoline_ecx
__llvm_external_retpoline_edx
__llvm_external_retpoline_push
```
And the target of the retpoline is passed in the named register, or in
the case of the `push` suffix on the top of the stack via a `pushl`
instruction.
There is one other important source of indirect branches in x86 ELF
binaries: the PLT. These patches also include support for LLD to
generate PLT entries that perform a retpoline-style indirection.
The only other indirect branches remaining that we are aware of are from
precompiled runtimes (such as crt0.o and similar). The ones we have
found are not really attackable, and so we have not focused on them
here, but eventually these runtimes should also be replicated for
retpoline-ed configurations for completeness.
For kernels or other freestanding or fully static executables, the
compiler switch `-mretpoline` is sufficient to fully mitigate this
particular attack. For dynamic executables, you must compile *all*
libraries with `-mretpoline` and additionally link the dynamic
executable and all shared libraries with LLD and pass `-z retpolineplt`
(or use similar functionality from some other linker). We strongly
recommend also using `-z now` as non-lazy binding allows the
retpoline-mitigated PLT to be substantially smaller.
When manually apply similar transformations to `-mretpoline` to the
Linux kernel we observed very small performance hits to applications
running typical workloads, and relatively minor hits (approximately 2%)
even for extremely syscall-heavy applications. This is largely due to
the small number of indirect branches that occur in performance
sensitive paths of the kernel.
When using these patches on statically linked applications, especially
C++ applications, you should expect to see a much more dramatic
performance hit. For microbenchmarks that are switch, indirect-, or
virtual-call heavy we have seen overheads ranging from 10% to 50%.
However, real-world workloads exhibit substantially lower performance
impact. Notably, techniques such as PGO and ThinLTO dramatically reduce
the impact of hot indirect calls (by speculatively promoting them to
direct calls) and allow optimized search trees to be used to lower
switches. If you need to deploy these techniques in C++ applications, we
*strongly* recommend that you ensure all hot call targets are statically
linked (avoiding PLT indirection) and use both PGO and ThinLTO. Well
tuned servers using all of these techniques saw 5% - 10% overhead from
the use of retpoline.
We will add detailed documentation covering these components in
subsequent patches, but wanted to make the core functionality available
as soon as possible. Happy for more code review, but we'd really like to
get these patches landed and backported ASAP for obvious reasons. We're
planning to backport this to both 6.0 and 5.0 release streams and get
a 5.0 release with just this cherry picked ASAP for distros and vendors.
This patch is the work of a number of people over the past month: Eric, Reid,
Rui, and myself. I'm mailing it out as a single commit due to the time
sensitive nature of landing this and the need to backport it. Huge thanks to
everyone who helped out here, and everyone at Intel who helped out in
discussions about how to craft this. Also, credit goes to Paul Turner (at
Google, but not an LLVM contributor) for much of the underlying retpoline
design.
Reviewers: echristo, rnk, ruiu, craig.topper, DavidKreitzer
Subscribers: sanjoy, emaste, mcrosier, mgorny, mehdi_amini, hiraditya, llvm-commits
Differential Revision: https://reviews.llvm.org/D41723
llvm-svn: 323155
2018-01-23 06:05:25 +08:00
|
|
|
template <class ELFT>
|
|
|
|
void RetpolineZNow<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
|
|
|
|
uint64_t PltEntryAddr, int32_t Index,
|
|
|
|
unsigned RelOff) const {
|
|
|
|
const uint8_t Insn[] = {
|
2018-03-29 22:03:01 +08:00
|
|
|
0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // mov foo@GOTPLT(%rip), %r11
|
|
|
|
0xe9, 0, 0, 0, 0, // jmp plt+0
|
|
|
|
0xcc, 0xcc, 0xcc, 0xcc, // int3; padding
|
Introduce the "retpoline" x86 mitigation technique for variant #2 of the speculative execution vulnerabilities disclosed today, specifically identified by CVE-2017-5715, "Branch Target Injection", and is one of the two halves to Spectre..
Summary:
First, we need to explain the core of the vulnerability. Note that this
is a very incomplete description, please see the Project Zero blog post
for details:
https://googleprojectzero.blogspot.com/2018/01/reading-privileged-memory-with-side.html
The basis for branch target injection is to direct speculative execution
of the processor to some "gadget" of executable code by poisoning the
prediction of indirect branches with the address of that gadget. The
gadget in turn contains an operation that provides a side channel for
reading data. Most commonly, this will look like a load of secret data
followed by a branch on the loaded value and then a load of some
predictable cache line. The attacker then uses timing of the processors
cache to determine which direction the branch took *in the speculative
execution*, and in turn what one bit of the loaded value was. Due to the
nature of these timing side channels and the branch predictor on Intel
processors, this allows an attacker to leak data only accessible to
a privileged domain (like the kernel) back into an unprivileged domain.
The goal is simple: avoid generating code which contains an indirect
branch that could have its prediction poisoned by an attacker. In many
cases, the compiler can simply use directed conditional branches and
a small search tree. LLVM already has support for lowering switches in
this way and the first step of this patch is to disable jump-table
lowering of switches and introduce a pass to rewrite explicit indirectbr
sequences into a switch over integers.
However, there is no fully general alternative to indirect calls. We
introduce a new construct we call a "retpoline" to implement indirect
calls in a non-speculatable way. It can be thought of loosely as
a trampoline for indirect calls which uses the RET instruction on x86.
Further, we arrange for a specific call->ret sequence which ensures the
processor predicts the return to go to a controlled, known location. The
retpoline then "smashes" the return address pushed onto the stack by the
call with the desired target of the original indirect call. The result
is a predicted return to the next instruction after a call (which can be
used to trap speculative execution within an infinite loop) and an
actual indirect branch to an arbitrary address.
On 64-bit x86 ABIs, this is especially easily done in the compiler by
using a guaranteed scratch register to pass the target into this device.
For 32-bit ABIs there isn't a guaranteed scratch register and so several
different retpoline variants are introduced to use a scratch register if
one is available in the calling convention and to otherwise use direct
stack push/pop sequences to pass the target address.
This "retpoline" mitigation is fully described in the following blog
post: https://support.google.com/faqs/answer/7625886
We also support a target feature that disables emission of the retpoline
thunk by the compiler to allow for custom thunks if users want them.
These are particularly useful in environments like kernels that
routinely do hot-patching on boot and want to hot-patch their thunk to
different code sequences. They can write this custom thunk and use
`-mretpoline-external-thunk` *in addition* to `-mretpoline`. In this
case, on x86-64 thu thunk names must be:
```
__llvm_external_retpoline_r11
```
or on 32-bit:
```
__llvm_external_retpoline_eax
__llvm_external_retpoline_ecx
__llvm_external_retpoline_edx
__llvm_external_retpoline_push
```
And the target of the retpoline is passed in the named register, or in
the case of the `push` suffix on the top of the stack via a `pushl`
instruction.
There is one other important source of indirect branches in x86 ELF
binaries: the PLT. These patches also include support for LLD to
generate PLT entries that perform a retpoline-style indirection.
The only other indirect branches remaining that we are aware of are from
precompiled runtimes (such as crt0.o and similar). The ones we have
found are not really attackable, and so we have not focused on them
here, but eventually these runtimes should also be replicated for
retpoline-ed configurations for completeness.
For kernels or other freestanding or fully static executables, the
compiler switch `-mretpoline` is sufficient to fully mitigate this
particular attack. For dynamic executables, you must compile *all*
libraries with `-mretpoline` and additionally link the dynamic
executable and all shared libraries with LLD and pass `-z retpolineplt`
(or use similar functionality from some other linker). We strongly
recommend also using `-z now` as non-lazy binding allows the
retpoline-mitigated PLT to be substantially smaller.
When manually apply similar transformations to `-mretpoline` to the
Linux kernel we observed very small performance hits to applications
running typical workloads, and relatively minor hits (approximately 2%)
even for extremely syscall-heavy applications. This is largely due to
the small number of indirect branches that occur in performance
sensitive paths of the kernel.
When using these patches on statically linked applications, especially
C++ applications, you should expect to see a much more dramatic
performance hit. For microbenchmarks that are switch, indirect-, or
virtual-call heavy we have seen overheads ranging from 10% to 50%.
However, real-world workloads exhibit substantially lower performance
impact. Notably, techniques such as PGO and ThinLTO dramatically reduce
the impact of hot indirect calls (by speculatively promoting them to
direct calls) and allow optimized search trees to be used to lower
switches. If you need to deploy these techniques in C++ applications, we
*strongly* recommend that you ensure all hot call targets are statically
linked (avoiding PLT indirection) and use both PGO and ThinLTO. Well
tuned servers using all of these techniques saw 5% - 10% overhead from
the use of retpoline.
We will add detailed documentation covering these components in
subsequent patches, but wanted to make the core functionality available
as soon as possible. Happy for more code review, but we'd really like to
get these patches landed and backported ASAP for obvious reasons. We're
planning to backport this to both 6.0 and 5.0 release streams and get
a 5.0 release with just this cherry picked ASAP for distros and vendors.
This patch is the work of a number of people over the past month: Eric, Reid,
Rui, and myself. I'm mailing it out as a single commit due to the time
sensitive nature of landing this and the need to backport it. Huge thanks to
everyone who helped out here, and everyone at Intel who helped out in
discussions about how to craft this. Also, credit goes to Paul Turner (at
Google, but not an LLVM contributor) for much of the underlying retpoline
design.
Reviewers: echristo, rnk, ruiu, craig.topper, DavidKreitzer
Subscribers: sanjoy, emaste, mcrosier, mgorny, mehdi_amini, hiraditya, llvm-commits
Differential Revision: https://reviews.llvm.org/D41723
llvm-svn: 323155
2018-01-23 06:05:25 +08:00
|
|
|
};
|
|
|
|
memcpy(Buf, Insn, sizeof(Insn));
|
|
|
|
|
|
|
|
write32le(Buf + 3, GotPltEntryAddr - PltEntryAddr - 7);
|
2018-03-15 01:41:34 +08:00
|
|
|
write32le(Buf + 8, -TargetInfo::getPltEntryOffset(Index) - 12);
|
2017-06-17 04:15:03 +08:00
|
|
|
}
|
Introduce the "retpoline" x86 mitigation technique for variant #2 of the speculative execution vulnerabilities disclosed today, specifically identified by CVE-2017-5715, "Branch Target Injection", and is one of the two halves to Spectre..
Summary:
First, we need to explain the core of the vulnerability. Note that this
is a very incomplete description, please see the Project Zero blog post
for details:
https://googleprojectzero.blogspot.com/2018/01/reading-privileged-memory-with-side.html
The basis for branch target injection is to direct speculative execution
of the processor to some "gadget" of executable code by poisoning the
prediction of indirect branches with the address of that gadget. The
gadget in turn contains an operation that provides a side channel for
reading data. Most commonly, this will look like a load of secret data
followed by a branch on the loaded value and then a load of some
predictable cache line. The attacker then uses timing of the processors
cache to determine which direction the branch took *in the speculative
execution*, and in turn what one bit of the loaded value was. Due to the
nature of these timing side channels and the branch predictor on Intel
processors, this allows an attacker to leak data only accessible to
a privileged domain (like the kernel) back into an unprivileged domain.
The goal is simple: avoid generating code which contains an indirect
branch that could have its prediction poisoned by an attacker. In many
cases, the compiler can simply use directed conditional branches and
a small search tree. LLVM already has support for lowering switches in
this way and the first step of this patch is to disable jump-table
lowering of switches and introduce a pass to rewrite explicit indirectbr
sequences into a switch over integers.
However, there is no fully general alternative to indirect calls. We
introduce a new construct we call a "retpoline" to implement indirect
calls in a non-speculatable way. It can be thought of loosely as
a trampoline for indirect calls which uses the RET instruction on x86.
Further, we arrange for a specific call->ret sequence which ensures the
processor predicts the return to go to a controlled, known location. The
retpoline then "smashes" the return address pushed onto the stack by the
call with the desired target of the original indirect call. The result
is a predicted return to the next instruction after a call (which can be
used to trap speculative execution within an infinite loop) and an
actual indirect branch to an arbitrary address.
On 64-bit x86 ABIs, this is especially easily done in the compiler by
using a guaranteed scratch register to pass the target into this device.
For 32-bit ABIs there isn't a guaranteed scratch register and so several
different retpoline variants are introduced to use a scratch register if
one is available in the calling convention and to otherwise use direct
stack push/pop sequences to pass the target address.
This "retpoline" mitigation is fully described in the following blog
post: https://support.google.com/faqs/answer/7625886
We also support a target feature that disables emission of the retpoline
thunk by the compiler to allow for custom thunks if users want them.
These are particularly useful in environments like kernels that
routinely do hot-patching on boot and want to hot-patch their thunk to
different code sequences. They can write this custom thunk and use
`-mretpoline-external-thunk` *in addition* to `-mretpoline`. In this
case, on x86-64 thu thunk names must be:
```
__llvm_external_retpoline_r11
```
or on 32-bit:
```
__llvm_external_retpoline_eax
__llvm_external_retpoline_ecx
__llvm_external_retpoline_edx
__llvm_external_retpoline_push
```
And the target of the retpoline is passed in the named register, or in
the case of the `push` suffix on the top of the stack via a `pushl`
instruction.
There is one other important source of indirect branches in x86 ELF
binaries: the PLT. These patches also include support for LLD to
generate PLT entries that perform a retpoline-style indirection.
The only other indirect branches remaining that we are aware of are from
precompiled runtimes (such as crt0.o and similar). The ones we have
found are not really attackable, and so we have not focused on them
here, but eventually these runtimes should also be replicated for
retpoline-ed configurations for completeness.
For kernels or other freestanding or fully static executables, the
compiler switch `-mretpoline` is sufficient to fully mitigate this
particular attack. For dynamic executables, you must compile *all*
libraries with `-mretpoline` and additionally link the dynamic
executable and all shared libraries with LLD and pass `-z retpolineplt`
(or use similar functionality from some other linker). We strongly
recommend also using `-z now` as non-lazy binding allows the
retpoline-mitigated PLT to be substantially smaller.
When manually apply similar transformations to `-mretpoline` to the
Linux kernel we observed very small performance hits to applications
running typical workloads, and relatively minor hits (approximately 2%)
even for extremely syscall-heavy applications. This is largely due to
the small number of indirect branches that occur in performance
sensitive paths of the kernel.
When using these patches on statically linked applications, especially
C++ applications, you should expect to see a much more dramatic
performance hit. For microbenchmarks that are switch, indirect-, or
virtual-call heavy we have seen overheads ranging from 10% to 50%.
However, real-world workloads exhibit substantially lower performance
impact. Notably, techniques such as PGO and ThinLTO dramatically reduce
the impact of hot indirect calls (by speculatively promoting them to
direct calls) and allow optimized search trees to be used to lower
switches. If you need to deploy these techniques in C++ applications, we
*strongly* recommend that you ensure all hot call targets are statically
linked (avoiding PLT indirection) and use both PGO and ThinLTO. Well
tuned servers using all of these techniques saw 5% - 10% overhead from
the use of retpoline.
We will add detailed documentation covering these components in
subsequent patches, but wanted to make the core functionality available
as soon as possible. Happy for more code review, but we'd really like to
get these patches landed and backported ASAP for obvious reasons. We're
planning to backport this to both 6.0 and 5.0 release streams and get
a 5.0 release with just this cherry picked ASAP for distros and vendors.
This patch is the work of a number of people over the past month: Eric, Reid,
Rui, and myself. I'm mailing it out as a single commit due to the time
sensitive nature of landing this and the need to backport it. Huge thanks to
everyone who helped out here, and everyone at Intel who helped out in
discussions about how to craft this. Also, credit goes to Paul Turner (at
Google, but not an LLVM contributor) for much of the underlying retpoline
design.
Reviewers: echristo, rnk, ruiu, craig.topper, DavidKreitzer
Subscribers: sanjoy, emaste, mcrosier, mgorny, mehdi_amini, hiraditya, llvm-commits
Differential Revision: https://reviews.llvm.org/D41723
llvm-svn: 323155
2018-01-23 06:05:25 +08:00
|
|
|
|
|
|
|
template <class ELFT> TargetInfo *getTargetInfo() {
|
|
|
|
if (Config->ZRetpolineplt) {
|
|
|
|
if (Config->ZNow) {
|
|
|
|
static RetpolineZNow<ELFT> T;
|
|
|
|
return &T;
|
|
|
|
}
|
|
|
|
static Retpoline<ELFT> T;
|
|
|
|
return &T;
|
|
|
|
}
|
|
|
|
|
|
|
|
static X86_64<ELFT> T;
|
|
|
|
return &T;
|
|
|
|
}
|
|
|
|
|
|
|
|
TargetInfo *elf::getX32TargetInfo() { return getTargetInfo<ELF32LE>(); }
|
|
|
|
TargetInfo *elf::getX86_64TargetInfo() { return getTargetInfo<ELF64LE>(); }
|