blob: cc8abb8a60a07185b33fdaf7e36d669fb27b7a3d [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);
Evgeniy Stepanov80ccda22018-02-09 00:59:10 +0000136 Value *tagPointer(IRBuilder<> &IRB, Type *Ty, Value *PtrLong, Value *Tag);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000137 bool instrumentStack(SmallVectorImpl<AllocaInst *> &Allocas,
138 SmallVectorImpl<Instruction *> &RetVec);
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000139 Value *getNextTagWithCall(IRBuilder<> &IRB);
140 Value *getStackBaseTag(IRBuilder<> &IRB);
141 Value *getAllocaTag(IRBuilder<> &IRB, Value *StackTag, AllocaInst *AI,
142 unsigned AllocaNo);
143 Value *getUARTag(IRBuilder<> &IRB, Value *StackTag);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000144
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000145private:
146 LLVMContext *C;
147 Type *IntptrTy;
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000148 Type *Int8Ty;
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000149
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000150 bool Recover;
151
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000152 Function *HwasanCtorFunction;
153
154 Function *HwasanMemoryAccessCallback[2][kNumberOfAccessSizes];
155 Function *HwasanMemoryAccessCallbackSized[2];
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000156
157 Function *HwasanTagMemoryFunc;
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000158 Function *HwasanGenerateTagFunc;
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000159};
160
161} // end anonymous namespace
162
163char HWAddressSanitizer::ID = 0;
164
165INITIALIZE_PASS_BEGIN(
166 HWAddressSanitizer, "hwasan",
167 "HWAddressSanitizer: detect memory bugs using tagged addressing.", false, false)
168INITIALIZE_PASS_END(
169 HWAddressSanitizer, "hwasan",
170 "HWAddressSanitizer: detect memory bugs using tagged addressing.", false, false)
171
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000172FunctionPass *llvm::createHWAddressSanitizerPass(bool Recover) {
173 return new HWAddressSanitizer(Recover);
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000174}
175
176/// \brief Module-level initialization.
177///
178/// inserts a call to __hwasan_init to the module's constructor list.
179bool HWAddressSanitizer::doInitialization(Module &M) {
180 DEBUG(dbgs() << "Init " << M.getName() << "\n");
181 auto &DL = M.getDataLayout();
182
183 Triple TargetTriple(M.getTargetTriple());
184
185 C = &(M.getContext());
186 IRBuilder<> IRB(*C);
187 IntptrTy = IRB.getIntPtrTy(DL);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000188 Int8Ty = IRB.getInt8Ty();
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000189
Benjamin Kramerbfc1d972018-01-18 14:19:04 +0000190 HwasanCtorFunction = nullptr;
Evgeniy Stepanov5bd669d2018-01-17 23:24:38 +0000191 if (!ClEnableKhwasan) {
192 std::tie(HwasanCtorFunction, std::ignore) =
193 createSanitizerCtorAndInitFunctions(M, kHwasanModuleCtorName,
194 kHwasanInitName,
195 /*InitArgTypes=*/{},
196 /*InitArgs=*/{});
197 appendToGlobalCtors(M, HwasanCtorFunction, 0);
198 }
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000199 return true;
200}
201
202void HWAddressSanitizer::initializeCallbacks(Module &M) {
203 IRBuilder<> IRB(*C);
204 for (size_t AccessIsWrite = 0; AccessIsWrite <= 1; AccessIsWrite++) {
205 const std::string TypeStr = AccessIsWrite ? "store" : "load";
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000206 const std::string EndingStr = Recover ? "_noabort" : "";
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000207
208 HwasanMemoryAccessCallbackSized[AccessIsWrite] =
209 checkSanitizerInterfaceFunction(M.getOrInsertFunction(
Evgeniy Stepanovc07e0bd2018-01-16 23:15:08 +0000210 ClMemoryAccessCallbackPrefix + TypeStr + "N" + EndingStr,
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000211 FunctionType::get(IRB.getVoidTy(), {IntptrTy, IntptrTy}, false)));
212
213 for (size_t AccessSizeIndex = 0; AccessSizeIndex < kNumberOfAccessSizes;
214 AccessSizeIndex++) {
215 HwasanMemoryAccessCallback[AccessIsWrite][AccessSizeIndex] =
216 checkSanitizerInterfaceFunction(M.getOrInsertFunction(
217 ClMemoryAccessCallbackPrefix + TypeStr +
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000218 itostr(1ULL << AccessSizeIndex) + EndingStr,
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000219 FunctionType::get(IRB.getVoidTy(), {IntptrTy}, false)));
220 }
221 }
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000222
223 HwasanTagMemoryFunc = checkSanitizerInterfaceFunction(M.getOrInsertFunction(
224 "__hwasan_tag_memory", IRB.getVoidTy(), IntptrTy, Int8Ty, IntptrTy));
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000225 HwasanGenerateTagFunc = checkSanitizerInterfaceFunction(
226 M.getOrInsertFunction("__hwasan_generate_tag", Int8Ty));
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000227}
228
229Value *HWAddressSanitizer::isInterestingMemoryAccess(Instruction *I,
230 bool *IsWrite,
231 uint64_t *TypeSize,
232 unsigned *Alignment,
233 Value **MaybeMask) {
234 // Skip memory accesses inserted by another instrumentation.
235 if (I->getMetadata("nosanitize")) return nullptr;
236
237 Value *PtrOperand = nullptr;
238 const DataLayout &DL = I->getModule()->getDataLayout();
239 if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
240 if (!ClInstrumentReads) return nullptr;
241 *IsWrite = false;
242 *TypeSize = DL.getTypeStoreSizeInBits(LI->getType());
243 *Alignment = LI->getAlignment();
244 PtrOperand = LI->getPointerOperand();
245 } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
246 if (!ClInstrumentWrites) return nullptr;
247 *IsWrite = true;
248 *TypeSize = DL.getTypeStoreSizeInBits(SI->getValueOperand()->getType());
249 *Alignment = SI->getAlignment();
250 PtrOperand = SI->getPointerOperand();
251 } else if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(I)) {
252 if (!ClInstrumentAtomics) return nullptr;
253 *IsWrite = true;
254 *TypeSize = DL.getTypeStoreSizeInBits(RMW->getValOperand()->getType());
255 *Alignment = 0;
256 PtrOperand = RMW->getPointerOperand();
257 } else if (AtomicCmpXchgInst *XCHG = dyn_cast<AtomicCmpXchgInst>(I)) {
258 if (!ClInstrumentAtomics) return nullptr;
259 *IsWrite = true;
260 *TypeSize = DL.getTypeStoreSizeInBits(XCHG->getCompareOperand()->getType());
261 *Alignment = 0;
262 PtrOperand = XCHG->getPointerOperand();
263 }
264
265 if (PtrOperand) {
266 // Do not instrument acesses from different address spaces; we cannot deal
267 // with them.
268 Type *PtrTy = cast<PointerType>(PtrOperand->getType()->getScalarType());
269 if (PtrTy->getPointerAddressSpace() != 0)
270 return nullptr;
271
272 // Ignore swifterror addresses.
273 // swifterror memory addresses are mem2reg promoted by instruction
274 // selection. As such they cannot have regular uses like an instrumentation
275 // function and it makes no sense to track them as memory.
276 if (PtrOperand->isSwiftError())
277 return nullptr;
278 }
279
280 return PtrOperand;
281}
282
283static size_t TypeSizeToSizeIndex(uint32_t TypeSize) {
284 size_t Res = countTrailingZeros(TypeSize / 8);
285 assert(Res < kNumberOfAccessSizes);
286 return Res;
287}
288
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000289void HWAddressSanitizer::instrumentMemAccessInline(Value *PtrLong, bool IsWrite,
290 unsigned AccessSizeIndex,
291 Instruction *InsertBefore) {
292 IRBuilder<> IRB(InsertBefore);
293 Value *PtrTag = IRB.CreateTrunc(IRB.CreateLShr(PtrLong, kPointerTagShift), IRB.getInt8Ty());
294 Value *AddrLong =
295 IRB.CreateAnd(PtrLong, ConstantInt::get(PtrLong->getType(),
296 ~(0xFFULL << kPointerTagShift)));
297 Value *ShadowLong = IRB.CreateLShr(AddrLong, kShadowScale);
Evgeniy Stepanov5bd669d2018-01-17 23:24:38 +0000298 if (ClMappingOffset)
299 ShadowLong = IRB.CreateAdd(
300 ShadowLong, ConstantInt::get(PtrLong->getType(), ClMappingOffset,
301 /*isSigned=*/false));
302 Value *MemTag =
303 IRB.CreateLoad(IRB.CreateIntToPtr(ShadowLong, IRB.getInt8PtrTy()));
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000304 Value *TagMismatch = IRB.CreateICmpNE(PtrTag, MemTag);
305
306 TerminatorInst *CheckTerm =
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000307 SplitBlockAndInsertIfThen(TagMismatch, InsertBefore, !Recover,
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000308 MDBuilder(*C).createBranchWeights(1, 100000));
309
310 IRB.SetInsertPoint(CheckTerm);
311 // The signal handler will find the data address in x0.
312 InlineAsm *Asm = InlineAsm::get(
313 FunctionType::get(IRB.getVoidTy(), {PtrLong->getType()}, false),
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000314 "hlt #" +
315 itostr(0x100 + Recover * 0x20 + IsWrite * 0x10 + AccessSizeIndex),
316 "{x0}",
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000317 /*hasSideEffects=*/true);
318 IRB.CreateCall(Asm, PtrLong);
319}
320
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000321bool HWAddressSanitizer::instrumentMemAccess(Instruction *I) {
322 DEBUG(dbgs() << "Instrumenting: " << *I << "\n");
323 bool IsWrite = false;
324 unsigned Alignment = 0;
325 uint64_t TypeSize = 0;
326 Value *MaybeMask = nullptr;
327 Value *Addr =
328 isInterestingMemoryAccess(I, &IsWrite, &TypeSize, &Alignment, &MaybeMask);
329
330 if (!Addr)
331 return false;
332
333 if (MaybeMask)
334 return false; //FIXME
335
336 IRBuilder<> IRB(I);
337 Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy);
338 if (isPowerOf2_64(TypeSize) &&
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000339 (TypeSize / 8 <= (1UL << (kNumberOfAccessSizes - 1))) &&
340 (Alignment >= (1UL << kShadowScale) || Alignment == 0 ||
341 Alignment >= TypeSize / 8)) {
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000342 size_t AccessSizeIndex = TypeSizeToSizeIndex(TypeSize);
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000343 if (ClInstrumentWithCalls) {
344 IRB.CreateCall(HwasanMemoryAccessCallback[IsWrite][AccessSizeIndex],
345 AddrLong);
346 } else {
347 instrumentMemAccessInline(AddrLong, IsWrite, AccessSizeIndex, I);
348 }
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000349 } else {
350 IRB.CreateCall(HwasanMemoryAccessCallbackSized[IsWrite],
351 {AddrLong, ConstantInt::get(IntptrTy, TypeSize / 8)});
352 }
353
354 return true;
355}
356
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000357static uint64_t getAllocaSizeInBytes(const AllocaInst &AI) {
358 uint64_t ArraySize = 1;
359 if (AI.isArrayAllocation()) {
360 const ConstantInt *CI = dyn_cast<ConstantInt>(AI.getArraySize());
361 assert(CI && "non-constant array size");
362 ArraySize = CI->getZExtValue();
363 }
364 Type *Ty = AI.getAllocatedType();
365 uint64_t SizeInBytes = AI.getModule()->getDataLayout().getTypeAllocSize(Ty);
366 return SizeInBytes * ArraySize;
367}
368
369bool HWAddressSanitizer::tagAlloca(IRBuilder<> &IRB, AllocaInst *AI,
370 Value *Tag) {
371 size_t Size = (getAllocaSizeInBytes(*AI) + kAllocaAlignment - 1) &
372 ~(kAllocaAlignment - 1);
373
374 Value *JustTag = IRB.CreateTrunc(Tag, IRB.getInt8Ty());
375 if (ClInstrumentWithCalls) {
376 IRB.CreateCall(HwasanTagMemoryFunc,
377 {IRB.CreatePointerCast(AI, IntptrTy), JustTag,
378 ConstantInt::get(IntptrTy, Size)});
379 } else {
380 size_t ShadowSize = Size >> kShadowScale;
381 Value *ShadowPtr = IRB.CreateIntToPtr(
382 IRB.CreateLShr(IRB.CreatePointerCast(AI, IntptrTy), kShadowScale),
383 IRB.getInt8PtrTy());
384 // If this memset is not inlined, it will be intercepted in the hwasan
385 // runtime library. That's OK, because the interceptor skips the checks if
386 // the address is in the shadow region.
387 // FIXME: the interceptor is not as fast as real memset. Consider lowering
388 // llvm.memset right here into either a sequence of stores, or a call to
389 // hwasan_tag_memory.
390 IRB.CreateMemSet(ShadowPtr, JustTag, ShadowSize, /*Align=*/1);
391 }
392 return true;
393}
394
395static unsigned RetagMask(unsigned AllocaNo) {
396 // A list of 8-bit numbers that have at most one run of non-zero bits.
397 // x = x ^ (mask << 56) can be encoded as a single armv8 instruction for these
398 // masks.
399 // The list does not include the value 255, which is used for UAR.
400 static unsigned FastMasks[] = {
401 0, 1, 2, 3, 4, 6, 7, 8, 12, 14, 15, 16, 24,
402 28, 30, 31, 32, 48, 56, 60, 62, 63, 64, 96, 112, 120,
403 124, 126, 127, 128, 192, 224, 240, 248, 252, 254};
404 return FastMasks[AllocaNo % (sizeof(FastMasks) / sizeof(FastMasks[0]))];
405}
406
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000407Value *HWAddressSanitizer::getNextTagWithCall(IRBuilder<> &IRB) {
408 return IRB.CreateZExt(IRB.CreateCall(HwasanGenerateTagFunc), IntptrTy);
409}
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000410
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000411Value *HWAddressSanitizer::getStackBaseTag(IRBuilder<> &IRB) {
412 if (ClGenerateTagsWithCalls)
413 return nullptr;
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000414 // FIXME: use addressofreturnaddress (but implement it in aarch64 backend
415 // first).
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000416 Module *M = IRB.GetInsertBlock()->getParent()->getParent();
417 auto GetStackPointerFn =
418 Intrinsic::getDeclaration(M, Intrinsic::frameaddress);
419 Value *StackPointer = IRB.CreateCall(
420 GetStackPointerFn, {Constant::getNullValue(IRB.getInt32Ty())});
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000421
422 // Extract some entropy from the stack pointer for the tags.
423 // Take bits 20..28 (ASLR entropy) and xor with bits 0..8 (these differ
424 // between functions).
425 Value *StackPointerLong = IRB.CreatePointerCast(StackPointer, IntptrTy);
426 Value *StackTag =
427 IRB.CreateXor(StackPointerLong, IRB.CreateLShr(StackPointerLong, 20),
428 "hwasan.stack.base.tag");
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000429 return StackTag;
430}
431
432Value *HWAddressSanitizer::getAllocaTag(IRBuilder<> &IRB, Value *StackTag,
433 AllocaInst *AI, unsigned AllocaNo) {
434 if (ClGenerateTagsWithCalls)
435 return getNextTagWithCall(IRB);
436 return IRB.CreateXor(StackTag,
437 ConstantInt::get(IntptrTy, RetagMask(AllocaNo)));
438}
439
440Value *HWAddressSanitizer::getUARTag(IRBuilder<> &IRB, Value *StackTag) {
441 if (ClGenerateTagsWithCalls)
442 return getNextTagWithCall(IRB);
443 return IRB.CreateXor(StackTag, ConstantInt::get(IntptrTy, 0xFFU));
444}
445
Evgeniy Stepanov80ccda22018-02-09 00:59:10 +0000446// Add a tag to an address.
447Value *HWAddressSanitizer::tagPointer(IRBuilder<> &IRB, Type *Ty, Value *PtrLong,
448 Value *Tag) {
449 Value *TaggedPtrLong;
450 if (ClEnableKhwasan) {
451 // Kernel addresses have 0xFF in the most significant byte.
452 Value *ShiftedTag = IRB.CreateOr(
453 IRB.CreateShl(Tag, kPointerTagShift),
454 ConstantInt::get(IntptrTy, (1ULL << kPointerTagShift) - 1));
455 TaggedPtrLong = IRB.CreateAnd(PtrLong, ShiftedTag);
456 } else {
457 // Userspace can simply do OR (tag << 56);
458 Value *ShiftedTag = IRB.CreateShl(Tag, kPointerTagShift);
459 TaggedPtrLong = IRB.CreateOr(PtrLong, ShiftedTag);
460 }
461 return IRB.CreateIntToPtr(TaggedPtrLong, Ty);
462}
463
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000464bool HWAddressSanitizer::instrumentStack(
465 SmallVectorImpl<AllocaInst *> &Allocas,
466 SmallVectorImpl<Instruction *> &RetVec) {
467 Function *F = Allocas[0]->getParent()->getParent();
468 Instruction *InsertPt = &*F->getEntryBlock().begin();
469 IRBuilder<> IRB(InsertPt);
470
471 Value *StackTag = getStackBaseTag(IRB);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000472
473 // Ideally, we want to calculate tagged stack base pointer, and rewrite all
474 // alloca addresses using that. Unfortunately, offsets are not known yet
475 // (unless we use ASan-style mega-alloca). Instead we keep the base tag in a
476 // temp, shift-OR it into each alloca address and xor with the retag mask.
477 // This generates one extra instruction per alloca use.
478 for (unsigned N = 0; N < Allocas.size(); ++N) {
479 auto *AI = Allocas[N];
480 IRB.SetInsertPoint(AI->getNextNode());
481
482 // Replace uses of the alloca with tagged address.
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000483 Value *Tag = getAllocaTag(IRB, StackTag, AI, N);
484 Value *AILong = IRB.CreatePointerCast(AI, IntptrTy);
Evgeniy Stepanov80ccda22018-02-09 00:59:10 +0000485 Value *Replacement = tagPointer(IRB, AI->getType(), AILong, Tag);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000486 std::string Name =
487 AI->hasName() ? AI->getName().str() : "alloca." + itostr(N);
Evgeniy Stepanov80ccda22018-02-09 00:59:10 +0000488 Replacement->setName(Name + ".hwasan");
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000489
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000490 for (auto UI = AI->use_begin(), UE = AI->use_end(); UI != UE;) {
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000491 Use &U = *UI++;
492 if (U.getUser() != AILong)
493 U.set(Replacement);
494 }
495
496 tagAlloca(IRB, AI, Tag);
497
498 for (auto RI : RetVec) {
499 IRB.SetInsertPoint(RI);
500
501 // Re-tag alloca memory with the special UAR tag.
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000502 Value *Tag = getUARTag(IRB, StackTag);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000503 tagAlloca(IRB, AI, Tag);
504 }
505 }
506
507 return true;
508}
509
510bool HWAddressSanitizer::isInterestingAlloca(const AllocaInst &AI) {
511 return (AI.getAllocatedType()->isSized() &&
512 // FIXME: instrument dynamic allocas, too
513 AI.isStaticAlloca() &&
514 // alloca() may be called with 0 size, ignore it.
515 getAllocaSizeInBytes(AI) > 0 &&
516 // We are only interested in allocas not promotable to registers.
517 // Promotable allocas are common under -O0.
518 !isAllocaPromotable(&AI) &&
519 // inalloca allocas are not treated as static, and we don't want
520 // dynamic alloca instrumentation for them as well.
521 !AI.isUsedWithInAlloca() &&
522 // swifterror allocas are register promoted by ISel
523 !AI.isSwiftError());
524}
525
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000526bool HWAddressSanitizer::runOnFunction(Function &F) {
527 if (&F == HwasanCtorFunction)
528 return false;
529
530 if (!F.hasFnAttribute(Attribute::SanitizeHWAddress))
531 return false;
532
533 DEBUG(dbgs() << "Function: " << F.getName() << "\n");
534
535 initializeCallbacks(*F.getParent());
536
537 bool Changed = false;
538 SmallVector<Instruction*, 16> ToInstrument;
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000539 SmallVector<AllocaInst*, 8> AllocasToInstrument;
540 SmallVector<Instruction*, 8> RetVec;
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000541 for (auto &BB : F) {
542 for (auto &Inst : BB) {
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000543 if (ClInstrumentStack)
544 if (AllocaInst *AI = dyn_cast<AllocaInst>(&Inst)) {
545 // Realign all allocas. We don't want small uninteresting allocas to
546 // hide in instrumented alloca's padding.
547 if (AI->getAlignment() < kAllocaAlignment)
548 AI->setAlignment(kAllocaAlignment);
549 // Instrument some of them.
550 if (isInterestingAlloca(*AI))
551 AllocasToInstrument.push_back(AI);
552 continue;
553 }
554
555 if (isa<ReturnInst>(Inst) || isa<ResumeInst>(Inst) || isa<CleanupReturnInst>(Inst))
556 RetVec.push_back(&Inst);
557
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000558 Value *MaybeMask = nullptr;
559 bool IsWrite;
560 unsigned Alignment;
561 uint64_t TypeSize;
562 Value *Addr = isInterestingMemoryAccess(&Inst, &IsWrite, &TypeSize,
563 &Alignment, &MaybeMask);
564 if (Addr || isa<MemIntrinsic>(Inst))
565 ToInstrument.push_back(&Inst);
566 }
567 }
568
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000569 if (!AllocasToInstrument.empty())
570 Changed |= instrumentStack(AllocasToInstrument, RetVec);
571
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000572 for (auto Inst : ToInstrument)
573 Changed |= instrumentMemAccess(Inst);
574
575 return Changed;
576}