brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.1 KiB · 64728a2 Raw
120 lines · cpp
1//===-- X86LoadValueInjectionRetHardening.cpp - LVI RET hardening for x86 --==//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///9/// Description: Replaces every `ret` instruction with the sequence:10/// ```11/// pop <scratch-reg>12/// lfence13/// jmp *<scratch-reg>14/// ```15/// where `<scratch-reg>` is some available scratch register, according to the16/// calling convention of the function being mitigated.17///18//===----------------------------------------------------------------------===//19 20#include "X86.h"21#include "X86InstrBuilder.h"22#include "X86Subtarget.h"23#include "llvm/ADT/Statistic.h"24#include "llvm/CodeGen/MachineBasicBlock.h"25#include "llvm/CodeGen/MachineFunction.h"26#include "llvm/CodeGen/MachineFunctionPass.h"27#include "llvm/CodeGen/MachineInstrBuilder.h"28#include "llvm/IR/Function.h"29#include "llvm/Support/Debug.h"30 31using namespace llvm;32 33#define PASS_KEY "x86-lvi-ret"34#define DEBUG_TYPE PASS_KEY35 36STATISTIC(NumFences, "Number of LFENCEs inserted for LVI mitigation");37STATISTIC(NumFunctionsConsidered, "Number of functions analyzed");38STATISTIC(NumFunctionsMitigated, "Number of functions for which mitigations "39                                 "were deployed");40 41namespace {42 43class X86LoadValueInjectionRetHardeningPass : public MachineFunctionPass {44public:45  X86LoadValueInjectionRetHardeningPass() : MachineFunctionPass(ID) {}46  StringRef getPassName() const override {47    return "X86 Load Value Injection (LVI) Ret-Hardening";48  }49  bool runOnMachineFunction(MachineFunction &MF) override;50 51  static char ID;52};53 54} // end anonymous namespace55 56char X86LoadValueInjectionRetHardeningPass::ID = 0;57 58bool X86LoadValueInjectionRetHardeningPass::runOnMachineFunction(59    MachineFunction &MF) {60  const X86Subtarget *Subtarget = &MF.getSubtarget<X86Subtarget>();61  if (!Subtarget->useLVIControlFlowIntegrity() || !Subtarget->is64Bit())62    return false; // FIXME: support 32-bit63 64  // Don't skip functions with the "optnone" attr but participate in opt-bisect.65  const Function &F = MF.getFunction();66  if (!F.hasOptNone() && skipFunction(F))67    return false;68 69  LLVM_DEBUG(dbgs() << "***** " << getPassName() << " : " << MF.getName()70                    << " *****\n");71  ++NumFunctionsConsidered;72  const X86RegisterInfo *TRI = Subtarget->getRegisterInfo();73  const X86InstrInfo *TII = Subtarget->getInstrInfo();74 75  bool Modified = false;76  for (auto &MBB : MF) {77    for (auto MBBI = MBB.begin(); MBBI != MBB.end(); ++MBBI) {78      if (MBBI->getOpcode() != X86::RET64)79        continue;80 81      unsigned ClobberReg = TRI->findDeadCallerSavedReg(MBB, MBBI);82      if (ClobberReg != X86::NoRegister) {83        BuildMI(MBB, MBBI, DebugLoc(), TII->get(X86::POP64r))84            .addReg(ClobberReg, RegState::Define)85            .setMIFlag(MachineInstr::FrameDestroy);86        BuildMI(MBB, MBBI, DebugLoc(), TII->get(X86::LFENCE));87        BuildMI(MBB, MBBI, DebugLoc(), TII->get(X86::JMP64r))88            .addReg(ClobberReg);89        MBB.erase(MBBI);90      } else {91        // In case there is no available scratch register, we can still read92        // from RSP to assert that RSP points to a valid page. The write to RSP93        // is also helpful because it verifies that the stack's write94        // permissions are intact.95        MachineInstr *Fence =96            BuildMI(MBB, MBBI, DebugLoc(), TII->get(X86::LFENCE));97        addRegOffset(BuildMI(MBB, Fence, DebugLoc(), TII->get(X86::SHL64mi)),98                     X86::RSP, false, 0)99            .addImm(0)100            ->addRegisterDead(X86::EFLAGS, TRI);101      }102 103      ++NumFences;104      Modified = true;105      break;106    }107  }108 109  if (Modified)110    ++NumFunctionsMitigated;111  return Modified;112}113 114INITIALIZE_PASS(X86LoadValueInjectionRetHardeningPass, PASS_KEY,115                "X86 LVI ret hardener", false, false)116 117FunctionPass *llvm::createX86LoadValueInjectionRetHardeningPass() {118  return new X86LoadValueInjectionRetHardeningPass();119}120