blob: 3da9fe7e20174409fbab63a5809839ed4056db82 [file] [log] [blame]
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +00001//===- 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/Function.h"
26#include "llvm/IR/IRBuilder.h"
27#include "llvm/IR/InlineAsm.h"
28#include "llvm/IR/InstVisitor.h"
29#include "llvm/IR/Instruction.h"
30#include "llvm/IR/Instructions.h"
31#include "llvm/IR/IntrinsicInst.h"
32#include "llvm/IR/Intrinsics.h"
33#include "llvm/IR/LLVMContext.h"
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +000034#include "llvm/IR/MDBuilder.h"
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +000035#include "llvm/IR/Module.h"
36#include "llvm/IR/Type.h"
37#include "llvm/IR/Value.h"
38#include "llvm/Pass.h"
39#include "llvm/Support/Casting.h"
40#include "llvm/Support/CommandLine.h"
41#include "llvm/Support/Debug.h"
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +000042#include "llvm/Support/raw_ostream.h"
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +000043#include "llvm/Transforms/Instrumentation.h"
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +000044#include "llvm/Transforms/Utils/BasicBlockUtils.h"
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +000045#include "llvm/Transforms/Utils/ModuleUtils.h"
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +000046#include "llvm/Transforms/Utils/PromoteMemToReg.h"
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +000047
48using namespace llvm;
49
50#define DEBUG_TYPE "hwasan"
51
52static const char *const kHwasanModuleCtorName = "hwasan.module_ctor";
53static const char *const kHwasanInitName = "__hwasan_init";
54
55// Accesses sizes are powers of two: 1, 2, 4, 8, 16.
56static const size_t kNumberOfAccessSizes = 5;
57
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +000058static const size_t kShadowScale = 4;
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +000059static const unsigned kAllocaAlignment = 1U << kShadowScale;
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +000060static const unsigned kPointerTagShift = 56;
61
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +000062static cl::opt<std::string> ClMemoryAccessCallbackPrefix(
63 "hwasan-memory-access-callback-prefix",
64 cl::desc("Prefix for memory access callbacks"), cl::Hidden,
65 cl::init("__hwasan_"));
66
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +000067static cl::opt<bool>
68 ClInstrumentWithCalls("hwasan-instrument-with-calls",
69 cl::desc("instrument reads and writes with callbacks"),
70 cl::Hidden, cl::init(false));
71
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +000072static cl::opt<bool> ClInstrumentReads("hwasan-instrument-reads",
73 cl::desc("instrument read instructions"),
74 cl::Hidden, cl::init(true));
75
76static cl::opt<bool> ClInstrumentWrites(
77 "hwasan-instrument-writes", cl::desc("instrument write instructions"),
78 cl::Hidden, cl::init(true));
79
80static cl::opt<bool> ClInstrumentAtomics(
81 "hwasan-instrument-atomics",
82 cl::desc("instrument atomic instructions (rmw, cmpxchg)"), cl::Hidden,
83 cl::init(true));
84
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +000085static cl::opt<bool> ClRecover(
86 "hwasan-recover",
87 cl::desc("Enable recovery mode (continue-after-error)."),
88 cl::Hidden, cl::init(false));
89
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +000090static cl::opt<bool> ClInstrumentStack("hwasan-instrument-stack",
91 cl::desc("instrument stack (allocas)"),
92 cl::Hidden, cl::init(true));
93
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +000094static cl::opt<bool> ClGenerateTagsWithCalls(
95 "hwasan-generate-tags-with-calls",
96 cl::desc("generate new tags with runtime library calls"), cl::Hidden,
97 cl::init(false));
98
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +000099namespace {
100
101/// \brief An instrumentation pass implementing detection of addressability bugs
102/// using tagged pointers.
103class HWAddressSanitizer : public FunctionPass {
104public:
105 // Pass identification, replacement for typeid.
106 static char ID;
107
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000108 HWAddressSanitizer(bool Recover = false)
109 : FunctionPass(ID), Recover(Recover || ClRecover) {}
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000110
111 StringRef getPassName() const override { return "HWAddressSanitizer"; }
112
113 bool runOnFunction(Function &F) override;
114 bool doInitialization(Module &M) override;
115
116 void initializeCallbacks(Module &M);
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000117 void instrumentMemAccessInline(Value *PtrLong, bool IsWrite,
118 unsigned AccessSizeIndex,
119 Instruction *InsertBefore);
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000120 bool instrumentMemAccess(Instruction *I);
121 Value *isInterestingMemoryAccess(Instruction *I, bool *IsWrite,
122 uint64_t *TypeSize, unsigned *Alignment,
123 Value **MaybeMask);
124
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000125 bool isInterestingAlloca(const AllocaInst &AI);
126 bool tagAlloca(IRBuilder<> &IRB, AllocaInst *AI, Value *Tag);
127 bool instrumentStack(SmallVectorImpl<AllocaInst *> &Allocas,
128 SmallVectorImpl<Instruction *> &RetVec);
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000129 Value *getNextTagWithCall(IRBuilder<> &IRB);
130 Value *getStackBaseTag(IRBuilder<> &IRB);
131 Value *getAllocaTag(IRBuilder<> &IRB, Value *StackTag, AllocaInst *AI,
132 unsigned AllocaNo);
133 Value *getUARTag(IRBuilder<> &IRB, Value *StackTag);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000134
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000135private:
136 LLVMContext *C;
137 Type *IntptrTy;
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000138 Type *Int8Ty;
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000139
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000140 bool Recover;
141
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000142 Function *HwasanCtorFunction;
143
144 Function *HwasanMemoryAccessCallback[2][kNumberOfAccessSizes];
145 Function *HwasanMemoryAccessCallbackSized[2];
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000146
147 Function *HwasanTagMemoryFunc;
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000148 Function *HwasanGenerateTagFunc;
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000149};
150
151} // end anonymous namespace
152
153char HWAddressSanitizer::ID = 0;
154
155INITIALIZE_PASS_BEGIN(
156 HWAddressSanitizer, "hwasan",
157 "HWAddressSanitizer: detect memory bugs using tagged addressing.", false, false)
158INITIALIZE_PASS_END(
159 HWAddressSanitizer, "hwasan",
160 "HWAddressSanitizer: detect memory bugs using tagged addressing.", false, false)
161
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000162FunctionPass *llvm::createHWAddressSanitizerPass(bool Recover) {
163 return new HWAddressSanitizer(Recover);
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000164}
165
166/// \brief Module-level initialization.
167///
168/// inserts a call to __hwasan_init to the module's constructor list.
169bool HWAddressSanitizer::doInitialization(Module &M) {
170 DEBUG(dbgs() << "Init " << M.getName() << "\n");
171 auto &DL = M.getDataLayout();
172
173 Triple TargetTriple(M.getTargetTriple());
174
175 C = &(M.getContext());
176 IRBuilder<> IRB(*C);
177 IntptrTy = IRB.getIntPtrTy(DL);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000178 Int8Ty = IRB.getInt8Ty();
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000179
180 std::tie(HwasanCtorFunction, std::ignore) =
181 createSanitizerCtorAndInitFunctions(M, kHwasanModuleCtorName,
182 kHwasanInitName,
183 /*InitArgTypes=*/{},
184 /*InitArgs=*/{});
185 appendToGlobalCtors(M, HwasanCtorFunction, 0);
186 return true;
187}
188
189void HWAddressSanitizer::initializeCallbacks(Module &M) {
190 IRBuilder<> IRB(*C);
191 for (size_t AccessIsWrite = 0; AccessIsWrite <= 1; AccessIsWrite++) {
192 const std::string TypeStr = AccessIsWrite ? "store" : "load";
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000193 const std::string EndingStr = Recover ? "_noabort" : "";
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000194
195 HwasanMemoryAccessCallbackSized[AccessIsWrite] =
196 checkSanitizerInterfaceFunction(M.getOrInsertFunction(
Evgeniy Stepanovc07e0bd2018-01-16 23:15:08 +0000197 ClMemoryAccessCallbackPrefix + TypeStr + "N" + EndingStr,
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000198 FunctionType::get(IRB.getVoidTy(), {IntptrTy, IntptrTy}, false)));
199
200 for (size_t AccessSizeIndex = 0; AccessSizeIndex < kNumberOfAccessSizes;
201 AccessSizeIndex++) {
202 HwasanMemoryAccessCallback[AccessIsWrite][AccessSizeIndex] =
203 checkSanitizerInterfaceFunction(M.getOrInsertFunction(
204 ClMemoryAccessCallbackPrefix + TypeStr +
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000205 itostr(1ULL << AccessSizeIndex) + EndingStr,
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000206 FunctionType::get(IRB.getVoidTy(), {IntptrTy}, false)));
207 }
208 }
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000209
210 HwasanTagMemoryFunc = checkSanitizerInterfaceFunction(M.getOrInsertFunction(
211 "__hwasan_tag_memory", IRB.getVoidTy(), IntptrTy, Int8Ty, IntptrTy));
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000212 HwasanGenerateTagFunc = checkSanitizerInterfaceFunction(
213 M.getOrInsertFunction("__hwasan_generate_tag", Int8Ty));
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000214}
215
216Value *HWAddressSanitizer::isInterestingMemoryAccess(Instruction *I,
217 bool *IsWrite,
218 uint64_t *TypeSize,
219 unsigned *Alignment,
220 Value **MaybeMask) {
221 // Skip memory accesses inserted by another instrumentation.
222 if (I->getMetadata("nosanitize")) return nullptr;
223
224 Value *PtrOperand = nullptr;
225 const DataLayout &DL = I->getModule()->getDataLayout();
226 if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
227 if (!ClInstrumentReads) return nullptr;
228 *IsWrite = false;
229 *TypeSize = DL.getTypeStoreSizeInBits(LI->getType());
230 *Alignment = LI->getAlignment();
231 PtrOperand = LI->getPointerOperand();
232 } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
233 if (!ClInstrumentWrites) return nullptr;
234 *IsWrite = true;
235 *TypeSize = DL.getTypeStoreSizeInBits(SI->getValueOperand()->getType());
236 *Alignment = SI->getAlignment();
237 PtrOperand = SI->getPointerOperand();
238 } else if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(I)) {
239 if (!ClInstrumentAtomics) return nullptr;
240 *IsWrite = true;
241 *TypeSize = DL.getTypeStoreSizeInBits(RMW->getValOperand()->getType());
242 *Alignment = 0;
243 PtrOperand = RMW->getPointerOperand();
244 } else if (AtomicCmpXchgInst *XCHG = dyn_cast<AtomicCmpXchgInst>(I)) {
245 if (!ClInstrumentAtomics) return nullptr;
246 *IsWrite = true;
247 *TypeSize = DL.getTypeStoreSizeInBits(XCHG->getCompareOperand()->getType());
248 *Alignment = 0;
249 PtrOperand = XCHG->getPointerOperand();
250 }
251
252 if (PtrOperand) {
253 // Do not instrument acesses from different address spaces; we cannot deal
254 // with them.
255 Type *PtrTy = cast<PointerType>(PtrOperand->getType()->getScalarType());
256 if (PtrTy->getPointerAddressSpace() != 0)
257 return nullptr;
258
259 // Ignore swifterror addresses.
260 // swifterror memory addresses are mem2reg promoted by instruction
261 // selection. As such they cannot have regular uses like an instrumentation
262 // function and it makes no sense to track them as memory.
263 if (PtrOperand->isSwiftError())
264 return nullptr;
265 }
266
267 return PtrOperand;
268}
269
270static size_t TypeSizeToSizeIndex(uint32_t TypeSize) {
271 size_t Res = countTrailingZeros(TypeSize / 8);
272 assert(Res < kNumberOfAccessSizes);
273 return Res;
274}
275
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000276void HWAddressSanitizer::instrumentMemAccessInline(Value *PtrLong, bool IsWrite,
277 unsigned AccessSizeIndex,
278 Instruction *InsertBefore) {
279 IRBuilder<> IRB(InsertBefore);
280 Value *PtrTag = IRB.CreateTrunc(IRB.CreateLShr(PtrLong, kPointerTagShift), IRB.getInt8Ty());
281 Value *AddrLong =
282 IRB.CreateAnd(PtrLong, ConstantInt::get(PtrLong->getType(),
283 ~(0xFFULL << kPointerTagShift)));
284 Value *ShadowLong = IRB.CreateLShr(AddrLong, kShadowScale);
285 Value *MemTag = IRB.CreateLoad(IRB.CreateIntToPtr(ShadowLong, IRB.getInt8PtrTy()));
286 Value *TagMismatch = IRB.CreateICmpNE(PtrTag, MemTag);
287
288 TerminatorInst *CheckTerm =
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000289 SplitBlockAndInsertIfThen(TagMismatch, InsertBefore, !Recover,
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000290 MDBuilder(*C).createBranchWeights(1, 100000));
291
292 IRB.SetInsertPoint(CheckTerm);
293 // The signal handler will find the data address in x0.
294 InlineAsm *Asm = InlineAsm::get(
295 FunctionType::get(IRB.getVoidTy(), {PtrLong->getType()}, false),
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000296 "hlt #" +
297 itostr(0x100 + Recover * 0x20 + IsWrite * 0x10 + AccessSizeIndex),
298 "{x0}",
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000299 /*hasSideEffects=*/true);
300 IRB.CreateCall(Asm, PtrLong);
301}
302
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000303bool HWAddressSanitizer::instrumentMemAccess(Instruction *I) {
304 DEBUG(dbgs() << "Instrumenting: " << *I << "\n");
305 bool IsWrite = false;
306 unsigned Alignment = 0;
307 uint64_t TypeSize = 0;
308 Value *MaybeMask = nullptr;
309 Value *Addr =
310 isInterestingMemoryAccess(I, &IsWrite, &TypeSize, &Alignment, &MaybeMask);
311
312 if (!Addr)
313 return false;
314
315 if (MaybeMask)
316 return false; //FIXME
317
318 IRBuilder<> IRB(I);
319 Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy);
320 if (isPowerOf2_64(TypeSize) &&
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000321 (TypeSize / 8 <= (1UL << (kNumberOfAccessSizes - 1))) &&
322 (Alignment >= (1UL << kShadowScale) || Alignment == 0 ||
323 Alignment >= TypeSize / 8)) {
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000324 size_t AccessSizeIndex = TypeSizeToSizeIndex(TypeSize);
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000325 if (ClInstrumentWithCalls) {
326 IRB.CreateCall(HwasanMemoryAccessCallback[IsWrite][AccessSizeIndex],
327 AddrLong);
328 } else {
329 instrumentMemAccessInline(AddrLong, IsWrite, AccessSizeIndex, I);
330 }
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000331 } else {
332 IRB.CreateCall(HwasanMemoryAccessCallbackSized[IsWrite],
333 {AddrLong, ConstantInt::get(IntptrTy, TypeSize / 8)});
334 }
335
336 return true;
337}
338
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000339static uint64_t getAllocaSizeInBytes(const AllocaInst &AI) {
340 uint64_t ArraySize = 1;
341 if (AI.isArrayAllocation()) {
342 const ConstantInt *CI = dyn_cast<ConstantInt>(AI.getArraySize());
343 assert(CI && "non-constant array size");
344 ArraySize = CI->getZExtValue();
345 }
346 Type *Ty = AI.getAllocatedType();
347 uint64_t SizeInBytes = AI.getModule()->getDataLayout().getTypeAllocSize(Ty);
348 return SizeInBytes * ArraySize;
349}
350
351bool HWAddressSanitizer::tagAlloca(IRBuilder<> &IRB, AllocaInst *AI,
352 Value *Tag) {
353 size_t Size = (getAllocaSizeInBytes(*AI) + kAllocaAlignment - 1) &
354 ~(kAllocaAlignment - 1);
355
356 Value *JustTag = IRB.CreateTrunc(Tag, IRB.getInt8Ty());
357 if (ClInstrumentWithCalls) {
358 IRB.CreateCall(HwasanTagMemoryFunc,
359 {IRB.CreatePointerCast(AI, IntptrTy), JustTag,
360 ConstantInt::get(IntptrTy, Size)});
361 } else {
362 size_t ShadowSize = Size >> kShadowScale;
363 Value *ShadowPtr = IRB.CreateIntToPtr(
364 IRB.CreateLShr(IRB.CreatePointerCast(AI, IntptrTy), kShadowScale),
365 IRB.getInt8PtrTy());
366 // If this memset is not inlined, it will be intercepted in the hwasan
367 // runtime library. That's OK, because the interceptor skips the checks if
368 // the address is in the shadow region.
369 // FIXME: the interceptor is not as fast as real memset. Consider lowering
370 // llvm.memset right here into either a sequence of stores, or a call to
371 // hwasan_tag_memory.
372 IRB.CreateMemSet(ShadowPtr, JustTag, ShadowSize, /*Align=*/1);
373 }
374 return true;
375}
376
377static unsigned RetagMask(unsigned AllocaNo) {
378 // A list of 8-bit numbers that have at most one run of non-zero bits.
379 // x = x ^ (mask << 56) can be encoded as a single armv8 instruction for these
380 // masks.
381 // The list does not include the value 255, which is used for UAR.
382 static unsigned FastMasks[] = {
383 0, 1, 2, 3, 4, 6, 7, 8, 12, 14, 15, 16, 24,
384 28, 30, 31, 32, 48, 56, 60, 62, 63, 64, 96, 112, 120,
385 124, 126, 127, 128, 192, 224, 240, 248, 252, 254};
386 return FastMasks[AllocaNo % (sizeof(FastMasks) / sizeof(FastMasks[0]))];
387}
388
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000389Value *HWAddressSanitizer::getNextTagWithCall(IRBuilder<> &IRB) {
390 return IRB.CreateZExt(IRB.CreateCall(HwasanGenerateTagFunc), IntptrTy);
391}
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000392
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000393Value *HWAddressSanitizer::getStackBaseTag(IRBuilder<> &IRB) {
394 if (ClGenerateTagsWithCalls)
395 return nullptr;
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000396 // FIXME: use addressofreturnaddress (but implement it in aarch64 backend
397 // first).
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000398 Module *M = IRB.GetInsertBlock()->getParent()->getParent();
399 auto GetStackPointerFn =
400 Intrinsic::getDeclaration(M, Intrinsic::frameaddress);
401 Value *StackPointer = IRB.CreateCall(
402 GetStackPointerFn, {Constant::getNullValue(IRB.getInt32Ty())});
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000403
404 // Extract some entropy from the stack pointer for the tags.
405 // Take bits 20..28 (ASLR entropy) and xor with bits 0..8 (these differ
406 // between functions).
407 Value *StackPointerLong = IRB.CreatePointerCast(StackPointer, IntptrTy);
408 Value *StackTag =
409 IRB.CreateXor(StackPointerLong, IRB.CreateLShr(StackPointerLong, 20),
410 "hwasan.stack.base.tag");
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000411 return StackTag;
412}
413
414Value *HWAddressSanitizer::getAllocaTag(IRBuilder<> &IRB, Value *StackTag,
415 AllocaInst *AI, unsigned AllocaNo) {
416 if (ClGenerateTagsWithCalls)
417 return getNextTagWithCall(IRB);
418 return IRB.CreateXor(StackTag,
419 ConstantInt::get(IntptrTy, RetagMask(AllocaNo)));
420}
421
422Value *HWAddressSanitizer::getUARTag(IRBuilder<> &IRB, Value *StackTag) {
423 if (ClGenerateTagsWithCalls)
424 return getNextTagWithCall(IRB);
425 return IRB.CreateXor(StackTag, ConstantInt::get(IntptrTy, 0xFFU));
426}
427
428bool HWAddressSanitizer::instrumentStack(
429 SmallVectorImpl<AllocaInst *> &Allocas,
430 SmallVectorImpl<Instruction *> &RetVec) {
431 Function *F = Allocas[0]->getParent()->getParent();
432 Instruction *InsertPt = &*F->getEntryBlock().begin();
433 IRBuilder<> IRB(InsertPt);
434
435 Value *StackTag = getStackBaseTag(IRB);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000436
437 // Ideally, we want to calculate tagged stack base pointer, and rewrite all
438 // alloca addresses using that. Unfortunately, offsets are not known yet
439 // (unless we use ASan-style mega-alloca). Instead we keep the base tag in a
440 // temp, shift-OR it into each alloca address and xor with the retag mask.
441 // This generates one extra instruction per alloca use.
442 for (unsigned N = 0; N < Allocas.size(); ++N) {
443 auto *AI = Allocas[N];
444 IRB.SetInsertPoint(AI->getNextNode());
445
446 // Replace uses of the alloca with tagged address.
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000447 Value *Tag = getAllocaTag(IRB, StackTag, AI, N);
448 Value *AILong = IRB.CreatePointerCast(AI, IntptrTy);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000449 std::string Name =
450 AI->hasName() ? AI->getName().str() : "alloca." + itostr(N);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000451 Value *Replacement = IRB.CreateIntToPtr(
452 IRB.CreateOr(AILong, IRB.CreateShl(Tag, kPointerTagShift)),
453 AI->getType(), Name + ".hwasan");
454
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000455 for (auto UI = AI->use_begin(), UE = AI->use_end(); UI != UE;) {
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000456 Use &U = *UI++;
457 if (U.getUser() != AILong)
458 U.set(Replacement);
459 }
460
461 tagAlloca(IRB, AI, Tag);
462
463 for (auto RI : RetVec) {
464 IRB.SetInsertPoint(RI);
465
466 // Re-tag alloca memory with the special UAR tag.
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000467 Value *Tag = getUARTag(IRB, StackTag);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000468 tagAlloca(IRB, AI, Tag);
469 }
470 }
471
472 return true;
473}
474
475bool HWAddressSanitizer::isInterestingAlloca(const AllocaInst &AI) {
476 return (AI.getAllocatedType()->isSized() &&
477 // FIXME: instrument dynamic allocas, too
478 AI.isStaticAlloca() &&
479 // alloca() may be called with 0 size, ignore it.
480 getAllocaSizeInBytes(AI) > 0 &&
481 // We are only interested in allocas not promotable to registers.
482 // Promotable allocas are common under -O0.
483 !isAllocaPromotable(&AI) &&
484 // inalloca allocas are not treated as static, and we don't want
485 // dynamic alloca instrumentation for them as well.
486 !AI.isUsedWithInAlloca() &&
487 // swifterror allocas are register promoted by ISel
488 !AI.isSwiftError());
489}
490
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000491bool HWAddressSanitizer::runOnFunction(Function &F) {
492 if (&F == HwasanCtorFunction)
493 return false;
494
495 if (!F.hasFnAttribute(Attribute::SanitizeHWAddress))
496 return false;
497
498 DEBUG(dbgs() << "Function: " << F.getName() << "\n");
499
500 initializeCallbacks(*F.getParent());
501
502 bool Changed = false;
503 SmallVector<Instruction*, 16> ToInstrument;
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000504 SmallVector<AllocaInst*, 8> AllocasToInstrument;
505 SmallVector<Instruction*, 8> RetVec;
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000506 for (auto &BB : F) {
507 for (auto &Inst : BB) {
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000508 if (ClInstrumentStack)
509 if (AllocaInst *AI = dyn_cast<AllocaInst>(&Inst)) {
510 // Realign all allocas. We don't want small uninteresting allocas to
511 // hide in instrumented alloca's padding.
512 if (AI->getAlignment() < kAllocaAlignment)
513 AI->setAlignment(kAllocaAlignment);
514 // Instrument some of them.
515 if (isInterestingAlloca(*AI))
516 AllocasToInstrument.push_back(AI);
517 continue;
518 }
519
520 if (isa<ReturnInst>(Inst) || isa<ResumeInst>(Inst) || isa<CleanupReturnInst>(Inst))
521 RetVec.push_back(&Inst);
522
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000523 Value *MaybeMask = nullptr;
524 bool IsWrite;
525 unsigned Alignment;
526 uint64_t TypeSize;
527 Value *Addr = isInterestingMemoryAccess(&Inst, &IsWrite, &TypeSize,
528 &Alignment, &MaybeMask);
529 if (Addr || isa<MemIntrinsic>(Inst))
530 ToInstrument.push_back(&Inst);
531 }
532 }
533
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000534 if (!AllocasToInstrument.empty())
535 Changed |= instrumentStack(AllocasToInstrument, RetVec);
536
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000537 for (auto Inst : ToInstrument)
538 Changed |= instrumentMemAccess(Inst);
539
540 return Changed;
541}