<div dir="ltr"><a class="GWVZpf gW" id="IloFPc-0" href="mailto:hans@chromium.org" tabindex="-1">+Hans Wennborg</a> <a class="GWVZpf gW" id="IloFPc-1" href="mailto:tstellar@redhat.com" tabindex="-1">+tstellar@redhat.com</a> <br><div><br></div><div>So the retpoline patch series we should get back ported start with this revision and have two follow ups:</div><div>r323155</div><div>r323288</div><div>r323915</div><div><br></div><div><a class="GWVZpf gW" id="IloFPc-2" href="mailto:rnk@google.com" tabindex="-1">+Reid Kleckner</a> was going to look at doing the (likely more involved) backport to the 5 branch....<br></div></div><br><div class="gmail_quote"><div dir="ltr">On Mon, Jan 22, 2018 at 2:06 PM Chandler Carruth via cfe-commits <<a href="mailto:cfe-commits@lists.llvm.org">cfe-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: chandlerc<br>
Date: Mon Jan 22 14:05:25 2018<br>
New Revision: 323155<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=323155&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=323155&view=rev</a><br>
Log:<br>
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..<br>
<br>
Summary:<br>
First, we need to explain the core of the vulnerability. Note that this<br>
is a very incomplete description, please see the Project Zero blog post<br>
for details:<br>
<a href="https://googleprojectzero.blogspot.com/2018/01/reading-privileged-memory-with-side.html" rel="noreferrer" target="_blank">https://googleprojectzero.blogspot.com/2018/01/reading-privileged-memory-with-side.html</a><br>
<br>
The basis for branch target injection is to direct speculative execution<br>
of the processor to some "gadget" of executable code by poisoning the<br>
prediction of indirect branches with the address of that gadget. The<br>
gadget in turn contains an operation that provides a side channel for<br>
reading data. Most commonly, this will look like a load of secret data<br>
followed by a branch on the loaded value and then a load of some<br>
predictable cache line. The attacker then uses timing of the processors<br>
cache to determine which direction the branch took *in the speculative<br>
execution*, and in turn what one bit of the loaded value was. Due to the<br>
nature of these timing side channels and the branch predictor on Intel<br>
processors, this allows an attacker to leak data only accessible to<br>
a privileged domain (like the kernel) back into an unprivileged domain.<br>
<br>
The goal is simple: avoid generating code which contains an indirect<br>
branch that could have its prediction poisoned by an attacker. In many<br>
cases, the compiler can simply use directed conditional branches and<br>
a small search tree. LLVM already has support for lowering switches in<br>
this way and the first step of this patch is to disable jump-table<br>
lowering of switches and introduce a pass to rewrite explicit indirectbr<br>
sequences into a switch over integers.<br>
<br>
However, there is no fully general alternative to indirect calls. We<br>
introduce a new construct we call a "retpoline" to implement indirect<br>
calls in a non-speculatable way. It can be thought of loosely as<br>
a trampoline for indirect calls which uses the RET instruction on x86.<br>
Further, we arrange for a specific call->ret sequence which ensures the<br>
processor predicts the return to go to a controlled, known location. The<br>
retpoline then "smashes" the return address pushed onto the stack by the<br>
call with the desired target of the original indirect call. The result<br>
is a predicted return to the next instruction after a call (which can be<br>
used to trap speculative execution within an infinite loop) and an<br>
actual indirect branch to an arbitrary address.<br>
<br>
On 64-bit x86 ABIs, this is especially easily done in the compiler by<br>
using a guaranteed scratch register to pass the target into this device.<br>
For 32-bit ABIs there isn't a guaranteed scratch register and so several<br>
different retpoline variants are introduced to use a scratch register if<br>
one is available in the calling convention and to otherwise use direct<br>
stack push/pop sequences to pass the target address.<br>
<br>
This "retpoline" mitigation is fully described in the following blog<br>
post: <a href="https://support.google.com/faqs/answer/7625886" rel="noreferrer" target="_blank">https://support.google.com/faqs/answer/7625886</a><br>
<br>
We also support a target feature that disables emission of the retpoline<br>
thunk by the compiler to allow for custom thunks if users want them.<br>
These are particularly useful in environments like kernels that<br>
routinely do hot-patching on boot and want to hot-patch their thunk to<br>
different code sequences. They can write this custom thunk and use<br>
`-mretpoline-external-thunk` *in addition* to `-mretpoline`. In this<br>
case, on x86-64 thu thunk names must be:<br>
```<br>
  __llvm_external_retpoline_r11<br>
```<br>
or on 32-bit:<br>
```<br>
  __llvm_external_retpoline_eax<br>
  __llvm_external_retpoline_ecx<br>
  __llvm_external_retpoline_edx<br>
  __llvm_external_retpoline_push<br>
```<br>
And the target of the retpoline is passed in the named register, or in<br>
the case of the `push` suffix on the top of the stack via a `pushl`<br>
instruction.<br>
<br>
There is one other important source of indirect branches in x86 ELF<br>
binaries: the PLT. These patches also include support for LLD to<br>
generate PLT entries that perform a retpoline-style indirection.<br>
<br>
The only other indirect branches remaining that we are aware of are from<br>
precompiled runtimes (such as crt0.o and similar). The ones we have<br>
found are not really attackable, and so we have not focused on them<br>
here, but eventually these runtimes should also be replicated for<br>
retpoline-ed configurations for completeness.<br>
<br>
For kernels or other freestanding or fully static executables, the<br>
compiler switch `-mretpoline` is sufficient to fully mitigate this<br>
particular attack. For dynamic executables, you must compile *all*<br>
libraries with `-mretpoline` and additionally link the dynamic<br>
executable and all shared libraries with LLD and pass `-z retpolineplt`<br>
(or use similar functionality from some other linker). We strongly<br>
recommend also using `-z now` as non-lazy binding allows the<br>
retpoline-mitigated PLT to be substantially smaller.<br>
<br>
When manually apply similar transformations to `-mretpoline` to the<br>
Linux kernel we observed very small performance hits to applications<br>
running typical workloads, and relatively minor hits (approximately 2%)<br>
even for extremely syscall-heavy applications. This is largely due to<br>
the small number of indirect branches that occur in performance<br>
sensitive paths of the kernel.<br>
<br>
When using these patches on statically linked applications, especially<br>
C++ applications, you should expect to see a much more dramatic<br>
performance hit. For microbenchmarks that are switch, indirect-, or<br>
virtual-call heavy we have seen overheads ranging from 10% to 50%.<br>
<br>
However, real-world workloads exhibit substantially lower performance<br>
impact. Notably, techniques such as PGO and ThinLTO dramatically reduce<br>
the impact of hot indirect calls (by speculatively promoting them to<br>
direct calls) and allow optimized search trees to be used to lower<br>
switches. If you need to deploy these techniques in C++ applications, we<br>
*strongly* recommend that you ensure all hot call targets are statically<br>
linked (avoiding PLT indirection) and use both PGO and ThinLTO. Well<br>
tuned servers using all of these techniques saw 5% - 10% overhead from<br>
the use of retpoline.<br>
<br>
We will add detailed documentation covering these components in<br>
subsequent patches, but wanted to make the core functionality available<br>
as soon as possible. Happy for more code review, but we'd really like to<br>
get these patches landed and backported ASAP for obvious reasons. We're<br>
planning to backport this to both 6.0 and 5.0 release streams and get<br>
a 5.0 release with just this cherry picked ASAP for distros and vendors.<br>
<br>
This patch is the work of a number of people over the past month: Eric, Reid,<br>
Rui, and myself. I'm mailing it out as a single commit due to the time<br>
sensitive nature of landing this and the need to backport it. Huge thanks to<br>
everyone who helped out here, and everyone at Intel who helped out in<br>
discussions about how to craft this. Also, credit goes to Paul Turner (at<br>
Google, but not an LLVM contributor) for much of the underlying retpoline<br>
design.<br>
<br>
Reviewers: echristo, rnk, ruiu, craig.topper, DavidKreitzer<br>
<br>
Subscribers: sanjoy, emaste, mcrosier, mgorny, mehdi_amini, hiraditya, llvm-commits<br>
<br>
Differential Revision: <a href="https://reviews.llvm.org/D41723" rel="noreferrer" target="_blank">https://reviews.llvm.org/D41723</a><br>
<br>
Modified:<br>
    cfe/trunk/include/clang/Driver/Options.td<br>
    cfe/trunk/lib/Basic/Targets/X86.cpp<br>
    cfe/trunk/lib/Basic/Targets/X86.h<br>
    cfe/trunk/test/Driver/x86-target-features.c<br>
