blob: df2fe37a6d43678339e1dc6e0022b644b21639f9 [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
Benjamin Kramerbfc1d972018-01-18 14:19:04 +0000189 HwasanCtorFunction = nullptr;
Evgeniy Stepanov5bd669d2018-01-17 23:24:38 +0000190 if (!ClEnableKhwasan) {
191 std::tie(HwasanCtorFunction, std::ignore) =
192 createSanitizerCtorAndInitFunctions(M, kHwasanModuleCtorName,
193 kHwasanInitName,
194 /*InitArgTypes=*/{},
195 /*InitArgs=*/{});
196 appendToGlobalCtors(M, HwasanCtorFunction, 0);
197 }
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000198 return true;
199}
200
201void HWAddressSanitizer::initializeCallbacks(Module &M) {
202 IRBuilder<> IRB(*C);
203 for (size_t AccessIsWrite = 0; AccessIsWrite <= 1; AccessIsWrite++) {
204 const std::string TypeStr = AccessIsWrite ? "store" : "load";
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000205 const std::string EndingStr = Recover ? "_noabort" : "";
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000206
207 HwasanMemoryAccessCallbackSized[AccessIsWrite] =
208 checkSanitizerInterfaceFunction(M.getOrInsertFunction(
Evgeniy Stepanovc07e0bd2018-01-16 23:15:08 +0000209 ClMemoryAccessCallbackPrefix + TypeStr + "N" + EndingStr,
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000210 FunctionType::get(IRB.getVoidTy(), {IntptrTy, IntptrTy}, false)));
211
212 for (size_t AccessSizeIndex = 0; AccessSizeIndex < kNumberOfAccessSizes;
213 AccessSizeIndex++) {
214 HwasanMemoryAccessCallback[AccessIsWrite][AccessSizeIndex] =
215 checkSanitizerInterfaceFunction(M.getOrInsertFunction(
216 ClMemoryAccessCallbackPrefix + TypeStr +
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000217 itostr(1ULL << AccessSizeIndex) + EndingStr,
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000218 FunctionType::get(IRB.getVoidTy(), {IntptrTy}, false)));
219 }
220 }
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000221
222 HwasanTagMemoryFunc = checkSanitizerInterfaceFunction(M.getOrInsertFunction(
223 "__hwasan_tag_memory", IRB.getVoidTy(), IntptrTy, Int8Ty, IntptrTy));
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000224 HwasanGenerateTagFunc = checkSanitizerInterfaceFunction(
225 M.getOrInsertFunction("__hwasan_generate_tag", Int8Ty));
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000226}
227
228Value *HWAddressSanitizer::isInterestingMemoryAccess(Instruction *I,
229 bool *IsWrite,
230 uint64_t *TypeSize,
231 unsigned *Alignment,
232 Value **MaybeMask) {
233 // Skip memory accesses inserted by another instrumentation.
234 if (I->getMetadata("nosanitize")) return nullptr;
235
236 Value *PtrOperand = nullptr;
237 const DataLayout &DL = I->getModule()->getDataLayout();
238 if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
239 if (!ClInstrumentReads) return nullptr;
240 *IsWrite = false;
241 *TypeSize = DL.getTypeStoreSizeInBits(LI->getType());
242 *Alignment = LI->getAlignment();
243 PtrOperand = LI->getPointerOperand();
244 } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
245 if (!ClInstrumentWrites) return nullptr;
246 *IsWrite = true;
247 *TypeSize = DL.getTypeStoreSizeInBits(SI->getValueOperand()->getType());
248 *Alignment = SI->getAlignment();
249 PtrOperand = SI->getPointerOperand();
250 } else if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(I)) {
251 if (!ClInstrumentAtomics) return nullptr;
252 *IsWrite = true;
253 *TypeSize = DL.getTypeStoreSizeInBits(RMW->getValOperand()->getType());
254 *Alignment = 0;
255 PtrOperand = RMW->getPointerOperand();
256 } else if (AtomicCmpXchgInst *XCHG = dyn_cast<AtomicCmpXchgInst>(I)) {
257 if (!ClInstrumentAtomics) return nullptr;
258 *IsWrite = true;
259 *TypeSize = DL.getTypeStoreSizeInBits(XCHG->getCompareOperand()->getType());
260 *Alignment = 0;
261 PtrOperand = XCHG->getPointerOperand();
262 }
263
264 if (PtrOperand) {
265 // Do not instrument acesses from different address spaces; we cannot deal
266 // with them.
267 Type *PtrTy = cast<PointerType>(PtrOperand->getType()->getScalarType());
268 if (PtrTy->getPointerAddressSpace() != 0)
269 return nullptr;
270
271 // Ignore swifterror addresses.
272 // swifterror memory addresses are mem2reg promoted by instruction
273 // selection. As such they cannot have regular uses like an instrumentation
274 // function and it makes no sense to track them as memory.
275 if (PtrOperand->isSwiftError())
276 return nullptr;
277 }
278
279 return PtrOperand;
280}
281
282static size_t TypeSizeToSizeIndex(uint32_t TypeSize) {
283 size_t Res = countTrailingZeros(TypeSize / 8);
284 assert(Res < kNumberOfAccessSizes);
285 return Res;
286}
287
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000288void HWAddressSanitizer::instrumentMemAccessInline(Value *PtrLong, bool IsWrite,
289 unsigned AccessSizeIndex,
290 Instruction *InsertBefore) {
291 IRBuilder<> IRB(InsertBefore);
292 Value *PtrTag = IRB.CreateTrunc(IRB.CreateLShr(PtrLong, kPointerTagShift), IRB.getInt8Ty());
293 Value *AddrLong =
294 IRB.CreateAnd(PtrLong, ConstantInt::get(PtrLong->getType(),
295 ~(0xFFULL << kPointerTagShift)));
296 Value *ShadowLong = IRB.CreateLShr(AddrLong, kShadowScale);
Evgeniy Stepanov5bd669d2018-01-17 23:24:38 +0000297 if (ClMappingOffset)
298 ShadowLong = IRB.CreateAdd(
299 ShadowLong, ConstantInt::get(PtrLong->getType(), ClMappingOffset,
300 /*isSigned=*/false));
301 Value *MemTag =
302 IRB.CreateLoad(IRB.CreateIntToPtr(ShadowLong, IRB.getInt8PtrTy()));
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000303 Value *TagMismatch = IRB.CreateICmpNE(PtrTag, MemTag);
304
305 TerminatorInst *CheckTerm =
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000306 SplitBlockAndInsertIfThen(TagMismatch, InsertBefore, !Recover,
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000307 MDBuilder(*C).createBranchWeights(1, 100000));
308
309 IRB.SetInsertPoint(CheckTerm);
310 // The signal handler will find the data address in x0.
311 InlineAsm *Asm = InlineAsm::get(
312 FunctionType::get(IRB.getVoidTy(), {PtrLong->getType()}, false),
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000313 "hlt #" +
314 itostr(0x100 + Recover * 0x20 + IsWrite * 0x10 + AccessSizeIndex),
315 "{x0}",
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000316 /*hasSideEffects=*/true);
317 IRB.CreateCall(Asm, PtrLong);
318}
319
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000320bool HWAddressSanitizer::instrumentMemAccess(Instruction *I) {
321 DEBUG(dbgs() << "Instrumenting: " << *I << "\n");
322 bool IsWrite = false;
323 unsigned Alignment = 0;
324 uint64_t TypeSize = 0;
325 Value *MaybeMask = nullptr;
326 Value *Addr =
327 isInterestingMemoryAccess(I, &IsWrite, &TypeSize, &Alignment, &MaybeMask);
328
329 if (!Addr)
330 return false;
331
332 if (MaybeMask)
333 return false; //FIXME
334
335 IRBuilder<> IRB(I);
336 Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy);
337 if (isPowerOf2_64(TypeSize) &&
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000338 (TypeSize / 8 <= (1UL << (kNumberOfAccessSizes - 1))) &&
339 (Alignment >= (1UL << kShadowScale) || Alignment == 0 ||
340 Alignment >= TypeSize / 8)) {
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000341 size_t AccessSizeIndex = TypeSizeToSizeIndex(TypeSize);
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000342 if (ClInstrumentWithCalls) {
343 IRB.CreateCall(HwasanMemoryAccessCallback[IsWrite][AccessSizeIndex],
344 AddrLong);
345 } else {
346 instrumentMemAccessInline(AddrLong, IsWrite, AccessSizeIndex, I);
347 }
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000348 } else {
349 IRB.CreateCall(HwasanMemoryAccessCallbackSized[IsWrite],
350 {AddrLong, ConstantInt::get(IntptrTy, TypeSize / 8)});
351 }
352
353 return true;
354}
355
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000356static uint64_t getAllocaSizeInBytes(const AllocaInst &AI) {
357 uint64_t ArraySize = 1;
358 if (AI.isArrayAllocation()) {
359 const ConstantInt *CI = dyn_cast<ConstantInt>(AI.getArraySize());
360 assert(CI && "non-constant array size");
361 ArraySize = CI->getZExtValue();
362 }
363 Type *Ty = AI.getAllocatedType();
364 uint64_t SizeInBytes = AI.getModule()->getDataLayout().getTypeAllocSize(Ty);
365 return SizeInBytes * ArraySize;
366}
367
368bool HWAddressSanitizer::tagAlloca(IRBuilder<> &IRB, AllocaInst *AI,
369 Value *Tag) {
370 size_t Size = (getAllocaSizeInBytes(*AI) + kAllocaAlignment - 1) &
371 ~(kAllocaAlignment - 1);
372
373 Value *JustTag = IRB.CreateTrunc(Tag, IRB.getInt8Ty());
374 if (ClInstrumentWithCalls) {
375 IRB.CreateCall(HwasanTagMemoryFunc,
376 {IRB.CreatePointerCast(AI, IntptrTy), JustTag,
377 ConstantInt::get(IntptrTy, Size)});
378 } else {
379 size_t ShadowSize = Size >> kShadowScale;
380 Value *ShadowPtr = IRB.CreateIntToPtr(
381 IRB.CreateLShr(IRB.CreatePointerCast(AI, IntptrTy), kShadowScale),
382 IRB.getInt8PtrTy());
383 // If this memset is not inlined, it will be intercepted in the hwasan
384 // runtime library. That's OK, because the interceptor skips the checks if
385 // the address is in the shadow region.
386 // FIXME: the interceptor is not as fast as real memset. Consider lowering
387 // llvm.memset right here into either a sequence of stores, or a call to
388 // hwasan_tag_memory.
389 IRB.CreateMemSet(ShadowPtr, JustTag, ShadowSize, /*Align=*/1);
390 }
391 return true;
392}
393
394static unsigned RetagMask(unsigned AllocaNo) {
395 // A list of 8-bit numbers that have at most one run of non-zero bits.
396 // x = x ^ (mask << 56) can be encoded as a single armv8 instruction for these
397 // masks.
398 // The list does not include the value 255, which is used for UAR.
399 static unsigned FastMasks[] = {
400 0, 1, 2, 3, 4, 6, 7, 8, 12, 14, 15, 16, 24,
401 28, 30, 31, 32, 48, 56, 60, 62, 63, 64, 96, 112, 120,
402 124, 126, 127, 128, 192, 224, 240, 248, 252, 254};
403 return FastMasks[AllocaNo % (sizeof(FastMasks) / sizeof(FastMasks[0]))];
404}
405
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000406Value *HWAddressSanitizer::getNextTagWithCall(IRBuilder<> &IRB) {
407 return IRB.CreateZExt(IRB.CreateCall(HwasanGenerateTagFunc), IntptrTy);
408}
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000409
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000410Value *HWAddressSanitizer::getStackBaseTag(IRBuilder<> &IRB) {
411 if (ClGenerateTagsWithCalls)
412 return nullptr;
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000413 // FIXME: use addressofreturnaddress (but implement it in aarch64 backend
414 // first).
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000415 Module *M = IRB.GetInsertBlock()->getParent()->getParent();
416 auto GetStackPointerFn =
417 Intrinsic::getDeclaration(M, Intrinsic::frameaddress);
418 Value *StackPointer = IRB.CreateCall(
419 GetStackPointerFn, {Constant::getNullValue(IRB.getInt32Ty())});
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000420
421 // Extract some entropy from the stack pointer for the tags.
422 // Take bits 20..28 (ASLR entropy) and xor with bits 0..8 (these differ
423 // between functions).
424 Value *StackPointerLong = IRB.CreatePointerCast(StackPointer, IntptrTy);
425 Value *StackTag =
426 IRB.CreateXor(StackPointerLong, IRB.CreateLShr(StackPointerLong, 20),
427 "hwasan.stack.base.tag");
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000428 return StackTag;
429}
430
431Value *HWAddressSanitizer::getAllocaTag(IRBuilder<> &IRB, Value *StackTag,
432 AllocaInst *AI, unsigned AllocaNo) {
433 if (ClGenerateTagsWithCalls)
434 return getNextTagWithCall(IRB);
435 return IRB.CreateXor(StackTag,
436 ConstantInt::get(IntptrTy, RetagMask(AllocaNo)));
437}
438
439Value *HWAddressSanitizer::getUARTag(IRBuilder<> &IRB, Value *StackTag) {
440 if (ClGenerateTagsWithCalls)
441 return getNextTagWithCall(IRB);
442 return IRB.CreateXor(StackTag, ConstantInt::get(IntptrTy, 0xFFU));
443}
444
445bool HWAddressSanitizer::instrumentStack(
446 SmallVectorImpl<AllocaInst *> &Allocas,
447 SmallVectorImpl<Instruction *> &RetVec) {
448 Function *F = Allocas[0]->getParent()->getParent();
449 Instruction *InsertPt = &*F->getEntryBlock().begin();
450 IRBuilder<> IRB(InsertPt);
451
452 Value *StackTag = getStackBaseTag(IRB);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000453
454 // Ideally, we want to calculate tagged stack base pointer, and rewrite all
455 // alloca addresses using that. Unfortunately, offsets are not known yet
456 // (unless we use ASan-style mega-alloca). Instead we keep the base tag in a
457 // temp, shift-OR it into each alloca address and xor with the retag mask.
458 // This generates one extra instruction per alloca use.
459 for (unsigned N = 0; N < Allocas.size(); ++N) {
460 auto *AI = Allocas[N];
461 IRB.SetInsertPoint(AI->getNextNode());
462
463 // Replace uses of the alloca with tagged address.
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000464 Value *Tag = getAllocaTag(IRB, StackTag, AI, N);
465 Value *AILong = IRB.CreatePointerCast(AI, IntptrTy);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000466 std::string Name =
467 AI->hasName() ? AI->getName().str() : "alloca." + itostr(N);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000468 Value *Replacement = IRB.CreateIntToPtr(
469 IRB.CreateOr(AILong, IRB.CreateShl(Tag, kPointerTagShift)),
470 AI->getType(), Name + ".hwasan");
471
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000472 for (auto UI = AI->use_begin(), UE = AI->use_end(); UI != UE;) {
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000473 Use &U = *UI++;
474 if (U.getUser() != AILong)
475 U.set(Replacement);
476 }
477
478 tagAlloca(IRB, AI, Tag);
479
480 for (auto RI : RetVec) {
481 IRB.SetInsertPoint(RI);
482
483 // Re-tag alloca memory with the special UAR tag.
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000484 Value *Tag = getUARTag(IRB, StackTag);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000485 tagAlloca(IRB, AI, Tag);
486 }
487 }
488
489 return true;
490}
491
492bool HWAddressSanitizer::isInterestingAlloca(const AllocaInst &AI) {
493 return (AI.getAllocatedType()->isSized() &&
494 // FIXME: instrument dynamic allocas, too
495 AI.isStaticAlloca() &&
496 // alloca() may be called with 0 size, ignore it.
497 getAllocaSizeInBytes(AI) > 0 &&
498 // We are only interested in allocas not promotable to registers.
499 // Promotable allocas are common under -O0.
500 !isAllocaPromotable(&AI) &&
501 // inalloca allocas are not treated as static, and we don't want
502 // dynamic alloca instrumentation for them as well.
503 !AI.isUsedWithInAlloca() &&
504 // swifterror allocas are register promoted by ISel
505 !AI.isSwiftError());
506}
507
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000508bool HWAddressSanitizer::runOnFunction(Function &F) {
509 if (&F == HwasanCtorFunction)
510 return false;
511
512 if (!F.hasFnAttribute(Attribute::SanitizeHWAddress))
513 return false;
514
515 DEBUG(dbgs() << "Function: " << F.getName() << "\n");
516
517 initializeCallbacks(*F.getParent());
518
519 bool Changed = false;
520 SmallVector<Instruction*, 16> ToInstrument;
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000521 SmallVector<AllocaInst*, 8> AllocasToInstrument;
522 SmallVector<Instruction*, 8> RetVec;
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000523 for (auto &BB : F) {
524 for (auto &Inst : BB) {
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000525 if (ClInstrumentStack)
526 if (AllocaInst *AI = dyn_cast<AllocaInst>(&Inst)) {
527 // Realign all allocas. We don't want small uninteresting allocas to
528 // hide in instrumented alloca's padding.
529 if (AI->getAlignment() < kAllocaAlignment)
530 AI->setAlignment(kAllocaAlignment);
531 // Instrument some of them.
532 if (isInterestingAlloca(*AI))
533 AllocasToInstrument.push_back(AI);
534 continue;
535 }
536
537 if (isa<ReturnInst>(Inst) || isa<ResumeInst>(Inst) || isa<CleanupReturnInst>(Inst))
538 RetVec.push_back(&Inst);
539
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000540 Value *MaybeMask = nullptr;
541 bool IsWrite;
542 unsigned Alignment;
543 uint64_t TypeSize;
544 Value *Addr = isInterestingMemoryAccess(&Inst, &IsWrite, &TypeSize,
545 &Alignment, &MaybeMask);
546 if (Addr || isa<MemIntrinsic>(Inst))
547 ToInstrument.push_back(&Inst);
548 }
549 }
550
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000551 if (!AllocasToInstrument.empty())
552 Changed |= instrumentStack(AllocasToInstrument, RetVec);
553
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000554 for (auto Inst : ToInstrument)
555 Changed |= instrumentMemAccess(Inst);
556
557 return Changed;
558}