blob: 34a66296f6f9d0ddff290ce7a42d06be2f9575d8 [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"
Kostya Serebryanyaf955972018-10-23 00:50:40 +000047#include <sstream>
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +000048
49using namespace llvm;
50
51#define DEBUG_TYPE "hwasan"
52
53static const char *const kHwasanModuleCtorName = "hwasan.module_ctor";
54static const char *const kHwasanInitName = "__hwasan_init";
55
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +000056static const char *const kHwasanShadowMemoryDynamicAddress =
57 "__hwasan_shadow_memory_dynamic_address";
58
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +000059// Accesses sizes are powers of two: 1, 2, 4, 8, 16.
60static const size_t kNumberOfAccessSizes = 5;
61
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +000062static const size_t kDefaultShadowScale = 4;
63static const uint64_t kDynamicShadowSentinel =
64 std::numeric_limits<uint64_t>::max();
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +000065static const unsigned kPointerTagShift = 56;
66
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +000067static const unsigned kShadowBaseAlignment = 32;
68
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +000069static cl::opt<std::string> ClMemoryAccessCallbackPrefix(
70 "hwasan-memory-access-callback-prefix",
71 cl::desc("Prefix for memory access callbacks"), cl::Hidden,
72 cl::init("__hwasan_"));
73
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +000074static cl::opt<bool>
75 ClInstrumentWithCalls("hwasan-instrument-with-calls",
76 cl::desc("instrument reads and writes with callbacks"),
77 cl::Hidden, cl::init(false));
78
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +000079static cl::opt<bool> ClInstrumentReads("hwasan-instrument-reads",
80 cl::desc("instrument read instructions"),
81 cl::Hidden, cl::init(true));
82
83static cl::opt<bool> ClInstrumentWrites(
84 "hwasan-instrument-writes", cl::desc("instrument write instructions"),
85 cl::Hidden, cl::init(true));
86
87static cl::opt<bool> ClInstrumentAtomics(
88 "hwasan-instrument-atomics",
89 cl::desc("instrument atomic instructions (rmw, cmpxchg)"), cl::Hidden,
90 cl::init(true));
91
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +000092static cl::opt<bool> ClRecover(
93 "hwasan-recover",
94 cl::desc("Enable recovery mode (continue-after-error)."),
95 cl::Hidden, cl::init(false));
96
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +000097static cl::opt<bool> ClInstrumentStack("hwasan-instrument-stack",
98 cl::desc("instrument stack (allocas)"),
99 cl::Hidden, cl::init(true));
100
Alex Shlyapnikov788764c2018-06-29 20:20:17 +0000101static cl::opt<bool> ClUARRetagToZero(
102 "hwasan-uar-retag-to-zero",
103 cl::desc("Clear alloca tags before returning from the function to allow "
104 "non-instrumented and instrumented function calls mix. When set "
105 "to false, allocas are retagged before returning from the "
106 "function to detect use after return."),
107 cl::Hidden, cl::init(true));
108
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000109static cl::opt<bool> ClGenerateTagsWithCalls(
110 "hwasan-generate-tags-with-calls",
111 cl::desc("generate new tags with runtime library calls"), cl::Hidden,
112 cl::init(false));
113
Evgeniy Stepanov1f1a7a72018-04-04 20:44:59 +0000114static cl::opt<int> ClMatchAllTag(
115 "hwasan-match-all-tag",
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000116 cl::desc("don't report bad accesses via pointers with this tag"),
117 cl::Hidden, cl::init(-1));
Evgeniy Stepanov1f1a7a72018-04-04 20:44:59 +0000118
Evgeniy Stepanov5bd669d2018-01-17 23:24:38 +0000119static cl::opt<bool> ClEnableKhwasan(
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000120 "hwasan-kernel",
121 cl::desc("Enable KernelHWAddressSanitizer instrumentation"),
Evgeniy Stepanov5bd669d2018-01-17 23:24:38 +0000122 cl::Hidden, cl::init(false));
123
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000124// These flags allow to change the shadow mapping and control how shadow memory
125// is accessed. The shadow mapping looks like:
126// Shadow = (Mem >> scale) + offset
127
128static cl::opt<unsigned long long> ClMappingOffset(
129 "hwasan-mapping-offset",
130 cl::desc("HWASan shadow mapping offset [EXPERIMENTAL]"), cl::Hidden,
131 cl::init(0));
132
Evgeniy Stepanov453e7ac2018-08-10 16:21:37 +0000133static cl::opt<bool>
134 ClWithIfunc("hwasan-with-ifunc",
135 cl::desc("Access dynamic shadow through an ifunc global on "
136 "platforms that support this"),
137 cl::Hidden, cl::init(false));
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000138
139static cl::opt<bool> ClWithTls(
140 "hwasan-with-tls",
141 cl::desc("Access dynamic shadow through an thread-local pointer on "
142 "platforms that support this"),
143 cl::Hidden, cl::init(true));
144
145static cl::opt<bool>
146 ClRecordStackHistory("hwasan-record-stack-history",
147 cl::desc("Record stack frames with tagged allocations "
148 "in a thread-local ring buffer"),
149 cl::Hidden, cl::init(true));
Kostya Serebryanyaf955972018-10-23 00:50:40 +0000150static cl::opt<bool>
151 ClCreateFrameDescriptions("hwasan-create-frame-descriptions",
152 cl::desc("create static frame descriptions"),
153 cl::Hidden, cl::init(true));
154
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000155namespace {
156
Adrian Prantl5f8f34e42018-05-01 15:54:18 +0000157/// An instrumentation pass implementing detection of addressability bugs
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000158/// using tagged pointers.
159class HWAddressSanitizer : public FunctionPass {
160public:
161 // Pass identification, replacement for typeid.
162 static char ID;
163
Andrey Konovalov1ba9d9c2018-04-13 18:05:21 +0000164 explicit HWAddressSanitizer(bool CompileKernel = false, bool Recover = false)
165 : FunctionPass(ID) {
166 this->Recover = ClRecover.getNumOccurrences() > 0 ? ClRecover : Recover;
167 this->CompileKernel = ClEnableKhwasan.getNumOccurrences() > 0 ?
168 ClEnableKhwasan : CompileKernel;
169 }
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000170
171 StringRef getPassName() const override { return "HWAddressSanitizer"; }
172
173 bool runOnFunction(Function &F) override;
174 bool doInitialization(Module &M) override;
175
176 void initializeCallbacks(Module &M);
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000177
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000178 Value *getDynamicShadowNonTls(IRBuilder<> &IRB);
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000179
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000180 void untagPointerOperand(Instruction *I, Value *Addr);
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000181 Value *memToShadow(Value *Shadow, Type *Ty, IRBuilder<> &IRB);
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000182 void instrumentMemAccessInline(Value *PtrLong, bool IsWrite,
183 unsigned AccessSizeIndex,
184 Instruction *InsertBefore);
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000185 bool instrumentMemAccess(Instruction *I);
186 Value *isInterestingMemoryAccess(Instruction *I, bool *IsWrite,
187 uint64_t *TypeSize, unsigned *Alignment,
188 Value **MaybeMask);
189
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000190 bool isInterestingAlloca(const AllocaInst &AI);
191 bool tagAlloca(IRBuilder<> &IRB, AllocaInst *AI, Value *Tag);
Evgeniy Stepanov80ccda22018-02-09 00:59:10 +0000192 Value *tagPointer(IRBuilder<> &IRB, Type *Ty, Value *PtrLong, Value *Tag);
Evgeniy Stepanov43271b12018-02-21 19:52:23 +0000193 Value *untagPointer(IRBuilder<> &IRB, Value *PtrLong);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000194 bool instrumentStack(SmallVectorImpl<AllocaInst *> &Allocas,
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000195 SmallVectorImpl<Instruction *> &RetVec, Value *StackTag);
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000196 Value *getNextTagWithCall(IRBuilder<> &IRB);
197 Value *getStackBaseTag(IRBuilder<> &IRB);
198 Value *getAllocaTag(IRBuilder<> &IRB, Value *StackTag, AllocaInst *AI,
199 unsigned AllocaNo);
200 Value *getUARTag(IRBuilder<> &IRB, Value *StackTag);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000201
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000202 Value *getHwasanThreadSlotPtr(IRBuilder<> &IRB, Type *Ty);
203 Value *emitPrologue(IRBuilder<> &IRB, bool WithFrameRecord);
204
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000205private:
206 LLVMContext *C;
Kostya Serebryanyaf955972018-10-23 00:50:40 +0000207 std::string CurModuleUniqueId;
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000208 Triple TargetTriple;
209
Kostya Serebryanyaf955972018-10-23 00:50:40 +0000210 // Frame description is a way to pass names/sizes of local variables
211 // to the run-time w/o adding extra executable code in every function.
212 // We do this by creating a separate section with {PC,Descr} pairs and passing
213 // the section beg/end to __hwasan_init_frames() at module init time.
214 std::string createFrameString(ArrayRef<AllocaInst*> Allocas);
215 void createFrameGlobal(Function &F, const std::string &FrameString);
216 // Get the section name for frame descriptions. Currently ELF-only.
217 const char *getFrameSection() { return "__hwasan_frames"; }
218 const char *getFrameSectionBeg() { return "__start___hwasan_frames"; }
219 const char *getFrameSectionEnd() { return "__stop___hwasan_frames"; }
220 GlobalVariable *createFrameSectionBound(Module &M, Type *Ty,
221 const char *Name) {
222 auto GV = new GlobalVariable(M, Ty, false, GlobalVariable::ExternalLinkage,
223 nullptr, Name);
224 GV->setVisibility(GlobalValue::HiddenVisibility);
225 return GV;
226 }
227
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000228 /// This struct defines the shadow mapping using the rule:
229 /// shadow = (mem >> Scale) + Offset.
230 /// If InGlobal is true, then
231 /// extern char __hwasan_shadow[];
232 /// shadow = (mem >> Scale) + &__hwasan_shadow
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000233 /// If InTls is true, then
234 /// extern char *__hwasan_tls;
Kostya Serebryanyaf955972018-10-23 00:50:40 +0000235 /// shadow = (mem>>Scale) + align_up(__hwasan_shadow, kShadowBaseAlignment)
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000236 struct ShadowMapping {
237 int Scale;
238 uint64_t Offset;
239 bool InGlobal;
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000240 bool InTls;
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000241
242 void init(Triple &TargetTriple);
243 unsigned getAllocaAlignment() const { return 1U << Scale; }
244 };
245 ShadowMapping Mapping;
246
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000247 Type *IntptrTy;
Evgeniy Stepanova265a132018-08-15 00:39:35 +0000248 Type *Int8PtrTy;
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000249 Type *Int8Ty;
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000250
Andrey Konovalov1ba9d9c2018-04-13 18:05:21 +0000251 bool CompileKernel;
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000252 bool Recover;
253
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000254 Function *HwasanCtorFunction;
255
256 Function *HwasanMemoryAccessCallback[2][kNumberOfAccessSizes];
257 Function *HwasanMemoryAccessCallbackSized[2];
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000258
259 Function *HwasanTagMemoryFunc;
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000260 Function *HwasanGenerateTagFunc;
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000261
262 Constant *ShadowGlobal;
263
264 Value *LocalDynamicShadow = nullptr;
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000265 GlobalValue *ThreadPtrGlobal = nullptr;
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000266};
267
268} // end anonymous namespace
269
270char HWAddressSanitizer::ID = 0;
271
272INITIALIZE_PASS_BEGIN(
273 HWAddressSanitizer, "hwasan",
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000274 "HWAddressSanitizer: detect memory bugs using tagged addressing.", false,
275 false)
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000276INITIALIZE_PASS_END(
277 HWAddressSanitizer, "hwasan",
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000278 "HWAddressSanitizer: detect memory bugs using tagged addressing.", false,
279 false)
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000280
Andrey Konovalov1ba9d9c2018-04-13 18:05:21 +0000281FunctionPass *llvm::createHWAddressSanitizerPass(bool CompileKernel,
282 bool Recover) {
283 assert(!CompileKernel || Recover);
284 return new HWAddressSanitizer(CompileKernel, Recover);
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000285}
286
Adrian Prantl5f8f34e42018-05-01 15:54:18 +0000287/// Module-level initialization.
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000288///
289/// inserts a call to __hwasan_init to the module's constructor list.
290bool HWAddressSanitizer::doInitialization(Module &M) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000291 LLVM_DEBUG(dbgs() << "Init " << M.getName() << "\n");
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000292 auto &DL = M.getDataLayout();
293
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000294 TargetTriple = Triple(M.getTargetTriple());
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000295
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000296 Mapping.init(TargetTriple);
297
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000298 C = &(M.getContext());
Kostya Serebryanyaf955972018-10-23 00:50:40 +0000299 CurModuleUniqueId = getUniqueModuleId(&M);
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000300 IRBuilder<> IRB(*C);
301 IntptrTy = IRB.getIntPtrTy(DL);
Evgeniy Stepanova265a132018-08-15 00:39:35 +0000302 Int8PtrTy = IRB.getInt8PtrTy();
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000303 Int8Ty = IRB.getInt8Ty();
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000304
Benjamin Kramerbfc1d972018-01-18 14:19:04 +0000305 HwasanCtorFunction = nullptr;
Andrey Konovalov1ba9d9c2018-04-13 18:05:21 +0000306 if (!CompileKernel) {
Evgeniy Stepanov5bd669d2018-01-17 23:24:38 +0000307 std::tie(HwasanCtorFunction, std::ignore) =
308 createSanitizerCtorAndInitFunctions(M, kHwasanModuleCtorName,
309 kHwasanInitName,
310 /*InitArgTypes=*/{},
311 /*InitArgs=*/{});
312 appendToGlobalCtors(M, HwasanCtorFunction, 0);
313 }
Kostya Serebryanyaf955972018-10-23 00:50:40 +0000314
315 // Create a call to __hwasan_init_frames.
316 if (HwasanCtorFunction) {
317 // Create a dummy frame description for the CTOR function.
318 // W/o it we would have to create the call to __hwasan_init_frames after
319 // all functions are instrumented (i.e. need to have a ModulePass).
320 createFrameGlobal(*HwasanCtorFunction, "");
321 IRBuilder<> IRBCtor(HwasanCtorFunction->getEntryBlock().getTerminator());
322 IRBCtor.CreateCall(
323 declareSanitizerInitFunction(M, "__hwasan_init_frames",
324 {Int8PtrTy, Int8PtrTy}),
325 {createFrameSectionBound(M, Int8Ty, getFrameSectionBeg()),
326 createFrameSectionBound(M, Int8Ty, getFrameSectionEnd())});
327 }
328
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000329 if (!TargetTriple.isAndroid())
330 appendToCompilerUsed(
331 M, ThreadPtrGlobal = new GlobalVariable(
332 M, IntptrTy, false, GlobalVariable::ExternalLinkage, nullptr,
333 "__hwasan_tls", nullptr, GlobalVariable::InitialExecTLSModel));
334
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000335 return true;
336}
337
338void HWAddressSanitizer::initializeCallbacks(Module &M) {
339 IRBuilder<> IRB(*C);
340 for (size_t AccessIsWrite = 0; AccessIsWrite <= 1; AccessIsWrite++) {
341 const std::string TypeStr = AccessIsWrite ? "store" : "load";
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000342 const std::string EndingStr = Recover ? "_noabort" : "";
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000343
344 HwasanMemoryAccessCallbackSized[AccessIsWrite] =
345 checkSanitizerInterfaceFunction(M.getOrInsertFunction(
Evgeniy Stepanovc07e0bd2018-01-16 23:15:08 +0000346 ClMemoryAccessCallbackPrefix + TypeStr + "N" + EndingStr,
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000347 FunctionType::get(IRB.getVoidTy(), {IntptrTy, IntptrTy}, false)));
348
349 for (size_t AccessSizeIndex = 0; AccessSizeIndex < kNumberOfAccessSizes;
350 AccessSizeIndex++) {
351 HwasanMemoryAccessCallback[AccessIsWrite][AccessSizeIndex] =
352 checkSanitizerInterfaceFunction(M.getOrInsertFunction(
353 ClMemoryAccessCallbackPrefix + TypeStr +
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000354 itostr(1ULL << AccessSizeIndex) + EndingStr,
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000355 FunctionType::get(IRB.getVoidTy(), {IntptrTy}, false)));
356 }
357 }
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000358
359 HwasanTagMemoryFunc = checkSanitizerInterfaceFunction(M.getOrInsertFunction(
Evgeniy Stepanova265a132018-08-15 00:39:35 +0000360 "__hwasan_tag_memory", IRB.getVoidTy(), Int8PtrTy, Int8Ty, IntptrTy));
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000361 HwasanGenerateTagFunc = checkSanitizerInterfaceFunction(
362 M.getOrInsertFunction("__hwasan_generate_tag", Int8Ty));
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000363
364 if (Mapping.InGlobal)
365 ShadowGlobal = M.getOrInsertGlobal("__hwasan_shadow",
366 ArrayType::get(IRB.getInt8Ty(), 0));
367}
368
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000369Value *HWAddressSanitizer::getDynamicShadowNonTls(IRBuilder<> &IRB) {
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000370 // Generate code only when dynamic addressing is needed.
371 if (Mapping.Offset != kDynamicShadowSentinel)
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000372 return nullptr;
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000373
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000374 if (Mapping.InGlobal) {
375 // An empty inline asm with input reg == output reg.
376 // An opaque pointer-to-int cast, basically.
377 InlineAsm *Asm = InlineAsm::get(
378 FunctionType::get(IntptrTy, {ShadowGlobal->getType()}, false),
379 StringRef(""), StringRef("=r,0"),
380 /*hasSideEffects=*/false);
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000381 return IRB.CreateCall(Asm, {ShadowGlobal}, ".hwasan.shadow");
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000382 } else {
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000383 Value *GlobalDynamicAddress =
384 IRB.GetInsertBlock()->getParent()->getParent()->getOrInsertGlobal(
385 kHwasanShadowMemoryDynamicAddress, IntptrTy);
386 return IRB.CreateLoad(GlobalDynamicAddress);
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000387 }
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000388}
389
390Value *HWAddressSanitizer::isInterestingMemoryAccess(Instruction *I,
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000391 bool *IsWrite,
392 uint64_t *TypeSize,
393 unsigned *Alignment,
394 Value **MaybeMask) {
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000395 // Skip memory accesses inserted by another instrumentation.
396 if (I->getMetadata("nosanitize")) return nullptr;
397
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000398 // Do not instrument the load fetching the dynamic shadow address.
399 if (LocalDynamicShadow == I)
400 return nullptr;
401
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000402 Value *PtrOperand = nullptr;
403 const DataLayout &DL = I->getModule()->getDataLayout();
404 if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
405 if (!ClInstrumentReads) return nullptr;
406 *IsWrite = false;
407 *TypeSize = DL.getTypeStoreSizeInBits(LI->getType());
408 *Alignment = LI->getAlignment();
409 PtrOperand = LI->getPointerOperand();
410 } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
411 if (!ClInstrumentWrites) return nullptr;
412 *IsWrite = true;
413 *TypeSize = DL.getTypeStoreSizeInBits(SI->getValueOperand()->getType());
414 *Alignment = SI->getAlignment();
415 PtrOperand = SI->getPointerOperand();
416 } else if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(I)) {
417 if (!ClInstrumentAtomics) return nullptr;
418 *IsWrite = true;
419 *TypeSize = DL.getTypeStoreSizeInBits(RMW->getValOperand()->getType());
420 *Alignment = 0;
421 PtrOperand = RMW->getPointerOperand();
422 } else if (AtomicCmpXchgInst *XCHG = dyn_cast<AtomicCmpXchgInst>(I)) {
423 if (!ClInstrumentAtomics) return nullptr;
424 *IsWrite = true;
425 *TypeSize = DL.getTypeStoreSizeInBits(XCHG->getCompareOperand()->getType());
426 *Alignment = 0;
427 PtrOperand = XCHG->getPointerOperand();
428 }
429
430 if (PtrOperand) {
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000431 // Do not instrument accesses from different address spaces; we cannot deal
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000432 // with them.
433 Type *PtrTy = cast<PointerType>(PtrOperand->getType()->getScalarType());
434 if (PtrTy->getPointerAddressSpace() != 0)
435 return nullptr;
436
437 // Ignore swifterror addresses.
438 // swifterror memory addresses are mem2reg promoted by instruction
439 // selection. As such they cannot have regular uses like an instrumentation
440 // function and it makes no sense to track them as memory.
441 if (PtrOperand->isSwiftError())
442 return nullptr;
443 }
444
445 return PtrOperand;
446}
447
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000448static unsigned getPointerOperandIndex(Instruction *I) {
449 if (LoadInst *LI = dyn_cast<LoadInst>(I))
450 return LI->getPointerOperandIndex();
451 if (StoreInst *SI = dyn_cast<StoreInst>(I))
452 return SI->getPointerOperandIndex();
453 if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(I))
454 return RMW->getPointerOperandIndex();
455 if (AtomicCmpXchgInst *XCHG = dyn_cast<AtomicCmpXchgInst>(I))
456 return XCHG->getPointerOperandIndex();
457 report_fatal_error("Unexpected instruction");
458 return -1;
459}
460
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000461static size_t TypeSizeToSizeIndex(uint32_t TypeSize) {
462 size_t Res = countTrailingZeros(TypeSize / 8);
463 assert(Res < kNumberOfAccessSizes);
464 return Res;
465}
466
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000467void HWAddressSanitizer::untagPointerOperand(Instruction *I, Value *Addr) {
468 if (TargetTriple.isAArch64())
469 return;
470
471 IRBuilder<> IRB(I);
472 Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy);
473 Value *UntaggedPtr =
474 IRB.CreateIntToPtr(untagPointer(IRB, AddrLong), Addr->getType());
475 I->setOperand(getPointerOperandIndex(I), UntaggedPtr);
476}
477
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000478Value *HWAddressSanitizer::memToShadow(Value *Mem, Type *Ty, IRBuilder<> &IRB) {
479 // Mem >> Scale
480 Value *Shadow = IRB.CreateLShr(Mem, Mapping.Scale);
481 if (Mapping.Offset == 0)
482 return Shadow;
483 // (Mem >> Scale) + Offset
484 Value *ShadowBase;
485 if (LocalDynamicShadow)
486 ShadowBase = LocalDynamicShadow;
487 else
488 ShadowBase = ConstantInt::get(Ty, Mapping.Offset);
489 return IRB.CreateAdd(Shadow, ShadowBase);
490}
491
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000492void HWAddressSanitizer::instrumentMemAccessInline(Value *PtrLong, bool IsWrite,
493 unsigned AccessSizeIndex,
494 Instruction *InsertBefore) {
495 IRBuilder<> IRB(InsertBefore);
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000496 Value *PtrTag = IRB.CreateTrunc(IRB.CreateLShr(PtrLong, kPointerTagShift),
497 IRB.getInt8Ty());
Evgeniy Stepanov43271b12018-02-21 19:52:23 +0000498 Value *AddrLong = untagPointer(IRB, PtrLong);
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000499 Value *ShadowLong = memToShadow(AddrLong, PtrLong->getType(), IRB);
Evgeniy Stepanova265a132018-08-15 00:39:35 +0000500 Value *MemTag = IRB.CreateLoad(IRB.CreateIntToPtr(ShadowLong, Int8PtrTy));
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000501 Value *TagMismatch = IRB.CreateICmpNE(PtrTag, MemTag);
502
Andrey Konovalov1ba9d9c2018-04-13 18:05:21 +0000503 int matchAllTag = ClMatchAllTag.getNumOccurrences() > 0 ?
504 ClMatchAllTag : (CompileKernel ? 0xFF : -1);
505 if (matchAllTag != -1) {
Evgeniy Stepanov1f1a7a72018-04-04 20:44:59 +0000506 Value *TagNotIgnored = IRB.CreateICmpNE(PtrTag,
Andrey Konovalov1ba9d9c2018-04-13 18:05:21 +0000507 ConstantInt::get(PtrTag->getType(), matchAllTag));
Evgeniy Stepanov1f1a7a72018-04-04 20:44:59 +0000508 TagMismatch = IRB.CreateAnd(TagMismatch, TagNotIgnored);
509 }
510
Chandler Carruth4a2d58e2018-10-15 09:34:05 +0000511 Instruction *CheckTerm =
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000512 SplitBlockAndInsertIfThen(TagMismatch, InsertBefore, !Recover,
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000513 MDBuilder(*C).createBranchWeights(1, 100000));
514
515 IRB.SetInsertPoint(CheckTerm);
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000516 const int64_t AccessInfo = Recover * 0x20 + IsWrite * 0x10 + AccessSizeIndex;
517 InlineAsm *Asm;
518 switch (TargetTriple.getArch()) {
519 case Triple::x86_64:
520 // The signal handler will find the data address in rdi.
521 Asm = InlineAsm::get(
522 FunctionType::get(IRB.getVoidTy(), {PtrLong->getType()}, false),
523 "int3\nnopl " + itostr(0x40 + AccessInfo) + "(%rax)",
524 "{rdi}",
525 /*hasSideEffects=*/true);
526 break;
527 case Triple::aarch64:
528 case Triple::aarch64_be:
529 // The signal handler will find the data address in x0.
530 Asm = InlineAsm::get(
531 FunctionType::get(IRB.getVoidTy(), {PtrLong->getType()}, false),
532 "brk #" + itostr(0x900 + AccessInfo),
533 "{x0}",
534 /*hasSideEffects=*/true);
535 break;
536 default:
537 report_fatal_error("unsupported architecture");
538 }
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000539 IRB.CreateCall(Asm, PtrLong);
540}
541
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000542bool HWAddressSanitizer::instrumentMemAccess(Instruction *I) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000543 LLVM_DEBUG(dbgs() << "Instrumenting: " << *I << "\n");
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000544 bool IsWrite = false;
545 unsigned Alignment = 0;
546 uint64_t TypeSize = 0;
547 Value *MaybeMask = nullptr;
548 Value *Addr =
549 isInterestingMemoryAccess(I, &IsWrite, &TypeSize, &Alignment, &MaybeMask);
550
551 if (!Addr)
552 return false;
553
554 if (MaybeMask)
555 return false; //FIXME
556
557 IRBuilder<> IRB(I);
558 Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy);
559 if (isPowerOf2_64(TypeSize) &&
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000560 (TypeSize / 8 <= (1UL << (kNumberOfAccessSizes - 1))) &&
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000561 (Alignment >= (1UL << Mapping.Scale) || Alignment == 0 ||
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000562 Alignment >= TypeSize / 8)) {
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000563 size_t AccessSizeIndex = TypeSizeToSizeIndex(TypeSize);
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000564 if (ClInstrumentWithCalls) {
565 IRB.CreateCall(HwasanMemoryAccessCallback[IsWrite][AccessSizeIndex],
566 AddrLong);
567 } else {
568 instrumentMemAccessInline(AddrLong, IsWrite, AccessSizeIndex, I);
569 }
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000570 } else {
571 IRB.CreateCall(HwasanMemoryAccessCallbackSized[IsWrite],
572 {AddrLong, ConstantInt::get(IntptrTy, TypeSize / 8)});
573 }
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000574 untagPointerOperand(I, Addr);
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000575
576 return true;
577}
578
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000579static uint64_t getAllocaSizeInBytes(const AllocaInst &AI) {
580 uint64_t ArraySize = 1;
581 if (AI.isArrayAllocation()) {
582 const ConstantInt *CI = dyn_cast<ConstantInt>(AI.getArraySize());
583 assert(CI && "non-constant array size");
584 ArraySize = CI->getZExtValue();
585 }
586 Type *Ty = AI.getAllocatedType();
587 uint64_t SizeInBytes = AI.getModule()->getDataLayout().getTypeAllocSize(Ty);
588 return SizeInBytes * ArraySize;
589}
590
591bool HWAddressSanitizer::tagAlloca(IRBuilder<> &IRB, AllocaInst *AI,
592 Value *Tag) {
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000593 size_t Size = (getAllocaSizeInBytes(*AI) + Mapping.getAllocaAlignment() - 1) &
594 ~(Mapping.getAllocaAlignment() - 1);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000595
596 Value *JustTag = IRB.CreateTrunc(Tag, IRB.getInt8Ty());
597 if (ClInstrumentWithCalls) {
598 IRB.CreateCall(HwasanTagMemoryFunc,
Evgeniy Stepanova265a132018-08-15 00:39:35 +0000599 {IRB.CreatePointerCast(AI, Int8PtrTy), JustTag,
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000600 ConstantInt::get(IntptrTy, Size)});
601 } else {
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000602 size_t ShadowSize = Size >> Mapping.Scale;
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000603 Value *ShadowPtr = IRB.CreateIntToPtr(
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000604 memToShadow(IRB.CreatePointerCast(AI, IntptrTy), AI->getType(), IRB),
Evgeniy Stepanova265a132018-08-15 00:39:35 +0000605 Int8PtrTy);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000606 // If this memset is not inlined, it will be intercepted in the hwasan
607 // runtime library. That's OK, because the interceptor skips the checks if
608 // the address is in the shadow region.
609 // FIXME: the interceptor is not as fast as real memset. Consider lowering
610 // llvm.memset right here into either a sequence of stores, or a call to
611 // hwasan_tag_memory.
612 IRB.CreateMemSet(ShadowPtr, JustTag, ShadowSize, /*Align=*/1);
613 }
614 return true;
615}
616
617static unsigned RetagMask(unsigned AllocaNo) {
618 // A list of 8-bit numbers that have at most one run of non-zero bits.
619 // x = x ^ (mask << 56) can be encoded as a single armv8 instruction for these
620 // masks.
621 // The list does not include the value 255, which is used for UAR.
622 static unsigned FastMasks[] = {
623 0, 1, 2, 3, 4, 6, 7, 8, 12, 14, 15, 16, 24,
624 28, 30, 31, 32, 48, 56, 60, 62, 63, 64, 96, 112, 120,
625 124, 126, 127, 128, 192, 224, 240, 248, 252, 254};
626 return FastMasks[AllocaNo % (sizeof(FastMasks) / sizeof(FastMasks[0]))];
627}
628
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000629Value *HWAddressSanitizer::getNextTagWithCall(IRBuilder<> &IRB) {
630 return IRB.CreateZExt(IRB.CreateCall(HwasanGenerateTagFunc), IntptrTy);
631}
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000632
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000633Value *HWAddressSanitizer::getStackBaseTag(IRBuilder<> &IRB) {
634 if (ClGenerateTagsWithCalls)
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000635 return getNextTagWithCall(IRB);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000636 // FIXME: use addressofreturnaddress (but implement it in aarch64 backend
637 // first).
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000638 Module *M = IRB.GetInsertBlock()->getParent()->getParent();
639 auto GetStackPointerFn =
640 Intrinsic::getDeclaration(M, Intrinsic::frameaddress);
641 Value *StackPointer = IRB.CreateCall(
642 GetStackPointerFn, {Constant::getNullValue(IRB.getInt32Ty())});
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000643
644 // Extract some entropy from the stack pointer for the tags.
645 // Take bits 20..28 (ASLR entropy) and xor with bits 0..8 (these differ
646 // between functions).
647 Value *StackPointerLong = IRB.CreatePointerCast(StackPointer, IntptrTy);
648 Value *StackTag =
649 IRB.CreateXor(StackPointerLong, IRB.CreateLShr(StackPointerLong, 20),
650 "hwasan.stack.base.tag");
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000651 return StackTag;
652}
653
654Value *HWAddressSanitizer::getAllocaTag(IRBuilder<> &IRB, Value *StackTag,
655 AllocaInst *AI, unsigned AllocaNo) {
656 if (ClGenerateTagsWithCalls)
657 return getNextTagWithCall(IRB);
658 return IRB.CreateXor(StackTag,
659 ConstantInt::get(IntptrTy, RetagMask(AllocaNo)));
660}
661
662Value *HWAddressSanitizer::getUARTag(IRBuilder<> &IRB, Value *StackTag) {
Alex Shlyapnikov788764c2018-06-29 20:20:17 +0000663 if (ClUARRetagToZero)
664 return ConstantInt::get(IntptrTy, 0);
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000665 if (ClGenerateTagsWithCalls)
666 return getNextTagWithCall(IRB);
667 return IRB.CreateXor(StackTag, ConstantInt::get(IntptrTy, 0xFFU));
668}
669
Evgeniy Stepanov80ccda22018-02-09 00:59:10 +0000670// Add a tag to an address.
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000671Value *HWAddressSanitizer::tagPointer(IRBuilder<> &IRB, Type *Ty,
672 Value *PtrLong, Value *Tag) {
Evgeniy Stepanov80ccda22018-02-09 00:59:10 +0000673 Value *TaggedPtrLong;
Andrey Konovalov1ba9d9c2018-04-13 18:05:21 +0000674 if (CompileKernel) {
Evgeniy Stepanov80ccda22018-02-09 00:59:10 +0000675 // Kernel addresses have 0xFF in the most significant byte.
676 Value *ShiftedTag = IRB.CreateOr(
677 IRB.CreateShl(Tag, kPointerTagShift),
678 ConstantInt::get(IntptrTy, (1ULL << kPointerTagShift) - 1));
679 TaggedPtrLong = IRB.CreateAnd(PtrLong, ShiftedTag);
680 } else {
681 // Userspace can simply do OR (tag << 56);
682 Value *ShiftedTag = IRB.CreateShl(Tag, kPointerTagShift);
683 TaggedPtrLong = IRB.CreateOr(PtrLong, ShiftedTag);
684 }
685 return IRB.CreateIntToPtr(TaggedPtrLong, Ty);
686}
687
Evgeniy Stepanov43271b12018-02-21 19:52:23 +0000688// Remove tag from an address.
689Value *HWAddressSanitizer::untagPointer(IRBuilder<> &IRB, Value *PtrLong) {
690 Value *UntaggedPtrLong;
Andrey Konovalov1ba9d9c2018-04-13 18:05:21 +0000691 if (CompileKernel) {
Evgeniy Stepanov43271b12018-02-21 19:52:23 +0000692 // Kernel addresses have 0xFF in the most significant byte.
693 UntaggedPtrLong = IRB.CreateOr(PtrLong,
694 ConstantInt::get(PtrLong->getType(), 0xFFULL << kPointerTagShift));
695 } else {
696 // Userspace addresses have 0x00.
697 UntaggedPtrLong = IRB.CreateAnd(PtrLong,
698 ConstantInt::get(PtrLong->getType(), ~(0xFFULL << kPointerTagShift)));
699 }
700 return UntaggedPtrLong;
701}
702
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000703Value *HWAddressSanitizer::getHwasanThreadSlotPtr(IRBuilder<> &IRB, Type *Ty) {
704 Module *M = IRB.GetInsertBlock()->getParent()->getParent();
705 if (TargetTriple.isAArch64() && TargetTriple.isAndroid()) {
706 Function *ThreadPointerFunc =
707 Intrinsic::getDeclaration(M, Intrinsic::thread_pointer);
708 Value *SlotPtr = IRB.CreatePointerCast(
709 IRB.CreateConstGEP1_32(IRB.CreateCall(ThreadPointerFunc), 0x40),
710 Ty->getPointerTo(0));
711 return SlotPtr;
712 }
713 if (ThreadPtrGlobal)
714 return ThreadPtrGlobal;
715
716
717 return nullptr;
718}
719
Kostya Serebryanyaf955972018-10-23 00:50:40 +0000720// Creates a string with a description of the stack frame (set of Allocas).
721// The string is intended to be human readable.
722// The current form is: Size1 Name1; Size2 Name2; ...
723std::string
724HWAddressSanitizer::createFrameString(ArrayRef<AllocaInst *> Allocas) {
725 std::ostringstream Descr;
726 for (auto AI : Allocas)
727 Descr << getAllocaSizeInBytes(*AI) << " " << AI->getName().str() << "; ";
728 return Descr.str();
729}
730
731// Creates a global in the frame section which consists of two pointers:
732// the function PC and the frame string constant.
733void HWAddressSanitizer::createFrameGlobal(Function &F,
734 const std::string &FrameString) {
735 Module &M = *F.getParent();
736 auto DescrGV = createPrivateGlobalForString(M, FrameString, true);
737 auto PtrPairTy = StructType::get(F.getType(), DescrGV->getType());
738 auto GV = new GlobalVariable(
739 M, PtrPairTy, /*isConstantGlobal*/ true, GlobalVariable::PrivateLinkage,
740 ConstantStruct::get(PtrPairTy, (Constant *)&F, (Constant *)DescrGV),
741 "__hwasan");
742 GV->setSection(getFrameSection());
743 appendToCompilerUsed(M, GV);
744 // Put GV into the F's Comadat so that if F is deleted GV can be deleted too.
745 if (&F != HwasanCtorFunction)
746 if (auto Comdat = GetOrCreateFunctionComdat(F, CurModuleUniqueId))
747 GV->setComdat(Comdat);
748}
749
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000750Value *HWAddressSanitizer::emitPrologue(IRBuilder<> &IRB,
751 bool WithFrameRecord) {
752 if (!Mapping.InTls)
753 return getDynamicShadowNonTls(IRB);
754
755 Value *SlotPtr = getHwasanThreadSlotPtr(IRB, IntptrTy);
756 assert(SlotPtr);
757
758 Value *ThreadLong = IRB.CreateLoad(SlotPtr);
759 // Extract the address field from ThreadLong. Unnecessary on AArch64 with TBI.
760 Value *ThreadLongMaybeUntagged =
761 TargetTriple.isAArch64() ? ThreadLong : untagPointer(IRB, ThreadLong);
762
763 if (WithFrameRecord) {
764 // Prepare ring buffer data.
765 Function *F = IRB.GetInsertBlock()->getParent();
766 auto PC = IRB.CreatePtrToInt(F, IntptrTy);
767 auto GetStackPointerFn =
768 Intrinsic::getDeclaration(F->getParent(), Intrinsic::frameaddress);
769 Value *SP = IRB.CreatePtrToInt(
770 IRB.CreateCall(GetStackPointerFn,
771 {Constant::getNullValue(IRB.getInt32Ty())}),
772 IntptrTy);
773 // Mix SP and PC. TODO: also add the tag to the mix.
774 // Assumptions:
775 // PC is 0x0000PPPPPPPPPPPP (48 bits are meaningful, others are zero)
776 // SP is 0xsssssssssssSSSS0 (4 lower bits are zero)
777 // We only really need ~20 lower non-zero bits (SSSS), so we mix like this:
778 // 0xSSSSPPPPPPPPPPPP
779 SP = IRB.CreateShl(SP, 44);
780
781 // Store data to ring buffer.
782 Value *RecordPtr =
783 IRB.CreateIntToPtr(ThreadLongMaybeUntagged, IntptrTy->getPointerTo(0));
784 IRB.CreateStore(IRB.CreateOr(PC, SP), RecordPtr);
785
786 // Update the ring buffer. Top byte of ThreadLong defines the size of the
787 // buffer in pages, it must be a power of two, and the start of the buffer
788 // must be aligned by twice that much. Therefore wrap around of the ring
789 // buffer is simply Addr &= ~((ThreadLong >> 56) << 12).
790 // The use of AShr instead of LShr is due to
791 // https://bugs.llvm.org/show_bug.cgi?id=39030
792 // Runtime library makes sure not to use the highest bit.
793 Value *WrapMask = IRB.CreateXor(
794 IRB.CreateShl(IRB.CreateAShr(ThreadLong, 56), 12, "", true, true),
795 ConstantInt::get(IntptrTy, (uint64_t)-1));
796 Value *ThreadLongNew = IRB.CreateAnd(
797 IRB.CreateAdd(ThreadLong, ConstantInt::get(IntptrTy, 8)), WrapMask);
798 IRB.CreateStore(ThreadLongNew, SlotPtr);
799 }
800
801 // Get shadow base address by aligning RecordPtr up.
802 // Note: this is not correct if the pointer is already aligned.
803 // Runtime library will make sure this never happens.
804 Value *ShadowBase = IRB.CreateAdd(
805 IRB.CreateOr(
806 ThreadLongMaybeUntagged,
807 ConstantInt::get(IntptrTy, (1ULL << kShadowBaseAlignment) - 1)),
808 ConstantInt::get(IntptrTy, 1), "hwasan.shadow");
809 return ShadowBase;
810}
811
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000812bool HWAddressSanitizer::instrumentStack(
813 SmallVectorImpl<AllocaInst *> &Allocas,
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000814 SmallVectorImpl<Instruction *> &RetVec, Value *StackTag) {
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000815 // Ideally, we want to calculate tagged stack base pointer, and rewrite all
816 // alloca addresses using that. Unfortunately, offsets are not known yet
817 // (unless we use ASan-style mega-alloca). Instead we keep the base tag in a
818 // temp, shift-OR it into each alloca address and xor with the retag mask.
819 // This generates one extra instruction per alloca use.
820 for (unsigned N = 0; N < Allocas.size(); ++N) {
821 auto *AI = Allocas[N];
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000822 IRBuilder<> IRB(AI->getNextNode());
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000823
824 // Replace uses of the alloca with tagged address.
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000825 Value *Tag = getAllocaTag(IRB, StackTag, AI, N);
826 Value *AILong = IRB.CreatePointerCast(AI, IntptrTy);
Evgeniy Stepanov80ccda22018-02-09 00:59:10 +0000827 Value *Replacement = tagPointer(IRB, AI->getType(), AILong, Tag);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000828 std::string Name =
829 AI->hasName() ? AI->getName().str() : "alloca." + itostr(N);
Evgeniy Stepanov80ccda22018-02-09 00:59:10 +0000830 Replacement->setName(Name + ".hwasan");
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000831
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000832 for (auto UI = AI->use_begin(), UE = AI->use_end(); UI != UE;) {
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000833 Use &U = *UI++;
834 if (U.getUser() != AILong)
835 U.set(Replacement);
836 }
837
838 tagAlloca(IRB, AI, Tag);
839
840 for (auto RI : RetVec) {
841 IRB.SetInsertPoint(RI);
842
843 // Re-tag alloca memory with the special UAR tag.
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000844 Value *Tag = getUARTag(IRB, StackTag);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000845 tagAlloca(IRB, AI, Tag);
846 }
847 }
848
849 return true;
850}
851
852bool HWAddressSanitizer::isInterestingAlloca(const AllocaInst &AI) {
853 return (AI.getAllocatedType()->isSized() &&
854 // FIXME: instrument dynamic allocas, too
855 AI.isStaticAlloca() &&
856 // alloca() may be called with 0 size, ignore it.
857 getAllocaSizeInBytes(AI) > 0 &&
858 // We are only interested in allocas not promotable to registers.
859 // Promotable allocas are common under -O0.
860 !isAllocaPromotable(&AI) &&
861 // inalloca allocas are not treated as static, and we don't want
862 // dynamic alloca instrumentation for them as well.
863 !AI.isUsedWithInAlloca() &&
864 // swifterror allocas are register promoted by ISel
865 !AI.isSwiftError());
866}
867
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000868bool HWAddressSanitizer::runOnFunction(Function &F) {
869 if (&F == HwasanCtorFunction)
870 return false;
871
872 if (!F.hasFnAttribute(Attribute::SanitizeHWAddress))
873 return false;
874
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000875 LLVM_DEBUG(dbgs() << "Function: " << F.getName() << "\n");
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000876
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000877 SmallVector<Instruction*, 16> ToInstrument;
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000878 SmallVector<AllocaInst*, 8> AllocasToInstrument;
879 SmallVector<Instruction*, 8> RetVec;
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000880 for (auto &BB : F) {
881 for (auto &Inst : BB) {
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000882 if (ClInstrumentStack)
883 if (AllocaInst *AI = dyn_cast<AllocaInst>(&Inst)) {
884 // Realign all allocas. We don't want small uninteresting allocas to
885 // hide in instrumented alloca's padding.
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000886 if (AI->getAlignment() < Mapping.getAllocaAlignment())
887 AI->setAlignment(Mapping.getAllocaAlignment());
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000888 // Instrument some of them.
889 if (isInterestingAlloca(*AI))
890 AllocasToInstrument.push_back(AI);
891 continue;
892 }
893
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000894 if (isa<ReturnInst>(Inst) || isa<ResumeInst>(Inst) ||
895 isa<CleanupReturnInst>(Inst))
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000896 RetVec.push_back(&Inst);
897
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000898 Value *MaybeMask = nullptr;
899 bool IsWrite;
900 unsigned Alignment;
901 uint64_t TypeSize;
902 Value *Addr = isInterestingMemoryAccess(&Inst, &IsWrite, &TypeSize,
903 &Alignment, &MaybeMask);
904 if (Addr || isa<MemIntrinsic>(Inst))
905 ToInstrument.push_back(&Inst);
906 }
907 }
908
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000909 if (AllocasToInstrument.empty() && ToInstrument.empty())
910 return false;
911
Kostya Serebryanyaf955972018-10-23 00:50:40 +0000912 if (ClCreateFrameDescriptions && !AllocasToInstrument.empty())
913 createFrameGlobal(F, createFrameString(AllocasToInstrument));
914
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000915 initializeCallbacks(*F.getParent());
916
917 assert(!LocalDynamicShadow);
918
919 Instruction *InsertPt = &*F.getEntryBlock().begin();
920 IRBuilder<> EntryIRB(InsertPt);
921 LocalDynamicShadow = emitPrologue(EntryIRB,
922 /*WithFrameRecord*/ ClRecordStackHistory &&
923 !AllocasToInstrument.empty());
924
925 bool Changed = false;
926 if (!AllocasToInstrument.empty()) {
927 Value *StackTag =
928 ClGenerateTagsWithCalls ? nullptr : getStackBaseTag(EntryIRB);
929 Changed |= instrumentStack(AllocasToInstrument, RetVec, StackTag);
930 }
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000931
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000932 for (auto Inst : ToInstrument)
933 Changed |= instrumentMemAccess(Inst);
934
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000935 LocalDynamicShadow = nullptr;
936
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000937 return Changed;
938}
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000939
940void HWAddressSanitizer::ShadowMapping::init(Triple &TargetTriple) {
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000941 Scale = kDefaultShadowScale;
Evgeniy Stepanov453e7ac2018-08-10 16:21:37 +0000942 if (ClMappingOffset.getNumOccurrences() > 0) {
943 InGlobal = false;
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000944 InTls = false;
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000945 Offset = ClMappingOffset;
Evgeniy Stepanov453e7ac2018-08-10 16:21:37 +0000946 } else if (ClEnableKhwasan || ClInstrumentWithCalls) {
947 InGlobal = false;
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000948 InTls = false;
Evgeniy Stepanov453e7ac2018-08-10 16:21:37 +0000949 Offset = 0;
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000950 } else if (ClWithIfunc) {
Evgeniy Stepanov453e7ac2018-08-10 16:21:37 +0000951 InGlobal = true;
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000952 InTls = false;
953 Offset = kDynamicShadowSentinel;
954 } else if (ClWithTls) {
955 InGlobal = false;
956 InTls = true;
Evgeniy Stepanov453e7ac2018-08-10 16:21:37 +0000957 Offset = kDynamicShadowSentinel;
958 } else {
959 InGlobal = false;
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000960 InTls = false;
Evgeniy Stepanov453e7ac2018-08-10 16:21:37 +0000961 Offset = kDynamicShadowSentinel;
962 }
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000963}