blob: 15d97b3ae6f68aafe00bedf3f50126ca972f05d2 [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 Stepanov5bd669d2018-01-17 23:24:38 +000099static cl::opt<unsigned long long> ClMappingOffset(
100 "hwasan-mapping-offset",
101 cl::desc("offset of hwasan shadow mapping [EXPERIMENTAL]"), cl::Hidden,
102 cl::init(0));
103
104static cl::opt<bool> ClEnableKhwasan(
105 "hwasan-kernel", cl::desc("Enable KernelHWAddressSanitizer instrumentation"),
106 cl::Hidden, cl::init(false));
107
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000108namespace {
109
110/// \brief An instrumentation pass implementing detection of addressability bugs
111/// using tagged pointers.
112class HWAddressSanitizer : public FunctionPass {
113public:
114 // Pass identification, replacement for typeid.
115 static char ID;
116
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000117 HWAddressSanitizer(bool Recover = false)
118 : FunctionPass(ID), Recover(Recover || ClRecover) {}
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000119
120 StringRef getPassName() const override { return "HWAddressSanitizer"; }
121
122 bool runOnFunction(Function &F) override;
123 bool doInitialization(Module &M) override;
124
125 void initializeCallbacks(Module &M);
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000126 void instrumentMemAccessInline(Value *PtrLong, bool IsWrite,
127 unsigned AccessSizeIndex,
128 Instruction *InsertBefore);
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000129 bool instrumentMemAccess(Instruction *I);
130 Value *isInterestingMemoryAccess(Instruction *I, bool *IsWrite,
131 uint64_t *TypeSize, unsigned *Alignment,
132 Value **MaybeMask);
133
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000134 bool isInterestingAlloca(const AllocaInst &AI);
135 bool tagAlloca(IRBuilder<> &IRB, AllocaInst *AI, Value *Tag);
136 bool instrumentStack(SmallVectorImpl<AllocaInst *> &Allocas,
137 SmallVectorImpl<Instruction *> &RetVec);
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000138 Value *getNextTagWithCall(IRBuilder<> &IRB);
139 Value *getStackBaseTag(IRBuilder<> &IRB);
140 Value *getAllocaTag(IRBuilder<> &IRB, Value *StackTag, AllocaInst *AI,
141 unsigned AllocaNo);
142 Value *getUARTag(IRBuilder<> &IRB, Value *StackTag);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000143
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000144private:
145 LLVMContext *C;
146 Type *IntptrTy;
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000147 Type *Int8Ty;
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000148
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000149 bool Recover;
150
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000151 Function *HwasanCtorFunction;
152
153 Function *HwasanMemoryAccessCallback[2][kNumberOfAccessSizes];
154 Function *HwasanMemoryAccessCallbackSized[2];
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000155
156 Function *HwasanTagMemoryFunc;
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000157 Function *HwasanGenerateTagFunc;
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000158};
159
160} // end anonymous namespace
161
162char HWAddressSanitizer::ID = 0;
163
164INITIALIZE_PASS_BEGIN(
165 HWAddressSanitizer, "hwasan",
166 "HWAddressSanitizer: detect memory bugs using tagged addressing.", false, false)
167INITIALIZE_PASS_END(
168 HWAddressSanitizer, "hwasan",
169 "HWAddressSanitizer: detect memory bugs using tagged addressing.", false, false)
170
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000171FunctionPass *llvm::createHWAddressSanitizerPass(bool Recover) {
172 return new HWAddressSanitizer(Recover);
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000173}
174
175/// \brief Module-level initialization.
176///
177/// inserts a call to __hwasan_init to the module's constructor list.
178bool HWAddressSanitizer::doInitialization(Module &M) {
179 DEBUG(dbgs() << "Init " << M.getName() << "\n");
180 auto &DL = M.getDataLayout();
181
182 Triple TargetTriple(M.getTargetTriple());
183
184 C = &(M.getContext());
185 IRBuilder<> IRB(*C);
186 IntptrTy = IRB.getIntPtrTy(DL);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000187 Int8Ty = IRB.getInt8Ty();
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000188
Evgeniy Stepanov5bd669d2018-01-17 23:24:38 +0000189 if (!ClEnableKhwasan) {
190 std::tie(HwasanCtorFunction, std::ignore) =
191 createSanitizerCtorAndInitFunctions(M, kHwasanModuleCtorName,
192 kHwasanInitName,
193 /*InitArgTypes=*/{},
194 /*InitArgs=*/{});
195 appendToGlobalCtors(M, HwasanCtorFunction, 0);
196 }
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000197 return true;
198}
199
200void HWAddressSanitizer::initializeCallbacks(Module &M) {
201 IRBuilder<> IRB(*C);
202 for (size_t AccessIsWrite = 0; AccessIsWrite <= 1; AccessIsWrite++) {
203 const std::string TypeStr = AccessIsWrite ? "store" : "load";
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000204 const std::string EndingStr = Recover ? "_noabort" : "";
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000205
206 HwasanMemoryAccessCallbackSized[AccessIsWrite] =
207 checkSanitizerInterfaceFunction(M.getOrInsertFunction(
Evgeniy Stepanovc07e0bd2018-01-16 23:15:08 +0000208 ClMemoryAccessCallbackPrefix + TypeStr + "N" + EndingStr,
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000209 FunctionType::get(IRB.getVoidTy(), {IntptrTy, IntptrTy}, false)));
210
211 for (size_t AccessSizeIndex = 0; AccessSizeIndex < kNumberOfAccessSizes;
212 AccessSizeIndex++) {
213 HwasanMemoryAccessCallback[AccessIsWrite][AccessSizeIndex] =
214 checkSanitizerInterfaceFunction(M.getOrInsertFunction(
215 ClMemoryAccessCallbackPrefix + TypeStr +
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000216 itostr(1ULL << AccessSizeIndex) + EndingStr,
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000217 FunctionType::get(IRB.getVoidTy(), {IntptrTy}, false)));
218 }
219 }
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000220
221 HwasanTagMemoryFunc = checkSanitizerInterfaceFunction(M.getOrInsertFunction(
222 "__hwasan_tag_memory", IRB.getVoidTy(), IntptrTy, Int8Ty, IntptrTy));
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000223 HwasanGenerateTagFunc = checkSanitizerInterfaceFunction(
224 M.getOrInsertFunction("__hwasan_generate_tag", Int8Ty));
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000225}
226
227Value *HWAddressSanitizer::isInterestingMemoryAccess(Instruction *I,
228 bool *IsWrite,
229 uint64_t *TypeSize,
230 unsigned *Alignment,
231 Value **MaybeMask) {
232 // Skip memory accesses inserted by another instrumentation.
233 if (I->getMetadata("nosanitize")) return nullptr;
234
235 Value *PtrOperand = nullptr;
236 const DataLayout &DL = I->getModule()->getDataLayout();
237 if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
238 if (!ClInstrumentReads) return nullptr;
239 *IsWrite = false;
240 *TypeSize = DL.getTypeStoreSizeInBits(LI->getType());
241 *Alignment = LI->getAlignment();
242 PtrOperand = LI->getPointerOperand();
243 } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
244 if (!ClInstrumentWrites) return nullptr;
245 *IsWrite = true;
246 *TypeSize = DL.getTypeStoreSizeInBits(SI->getValueOperand()->getType());
247 *Alignment = SI->getAlignment();
248 PtrOperand = SI->getPointerOperand();
249 } else if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(I)) {
250 if (!ClInstrumentAtomics) return nullptr;
251 *IsWrite = true;
252 *TypeSize = DL.getTypeStoreSizeInBits(RMW->getValOperand()->getType());
253 *Alignment = 0;
254 PtrOperand = RMW->getPointerOperand();
255 } else if (AtomicCmpXchgInst *XCHG = dyn_cast<AtomicCmpXchgInst>(I)) {
256 if (!ClInstrumentAtomics) return nullptr;
257 *IsWrite = true;
258 *TypeSize = DL.getTypeStoreSizeInBits(XCHG->getCompareOperand()->getType());
259 *Alignment = 0;
260 PtrOperand = XCHG->getPointerOperand();
261 }
262
263 if (PtrOperand) {
264 // Do not instrument acesses from different address spaces; we cannot deal
265 // with them.
266 Type *PtrTy = cast<PointerType>(PtrOperand->getType()->getScalarType());
267 if (PtrTy->getPointerAddressSpace() != 0)
268 return nullptr;
269
270 // Ignore swifterror addresses.
271 // swifterror memory addresses are mem2reg promoted by instruction
272 // selection. As such they cannot have regular uses like an instrumentation
273 // function and it makes no sense to track them as memory.
274 if (PtrOperand->isSwiftError())
275 return nullptr;
276 }
277
278 return PtrOperand;
279}
280
281static size_t TypeSizeToSizeIndex(uint32_t TypeSize) {
282 size_t Res = countTrailingZeros(TypeSize / 8);
283 assert(Res < kNumberOfAccessSizes);
284 return Res;
285}
286
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000287void HWAddressSanitizer::instrumentMemAccessInline(Value *PtrLong, bool IsWrite,
288 unsigned AccessSizeIndex,
289 Instruction *InsertBefore) {
290 IRBuilder<> IRB(InsertBefore);
291 Value *PtrTag = IRB.CreateTrunc(IRB.CreateLShr(PtrLong, kPointerTagShift), IRB.getInt8Ty());
292 Value *AddrLong =
293 IRB.CreateAnd(PtrLong, ConstantInt::get(PtrLong->getType(),
294 ~(0xFFULL << kPointerTagShift)));
295 Value *ShadowLong = IRB.CreateLShr(AddrLong, kShadowScale);
Evgeniy Stepanov5bd669d2018-01-17 23:24:38 +0000296 if (ClMappingOffset)
297 ShadowLong = IRB.CreateAdd(
298 ShadowLong, ConstantInt::get(PtrLong->getType(), ClMappingOffset,
299 /*isSigned=*/false));
300 Value *MemTag =
301 IRB.CreateLoad(IRB.CreateIntToPtr(ShadowLong, IRB.getInt8PtrTy()));
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000302 Value *TagMismatch = IRB.CreateICmpNE(PtrTag, MemTag);
303
304 TerminatorInst *CheckTerm =
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000305 SplitBlockAndInsertIfThen(TagMismatch, InsertBefore, !Recover,
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000306 MDBuilder(*C).createBranchWeights(1, 100000));
307
308 IRB.SetInsertPoint(CheckTerm);
309 // The signal handler will find the data address in x0.
310 InlineAsm *Asm = InlineAsm::get(
311 FunctionType::get(IRB.getVoidTy(), {PtrLong->getType()}, false),
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000312 "hlt #" +
313 itostr(0x100 + Recover * 0x20 + IsWrite * 0x10 + AccessSizeIndex),
314 "{x0}",
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000315 /*hasSideEffects=*/true);
316 IRB.CreateCall(Asm, PtrLong);
317}
318
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000319bool HWAddressSanitizer::instrumentMemAccess(Instruction *I) {
320 DEBUG(dbgs() << "Instrumenting: " << *I << "\n");
321 bool IsWrite = false;
322 unsigned Alignment = 0;
323 uint64_t TypeSize = 0;
324 Value *MaybeMask = nullptr;
325 Value *Addr =
326 isInterestingMemoryAccess(I, &IsWrite, &TypeSize, &Alignment, &MaybeMask);
327
328 if (!Addr)
329 return false;
330
331 if (MaybeMask)
332 return false; //FIXME
333
334 IRBuilder<> IRB(I);
335 Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy);
336 if (isPowerOf2_64(TypeSize) &&
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000337 (TypeSize / 8 <= (1UL << (kNumberOfAccessSizes - 1))) &&
338 (Alignment >= (1UL << kShadowScale) || Alignment == 0 ||
339 Alignment >= TypeSize / 8)) {
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000340 size_t AccessSizeIndex = TypeSizeToSizeIndex(TypeSize);
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000341 if (ClInstrumentWithCalls) {
342 IRB.CreateCall(HwasanMemoryAccessCallback[IsWrite][AccessSizeIndex],
343 AddrLong);
344 } else {
345 instrumentMemAccessInline(AddrLong, IsWrite, AccessSizeIndex, I);
346 }
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000347 } else {
348 IRB.CreateCall(HwasanMemoryAccessCallbackSized[IsWrite],
349 {AddrLong, ConstantInt::get(IntptrTy, TypeSize / 8)});
350 }
351
352 return true;
353}
354
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000355static uint64_t getAllocaSizeInBytes(const AllocaInst &AI) {
356 uint64_t ArraySize = 1;
357 if (AI.isArrayAllocation()) {
358 const ConstantInt *CI = dyn_cast<ConstantInt>(AI.getArraySize());
359 assert(CI && "non-constant array size");
360 ArraySize = CI->getZExtValue();
361 }
362 Type *Ty = AI.getAllocatedType();
363 uint64_t SizeInBytes = AI.getModule()->getDataLayout().getTypeAllocSize(Ty);
364 return SizeInBytes * ArraySize;
365}
366
367bool HWAddressSanitizer::tagAlloca(IRBuilder<> &IRB, AllocaInst *AI,
368 Value *Tag) {
369 size_t Size = (getAllocaSizeInBytes(*AI) + kAllocaAlignment - 1) &
370 ~(kAllocaAlignment - 1);
371
372 Value *JustTag = IRB.CreateTrunc(Tag, IRB.getInt8Ty());
373 if (ClInstrumentWithCalls) {
374 IRB.CreateCall(HwasanTagMemoryFunc,
375 {IRB.CreatePointerCast(AI, IntptrTy), JustTag,
376 ConstantInt::get(IntptrTy, Size)});
377 } else {
378 size_t ShadowSize = Size >> kShadowScale;
379 Value *ShadowPtr = IRB.CreateIntToPtr(
380 IRB.CreateLShr(IRB.CreatePointerCast(AI, IntptrTy), kShadowScale),
381 IRB.getInt8PtrTy());
382 // If this memset is not inlined, it will be intercepted in the hwasan
383 // runtime library. That's OK, because the interceptor skips the checks if
384 // the address is in the shadow region.
385 // FIXME: the interceptor is not as fast as real memset. Consider lowering
386 // llvm.memset right here into either a sequence of stores, or a call to
387 // hwasan_tag_memory.
388 IRB.CreateMemSet(ShadowPtr, JustTag, ShadowSize, /*Align=*/1);
389 }
390 return true;
391}
392
393static unsigned RetagMask(unsigned AllocaNo) {
394 // A list of 8-bit numbers that have at most one run of non-zero bits.
395 // x = x ^ (mask << 56) can be encoded as a single armv8 instruction for these
396 // masks.
397 // The list does not include the value 255, which is used for UAR.
398 static unsigned FastMasks[] = {
399 0, 1, 2, 3, 4, 6, 7, 8, 12, 14, 15, 16, 24,
400 28, 30, 31, 32, 48, 56, 60, 62, 63, 64, 96, 112, 120,
401 124, 126, 127, 128, 192, 224, 240, 248, 252, 254};
402 return FastMasks[AllocaNo % (sizeof(FastMasks) / sizeof(FastMasks[0]))];
403}
404
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000405Value *HWAddressSanitizer::getNextTagWithCall(IRBuilder<> &IRB) {
406 return IRB.CreateZExt(IRB.CreateCall(HwasanGenerateTagFunc), IntptrTy);
407}
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000408
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000409Value *HWAddressSanitizer::getStackBaseTag(IRBuilder<> &IRB) {
410 if (ClGenerateTagsWithCalls)
411 return nullptr;
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000412 // FIXME: use addressofreturnaddress (but implement it in aarch64 backend
413 // first).
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000414 Module *M = IRB.GetInsertBlock()->getParent()->getParent();
415 auto GetStackPointerFn =
416 Intrinsic::getDeclaration(M, Intrinsic::frameaddress);
417 Value *StackPointer = IRB.CreateCall(
418 GetStackPointerFn, {Constant::getNullValue(IRB.getInt32Ty())});
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000419
420 // Extract some entropy from the stack pointer for the tags.
421 // Take bits 20..28 (ASLR entropy) and xor with bits 0..8 (these differ
422 // between functions).
423 Value *StackPointerLong = IRB.CreatePointerCast(StackPointer, IntptrTy);
424 Value *StackTag =
425 IRB.CreateXor(StackPointerLong, IRB.CreateLShr(StackPointerLong, 20),
426 "hwasan.stack.base.tag");
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000427 return StackTag;
428}
429
430Value *HWAddressSanitizer::getAllocaTag(IRBuilder<> &IRB, Value *StackTag,
431 AllocaInst *AI, unsigned AllocaNo) {
432 if (ClGenerateTagsWithCalls)
433 return getNextTagWithCall(IRB);
434 return IRB.CreateXor(StackTag,
435 ConstantInt::get(IntptrTy, RetagMask(AllocaNo)));
436}
437
438Value *HWAddressSanitizer::getUARTag(IRBuilder<> &IRB, Value *StackTag) {
439 if (ClGenerateTagsWithCalls)
440 return getNextTagWithCall(IRB);
441 return IRB.CreateXor(StackTag, ConstantInt::get(IntptrTy, 0xFFU));
442}
443
444bool HWAddressSanitizer::instrumentStack(
445 SmallVectorImpl<AllocaInst *> &Allocas,
446 SmallVectorImpl<Instruction *> &RetVec) {
447 Function *F = Allocas[0]->getParent()->getParent();
448 Instruction *InsertPt = &*F->getEntryBlock().begin();
449 IRBuilder<> IRB(InsertPt);
450
451 Value *StackTag = getStackBaseTag(IRB);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000452
453 // Ideally, we want to calculate tagged stack base pointer, and rewrite all
454 // alloca addresses using that. Unfortunately, offsets are not known yet
455 // (unless we use ASan-style mega-alloca). Instead we keep the base tag in a
456 // temp, shift-OR it into each alloca address and xor with the retag mask.
457 // This generates one extra instruction per alloca use.
458 for (unsigned N = 0; N < Allocas.size(); ++N) {
459 auto *AI = Allocas[N];
460 IRB.SetInsertPoint(AI->getNextNode());
461
462 // Replace uses of the alloca with tagged address.
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000463 Value *Tag = getAllocaTag(IRB, StackTag, AI, N);
464 Value *AILong = IRB.CreatePointerCast(AI, IntptrTy);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000465 std::string Name =
466 AI->hasName() ? AI->getName().str() : "alloca." + itostr(N);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000467 Value *Replacement = IRB.CreateIntToPtr(
468 IRB.CreateOr(AILong, IRB.CreateShl(Tag, kPointerTagShift)),
469 AI->getType(), Name + ".hwasan");
470
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000471 for (auto UI = AI->use_begin(), UE = AI->use_end(); UI != UE;) {
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000472 Use &U = *UI++;
473 if (U.getUser() != AILong)
474 U.set(Replacement);
475 }
476
477 tagAlloca(IRB, AI, Tag);
478
479 for (auto RI : RetVec) {
480 IRB.SetInsertPoint(RI);
481
482 // Re-tag alloca memory with the special UAR tag.
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000483 Value *Tag = getUARTag(IRB, StackTag);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000484 tagAlloca(IRB, AI, Tag);
485 }
486 }
487
488 return true;
489}
490
491bool HWAddressSanitizer::isInterestingAlloca(const AllocaInst &AI) {
492 return (AI.getAllocatedType()->isSized() &&
493 // FIXME: instrument dynamic allocas, too
494 AI.isStaticAlloca() &&
495 // alloca() may be called with 0 size, ignore it.
496 getAllocaSizeInBytes(AI) > 0 &&
497 // We are only interested in allocas not promotable to registers.
498 // Promotable allocas are common under -O0.
499 !isAllocaPromotable(&AI) &&
500 // inalloca allocas are not treated as static, and we don't want
501 // dynamic alloca instrumentation for them as well.
502 !AI.isUsedWithInAlloca() &&
503 // swifterror allocas are register promoted by ISel
504 !AI.isSwiftError());
505}
506
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000507bool HWAddressSanitizer::runOnFunction(Function &F) {
508 if (&F == HwasanCtorFunction)
509 return false;
510
511 if (!F.hasFnAttribute(Attribute::SanitizeHWAddress))
512 return false;
513
514 DEBUG(dbgs() << "Function: " << F.getName() << "\n");
515
516 initializeCallbacks(*F.getParent());
517
518 bool Changed = false;
519 SmallVector<Instruction*, 16> ToInstrument;
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000520 SmallVector<AllocaInst*, 8> AllocasToInstrument;
521 SmallVector<Instruction*, 8> RetVec;
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000522 for (auto &BB : F) {
523 for (auto &Inst : BB) {
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000524 if (ClInstrumentStack)
525 if (AllocaInst *AI = dyn_cast<AllocaInst>(&Inst)) {
526 // Realign all allocas. We don't want small uninteresting allocas to
527 // hide in instrumented alloca's padding.
528 if (AI->getAlignment() < kAllocaAlignment)
529 AI->setAlignment(kAllocaAlignment);
530 // Instrument some of them.
531 if (isInterestingAlloca(*AI))
532 AllocasToInstrument.push_back(AI);
533 continue;
534 }
535
536 if (isa<ReturnInst>(Inst) || isa<ResumeInst>(Inst) || isa<CleanupReturnInst>(Inst))
537 RetVec.push_back(&Inst);
538
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000539 Value *MaybeMask = nullptr;
540 bool IsWrite;
541 unsigned Alignment;
542 uint64_t TypeSize;
543 Value *Addr = isInterestingMemoryAccess(&Inst, &IsWrite, &TypeSize,
544 &Alignment, &MaybeMask);
545 if (Addr || isa<MemIntrinsic>(Inst))
546 ToInstrument.push_back(&Inst);
547 }
548 }
549
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000550 if (!AllocasToInstrument.empty())
551 Changed |= instrumentStack(AllocasToInstrument, RetVec);
552
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000553 for (auto Inst : ToInstrument)
554 Changed |= instrumentMemAccess(Inst);
555
556 return Changed;
557}