<br>
Modified: cfe/trunk/include/clang/Driver/Options.td<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/Options.td?rev=323155&r1=323154&r2=323155&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/Options.td?rev=323155&r1=323154&r2=323155&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Driver/Options.td (original)<br>
+++ cfe/trunk/include/clang/Driver/Options.td Mon Jan 22 14:05:25 2018<br>
@@ -2594,6 +2594,10 @@ def mshstk : Flag<["-"], "mshstk">, Grou<br>
 def mno_shstk : Flag<["-"], "mno-shstk">, Group<m_x86_Features_Group>;<br>
 def mibt : Flag<["-"], "mibt">, Group<m_x86_Features_Group>;<br>
 def mno_ibt : Flag<["-"], "mno-ibt">, Group<m_x86_Features_Group>;<br>
+def mretpoline : Flag<["-"], "mretpoline">, Group<m_x86_Features_Group>;<br>
+def mno_retpoline : Flag<["-"], "mno-retpoline">, Group<m_x86_Features_Group>;<br>
+def mretpoline_external_thunk : Flag<["-"], "mretpoline-external-thunk">, Group<m_x86_Features_Group>;<br>
+def mno_retpoline_external_thunk : Flag<["-"], "mno-retpoline-external-thunk">, Group<m_x86_Features_Group>;<br>
<br>
 // These are legacy user-facing driver-level option spellings. They are always<br>
 // aliases for options that are spelled using the more common Unix / GNU flag<br>
