Home | History | Annotate | Line # | Download | only in aarch64
aarch64-speculation.cc revision 1.1.1.2
      1 /* Speculation tracking and mitigation (e.g. CVE 2017-5753) for AArch64.
      2    Copyright (C) 2018-2020 Free Software Foundation, Inc.
      3    Contributed by ARM Ltd.
      4 
      5    This file is part of GCC.
      6 
      7    GCC is free software; you can redistribute it and/or modify it
      8    under the terms of the GNU General Public License as published by
      9    the Free Software Foundation; either version 3, or (at your option)
     10    any later version.
     11 
     12    GCC is distributed in the hope that it will be useful, but
     13    WITHOUT ANY WARRANTY; without even the implied warranty of
     14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15    General Public License for more details.
     16 
     17    You should have received a copy of the GNU General Public License
     18    along with GCC; see the file COPYING3.  If not see
     19    <http://www.gnu.org/licenses/>.  */
     20 
     21 #include "config.h"
     22 #include "system.h"
     23 #include "coretypes.h"
     24 #include "target.h"
     25 #include "rtl.h"
     26 #include "tree-pass.h"
     27 #include "profile-count.h"
     28 #include "backend.h"
     29 #include "cfgbuild.h"
     30 #include "print-rtl.h"
     31 #include "cfgrtl.h"
     32 #include "function.h"
     33 #include "basic-block.h"
     34 #include "memmodel.h"
     35 #include "emit-rtl.h"
     36 #include "insn-attr.h"
     37 #include "df.h"
     38 #include "tm_p.h"
     39 #include "insn-config.h"
     40 #include "recog.h"
     41 
     42 /* This pass scans the RTL just before the final branch
     43    re-organisation pass.  The aim is to identify all places where
     44    there is conditional control flow and to insert code that tracks
     45    any speculative execution of a conditional branch.
     46 
     47    To do this we reserve a call-clobbered register (so that it can be
     48    initialized very early in the function prologue) that can then be
     49    updated each time there is a conditional branch.  At each such
     50    branch we then generate a code sequence that uses conditional
     51    select operations that are not subject to speculation themselves
     52    (we ignore for the moment situations where that might not always be
     53    strictly true).  For example, a branch sequence such as:
     54 
     55 	B.EQ	<dst>
     56 	...
     57    <dst>:
     58 
     59    is transformed to:
     60 
     61 	B.EQ	<dst>
     62 	CSEL	tracker, tracker, XZr, ne
     63 	...
     64    <dst>:
     65 	CSEL	tracker, tracker, XZr, eq
     66 
     67    Since we start with the tracker initialized to all bits one, if at any
     68    time the predicted control flow diverges from the architectural program
     69    behavior, then the tracker will become zero (but not otherwise).
     70 
     71    The tracker value can be used at any time at which a value needs
     72    guarding against incorrect speculation.  This can be done in
     73    several ways, but they all amount to the same thing.  For an
     74    untrusted address, or an untrusted offset to a trusted address, we
     75    can simply mask the address with the tracker with the untrusted
     76    value.  If the CPU is not speculating, or speculating correctly,
     77    then the value will remain unchanged, otherwise it will be clamped
     78    to zero.  For more complex scenarios we can compare the tracker
     79    against zero and use the flags to form a new selection with an
     80    alternate safe value.
     81 
     82    On implementations where the data processing instructions may
     83    themselves produce speculative values, the architecture requires
     84    that a CSDB instruction will resolve such data speculation, so each
     85    time we use the tracker for protecting a vulnerable value we also
     86    emit a CSDB: we do not need to do that each time the tracker itself
     87    is updated.
     88 
     89    At function boundaries, we need to communicate the speculation
     90    tracking state with the caller or the callee.  This is tricky
     91    because there is no register available for such a purpose without
     92    creating a new ABI.  We deal with this by relying on the principle
     93    that in all real programs the stack pointer, SP will never be NULL
     94    at a function boundary; we can thus encode the speculation state in
     95    SP by clearing SP if the speculation tracker itself is NULL.  After
     96    the call we recover the tracking state back from SP into the
     97    tracker register.  The results is that a function call sequence is
     98    transformed to
     99 
    100 	MOV	tmp, SP
    101 	AND	tmp, tmp, tracker
    102 	MOV	SP, tmp
    103 	BL	<callee>
    104 	CMP	SP, #0
    105 	CSETM	tracker, ne
    106 
    107    The additional MOV instructions in the pre-call sequence are needed
    108    because SP cannot be used directly with the AND instruction.
    109 
    110    The code inside a function body uses the post-call sequence in the
    111    prologue to establish the tracker and the pre-call sequence in the
    112    epilogue to re-encode the state for the return.
    113 
    114    The code sequences have the nice property that if called from, or
    115    calling a function that does not track speculation then the stack pointer
    116    will always be non-NULL and hence the tracker will be initialized to all
    117    bits one as we need: we lose the ability to fully track speculation in that
    118    case, but we are still architecturally safe.
    119 
    120    Tracking speculation in this way is quite expensive, both in code
    121    size and execution time.  We employ a number of tricks to try to
    122    limit this:
    123 
    124    1) Simple leaf functions with no conditional branches (or use of
    125    the tracker) do not need to establish a new tracker: they simply
    126    carry the tracking state through SP for the duration of the call.
    127    The same is also true for leaf functions that end in a tail-call.
    128 
    129    2) Back-to-back function calls in a single basic block also do not
    130    need to re-establish the tracker between the calls.  Again, we can
    131    carry the tracking state in SP for this period of time unless the
    132    tracker value is needed at that point in time.
    133 
    134    We run the pass just before the final branch reorganization pass so
    135    that we can handle most of the conditional branch cases using the
    136    standard edge insertion code.  The reorg pass will hopefully clean
    137    things up for afterwards so that the results aren't too
    138    horrible.  */
    139 
    140 /* Generate a code sequence to clobber SP if speculating incorreclty.  */
    141 static rtx_insn *
    142 aarch64_speculation_clobber_sp ()
    143 {
    144   rtx sp = gen_rtx_REG (DImode, SP_REGNUM);
    145   rtx tracker = gen_rtx_REG (DImode, SPECULATION_TRACKER_REGNUM);
    146   rtx scratch = gen_rtx_REG (DImode, SPECULATION_SCRATCH_REGNUM);
    147 
    148   start_sequence ();
    149   emit_insn (gen_rtx_SET (scratch, sp));
    150   emit_insn (gen_anddi3 (scratch, scratch, tracker));
    151   emit_insn (gen_rtx_SET (sp, scratch));
    152   rtx_insn *seq = get_insns ();
    153   end_sequence ();
    154   return seq;
    155 }
    156 
    157 /* Generate a code sequence to establish the tracker variable from the
    158    contents of SP.  */
    159 static rtx_insn *
    160 aarch64_speculation_establish_tracker ()
    161 {
    162   rtx sp = gen_rtx_REG (DImode, SP_REGNUM);
    163   rtx tracker = gen_rtx_REG (DImode, SPECULATION_TRACKER_REGNUM);
    164   start_sequence ();
    165   rtx cc = aarch64_gen_compare_reg (EQ, sp, const0_rtx);
    166   emit_insn (gen_cstoredi_neg (tracker,
    167 			       gen_rtx_NE (CCmode, cc, const0_rtx), cc));
    168   rtx_insn *seq = get_insns ();
    169   end_sequence ();
    170   return seq;
    171 }
    172 
    173 /* Main speculation tracking pass.  */
    174 unsigned int
    175 aarch64_do_track_speculation ()
    176 {
    177   basic_block bb;
    178   bool needs_tracking = false;
    179   bool need_second_pass = false;
    180   rtx_insn *insn;
    181   int fixups_pending = 0;
    182 
    183   FOR_EACH_BB_FN (bb, cfun)
    184     {
    185       insn = BB_END (bb);
    186 
    187       if (dump_file)
    188 	fprintf (dump_file, "Basic block %d:\n", bb->index);
    189 
    190       while (insn != BB_HEAD (bb)
    191 	     && NOTE_P (insn))
    192 	insn = PREV_INSN (insn);
    193 
    194       if (control_flow_insn_p (insn))
    195 	{
    196 	  if (any_condjump_p (insn))
    197 	    {
    198 	      if (dump_file)
    199 		{
    200 		  fprintf (dump_file, "  condjump\n");
    201 		  dump_insn_slim (dump_file, insn);
    202 		}
    203 
    204 	      rtx src = SET_SRC (pc_set (insn));
    205 
    206 	      /* Check for an inverted jump, where the fall-through edge
    207 		 appears first.  */
    208 	      bool inverted = GET_CODE (XEXP (src, 2)) != PC;
    209 	      /* The other edge must be the PC (we assume that we don't
    210 		 have conditional return instructions).  */
    211 	      gcc_assert (GET_CODE (XEXP (src, 1 + !inverted)) == PC);
    212 
    213 	      rtx cond = copy_rtx (XEXP (src, 0));
    214 	      gcc_assert (COMPARISON_P (cond)
    215 			  && REG_P (XEXP (cond, 0))
    216 			  && REGNO (XEXP (cond, 0)) == CC_REGNUM
    217 			  && XEXP (cond, 1) == const0_rtx);
    218 	      rtx branch_tracker = gen_speculation_tracker (copy_rtx (cond));
    219 	      rtx fallthru_tracker = gen_speculation_tracker_rev (cond);
    220 	      if (inverted)
    221 		std::swap (branch_tracker, fallthru_tracker);
    222 
    223 	      insert_insn_on_edge (branch_tracker, BRANCH_EDGE (bb));
    224 	      insert_insn_on_edge (fallthru_tracker, FALLTHRU_EDGE (bb));
    225 	      needs_tracking = true;
    226 	    }
    227 	  else if (GET_CODE (PATTERN (insn)) == RETURN)
    228 	    {
    229 	      /* If we already know we'll need a second pass, don't put
    230 		 out the return sequence now, or we might end up with
    231 		 two copies.  Instead, we'll do all return statements
    232 		 during the second pass.  However, if this is the
    233 		 first return insn we've found and we already
    234 		 know that we'll need to emit the code, we can save a
    235 		 second pass by emitting the code now.  */
    236 	      if (needs_tracking && ! need_second_pass)
    237 		{
    238 		  rtx_insn *seq = aarch64_speculation_clobber_sp ();
    239 		  emit_insn_before (seq, insn);
    240 		}
    241 	      else
    242 		{
    243 		  fixups_pending++;
    244 		  need_second_pass = true;
    245 		}
    246 	    }
    247 	  else if (find_reg_note (insn, REG_NON_LOCAL_GOTO, NULL_RTX))
    248 	    {
    249 	      rtx_insn *seq = aarch64_speculation_clobber_sp ();
    250 	      emit_insn_before (seq, insn);
    251 	      needs_tracking = true;
    252 	    }
    253 	}
    254       else
    255 	{
    256 	  if (dump_file)
    257 	    {
    258 	      fprintf (dump_file, "  other\n");
    259 	      dump_insn_slim (dump_file, insn);
    260 	    }
    261 	}
    262     }
    263 
    264   FOR_EACH_BB_FN (bb, cfun)
    265     {
    266       rtx_insn *end = BB_END (bb);
    267       rtx_insn *call_insn = NULL;
    268 
    269       if (bb->flags & BB_NON_LOCAL_GOTO_TARGET)
    270 	{
    271 	  rtx_insn *label = NULL;
    272 	  /* For non-local goto targets we have to recover the
    273 	     speculation state from SP.  Find the last code label at
    274 	     the head of the block and place the fixup sequence after
    275 	     that.  */
    276 	  for (insn = BB_HEAD (bb); insn != end; insn = NEXT_INSN (insn))
    277 	    {
    278 	      if (LABEL_P (insn))
    279 		label = insn;
    280 	      /* Never put anything before the basic block note.  */
    281 	      if (NOTE_INSN_BASIC_BLOCK_P (insn))
    282 		label = insn;
    283 	      if (INSN_P (insn))
    284 		break;
    285 	    }
    286 
    287 	  gcc_assert (label);
    288 	  emit_insn_after (aarch64_speculation_establish_tracker (), label);
    289 	}
    290 
    291       /* Scan the insns looking for calls.  We need to pass the
    292 	 speculation tracking state encoded in to SP.  After a call we
    293 	 restore the speculation tracking into the tracker register.
    294 	 To avoid unnecessary transfers we look for two or more calls
    295 	 within a single basic block and eliminate, where possible,
    296 	 any redundant operations.  */
    297       for (insn = BB_HEAD (bb); ; insn = NEXT_INSN (insn))
    298 	{
    299 	  if (NONDEBUG_INSN_P (insn)
    300 	      && recog_memoized (insn) >= 0
    301 	      && (get_attr_speculation_barrier (insn)
    302 		  == SPECULATION_BARRIER_TRUE))
    303 	    {
    304 	      if (call_insn)
    305 		{
    306 		  /* This instruction requires the speculation
    307 		     tracking to be in the tracker register.  If there
    308 		     was an earlier call in this block, we need to
    309 		     copy the speculation tracking back there.  */
    310 		  emit_insn_after (aarch64_speculation_establish_tracker (),
    311 				   call_insn);
    312 		  call_insn = NULL;
    313 		}
    314 
    315 	      needs_tracking = true;
    316 	    }
    317 
    318 	  if (CALL_P (insn))
    319 	    {
    320 	      bool tailcall
    321 		= (SIBLING_CALL_P (insn)
    322 		   || find_reg_note (insn, REG_NORETURN, NULL_RTX));
    323 
    324 	      /* Tailcalls are like returns, we can eliminate the
    325 		 transfer between the tracker register and SP if we
    326 		 know that this function does not itself need
    327 		 tracking.  */
    328 	      if (tailcall && (need_second_pass || !needs_tracking))
    329 		{
    330 		  /* Don't clear call_insn if it is set - needs_tracking
    331 		     will be true in that case and so we will end
    332 		     up putting out mitigation sequences.  */
    333 		  fixups_pending++;
    334 		  need_second_pass = true;
    335 		  break;
    336 		}
    337 
    338 	      needs_tracking = true;
    339 
    340 	      /* We always need a transfer before the first call in a BB.  */
    341 	      if (!call_insn)
    342 		emit_insn_before (aarch64_speculation_clobber_sp (), insn);
    343 
    344 	      /* Tail-calls and no-return calls don't need any post-call
    345 		 reestablishment of the tracker.  */
    346 	      if (! tailcall)
    347 		call_insn = insn;
    348 	      else
    349 		call_insn = NULL;
    350 	    }
    351 
    352 	  if (insn == end)
    353 	    break;
    354 	}
    355 
    356       if (call_insn)
    357 	{
    358 	  rtx_insn *seq = aarch64_speculation_establish_tracker ();
    359 
    360 	  /* Handle debug insns at the end of the BB.  Put the extra
    361 	     insns after them.  This ensures that we have consistent
    362 	     behaviour for the placement of the extra insns between
    363 	     debug and non-debug builds.  */
    364 	  for (insn = call_insn;
    365 	       insn != end && DEBUG_INSN_P (NEXT_INSN (insn));
    366 	       insn = NEXT_INSN (insn))
    367 	    ;
    368 
    369 	  if (insn == end)
    370 	    {
    371 	      edge e = find_fallthru_edge (bb->succs);
    372 	      /* We need to be very careful about some calls that
    373 		 appear at the end of a basic block.  If the call
    374 		 involves exceptions, then the compiler may depend on
    375 		 this being the last instruction in the block.  The
    376 		 easiest way to handle this is to commit the new
    377 		 instructions on the fall-through edge and to let
    378 		 commit_edge_insertions clean things up for us.
    379 
    380 		 Sometimes, eg with OMP, there may not even be an
    381 		 outgoing edge after the call.  In that case, there's
    382 		 not much we can do, presumably the compiler has
    383 		 decided that the call can never return in this
    384 		 context.  */
    385 	      if (e)
    386 		{
    387 		  /* We need to set the location lists explicitly in
    388 		     this case.  */
    389 		  if (! INSN_P (seq))
    390 		    {
    391 		      start_sequence ();
    392 		      emit_insn (seq);
    393 		      seq = get_insns ();
    394 		      end_sequence ();
    395 		    }
    396 
    397 		  for (rtx_insn *list = seq; list; list = NEXT_INSN (list))
    398 		    INSN_LOCATION (list) = INSN_LOCATION (call_insn);
    399 
    400 		  insert_insn_on_edge (seq, e);
    401 		}
    402 	    }
    403 	  else
    404 	    emit_insn_after (seq, call_insn);
    405 	}
    406     }
    407 
    408   if (needs_tracking)
    409     {
    410       if (need_second_pass)
    411 	{
    412 	  /* We found a return instruction before we found out whether
    413 	     or not we need to emit the tracking code, but we now
    414 	     know we do.  Run quickly over the basic blocks and
    415 	     fix up the return insns.  */
    416 	  FOR_EACH_BB_FN (bb, cfun)
    417 	    {
    418 	      insn = BB_END (bb);
    419 
    420 	      while (insn != BB_HEAD (bb)
    421 		     && NOTE_P (insn))
    422 		insn = PREV_INSN (insn);
    423 
    424 	      if ((control_flow_insn_p (insn)
    425 		   && GET_CODE (PATTERN (insn)) == RETURN)
    426 		  || (CALL_P (insn)
    427 		      && (SIBLING_CALL_P (insn)
    428 			  || find_reg_note (insn, REG_NORETURN, NULL_RTX))))
    429 		{
    430 		  rtx_insn *seq = aarch64_speculation_clobber_sp ();
    431 		  emit_insn_before (seq, insn);
    432 		  fixups_pending--;
    433 		}
    434 	    }
    435 	  gcc_assert (fixups_pending == 0);
    436 	}
    437 
    438       /* Set up the initial value of the tracker, using the incoming SP.  */
    439       insert_insn_on_edge (aarch64_speculation_establish_tracker (),
    440 			   single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
    441       commit_edge_insertions ();
    442     }
    443 
    444   return 0;
    445 }
    446 
    447 namespace {
    448 
    449 const pass_data pass_data_aarch64_track_speculation =
    450 {
    451   RTL_PASS,		/* type.  */
    452   "speculation",	/* name.  */
    453   OPTGROUP_NONE,	/* optinfo_flags.  */
    454   TV_MACH_DEP,		/* tv_id.  */
    455   0,			/* properties_required.  */
    456   0,			/* properties_provided.  */
    457   0,			/* properties_destroyed.  */
    458   0,			/* todo_flags_start.  */
    459   0			/* todo_flags_finish.  */
    460 };
    461 
    462 class pass_track_speculation : public rtl_opt_pass
    463 {
    464  public:
    465   pass_track_speculation(gcc::context *ctxt)
    466     : rtl_opt_pass(pass_data_aarch64_track_speculation, ctxt)
    467     {}
    468 
    469   /* opt_pass methods:  */
    470   virtual bool gate (function *)
    471     {
    472       return aarch64_track_speculation;
    473     }
    474 
    475   virtual unsigned int execute (function *)
    476     {
    477       return aarch64_do_track_speculation ();
    478     }
    479 }; // class pass_track_speculation.
    480 } // anon namespace.
    481 
    482 /* Create a new pass instance.  */
    483 rtl_opt_pass *
    484 make_pass_track_speculation (gcc::context *ctxt)
    485 {
    486   return new pass_track_speculation (ctxt);
    487 }
    488