]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp
MFC r316910: 7812 Remove gender specific language
[FreeBSD/FreeBSD.git] / contrib / llvm / lib / Transforms / Instrumentation / HWAddressSanitizer.cpp
1 //===- HWAddressSanitizer.cpp - detector of uninitialized reads -------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 /// \file
11 /// This file is a part of HWAddressSanitizer, an address sanity checker
12 /// based on tagged addressing.
13 //===----------------------------------------------------------------------===//
14
15 #include "llvm/ADT/SmallVector.h"
16 #include "llvm/ADT/StringExtras.h"
17 #include "llvm/ADT/StringRef.h"
18 #include "llvm/ADT/Triple.h"
19 #include "llvm/IR/Attributes.h"
20 #include "llvm/IR/BasicBlock.h"
21 #include "llvm/IR/Constant.h"
22 #include "llvm/IR/Constants.h"
23 #include "llvm/IR/DataLayout.h"
24 #include "llvm/IR/DerivedTypes.h"
25 #include "llvm/IR/MDBuilder.h"
26 #include "llvm/Support/raw_ostream.h"
27 #include "llvm/IR/Function.h"
28 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
29 #include "llvm/IR/IRBuilder.h"
30 #include "llvm/IR/InlineAsm.h"
31 #include "llvm/IR/InstVisitor.h"
32 #include "llvm/IR/Instruction.h"
33 #include "llvm/IR/Instructions.h"
34 #include "llvm/IR/IntrinsicInst.h"
35 #include "llvm/IR/Intrinsics.h"
36 #include "llvm/IR/LLVMContext.h"
37 #include "llvm/IR/Module.h"
38 #include "llvm/IR/Type.h"
39 #include "llvm/IR/Value.h"
40 #include "llvm/Pass.h"
41 #include "llvm/Support/Casting.h"
42 #include "llvm/Support/CommandLine.h"
43 #include "llvm/Support/Debug.h"
44 #include "llvm/Transforms/Instrumentation.h"
45 #include "llvm/Transforms/Utils/ModuleUtils.h"
46
47 using namespace llvm;
48
49 #define DEBUG_TYPE "hwasan"
50
51 static const char *const kHwasanModuleCtorName = "hwasan.module_ctor";
52 static const char *const kHwasanInitName = "__hwasan_init";
53
54 // Accesses sizes are powers of two: 1, 2, 4, 8, 16.
55 static const size_t kNumberOfAccessSizes = 5;
56
57 static const size_t kShadowScale = 4;
58 static const unsigned kPointerTagShift = 56;
59
60 static cl::opt<std::string> ClMemoryAccessCallbackPrefix(
61     "hwasan-memory-access-callback-prefix",
62     cl::desc("Prefix for memory access callbacks"), cl::Hidden,
63     cl::init("__hwasan_"));
64
65 static cl::opt<bool>
66     ClInstrumentWithCalls("hwasan-instrument-with-calls",
67                 cl::desc("instrument reads and writes with callbacks"),
68                 cl::Hidden, cl::init(false));
69
70 static cl::opt<bool> ClInstrumentReads("hwasan-instrument-reads",
71                                        cl::desc("instrument read instructions"),
72                                        cl::Hidden, cl::init(true));
73
74 static cl::opt<bool> ClInstrumentWrites(
75     "hwasan-instrument-writes", cl::desc("instrument write instructions"),
76     cl::Hidden, cl::init(true));
77
78 static cl::opt<bool> ClInstrumentAtomics(
79     "hwasan-instrument-atomics",
80     cl::desc("instrument atomic instructions (rmw, cmpxchg)"), cl::Hidden,
81     cl::init(true));
82
83 static cl::opt<bool> ClRecover(
84     "hwasan-recover",
85     cl::desc("Enable recovery mode (continue-after-error)."),
86     cl::Hidden, cl::init(false));
87
88 namespace {
89
90 /// \brief An instrumentation pass implementing detection of addressability bugs
91 /// using tagged pointers.
92 class HWAddressSanitizer : public FunctionPass {
93 public:
94   // Pass identification, replacement for typeid.
95   static char ID;
96
97   HWAddressSanitizer(bool Recover = false)
98       : FunctionPass(ID), Recover(Recover || ClRecover) {}
99
100   StringRef getPassName() const override { return "HWAddressSanitizer"; }
101
102   bool runOnFunction(Function &F) override;
103   bool doInitialization(Module &M) override;
104
105   void initializeCallbacks(Module &M);
106   void instrumentMemAccessInline(Value *PtrLong, bool IsWrite,
107                                  unsigned AccessSizeIndex,
108                                  Instruction *InsertBefore);
109   bool instrumentMemAccess(Instruction *I);
110   Value *isInterestingMemoryAccess(Instruction *I, bool *IsWrite,
111                                    uint64_t *TypeSize, unsigned *Alignment,
112                                    Value **MaybeMask);
113
114 private:
115   LLVMContext *C;
116   Type *IntptrTy;
117
118   bool Recover;
119
120   Function *HwasanCtorFunction;
121
122   Function *HwasanMemoryAccessCallback[2][kNumberOfAccessSizes];
123   Function *HwasanMemoryAccessCallbackSized[2];
124 };
125
126 } // end anonymous namespace
127
128 char HWAddressSanitizer::ID = 0;
129
130 INITIALIZE_PASS_BEGIN(
131     HWAddressSanitizer, "hwasan",
132     "HWAddressSanitizer: detect memory bugs using tagged addressing.", false, false)
133 INITIALIZE_PASS_END(
134     HWAddressSanitizer, "hwasan",
135     "HWAddressSanitizer: detect memory bugs using tagged addressing.", false, false)
136
137 FunctionPass *llvm::createHWAddressSanitizerPass(bool Recover) {
138   return new HWAddressSanitizer(Recover);
139 }
140
141 /// \brief Module-level initialization.
142 ///
143 /// inserts a call to __hwasan_init to the module's constructor list.
144 bool HWAddressSanitizer::doInitialization(Module &M) {
145   DEBUG(dbgs() << "Init " << M.getName() << "\n");
146   auto &DL = M.getDataLayout();
147
148   Triple TargetTriple(M.getTargetTriple());
149
150   C = &(M.getContext());
151   IRBuilder<> IRB(*C);
152   IntptrTy = IRB.getIntPtrTy(DL);
153
154   std::tie(HwasanCtorFunction, std::ignore) =
155       createSanitizerCtorAndInitFunctions(M, kHwasanModuleCtorName,
156                                           kHwasanInitName,
157                                           /*InitArgTypes=*/{},
158                                           /*InitArgs=*/{});
159   appendToGlobalCtors(M, HwasanCtorFunction, 0);
160   return true;
161 }
162
163 void HWAddressSanitizer::initializeCallbacks(Module &M) {
164   IRBuilder<> IRB(*C);
165   for (size_t AccessIsWrite = 0; AccessIsWrite <= 1; AccessIsWrite++) {
166     const std::string TypeStr = AccessIsWrite ? "store" : "load";
167     const std::string EndingStr = Recover ? "_noabort" : "";
168
169     HwasanMemoryAccessCallbackSized[AccessIsWrite] =
170         checkSanitizerInterfaceFunction(M.getOrInsertFunction(
171             ClMemoryAccessCallbackPrefix + TypeStr + EndingStr,
172             FunctionType::get(IRB.getVoidTy(), {IntptrTy, IntptrTy}, false)));
173
174     for (size_t AccessSizeIndex = 0; AccessSizeIndex < kNumberOfAccessSizes;
175          AccessSizeIndex++) {
176       HwasanMemoryAccessCallback[AccessIsWrite][AccessSizeIndex] =
177           checkSanitizerInterfaceFunction(M.getOrInsertFunction(
178               ClMemoryAccessCallbackPrefix + TypeStr +
179                   itostr(1ULL << AccessSizeIndex) + EndingStr,
180               FunctionType::get(IRB.getVoidTy(), {IntptrTy}, false)));
181     }
182   }
183 }
184
185 Value *HWAddressSanitizer::isInterestingMemoryAccess(Instruction *I,
186                                                    bool *IsWrite,
187                                                    uint64_t *TypeSize,
188                                                    unsigned *Alignment,
189                                                    Value **MaybeMask) {
190   // Skip memory accesses inserted by another instrumentation.
191   if (I->getMetadata("nosanitize")) return nullptr;
192
193   Value *PtrOperand = nullptr;
194   const DataLayout &DL = I->getModule()->getDataLayout();
195   if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
196     if (!ClInstrumentReads) return nullptr;
197     *IsWrite = false;
198     *TypeSize = DL.getTypeStoreSizeInBits(LI->getType());
199     *Alignment = LI->getAlignment();
200     PtrOperand = LI->getPointerOperand();
201   } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
202     if (!ClInstrumentWrites) return nullptr;
203     *IsWrite = true;
204     *TypeSize = DL.getTypeStoreSizeInBits(SI->getValueOperand()->getType());
205     *Alignment = SI->getAlignment();
206     PtrOperand = SI->getPointerOperand();
207   } else if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(I)) {
208     if (!ClInstrumentAtomics) return nullptr;
209     *IsWrite = true;
210     *TypeSize = DL.getTypeStoreSizeInBits(RMW->getValOperand()->getType());
211     *Alignment = 0;
212     PtrOperand = RMW->getPointerOperand();
213   } else if (AtomicCmpXchgInst *XCHG = dyn_cast<AtomicCmpXchgInst>(I)) {
214     if (!ClInstrumentAtomics) return nullptr;
215     *IsWrite = true;
216     *TypeSize = DL.getTypeStoreSizeInBits(XCHG->getCompareOperand()->getType());
217     *Alignment = 0;
218     PtrOperand = XCHG->getPointerOperand();
219   }
220
221   if (PtrOperand) {
222     // Do not instrument acesses from different address spaces; we cannot deal
223     // with them.
224     Type *PtrTy = cast<PointerType>(PtrOperand->getType()->getScalarType());
225     if (PtrTy->getPointerAddressSpace() != 0)
226       return nullptr;
227
228     // Ignore swifterror addresses.
229     // swifterror memory addresses are mem2reg promoted by instruction
230     // selection. As such they cannot have regular uses like an instrumentation
231     // function and it makes no sense to track them as memory.
232     if (PtrOperand->isSwiftError())
233       return nullptr;
234   }
235
236   return PtrOperand;
237 }
238
239 static size_t TypeSizeToSizeIndex(uint32_t TypeSize) {
240   size_t Res = countTrailingZeros(TypeSize / 8);
241   assert(Res < kNumberOfAccessSizes);
242   return Res;
243 }
244
245 void HWAddressSanitizer::instrumentMemAccessInline(Value *PtrLong, bool IsWrite,
246                                                    unsigned AccessSizeIndex,
247                                                    Instruction *InsertBefore) {
248   IRBuilder<> IRB(InsertBefore);
249   Value *PtrTag = IRB.CreateTrunc(IRB.CreateLShr(PtrLong, kPointerTagShift), IRB.getInt8Ty());
250   Value *AddrLong =
251       IRB.CreateAnd(PtrLong, ConstantInt::get(PtrLong->getType(),
252                                               ~(0xFFULL << kPointerTagShift)));
253   Value *ShadowLong = IRB.CreateLShr(AddrLong, kShadowScale);
254   Value *MemTag = IRB.CreateLoad(IRB.CreateIntToPtr(ShadowLong, IRB.getInt8PtrTy()));
255   Value *TagMismatch = IRB.CreateICmpNE(PtrTag, MemTag);
256
257   TerminatorInst *CheckTerm =
258       SplitBlockAndInsertIfThen(TagMismatch, InsertBefore, !Recover,
259                                 MDBuilder(*C).createBranchWeights(1, 100000));
260
261   IRB.SetInsertPoint(CheckTerm);
262   // The signal handler will find the data address in x0.
263   InlineAsm *Asm = InlineAsm::get(
264       FunctionType::get(IRB.getVoidTy(), {PtrLong->getType()}, false),
265       "hlt #" +
266           itostr(0x100 + Recover * 0x20 + IsWrite * 0x10 + AccessSizeIndex),
267       "{x0}",
268       /*hasSideEffects=*/true);
269   IRB.CreateCall(Asm, PtrLong);
270 }
271
272 bool HWAddressSanitizer::instrumentMemAccess(Instruction *I) {
273   DEBUG(dbgs() << "Instrumenting: " << *I << "\n");
274   bool IsWrite = false;
275   unsigned Alignment = 0;
276   uint64_t TypeSize = 0;
277   Value *MaybeMask = nullptr;
278   Value *Addr =
279       isInterestingMemoryAccess(I, &IsWrite, &TypeSize, &Alignment, &MaybeMask);
280
281   if (!Addr)
282     return false;
283
284   if (MaybeMask)
285     return false; //FIXME
286
287   IRBuilder<> IRB(I);
288   Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy);
289   if (isPowerOf2_64(TypeSize) &&
290       (TypeSize / 8 <= (1UL << (kNumberOfAccessSizes - 1))) &&
291       (Alignment >= (1UL << kShadowScale) || Alignment == 0 ||
292        Alignment >= TypeSize / 8)) {
293     size_t AccessSizeIndex = TypeSizeToSizeIndex(TypeSize);
294     if (ClInstrumentWithCalls) {
295       IRB.CreateCall(HwasanMemoryAccessCallback[IsWrite][AccessSizeIndex],
296                      AddrLong);
297     } else {
298       instrumentMemAccessInline(AddrLong, IsWrite, AccessSizeIndex, I);
299     }
300   } else {
301     IRB.CreateCall(HwasanMemoryAccessCallbackSized[IsWrite],
302                    {AddrLong, ConstantInt::get(IntptrTy, TypeSize / 8)});
303   }
304
305   return true;
306 }
307
308 bool HWAddressSanitizer::runOnFunction(Function &F) {
309   if (&F == HwasanCtorFunction)
310     return false;
311
312   if (!F.hasFnAttribute(Attribute::SanitizeHWAddress))
313     return false;
314
315   DEBUG(dbgs() << "Function: " << F.getName() << "\n");
316
317   initializeCallbacks(*F.getParent());
318
319   bool Changed = false;
320   SmallVector<Instruction*, 16> ToInstrument;
321   for (auto &BB : F) {
322     for (auto &Inst : BB) {
323       Value *MaybeMask = nullptr;
324       bool IsWrite;
325       unsigned Alignment;
326       uint64_t TypeSize;
327       Value *Addr = isInterestingMemoryAccess(&Inst, &IsWrite, &TypeSize,
328                                               &Alignment, &MaybeMask);
329       if (Addr || isa<MemIntrinsic>(Inst))
330         ToInstrument.push_back(&Inst);
331     }
332   }
333
334   for (auto Inst : ToInstrument)
335     Changed |= instrumentMemAccess(Inst);
336
337   return Changed;
338 }