brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.4 KiB · 51075be Raw
146 lines · cpp
1//===- bolt/Passes/MarkRAStates.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//9// This file implements the MarkRAStates class.10// Three CFIs have an influence on the RA State of an instruction:11// - NegateRAState flips the RA State,12// - RememberState pushes the RA State to a stack,13// - RestoreState pops the RA State from the stack.14// These are saved as MCAnnotations on instructions they refer to at CFI15// reading (in CFIReaderWriter::fillCFIInfoFor). In this pass, we can work out16// the RA State of each instruction, and save it as new MCAnnotations. The new17// annotations are Signing, Signed, Authenticating and Unsigned. After18// optimizations, .cfi_negate_ra_state CFIs are added to the places where the19// state changes in InsertNegateRAStatePass.20//21//===----------------------------------------------------------------------===//22#include "bolt/Passes/MarkRAStates.h"23#include "bolt/Core/BinaryFunction.h"24#include "bolt/Core/ParallelUtilities.h"25#include <cstdlib>26#include <optional>27#include <stack>28 29using namespace llvm;30 31namespace llvm {32namespace bolt {33 34bool MarkRAStates::runOnFunction(BinaryFunction &BF) {35 36  BinaryContext &BC = BF.getBinaryContext();37 38  for (const BinaryBasicBlock &BB : BF) {39    for (const MCInst &Inst : BB) {40      if ((BC.MIB->isPSignOnLR(Inst) ||41           (BC.MIB->isPAuthOnLR(Inst) && !BC.MIB->isPAuthAndRet(Inst))) &&42          !BC.MIB->hasNegateRAState(Inst)) {43        // Not all functions have .cfi_negate_ra_state in them. But if one does,44        // we expect psign/pauth instructions to have the hasNegateRAState45        // annotation.46        BC.outs() << "BOLT-INFO: inconsistent RAStates in function "47                  << BF.getPrintName()48                  << ": ptr sign/auth inst without .cfi_negate_ra_state\n";49        std::lock_guard<std::mutex> Lock(IgnoreMutex);50        BF.setIgnored();51        return false;52      }53    }54  }55 56  bool RAState = BF.getInitialRAState();57  std::stack<bool> RAStateStack;58  RAStateStack.push(RAState);59 60  for (BinaryBasicBlock &BB : BF) {61    for (MCInst &Inst : BB) {62      if (BC.MIB->isCFI(Inst))63        continue;64 65      if (BC.MIB->isPSignOnLR(Inst)) {66        if (RAState) {67          // RA signing instructions should only follow unsigned RA state.68          BC.outs() << "BOLT-INFO: inconsistent RAStates in function "69                    << BF.getPrintName()70                    << ": ptr signing inst encountered in Signed RA state\n";71          std::lock_guard<std::mutex> Lock(IgnoreMutex);72          BF.setIgnored();73          return false;74        }75      } else if (BC.MIB->isPAuthOnLR(Inst)) {76        if (!RAState) {77          // RA authenticating instructions should only follow signed RA state.78          BC.outs() << "BOLT-INFO: inconsistent RAStates in function "79                    << BF.getPrintName()80                    << ": ptr authenticating inst encountered in Unsigned RA "81                       "state\n";82          std::lock_guard<std::mutex> Lock(IgnoreMutex);83          BF.setIgnored();84          return false;85        }86      }87 88      BC.MIB->setRAState(Inst, RAState);89 90      // Updating RAState. All updates are valid from the next instruction.91      // Because the same instruction can have remember and restore, the order92      // here is relevant. This is the reason to loop over Annotations instead93      // of just checking each in a predefined order.94      for (unsigned int Idx = 0; Idx < Inst.getNumOperands(); Idx++) {95        std::optional<int64_t> Annotation =96            BC.MIB->getAnnotationAtOpIndex(Inst, Idx);97        if (!Annotation)98          continue;99        if (Annotation == MCPlus::MCAnnotation::kNegateState)100          RAState = !RAState;101        else if (Annotation == MCPlus::MCAnnotation::kRememberState)102          RAStateStack.push(RAState);103        else if (Annotation == MCPlus::MCAnnotation::kRestoreState) {104          RAState = RAStateStack.top();105          RAStateStack.pop();106        }107      }108    }109  }110  return true;111}112 113Error MarkRAStates::runOnFunctions(BinaryContext &BC) {114  std::atomic<uint64_t> FunctionsIgnored{0};115  ParallelUtilities::WorkFuncTy WorkFun = [&](BinaryFunction &BF) {116    if (!runOnFunction(BF)) {117      FunctionsIgnored++;118    }119  };120 121  ParallelUtilities::PredicateTy SkipPredicate = [&](const BinaryFunction &BF) {122    // We can skip functions which did not include negate-ra-state CFIs. This123    // includes code using pac-ret hardening as well, if the binary is124    // compiled with `-fno-exceptions -fno-unwind-tables125    // -fno-asynchronous-unwind-tables`126    return !BF.containedNegateRAState() || BF.isIgnored();127  };128 129  int Total = llvm::count_if(BC.getBinaryFunctions(), [&](auto &P) {130    return P.second.containedNegateRAState() && !P.second.isIgnored();131  });132 133  ParallelUtilities::runOnEachFunction(134      BC, ParallelUtilities::SchedulingPolicy::SP_INST_LINEAR, WorkFun,135      SkipPredicate, "MarkRAStates");136  BC.outs() << "BOLT-INFO: MarkRAStates ran on " << Total137            << " functions. Ignored " << FunctionsIgnored << " functions "138            << format("(%.2lf%%)", (100.0 * FunctionsIgnored) / Total)139            << " because of CFI inconsistencies\n";140 141  return Error::success();142}143 144} // end namespace bolt145} // end namespace llvm146