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