blob: 6365806d1f1f2ccf638eff4a26498df9dbc9ae89 [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);
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000126 void untagPointerOperand(Instruction *I, Value *Addr);
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000127 void instrumentMemAccessInline(Value *PtrLong, bool IsWrite,
128 unsigned AccessSizeIndex,
129 Instruction *InsertBefore);
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000130 bool instrumentMemAccess(Instruction *I);
131 Value *isInterestingMemoryAccess(Instruction *I, bool *IsWrite,
132 uint64_t *TypeSize, unsigned *Alignment,
133 Value **MaybeMask);
134
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000135 bool isInterestingAlloca(const AllocaInst &AI);
136 bool tagAlloca(IRBuilder<> &IRB, AllocaInst *AI, Value *Tag);
Evgeniy Stepanov80ccda22018-02-09 00:59:10 +0000137 Value *tagPointer(IRBuilder<> &IRB, Type *Ty, Value *PtrLong, Value *Tag);
Evgeniy Stepanov43271b12018-02-21 19:52:23 +0000138 Value *untagPointer(IRBuilder<> &IRB, Value *PtrLong);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000139 bool instrumentStack(SmallVectorImpl<AllocaInst *> &Allocas,
140 SmallVectorImpl<Instruction *> &RetVec);
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000141 Value *getNextTagWithCall(IRBuilder<> &IRB);
142 Value *getStackBaseTag(IRBuilder<> &IRB);
143 Value *getAllocaTag(IRBuilder<> &IRB, Value *StackTag, AllocaInst *AI,
144 unsigned AllocaNo);
145 Value *getUARTag(IRBuilder<> &IRB, Value *StackTag);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000146
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000147private:
148 LLVMContext *C;
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000149 Triple TargetTriple;
150
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000151 Type *IntptrTy;
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000152 Type *Int8Ty;
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000153
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000154 bool Recover;
155
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000156 Function *HwasanCtorFunction;
157
158 Function *HwasanMemoryAccessCallback[2][kNumberOfAccessSizes];
159 Function *HwasanMemoryAccessCallbackSized[2];
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000160
161 Function *HwasanTagMemoryFunc;
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000162 Function *HwasanGenerateTagFunc;
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000163};
164
165} // end anonymous namespace
166
167char HWAddressSanitizer::ID = 0;
168
169INITIALIZE_PASS_BEGIN(
170 HWAddressSanitizer, "hwasan",
171 "HWAddressSanitizer: detect memory bugs using tagged addressing.", false, false)
172INITIALIZE_PASS_END(
173 HWAddressSanitizer, "hwasan",
174 "HWAddressSanitizer: detect memory bugs using tagged addressing.", false, false)
175
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000176FunctionPass *llvm::createHWAddressSanitizerPass(bool Recover) {
177 return new HWAddressSanitizer(Recover);
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000178}
179
180/// \brief Module-level initialization.
181///
182/// inserts a call to __hwasan_init to the module's constructor list.
183bool HWAddressSanitizer::doInitialization(Module &M) {
184 DEBUG(dbgs() << "Init " << M.getName() << "\n");
185 auto &DL = M.getDataLayout();
186
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000187 TargetTriple = Triple(M.getTargetTriple());
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000188
189 C = &(M.getContext());
190 IRBuilder<> IRB(*C);
191 IntptrTy = IRB.getIntPtrTy(DL);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000192 Int8Ty = IRB.getInt8Ty();
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000193
Benjamin Kramerbfc1d972018-01-18 14:19:04 +0000194 HwasanCtorFunction = nullptr;
Evgeniy Stepanov5bd669d2018-01-17 23:24:38 +0000195 if (!ClEnableKhwasan) {
196 std::tie(HwasanCtorFunction, std::ignore) =
197 createSanitizerCtorAndInitFunctions(M, kHwasanModuleCtorName,
198 kHwasanInitName,
199 /*InitArgTypes=*/{},
200 /*InitArgs=*/{});
201 appendToGlobalCtors(M, HwasanCtorFunction, 0);
202 }
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000203 return true;
204}
205
206void HWAddressSanitizer::initializeCallbacks(Module &M) {
207 IRBuilder<> IRB(*C);
208 for (size_t AccessIsWrite = 0; AccessIsWrite <= 1; AccessIsWrite++) {
209 const std::string TypeStr = AccessIsWrite ? "store" : "load";
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000210 const std::string EndingStr = Recover ? "_noabort" : "";
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000211
212 HwasanMemoryAccessCallbackSized[AccessIsWrite] =
213 checkSanitizerInterfaceFunction(M.getOrInsertFunction(
Evgeniy Stepanovc07e0bd2018-01-16 23:15:08 +0000214 ClMemoryAccessCallbackPrefix + TypeStr + "N" + EndingStr,
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000215 FunctionType::get(IRB.getVoidTy(), {IntptrTy, IntptrTy}, false)));
216
217 for (size_t AccessSizeIndex = 0; AccessSizeIndex < kNumberOfAccessSizes;
218 AccessSizeIndex++) {
219 HwasanMemoryAccessCallback[AccessIsWrite][AccessSizeIndex] =
220 checkSanitizerInterfaceFunction(M.getOrInsertFunction(
221 ClMemoryAccessCallbackPrefix + TypeStr +
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000222 itostr(1ULL << AccessSizeIndex) + EndingStr,
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000223 FunctionType::get(IRB.getVoidTy(), {IntptrTy}, false)));
224 }
225 }
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000226
227 HwasanTagMemoryFunc = checkSanitizerInterfaceFunction(M.getOrInsertFunction(
228 "__hwasan_tag_memory", IRB.getVoidTy(), IntptrTy, Int8Ty, IntptrTy));
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000229 HwasanGenerateTagFunc = checkSanitizerInterfaceFunction(
230 M.getOrInsertFunction("__hwasan_generate_tag", Int8Ty));
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000231}
232
233Value *HWAddressSanitizer::isInterestingMemoryAccess(Instruction *I,
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000234 bool *IsWrite,
235 uint64_t *TypeSize,
236 unsigned *Alignment,
237 Value **MaybeMask) {
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000238 // Skip memory accesses inserted by another instrumentation.
239 if (I->getMetadata("nosanitize")) return nullptr;
240
241 Value *PtrOperand = nullptr;
242 const DataLayout &DL = I->getModule()->getDataLayout();
243 if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
244 if (!ClInstrumentReads) return nullptr;
245 *IsWrite = false;
246 *TypeSize = DL.getTypeStoreSizeInBits(LI->getType());
247 *Alignment = LI->getAlignment();
248 PtrOperand = LI->getPointerOperand();
249 } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
250 if (!ClInstrumentWrites) return nullptr;
251 *IsWrite = true;
252 *TypeSize = DL.getTypeStoreSizeInBits(SI->getValueOperand()->getType());
253 *Alignment = SI->getAlignment();
254 PtrOperand = SI->getPointerOperand();
255 } else if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(I)) {
256 if (!ClInstrumentAtomics) return nullptr;
257 *IsWrite = true;
258 *TypeSize = DL.getTypeStoreSizeInBits(RMW->getValOperand()->getType());
259 *Alignment = 0;
260 PtrOperand = RMW->getPointerOperand();
261 } else if (AtomicCmpXchgInst *XCHG = dyn_cast<AtomicCmpXchgInst>(I)) {
262 if (!ClInstrumentAtomics) return nullptr;
263 *IsWrite = true;
264 *TypeSize = DL.getTypeStoreSizeInBits(XCHG->getCompareOperand()->getType());
265 *Alignment = 0;
266 PtrOperand = XCHG->getPointerOperand();
267 }
268
269 if (PtrOperand) {
270 // Do not instrument acesses from different address spaces; we cannot deal
271 // with them.
272 Type *PtrTy = cast<PointerType>(PtrOperand->getType()->getScalarType());
273 if (PtrTy->getPointerAddressSpace() != 0)
274 return nullptr;
275
276 // Ignore swifterror addresses.
277 // swifterror memory addresses are mem2reg promoted by instruction
278 // selection. As such they cannot have regular uses like an instrumentation
279 // function and it makes no sense to track them as memory.
280 if (PtrOperand->isSwiftError())
281 return nullptr;
282 }
283
284 return PtrOperand;
285}
286
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000287static unsigned getPointerOperandIndex(Instruction *I) {
288 if (LoadInst *LI = dyn_cast<LoadInst>(I))
289 return LI->getPointerOperandIndex();
290 if (StoreInst *SI = dyn_cast<StoreInst>(I))
291 return SI->getPointerOperandIndex();
292 if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(I))
293 return RMW->getPointerOperandIndex();
294 if (AtomicCmpXchgInst *XCHG = dyn_cast<AtomicCmpXchgInst>(I))
295 return XCHG->getPointerOperandIndex();
296 report_fatal_error("Unexpected instruction");
297 return -1;
298}
299
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000300static size_t TypeSizeToSizeIndex(uint32_t TypeSize) {
301 size_t Res = countTrailingZeros(TypeSize / 8);
302 assert(Res < kNumberOfAccessSizes);
303 return Res;
304}
305
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000306void HWAddressSanitizer::untagPointerOperand(Instruction *I, Value *Addr) {
307 if (TargetTriple.isAArch64())
308 return;
309
310 IRBuilder<> IRB(I);
311 Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy);
312 Value *UntaggedPtr =
313 IRB.CreateIntToPtr(untagPointer(IRB, AddrLong), Addr->getType());
314 I->setOperand(getPointerOperandIndex(I), UntaggedPtr);
315}
316
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000317void HWAddressSanitizer::instrumentMemAccessInline(Value *PtrLong, bool IsWrite,
318 unsigned AccessSizeIndex,
319 Instruction *InsertBefore) {
320 IRBuilder<> IRB(InsertBefore);
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000321 Value *PtrTag = IRB.CreateTrunc(IRB.CreateLShr(PtrLong, kPointerTagShift),
322 IRB.getInt8Ty());
Evgeniy Stepanov43271b12018-02-21 19:52:23 +0000323 Value *AddrLong = untagPointer(IRB, PtrLong);
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000324 Value *ShadowLong = IRB.CreateLShr(AddrLong, kShadowScale);
Evgeniy Stepanov5bd669d2018-01-17 23:24:38 +0000325 if (ClMappingOffset)
326 ShadowLong = IRB.CreateAdd(
327 ShadowLong, ConstantInt::get(PtrLong->getType(), ClMappingOffset,
328 /*isSigned=*/false));
329 Value *MemTag =
330 IRB.CreateLoad(IRB.CreateIntToPtr(ShadowLong, IRB.getInt8PtrTy()));
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000331 Value *TagMismatch = IRB.CreateICmpNE(PtrTag, MemTag);
332
333 TerminatorInst *CheckTerm =
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000334 SplitBlockAndInsertIfThen(TagMismatch, InsertBefore, !Recover,
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000335 MDBuilder(*C).createBranchWeights(1, 100000));
336
337 IRB.SetInsertPoint(CheckTerm);
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000338 const int64_t AccessInfo = Recover * 0x20 + IsWrite * 0x10 + AccessSizeIndex;
339 InlineAsm *Asm;
340 switch (TargetTriple.getArch()) {
341 case Triple::x86_64:
342 // The signal handler will find the data address in rdi.
343 Asm = InlineAsm::get(
344 FunctionType::get(IRB.getVoidTy(), {PtrLong->getType()}, false),
345 "int3\nnopl " + itostr(0x40 + AccessInfo) + "(%rax)",
346 "{rdi}",
347 /*hasSideEffects=*/true);
348 break;
349 case Triple::aarch64:
350 case Triple::aarch64_be:
351 // The signal handler will find the data address in x0.
352 Asm = InlineAsm::get(
353 FunctionType::get(IRB.getVoidTy(), {PtrLong->getType()}, false),
354 "brk #" + itostr(0x900 + AccessInfo),
355 "{x0}",
356 /*hasSideEffects=*/true);
357 break;
358 default:
359 report_fatal_error("unsupported architecture");
360 }
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000361 IRB.CreateCall(Asm, PtrLong);
362}
363
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000364bool HWAddressSanitizer::instrumentMemAccess(Instruction *I) {
365 DEBUG(dbgs() << "Instrumenting: " << *I << "\n");
366 bool IsWrite = false;
367 unsigned Alignment = 0;
368 uint64_t TypeSize = 0;
369 Value *MaybeMask = nullptr;
370 Value *Addr =
371 isInterestingMemoryAccess(I, &IsWrite, &TypeSize, &Alignment, &MaybeMask);
372
373 if (!Addr)
374 return false;
375
376 if (MaybeMask)
377 return false; //FIXME
378
379 IRBuilder<> IRB(I);
380 Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy);
381 if (isPowerOf2_64(TypeSize) &&
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000382 (TypeSize / 8 <= (1UL << (kNumberOfAccessSizes - 1))) &&
383 (Alignment >= (1UL << kShadowScale) || Alignment == 0 ||
384 Alignment >= TypeSize / 8)) {
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000385 size_t AccessSizeIndex = TypeSizeToSizeIndex(TypeSize);
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000386 if (ClInstrumentWithCalls) {
387 IRB.CreateCall(HwasanMemoryAccessCallback[IsWrite][AccessSizeIndex],
388 AddrLong);
389 } else {
390 instrumentMemAccessInline(AddrLong, IsWrite, AccessSizeIndex, I);
391 }
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000392 } else {
393 IRB.CreateCall(HwasanMemoryAccessCallbackSized[IsWrite],
394 {AddrLong, ConstantInt::get(IntptrTy, TypeSize / 8)});
395 }
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000396 untagPointerOperand(I, Addr);
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000397
398 return true;
399}
400
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000401static uint64_t getAllocaSizeInBytes(const AllocaInst &AI) {
402 uint64_t ArraySize = 1;
403 if (AI.isArrayAllocation()) {
404 const ConstantInt *CI = dyn_cast<ConstantInt>(AI.getArraySize());
405 assert(CI && "non-constant array size");
406 ArraySize = CI->getZExtValue();
407 }
408 Type *Ty = AI.getAllocatedType();
409 uint64_t SizeInBytes = AI.getModule()->getDataLayout().getTypeAllocSize(Ty);
410 return SizeInBytes * ArraySize;
411}
412
413bool HWAddressSanitizer::tagAlloca(IRBuilder<> &IRB, AllocaInst *AI,
414 Value *Tag) {
415 size_t Size = (getAllocaSizeInBytes(*AI) + kAllocaAlignment - 1) &
416 ~(kAllocaAlignment - 1);
417
418 Value *JustTag = IRB.CreateTrunc(Tag, IRB.getInt8Ty());
419 if (ClInstrumentWithCalls) {
420 IRB.CreateCall(HwasanTagMemoryFunc,
421 {IRB.CreatePointerCast(AI, IntptrTy), JustTag,
422 ConstantInt::get(IntptrTy, Size)});
423 } else {
424 size_t ShadowSize = Size >> kShadowScale;
425 Value *ShadowPtr = IRB.CreateIntToPtr(
426 IRB.CreateLShr(IRB.CreatePointerCast(AI, IntptrTy), kShadowScale),
427 IRB.getInt8PtrTy());
428 // If this memset is not inlined, it will be intercepted in the hwasan
429 // runtime library. That's OK, because the interceptor skips the checks if
430 // the address is in the shadow region.
431 // FIXME: the interceptor is not as fast as real memset. Consider lowering
432 // llvm.memset right here into either a sequence of stores, or a call to
433 // hwasan_tag_memory.
434 IRB.CreateMemSet(ShadowPtr, JustTag, ShadowSize, /*Align=*/1);
435 }
436 return true;
437}
438
439static unsigned RetagMask(unsigned AllocaNo) {
440 // A list of 8-bit numbers that have at most one run of non-zero bits.
441 // x = x ^ (mask << 56) can be encoded as a single armv8 instruction for these
442 // masks.
443 // The list does not include the value 255, which is used for UAR.
444 static unsigned FastMasks[] = {
445 0, 1, 2, 3, 4, 6, 7, 8, 12, 14, 15, 16, 24,
446 28, 30, 31, 32, 48, 56, 60, 62, 63, 64, 96, 112, 120,
447 124, 126, 127, 128, 192, 224, 240, 248, 252, 254};
448 return FastMasks[AllocaNo % (sizeof(FastMasks) / sizeof(FastMasks[0]))];
449}
450
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000451Value *HWAddressSanitizer::getNextTagWithCall(IRBuilder<> &IRB) {
452 return IRB.CreateZExt(IRB.CreateCall(HwasanGenerateTagFunc), IntptrTy);
453}
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000454
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000455Value *HWAddressSanitizer::getStackBaseTag(IRBuilder<> &IRB) {
456 if (ClGenerateTagsWithCalls)
457 return nullptr;
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000458 // FIXME: use addressofreturnaddress (but implement it in aarch64 backend
459 // first).
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000460 Module *M = IRB.GetInsertBlock()->getParent()->getParent();
461 auto GetStackPointerFn =
462 Intrinsic::getDeclaration(M, Intrinsic::frameaddress);
463 Value *StackPointer = IRB.CreateCall(
464 GetStackPointerFn, {Constant::getNullValue(IRB.getInt32Ty())});
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000465
466 // Extract some entropy from the stack pointer for the tags.
467 // Take bits 20..28 (ASLR entropy) and xor with bits 0..8 (these differ
468 // between functions).
469 Value *StackPointerLong = IRB.CreatePointerCast(StackPointer, IntptrTy);
470 Value *StackTag =
471 IRB.CreateXor(StackPointerLong, IRB.CreateLShr(StackPointerLong, 20),
472 "hwasan.stack.base.tag");
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000473 return StackTag;
474}
475
476Value *HWAddressSanitizer::getAllocaTag(IRBuilder<> &IRB, Value *StackTag,
477 AllocaInst *AI, unsigned AllocaNo) {
478 if (ClGenerateTagsWithCalls)
479 return getNextTagWithCall(IRB);
480 return IRB.CreateXor(StackTag,
481 ConstantInt::get(IntptrTy, RetagMask(AllocaNo)));
482}
483
484Value *HWAddressSanitizer::getUARTag(IRBuilder<> &IRB, Value *StackTag) {
485 if (ClGenerateTagsWithCalls)
486 return getNextTagWithCall(IRB);
487 return IRB.CreateXor(StackTag, ConstantInt::get(IntptrTy, 0xFFU));
488}
489
Evgeniy Stepanov80ccda22018-02-09 00:59:10 +0000490// Add a tag to an address.
491Value *HWAddressSanitizer::tagPointer(IRBuilder<> &IRB, Type *Ty, Value *PtrLong,
492 Value *Tag) {
493 Value *TaggedPtrLong;
494 if (ClEnableKhwasan) {
495 // Kernel addresses have 0xFF in the most significant byte.
496 Value *ShiftedTag = IRB.CreateOr(
497 IRB.CreateShl(Tag, kPointerTagShift),
498 ConstantInt::get(IntptrTy, (1ULL << kPointerTagShift) - 1));
499 TaggedPtrLong = IRB.CreateAnd(PtrLong, ShiftedTag);
500 } else {
501 // Userspace can simply do OR (tag << 56);
502 Value *ShiftedTag = IRB.CreateShl(Tag, kPointerTagShift);
503 TaggedPtrLong = IRB.CreateOr(PtrLong, ShiftedTag);
504 }
505 return IRB.CreateIntToPtr(TaggedPtrLong, Ty);
506}
507
Evgeniy Stepanov43271b12018-02-21 19:52:23 +0000508// Remove tag from an address.
509Value *HWAddressSanitizer::untagPointer(IRBuilder<> &IRB, Value *PtrLong) {
510 Value *UntaggedPtrLong;
511 if (ClEnableKhwasan) {
512 // Kernel addresses have 0xFF in the most significant byte.
513 UntaggedPtrLong = IRB.CreateOr(PtrLong,
514 ConstantInt::get(PtrLong->getType(), 0xFFULL << kPointerTagShift));
515 } else {
516 // Userspace addresses have 0x00.
517 UntaggedPtrLong = IRB.CreateAnd(PtrLong,
518 ConstantInt::get(PtrLong->getType(), ~(0xFFULL << kPointerTagShift)));
519 }
520 return UntaggedPtrLong;
521}
522
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000523bool HWAddressSanitizer::instrumentStack(
524 SmallVectorImpl<AllocaInst *> &Allocas,
525 SmallVectorImpl<Instruction *> &RetVec) {
526 Function *F = Allocas[0]->getParent()->getParent();
527 Instruction *InsertPt = &*F->getEntryBlock().begin();
528 IRBuilder<> IRB(InsertPt);
529
530 Value *StackTag = getStackBaseTag(IRB);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000531
532 // Ideally, we want to calculate tagged stack base pointer, and rewrite all
533 // alloca addresses using that. Unfortunately, offsets are not known yet
534 // (unless we use ASan-style mega-alloca). Instead we keep the base tag in a
535 // temp, shift-OR it into each alloca address and xor with the retag mask.
536 // This generates one extra instruction per alloca use.
537 for (unsigned N = 0; N < Allocas.size(); ++N) {
538 auto *AI = Allocas[N];
539 IRB.SetInsertPoint(AI->getNextNode());
540
541 // Replace uses of the alloca with tagged address.
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000542 Value *Tag = getAllocaTag(IRB, StackTag, AI, N);
543 Value *AILong = IRB.CreatePointerCast(AI, IntptrTy);
Evgeniy Stepanov80ccda22018-02-09 00:59:10 +0000544 Value *Replacement = tagPointer(IRB, AI->getType(), AILong, Tag);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000545 std::string Name =
546 AI->hasName() ? AI->getName().str() : "alloca." + itostr(N);
Evgeniy Stepanov80ccda22018-02-09 00:59:10 +0000547 Replacement->setName(Name + ".hwasan");
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000548
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000549 for (auto UI = AI->use_begin(), UE = AI->use_end(); UI != UE;) {
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000550 Use &U = *UI++;
551 if (U.getUser() != AILong)
552 U.set(Replacement);
553 }
554
555 tagAlloca(IRB, AI, Tag);
556
557 for (auto RI : RetVec) {
558 IRB.SetInsertPoint(RI);
559
560 // Re-tag alloca memory with the special UAR tag.
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000561 Value *Tag = getUARTag(IRB, StackTag);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000562 tagAlloca(IRB, AI, Tag);
563 }
564 }
565
566 return true;
567}
568
569bool HWAddressSanitizer::isInterestingAlloca(const AllocaInst &AI) {
570 return (AI.getAllocatedType()->isSized() &&
571 // FIXME: instrument dynamic allocas, too
572 AI.isStaticAlloca() &&
573 // alloca() may be called with 0 size, ignore it.
574 getAllocaSizeInBytes(AI) > 0 &&
575 // We are only interested in allocas not promotable to registers.
576 // Promotable allocas are common under -O0.
577 !isAllocaPromotable(&AI) &&
578 // inalloca allocas are not treated as static, and we don't want
579 // dynamic alloca instrumentation for them as well.
580 !AI.isUsedWithInAlloca() &&
581 // swifterror allocas are register promoted by ISel
582 !AI.isSwiftError());
583}
584
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000585bool HWAddressSanitizer::runOnFunction(Function &F) {
586 if (&F == HwasanCtorFunction)
587 return false;
588
589 if (!F.hasFnAttribute(Attribute::SanitizeHWAddress))
590 return false;
591
592 DEBUG(dbgs() << "Function: " << F.getName() << "\n");
593
594 initializeCallbacks(*F.getParent());
595
596 bool Changed = false;
597 SmallVector<Instruction*, 16> ToInstrument;
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000598 SmallVector<AllocaInst*, 8> AllocasToInstrument;
599 SmallVector<Instruction*, 8> RetVec;
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000600 for (auto &BB : F) {
601 for (auto &Inst : BB) {
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000602 if (ClInstrumentStack)
603 if (AllocaInst *AI = dyn_cast<AllocaInst>(&Inst)) {
604 // Realign all allocas. We don't want small uninteresting allocas to
605 // hide in instrumented alloca's padding.
606 if (AI->getAlignment() < kAllocaAlignment)
607 AI->setAlignment(kAllocaAlignment);
608 // Instrument some of them.
609 if (isInterestingAlloca(*AI))
610 AllocasToInstrument.push_back(AI);
611 continue;
612 }
613
614 if (isa<ReturnInst>(Inst) || isa<ResumeInst>(Inst) || isa<CleanupReturnInst>(Inst))
615 RetVec.push_back(&Inst);
616
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000617 Value *MaybeMask = nullptr;
618 bool IsWrite;
619 unsigned Alignment;
620 uint64_t TypeSize;
621 Value *Addr = isInterestingMemoryAccess(&Inst, &IsWrite, &TypeSize,
622 &Alignment, &MaybeMask);
623 if (Addr || isa<MemIntrinsic>(Inst))
624 ToInstrument.push_back(&Inst);
625 }
626 }
627
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000628 if (!AllocasToInstrument.empty())
629 Changed |= instrumentStack(AllocasToInstrument, RetVec);
630
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000631 for (auto Inst : ToInstrument)
632 Changed |= instrumentMemAccess(Inst);
633
634 return Changed;
635}