brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.0 KiB · 5d93a37 Raw
183 lines · cpp
1//===-- X86SpeculativeExecutionSideEffectSuppression.cpp ------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8/// \file9///10/// This file contains the X86 implementation of the speculative execution side11/// effect suppression mitigation.12///13/// This must be used with the -mlvi-cfi flag in order to mitigate indirect14/// branches and returns.15//===----------------------------------------------------------------------===//16 17#include "X86.h"18#include "X86InstrInfo.h"19#include "X86Subtarget.h"20#include "llvm/ADT/Statistic.h"21#include "llvm/CodeGen/MachineFunction.h"22#include "llvm/CodeGen/MachineFunctionPass.h"23#include "llvm/CodeGen/MachineInstrBuilder.h"24#include "llvm/Pass.h"25#include "llvm/Target/TargetMachine.h"26using namespace llvm;27 28#define DEBUG_TYPE "x86-seses"29 30STATISTIC(NumLFENCEsInserted, "Number of lfence instructions inserted");31 32static cl::opt<bool> EnableSpeculativeExecutionSideEffectSuppression(33    "x86-seses-enable-without-lvi-cfi",34    cl::desc("Force enable speculative execution side effect suppression. "35             "(Note: User must pass -mlvi-cfi in order to mitigate indirect "36             "branches and returns.)"),37    cl::init(false), cl::Hidden);38 39static cl::opt<bool> OneLFENCEPerBasicBlock(40    "x86-seses-one-lfence-per-bb",41    cl::desc(42        "Omit all lfences other than the first to be placed in a basic block."),43    cl::init(false), cl::Hidden);44 45static cl::opt<bool> OnlyLFENCENonConst(46    "x86-seses-only-lfence-non-const",47    cl::desc("Only lfence before groups of terminators where at least one "48             "branch instruction has an input to the addressing mode that is a "49             "register other than %rip."),50    cl::init(false), cl::Hidden);51 52static cl::opt<bool>53    OmitBranchLFENCEs("x86-seses-omit-branch-lfences",54                      cl::desc("Omit all lfences before branch instructions."),55                      cl::init(false), cl::Hidden);56 57namespace {58 59class X86SpeculativeExecutionSideEffectSuppression60    : public MachineFunctionPass {61public:62  X86SpeculativeExecutionSideEffectSuppression() : MachineFunctionPass(ID) {}63 64  static char ID;65  StringRef getPassName() const override {66    return "X86 Speculative Execution Side Effect Suppression";67  }68 69  bool runOnMachineFunction(MachineFunction &MF) override;70};71} // namespace72 73char X86SpeculativeExecutionSideEffectSuppression::ID = 0;74 75// This function returns whether the passed instruction uses a memory addressing76// mode that is constant. We treat all memory addressing modes that read77// from a register that is not %rip as non-constant. Note that the use78// of the EFLAGS register results in an addressing mode being considered79// non-constant, therefore all JCC instructions will return false from this80// function since one of their operands will always be the EFLAGS register.81static bool hasConstantAddressingMode(const MachineInstr &MI) {82  for (const MachineOperand &MO : MI.uses())83    if (MO.isReg() && X86::RIP != MO.getReg())84      return false;85  return true;86}87 88bool X86SpeculativeExecutionSideEffectSuppression::runOnMachineFunction(89    MachineFunction &MF) {90 91  const auto &OptLevel = MF.getTarget().getOptLevel();92  const X86Subtarget &Subtarget = MF.getSubtarget<X86Subtarget>();93 94  // Check whether SESES needs to run as the fallback for LVI at O0, whether the95  // user explicitly passed an SESES flag, or whether the SESES target feature96  // was set.97  if (!EnableSpeculativeExecutionSideEffectSuppression &&98      !(Subtarget.useLVILoadHardening() && OptLevel == CodeGenOptLevel::None) &&99      !Subtarget.useSpeculativeExecutionSideEffectSuppression())100    return false;101 102  LLVM_DEBUG(dbgs() << "********** " << getPassName() << " : " << MF.getName()103                    << " **********\n");104  bool Modified = false;105  const X86InstrInfo *TII = Subtarget.getInstrInfo();106  for (MachineBasicBlock &MBB : MF) {107    MachineInstr *FirstTerminator = nullptr;108    // Keep track of whether the previous instruction was an LFENCE to avoid109    // adding redundant LFENCEs.110    bool PrevInstIsLFENCE = false;111    for (auto &MI : MBB) {112 113      if (MI.getOpcode() == X86::LFENCE) {114        PrevInstIsLFENCE = true;115        continue;116      }117      // We want to put an LFENCE before any instruction that118      // may load or store. This LFENCE is intended to avoid leaking any secret119      // data due to a given load or store. This results in closing the cache120      // and memory timing side channels. We will treat terminators that load121      // or store separately.122      if (MI.mayLoadOrStore() && !MI.isTerminator()) {123        if (!PrevInstIsLFENCE) {124          BuildMI(MBB, MI, DebugLoc(), TII->get(X86::LFENCE));125          NumLFENCEsInserted++;126          Modified = true;127        }128        if (OneLFENCEPerBasicBlock)129          break;130      }131      // The following section will be LFENCEing before groups of terminators132      // that include branches. This will close the branch prediction side133      // channels since we will prevent code executing after misspeculation as134      // a result of the LFENCEs placed with this logic.135 136      // Keep track of the first terminator in a basic block since if we need137      // to LFENCE the terminators in this basic block we must add the138      // instruction before the first terminator in the basic block (as139      // opposed to before the terminator that indicates an LFENCE is140      // required). An example of why this is necessary is that the141      // X86InstrInfo::analyzeBranch method assumes all terminators are grouped142      // together and terminates it's analysis once the first non-termintor143      // instruction is found.144      if (MI.isTerminator() && FirstTerminator == nullptr)145        FirstTerminator = &MI;146 147      // Look for branch instructions that will require an LFENCE to be put148      // before this basic block's terminators.149      if (!MI.isBranch() || OmitBranchLFENCEs) {150        // This isn't a branch or we're not putting LFENCEs before branches.151        PrevInstIsLFENCE = false;152        continue;153      }154 155      if (OnlyLFENCENonConst && hasConstantAddressingMode(MI)) {156        // This is a branch, but it only has constant addressing mode and we're157        // not adding LFENCEs before such branches.158        PrevInstIsLFENCE = false;159        continue;160      }161 162      // This branch requires adding an LFENCE.163      if (!PrevInstIsLFENCE) {164        assert(FirstTerminator && "Unknown terminator instruction");165        BuildMI(MBB, FirstTerminator, DebugLoc(), TII->get(X86::LFENCE));166        NumLFENCEsInserted++;167        Modified = true;168      }169      break;170    }171  }172 173  return Modified;174}175 176FunctionPass *llvm::createX86SpeculativeExecutionSideEffectSuppression() {177  return new X86SpeculativeExecutionSideEffectSuppression();178}179 180INITIALIZE_PASS(X86SpeculativeExecutionSideEffectSuppression, "x86-seses",181                "X86 Speculative Execution Side Effect Suppression", false,182                false)183