<br>
Modified: cfe/trunk/lib/Basic/Targets/X86.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/Targets/X86.cpp?rev=323155&r1=323154&r2=323155&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/Targets/X86.cpp?rev=323155&r1=323154&r2=323155&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Basic/Targets/X86.cpp (original)<br>
+++ cfe/trunk/lib/Basic/Targets/X86.cpp Mon Jan 22 14:05:25 2018<br>
@@ -787,6 +787,10 @@ bool X86TargetInfo::handleTargetFeatures<br>
       HasCLZERO = true;<br>
     } else if (Feature == "+rdpid") {<br>
       HasRDPID = true;<br>
+    } else if (Feature == "+retpoline") {<br>
+      HasRetpoline = true;<br>
+    } else if (Feature == "+retpoline-external-thunk") {<br>
+      HasRetpolineExternalThunk = true;<br>
     }<br>
<br>
     X86SSEEnum Level = llvm::StringSwitch<X86SSEEnum>(Feature)<br>
@@ -1333,6 +1337,8 @@ bool X86TargetInfo::hasFeature(StringRef<br>
       .Case("rdpid", HasRDPID)<br>
       .Case("rdrnd", HasRDRND)<br>
       .Case("rdseed", HasRDSEED)<br>
+      .Case("retpoline", HasRetpoline)<br>
+      .Case("retpoline-external-thunk", HasRetpolineExternalThunk)<br>
       .Case("rtm", HasRTM)<br>
       .Case("sgx", HasSGX)<br>
       .Case("sha", HasSHA)<br>
<br>
Modified: cfe/trunk/lib/Basic/Targets/X86.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/Targets/X86.h?rev=323155&r1=323154&r2=323155&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/Targets/X86.h?rev=323155&r1=323154&r2=323155&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Basic/Targets/X86.h (original)<br>
+++ cfe/trunk/lib/Basic/Targets/X86.h Mon Jan 22 14:05:25 2018<br>
@@ -97,6 +97,8 @@ class LLVM_LIBRARY_VISIBILITY X86TargetI<br>
   bool HasMOVBE = false;<br>
   bool HasPREFETCHWT1 = false;<br>
   bool HasRDPID = false;<br>
+  bool HasRetpoline = false;<br>
+  bool HasRetpolineExternalThunk = false;<br>
<br>
   /// \brief Enumeration of all of the X86 CPUs supported by Clang.<br>
   ///<br>
<br>
Modified: cfe/trunk/test/Driver/x86-target-features.c<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Driver/x86-target-features.c?rev=323155&r1=323154&r2=323155&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Driver/x86-target-features.c?rev=323155&r1=323154&r2=323155&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/Driver/x86-target-features.c (original)<br>
+++ cfe/trunk/test/Driver/x86-target-features.c Mon Jan 22 14:05:25 2018<br>
@@ -129,3 +129,13 @@<br>
 // RUN: %clang -target i386-unknown-linux-gnu -march=i386 -mno-rdpid %s -### -o %t.o 2>&1 | FileCheck -check-prefix=NO-RDPID %s<br>
 // RDPID: "-target-feature" "+rdpid"<br>
 // NO-RDPID: "-target-feature" "-rdpid"<br>
+<br>
+// RUN: %clang -target i386-linux-gnu -mretpoline %s -### -o %t.o 2>&1 | FileCheck -check-prefix=RETPOLINE %s<br>
+// RUN: %clang -target i386-linux-gnu -mno-retpoline %s -### -o %t.o 2>&1 | FileCheck -check-prefix=NO-RETPOLINE %s<br>
+// RETPOLINE: "-target-feature" "+retpoline"<br>
+// NO-RETPOLINE: "-target-feature" "-retpoline"<br>
+<br>
+// RUN: %clang -target i386-linux-gnu -mretpoline -mretpoline-external-thunk %s -### -o %t.o 2>&1 | FileCheck -check-prefix=RETPOLINE-EXTERNAL-THUNK %s<br>
+// RUN: %clang -target i386-linux-gnu -mretpoline -mno-retpoline-external-thunk %s -### -o %t.o 2>&1 | FileCheck -check-prefix=NO-RETPOLINE-EXTERNAL-THUNK %s<br>
+// RETPOLINE-EXTERNAL-THUNK: "-target-feature" "+retpoline-external-thunk"<br>
+// NO-RETPOLINE-EXTERNAL-THUNK: "-target-feature" "-retpoline-external-thunk"<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits</a><br>
</blockquote></div>