blob: 67a0e98cbd5223cf9abcf67cffe899a99371bc90 [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
Eugene Leviant2d98eb12018-12-20 09:04:33 +0000155static cl::opt<bool>
156 ClInstrumentMemIntrinsics("hwasan-instrument-mem-intrinsics",
157 cl::desc("instrument memory intrinsics"),
Eugene Leviant4dc3a3f2018-12-24 16:02:48 +0000158 cl::Hidden, cl::init(true));
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000159namespace {
160
Adrian Prantl5f8f34e42018-05-01 15:54:18 +0000161/// An instrumentation pass implementing detection of addressability bugs
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000162/// using tagged pointers.
163class HWAddressSanitizer : public FunctionPass {
164public:
165 // Pass identification, replacement for typeid.
166 static char ID;
167
Andrey Konovalov1ba9d9c2018-04-13 18:05:21 +0000168 explicit HWAddressSanitizer(bool CompileKernel = false, bool Recover = false)
169 : FunctionPass(ID) {
170 this->Recover = ClRecover.getNumOccurrences() > 0 ? ClRecover : Recover;
171 this->CompileKernel = ClEnableKhwasan.getNumOccurrences() > 0 ?
172 ClEnableKhwasan : CompileKernel;
173 }
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000174
175 StringRef getPassName() const override { return "HWAddressSanitizer"; }
176
177 bool runOnFunction(Function &F) override;
178 bool doInitialization(Module &M) override;
179
180 void initializeCallbacks(Module &M);
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000181
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000182 Value *getDynamicShadowNonTls(IRBuilder<> &IRB);
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000183
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000184 void untagPointerOperand(Instruction *I, Value *Addr);
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000185 Value *memToShadow(Value *Shadow, Type *Ty, IRBuilder<> &IRB);
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000186 void instrumentMemAccessInline(Value *PtrLong, bool IsWrite,
187 unsigned AccessSizeIndex,
188 Instruction *InsertBefore);
Eugene Leviant2d98eb12018-12-20 09:04:33 +0000189 void instrumentMemIntrinsic(MemIntrinsic *MI);
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000190 bool instrumentMemAccess(Instruction *I);
191 Value *isInterestingMemoryAccess(Instruction *I, bool *IsWrite,
192 uint64_t *TypeSize, unsigned *Alignment,
193 Value **MaybeMask);
194
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000195 bool isInterestingAlloca(const AllocaInst &AI);
196 bool tagAlloca(IRBuilder<> &IRB, AllocaInst *AI, Value *Tag);
Evgeniy Stepanov80ccda22018-02-09 00:59:10 +0000197 Value *tagPointer(IRBuilder<> &IRB, Type *Ty, Value *PtrLong, Value *Tag);
Evgeniy Stepanov43271b12018-02-21 19:52:23 +0000198 Value *untagPointer(IRBuilder<> &IRB, Value *PtrLong);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000199 bool instrumentStack(SmallVectorImpl<AllocaInst *> &Allocas,
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000200 SmallVectorImpl<Instruction *> &RetVec, Value *StackTag);
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000201 Value *getNextTagWithCall(IRBuilder<> &IRB);
202 Value *getStackBaseTag(IRBuilder<> &IRB);
203 Value *getAllocaTag(IRBuilder<> &IRB, Value *StackTag, AllocaInst *AI,
204 unsigned AllocaNo);
205 Value *getUARTag(IRBuilder<> &IRB, Value *StackTag);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000206
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000207 Value *getHwasanThreadSlotPtr(IRBuilder<> &IRB, Type *Ty);
208 Value *emitPrologue(IRBuilder<> &IRB, bool WithFrameRecord);
209
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000210private:
211 LLVMContext *C;
Kostya Serebryanyaf955972018-10-23 00:50:40 +0000212 std::string CurModuleUniqueId;
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000213 Triple TargetTriple;
Eugene Leviant2d98eb12018-12-20 09:04:33 +0000214 Function *HWAsanMemmove, *HWAsanMemcpy, *HWAsanMemset;
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000215
Kostya Serebryanyaf955972018-10-23 00:50:40 +0000216 // Frame description is a way to pass names/sizes of local variables
217 // to the run-time w/o adding extra executable code in every function.
218 // We do this by creating a separate section with {PC,Descr} pairs and passing
219 // the section beg/end to __hwasan_init_frames() at module init time.
220 std::string createFrameString(ArrayRef<AllocaInst*> Allocas);
221 void createFrameGlobal(Function &F, const std::string &FrameString);
222 // Get the section name for frame descriptions. Currently ELF-only.
223 const char *getFrameSection() { return "__hwasan_frames"; }
224 const char *getFrameSectionBeg() { return "__start___hwasan_frames"; }
225 const char *getFrameSectionEnd() { return "__stop___hwasan_frames"; }
226 GlobalVariable *createFrameSectionBound(Module &M, Type *Ty,
227 const char *Name) {
228 auto GV = new GlobalVariable(M, Ty, false, GlobalVariable::ExternalLinkage,
229 nullptr, Name);
230 GV->setVisibility(GlobalValue::HiddenVisibility);
231 return GV;
232 }
233
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000234 /// This struct defines the shadow mapping using the rule:
235 /// shadow = (mem >> Scale) + Offset.
236 /// If InGlobal is true, then
237 /// extern char __hwasan_shadow[];
238 /// shadow = (mem >> Scale) + &__hwasan_shadow
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000239 /// If InTls is true, then
240 /// extern char *__hwasan_tls;
Kostya Serebryanyaf955972018-10-23 00:50:40 +0000241 /// shadow = (mem>>Scale) + align_up(__hwasan_shadow, kShadowBaseAlignment)
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000242 struct ShadowMapping {
243 int Scale;
244 uint64_t Offset;
245 bool InGlobal;
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000246 bool InTls;
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000247
248 void init(Triple &TargetTriple);
249 unsigned getAllocaAlignment() const { return 1U << Scale; }
250 };
251 ShadowMapping Mapping;
252
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000253 Type *IntptrTy;
Evgeniy Stepanova265a132018-08-15 00:39:35 +0000254 Type *Int8PtrTy;
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000255 Type *Int8Ty;
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000256
Andrey Konovalov1ba9d9c2018-04-13 18:05:21 +0000257 bool CompileKernel;
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000258 bool Recover;
259
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000260 Function *HwasanCtorFunction;
261
262 Function *HwasanMemoryAccessCallback[2][kNumberOfAccessSizes];
263 Function *HwasanMemoryAccessCallbackSized[2];
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000264
265 Function *HwasanTagMemoryFunc;
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000266 Function *HwasanGenerateTagFunc;
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000267
268 Constant *ShadowGlobal;
269
270 Value *LocalDynamicShadow = nullptr;
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000271 GlobalValue *ThreadPtrGlobal = nullptr;
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000272};
273
274} // end anonymous namespace
275
276char HWAddressSanitizer::ID = 0;
277
278INITIALIZE_PASS_BEGIN(
279 HWAddressSanitizer, "hwasan",
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000280 "HWAddressSanitizer: detect memory bugs using tagged addressing.", false,
281 false)
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000282INITIALIZE_PASS_END(
283 HWAddressSanitizer, "hwasan",
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000284 "HWAddressSanitizer: detect memory bugs using tagged addressing.", false,
285 false)
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000286
Andrey Konovalov1ba9d9c2018-04-13 18:05:21 +0000287FunctionPass *llvm::createHWAddressSanitizerPass(bool CompileKernel,
288 bool Recover) {
289 assert(!CompileKernel || Recover);
290 return new HWAddressSanitizer(CompileKernel, Recover);
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000291}
292
Adrian Prantl5f8f34e42018-05-01 15:54:18 +0000293/// Module-level initialization.
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000294///
295/// inserts a call to __hwasan_init to the module's constructor list.
296bool HWAddressSanitizer::doInitialization(Module &M) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000297 LLVM_DEBUG(dbgs() << "Init " << M.getName() << "\n");
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000298 auto &DL = M.getDataLayout();
299
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000300 TargetTriple = Triple(M.getTargetTriple());
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000301
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000302 Mapping.init(TargetTriple);
303
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000304 C = &(M.getContext());
Kostya Serebryanyaf955972018-10-23 00:50:40 +0000305 CurModuleUniqueId = getUniqueModuleId(&M);
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000306 IRBuilder<> IRB(*C);
307 IntptrTy = IRB.getIntPtrTy(DL);
Evgeniy Stepanova265a132018-08-15 00:39:35 +0000308 Int8PtrTy = IRB.getInt8PtrTy();
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000309 Int8Ty = IRB.getInt8Ty();
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000310
Benjamin Kramerbfc1d972018-01-18 14:19:04 +0000311 HwasanCtorFunction = nullptr;
Andrey Konovalov1ba9d9c2018-04-13 18:05:21 +0000312 if (!CompileKernel) {
Evgeniy Stepanov5bd669d2018-01-17 23:24:38 +0000313 std::tie(HwasanCtorFunction, std::ignore) =
314 createSanitizerCtorAndInitFunctions(M, kHwasanModuleCtorName,
315 kHwasanInitName,
316 /*InitArgTypes=*/{},
317 /*InitArgs=*/{});
Peter Collingbourned3a3e4b2018-12-17 22:56:34 +0000318 Comdat *CtorComdat = M.getOrInsertComdat(kHwasanModuleCtorName);
319 HwasanCtorFunction->setComdat(CtorComdat);
320 appendToGlobalCtors(M, HwasanCtorFunction, 0, HwasanCtorFunction);
Kostya Serebryanyaf955972018-10-23 00:50:40 +0000321
Peter Collingbourned3a3e4b2018-12-17 22:56:34 +0000322 // Create a zero-length global in __hwasan_frame so that the linker will
323 // always create start and stop symbols.
324 //
325 // N.B. If we ever start creating associated metadata in this pass this
326 // global will need to be associated with the ctor.
327 Type *Int8Arr0Ty = ArrayType::get(Int8Ty, 0);
328 auto GV =
329 new GlobalVariable(M, Int8Arr0Ty, /*isConstantGlobal*/ true,
330 GlobalVariable::PrivateLinkage,
331 Constant::getNullValue(Int8Arr0Ty), "__hwasan");
332 GV->setSection(getFrameSection());
333 GV->setComdat(CtorComdat);
334 appendToCompilerUsed(M, GV);
335
Kostya Serebryanyaf955972018-10-23 00:50:40 +0000336 IRBuilder<> IRBCtor(HwasanCtorFunction->getEntryBlock().getTerminator());
337 IRBCtor.CreateCall(
338 declareSanitizerInitFunction(M, "__hwasan_init_frames",
339 {Int8PtrTy, Int8PtrTy}),
340 {createFrameSectionBound(M, Int8Ty, getFrameSectionBeg()),
341 createFrameSectionBound(M, Int8Ty, getFrameSectionEnd())});
342 }
343
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000344 if (!TargetTriple.isAndroid())
345 appendToCompilerUsed(
346 M, ThreadPtrGlobal = new GlobalVariable(
347 M, IntptrTy, false, GlobalVariable::ExternalLinkage, nullptr,
348 "__hwasan_tls", nullptr, GlobalVariable::InitialExecTLSModel));
349
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000350 return true;
351}
352
353void HWAddressSanitizer::initializeCallbacks(Module &M) {
354 IRBuilder<> IRB(*C);
355 for (size_t AccessIsWrite = 0; AccessIsWrite <= 1; AccessIsWrite++) {
356 const std::string TypeStr = AccessIsWrite ? "store" : "load";
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000357 const std::string EndingStr = Recover ? "_noabort" : "";
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000358
359 HwasanMemoryAccessCallbackSized[AccessIsWrite] =
360 checkSanitizerInterfaceFunction(M.getOrInsertFunction(
Evgeniy Stepanovc07e0bd2018-01-16 23:15:08 +0000361 ClMemoryAccessCallbackPrefix + TypeStr + "N" + EndingStr,
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000362 FunctionType::get(IRB.getVoidTy(), {IntptrTy, IntptrTy}, false)));
363
364 for (size_t AccessSizeIndex = 0; AccessSizeIndex < kNumberOfAccessSizes;
365 AccessSizeIndex++) {
366 HwasanMemoryAccessCallback[AccessIsWrite][AccessSizeIndex] =
367 checkSanitizerInterfaceFunction(M.getOrInsertFunction(
368 ClMemoryAccessCallbackPrefix + TypeStr +
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000369 itostr(1ULL << AccessSizeIndex) + EndingStr,
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000370 FunctionType::get(IRB.getVoidTy(), {IntptrTy}, false)));
371 }
372 }
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000373
374 HwasanTagMemoryFunc = checkSanitizerInterfaceFunction(M.getOrInsertFunction(
Evgeniy Stepanova265a132018-08-15 00:39:35 +0000375 "__hwasan_tag_memory", IRB.getVoidTy(), Int8PtrTy, Int8Ty, IntptrTy));
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000376 HwasanGenerateTagFunc = checkSanitizerInterfaceFunction(
377 M.getOrInsertFunction("__hwasan_generate_tag", Int8Ty));
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000378
379 if (Mapping.InGlobal)
380 ShadowGlobal = M.getOrInsertGlobal("__hwasan_shadow",
381 ArrayType::get(IRB.getInt8Ty(), 0));
Eugene Leviant2d98eb12018-12-20 09:04:33 +0000382
383 const std::string MemIntrinCallbackPrefix =
384 CompileKernel ? std::string("") : ClMemoryAccessCallbackPrefix;
385 HWAsanMemmove = checkSanitizerInterfaceFunction(M.getOrInsertFunction(
386 MemIntrinCallbackPrefix + "memmove", IRB.getInt8PtrTy(),
387 IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), IntptrTy));
388 HWAsanMemcpy = checkSanitizerInterfaceFunction(M.getOrInsertFunction(
389 MemIntrinCallbackPrefix + "memcpy", IRB.getInt8PtrTy(),
390 IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), IntptrTy));
391 HWAsanMemset = checkSanitizerInterfaceFunction(M.getOrInsertFunction(
392 MemIntrinCallbackPrefix + "memset", IRB.getInt8PtrTy(),
393 IRB.getInt8PtrTy(), IRB.getInt32Ty(), IntptrTy));
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000394}
395
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000396Value *HWAddressSanitizer::getDynamicShadowNonTls(IRBuilder<> &IRB) {
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000397 // Generate code only when dynamic addressing is needed.
398 if (Mapping.Offset != kDynamicShadowSentinel)
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000399 return nullptr;
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000400
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000401 if (Mapping.InGlobal) {
402 // An empty inline asm with input reg == output reg.
403 // An opaque pointer-to-int cast, basically.
404 InlineAsm *Asm = InlineAsm::get(
405 FunctionType::get(IntptrTy, {ShadowGlobal->getType()}, false),
406 StringRef(""), StringRef("=r,0"),
407 /*hasSideEffects=*/false);
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000408 return IRB.CreateCall(Asm, {ShadowGlobal}, ".hwasan.shadow");
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000409 } else {
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000410 Value *GlobalDynamicAddress =
411 IRB.GetInsertBlock()->getParent()->getParent()->getOrInsertGlobal(
412 kHwasanShadowMemoryDynamicAddress, IntptrTy);
413 return IRB.CreateLoad(GlobalDynamicAddress);
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000414 }
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000415}
416
417Value *HWAddressSanitizer::isInterestingMemoryAccess(Instruction *I,
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000418 bool *IsWrite,
419 uint64_t *TypeSize,
420 unsigned *Alignment,
421 Value **MaybeMask) {
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000422 // Skip memory accesses inserted by another instrumentation.
423 if (I->getMetadata("nosanitize")) return nullptr;
424
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000425 // Do not instrument the load fetching the dynamic shadow address.
426 if (LocalDynamicShadow == I)
427 return nullptr;
428
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000429 Value *PtrOperand = nullptr;
430 const DataLayout &DL = I->getModule()->getDataLayout();
431 if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
432 if (!ClInstrumentReads) return nullptr;
433 *IsWrite = false;
434 *TypeSize = DL.getTypeStoreSizeInBits(LI->getType());
435 *Alignment = LI->getAlignment();
436 PtrOperand = LI->getPointerOperand();
437 } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
438 if (!ClInstrumentWrites) return nullptr;
439 *IsWrite = true;
440 *TypeSize = DL.getTypeStoreSizeInBits(SI->getValueOperand()->getType());
441 *Alignment = SI->getAlignment();
442 PtrOperand = SI->getPointerOperand();
443 } else if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(I)) {
444 if (!ClInstrumentAtomics) return nullptr;
445 *IsWrite = true;
446 *TypeSize = DL.getTypeStoreSizeInBits(RMW->getValOperand()->getType());
447 *Alignment = 0;
448 PtrOperand = RMW->getPointerOperand();
449 } else if (AtomicCmpXchgInst *XCHG = dyn_cast<AtomicCmpXchgInst>(I)) {
450 if (!ClInstrumentAtomics) return nullptr;
451 *IsWrite = true;
452 *TypeSize = DL.getTypeStoreSizeInBits(XCHG->getCompareOperand()->getType());
453 *Alignment = 0;
454 PtrOperand = XCHG->getPointerOperand();
455 }
456
457 if (PtrOperand) {
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000458 // Do not instrument accesses from different address spaces; we cannot deal
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000459 // with them.
460 Type *PtrTy = cast<PointerType>(PtrOperand->getType()->getScalarType());
461 if (PtrTy->getPointerAddressSpace() != 0)
462 return nullptr;
463
464 // Ignore swifterror addresses.
465 // swifterror memory addresses are mem2reg promoted by instruction
466 // selection. As such they cannot have regular uses like an instrumentation
467 // function and it makes no sense to track them as memory.
468 if (PtrOperand->isSwiftError())
469 return nullptr;
470 }
471
472 return PtrOperand;
473}
474
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000475static unsigned getPointerOperandIndex(Instruction *I) {
476 if (LoadInst *LI = dyn_cast<LoadInst>(I))
477 return LI->getPointerOperandIndex();
478 if (StoreInst *SI = dyn_cast<StoreInst>(I))
479 return SI->getPointerOperandIndex();
480 if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(I))
481 return RMW->getPointerOperandIndex();
482 if (AtomicCmpXchgInst *XCHG = dyn_cast<AtomicCmpXchgInst>(I))
483 return XCHG->getPointerOperandIndex();
484 report_fatal_error("Unexpected instruction");
485 return -1;
486}
487
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000488static size_t TypeSizeToSizeIndex(uint32_t TypeSize) {
489 size_t Res = countTrailingZeros(TypeSize / 8);
490 assert(Res < kNumberOfAccessSizes);
491 return Res;
492}
493
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000494void HWAddressSanitizer::untagPointerOperand(Instruction *I, Value *Addr) {
495 if (TargetTriple.isAArch64())
496 return;
497
498 IRBuilder<> IRB(I);
499 Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy);
500 Value *UntaggedPtr =
501 IRB.CreateIntToPtr(untagPointer(IRB, AddrLong), Addr->getType());
502 I->setOperand(getPointerOperandIndex(I), UntaggedPtr);
503}
504
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000505Value *HWAddressSanitizer::memToShadow(Value *Mem, Type *Ty, IRBuilder<> &IRB) {
506 // Mem >> Scale
507 Value *Shadow = IRB.CreateLShr(Mem, Mapping.Scale);
508 if (Mapping.Offset == 0)
509 return Shadow;
510 // (Mem >> Scale) + Offset
511 Value *ShadowBase;
512 if (LocalDynamicShadow)
513 ShadowBase = LocalDynamicShadow;
514 else
515 ShadowBase = ConstantInt::get(Ty, Mapping.Offset);
516 return IRB.CreateAdd(Shadow, ShadowBase);
517}
518
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000519void HWAddressSanitizer::instrumentMemAccessInline(Value *PtrLong, bool IsWrite,
520 unsigned AccessSizeIndex,
521 Instruction *InsertBefore) {
522 IRBuilder<> IRB(InsertBefore);
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000523 Value *PtrTag = IRB.CreateTrunc(IRB.CreateLShr(PtrLong, kPointerTagShift),
524 IRB.getInt8Ty());
Evgeniy Stepanov43271b12018-02-21 19:52:23 +0000525 Value *AddrLong = untagPointer(IRB, PtrLong);
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000526 Value *ShadowLong = memToShadow(AddrLong, PtrLong->getType(), IRB);
Evgeniy Stepanova265a132018-08-15 00:39:35 +0000527 Value *MemTag = IRB.CreateLoad(IRB.CreateIntToPtr(ShadowLong, Int8PtrTy));
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000528 Value *TagMismatch = IRB.CreateICmpNE(PtrTag, MemTag);
529
Andrey Konovalov1ba9d9c2018-04-13 18:05:21 +0000530 int matchAllTag = ClMatchAllTag.getNumOccurrences() > 0 ?
531 ClMatchAllTag : (CompileKernel ? 0xFF : -1);
532 if (matchAllTag != -1) {
Evgeniy Stepanov1f1a7a72018-04-04 20:44:59 +0000533 Value *TagNotIgnored = IRB.CreateICmpNE(PtrTag,
Andrey Konovalov1ba9d9c2018-04-13 18:05:21 +0000534 ConstantInt::get(PtrTag->getType(), matchAllTag));
Evgeniy Stepanov1f1a7a72018-04-04 20:44:59 +0000535 TagMismatch = IRB.CreateAnd(TagMismatch, TagNotIgnored);
536 }
537
Chandler Carruth4a2d58e2018-10-15 09:34:05 +0000538 Instruction *CheckTerm =
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000539 SplitBlockAndInsertIfThen(TagMismatch, InsertBefore, !Recover,
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000540 MDBuilder(*C).createBranchWeights(1, 100000));
541
542 IRB.SetInsertPoint(CheckTerm);
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000543 const int64_t AccessInfo = Recover * 0x20 + IsWrite * 0x10 + AccessSizeIndex;
544 InlineAsm *Asm;
545 switch (TargetTriple.getArch()) {
546 case Triple::x86_64:
547 // The signal handler will find the data address in rdi.
548 Asm = InlineAsm::get(
549 FunctionType::get(IRB.getVoidTy(), {PtrLong->getType()}, false),
550 "int3\nnopl " + itostr(0x40 + AccessInfo) + "(%rax)",
551 "{rdi}",
552 /*hasSideEffects=*/true);
553 break;
554 case Triple::aarch64:
555 case Triple::aarch64_be:
556 // The signal handler will find the data address in x0.
557 Asm = InlineAsm::get(
558 FunctionType::get(IRB.getVoidTy(), {PtrLong->getType()}, false),
559 "brk #" + itostr(0x900 + AccessInfo),
560 "{x0}",
561 /*hasSideEffects=*/true);
562 break;
563 default:
564 report_fatal_error("unsupported architecture");
565 }
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000566 IRB.CreateCall(Asm, PtrLong);
567}
568
Eugene Leviant2d98eb12018-12-20 09:04:33 +0000569void HWAddressSanitizer::instrumentMemIntrinsic(MemIntrinsic *MI) {
570 IRBuilder<> IRB(MI);
571 if (isa<MemTransferInst>(MI)) {
572 IRB.CreateCall(
573 isa<MemMoveInst>(MI) ? HWAsanMemmove : HWAsanMemcpy,
574 {IRB.CreatePointerCast(MI->getOperand(0), IRB.getInt8PtrTy()),
575 IRB.CreatePointerCast(MI->getOperand(1), IRB.getInt8PtrTy()),
576 IRB.CreateIntCast(MI->getOperand(2), IntptrTy, false)});
577 } else if (isa<MemSetInst>(MI)) {
578 IRB.CreateCall(
579 HWAsanMemset,
580 {IRB.CreatePointerCast(MI->getOperand(0), IRB.getInt8PtrTy()),
581 IRB.CreateIntCast(MI->getOperand(1), IRB.getInt32Ty(), false),
582 IRB.CreateIntCast(MI->getOperand(2), IntptrTy, false)});
583 }
584 MI->eraseFromParent();
585}
586
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000587bool HWAddressSanitizer::instrumentMemAccess(Instruction *I) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000588 LLVM_DEBUG(dbgs() << "Instrumenting: " << *I << "\n");
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000589 bool IsWrite = false;
590 unsigned Alignment = 0;
591 uint64_t TypeSize = 0;
592 Value *MaybeMask = nullptr;
Eugene Leviant2d98eb12018-12-20 09:04:33 +0000593
594 if (ClInstrumentMemIntrinsics && isa<MemIntrinsic>(I)) {
595 instrumentMemIntrinsic(cast<MemIntrinsic>(I));
596 return true;
597 }
598
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000599 Value *Addr =
600 isInterestingMemoryAccess(I, &IsWrite, &TypeSize, &Alignment, &MaybeMask);
601
602 if (!Addr)
603 return false;
604
605 if (MaybeMask)
606 return false; //FIXME
607
608 IRBuilder<> IRB(I);
609 Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy);
610 if (isPowerOf2_64(TypeSize) &&
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000611 (TypeSize / 8 <= (1UL << (kNumberOfAccessSizes - 1))) &&
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000612 (Alignment >= (1UL << Mapping.Scale) || Alignment == 0 ||
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000613 Alignment >= TypeSize / 8)) {
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000614 size_t AccessSizeIndex = TypeSizeToSizeIndex(TypeSize);
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000615 if (ClInstrumentWithCalls) {
616 IRB.CreateCall(HwasanMemoryAccessCallback[IsWrite][AccessSizeIndex],
617 AddrLong);
618 } else {
619 instrumentMemAccessInline(AddrLong, IsWrite, AccessSizeIndex, I);
620 }
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000621 } else {
622 IRB.CreateCall(HwasanMemoryAccessCallbackSized[IsWrite],
623 {AddrLong, ConstantInt::get(IntptrTy, TypeSize / 8)});
624 }
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000625 untagPointerOperand(I, Addr);
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000626
627 return true;
628}
629
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000630static uint64_t getAllocaSizeInBytes(const AllocaInst &AI) {
631 uint64_t ArraySize = 1;
632 if (AI.isArrayAllocation()) {
633 const ConstantInt *CI = dyn_cast<ConstantInt>(AI.getArraySize());
634 assert(CI && "non-constant array size");
635 ArraySize = CI->getZExtValue();
636 }
637 Type *Ty = AI.getAllocatedType();
638 uint64_t SizeInBytes = AI.getModule()->getDataLayout().getTypeAllocSize(Ty);
639 return SizeInBytes * ArraySize;
640}
641
642bool HWAddressSanitizer::tagAlloca(IRBuilder<> &IRB, AllocaInst *AI,
643 Value *Tag) {
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000644 size_t Size = (getAllocaSizeInBytes(*AI) + Mapping.getAllocaAlignment() - 1) &
645 ~(Mapping.getAllocaAlignment() - 1);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000646
647 Value *JustTag = IRB.CreateTrunc(Tag, IRB.getInt8Ty());
648 if (ClInstrumentWithCalls) {
649 IRB.CreateCall(HwasanTagMemoryFunc,
Evgeniy Stepanova265a132018-08-15 00:39:35 +0000650 {IRB.CreatePointerCast(AI, Int8PtrTy), JustTag,
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000651 ConstantInt::get(IntptrTy, Size)});
652 } else {
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000653 size_t ShadowSize = Size >> Mapping.Scale;
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000654 Value *ShadowPtr = IRB.CreateIntToPtr(
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000655 memToShadow(IRB.CreatePointerCast(AI, IntptrTy), AI->getType(), IRB),
Evgeniy Stepanova265a132018-08-15 00:39:35 +0000656 Int8PtrTy);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000657 // If this memset is not inlined, it will be intercepted in the hwasan
658 // runtime library. That's OK, because the interceptor skips the checks if
659 // the address is in the shadow region.
660 // FIXME: the interceptor is not as fast as real memset. Consider lowering
661 // llvm.memset right here into either a sequence of stores, or a call to
662 // hwasan_tag_memory.
663 IRB.CreateMemSet(ShadowPtr, JustTag, ShadowSize, /*Align=*/1);
664 }
665 return true;
666}
667
668static unsigned RetagMask(unsigned AllocaNo) {
669 // A list of 8-bit numbers that have at most one run of non-zero bits.
670 // x = x ^ (mask << 56) can be encoded as a single armv8 instruction for these
671 // masks.
672 // The list does not include the value 255, which is used for UAR.
673 static unsigned FastMasks[] = {
674 0, 1, 2, 3, 4, 6, 7, 8, 12, 14, 15, 16, 24,
675 28, 30, 31, 32, 48, 56, 60, 62, 63, 64, 96, 112, 120,
676 124, 126, 127, 128, 192, 224, 240, 248, 252, 254};
677 return FastMasks[AllocaNo % (sizeof(FastMasks) / sizeof(FastMasks[0]))];
678}
679
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000680Value *HWAddressSanitizer::getNextTagWithCall(IRBuilder<> &IRB) {
681 return IRB.CreateZExt(IRB.CreateCall(HwasanGenerateTagFunc), IntptrTy);
682}
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000683
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000684Value *HWAddressSanitizer::getStackBaseTag(IRBuilder<> &IRB) {
685 if (ClGenerateTagsWithCalls)
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000686 return getNextTagWithCall(IRB);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000687 // FIXME: use addressofreturnaddress (but implement it in aarch64 backend
688 // first).
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000689 Module *M = IRB.GetInsertBlock()->getParent()->getParent();
690 auto GetStackPointerFn =
691 Intrinsic::getDeclaration(M, Intrinsic::frameaddress);
692 Value *StackPointer = IRB.CreateCall(
693 GetStackPointerFn, {Constant::getNullValue(IRB.getInt32Ty())});
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000694
695 // Extract some entropy from the stack pointer for the tags.
696 // Take bits 20..28 (ASLR entropy) and xor with bits 0..8 (these differ
697 // between functions).
698 Value *StackPointerLong = IRB.CreatePointerCast(StackPointer, IntptrTy);
699 Value *StackTag =
700 IRB.CreateXor(StackPointerLong, IRB.CreateLShr(StackPointerLong, 20),
701 "hwasan.stack.base.tag");
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000702 return StackTag;
703}
704
705Value *HWAddressSanitizer::getAllocaTag(IRBuilder<> &IRB, Value *StackTag,
706 AllocaInst *AI, unsigned AllocaNo) {
707 if (ClGenerateTagsWithCalls)
708 return getNextTagWithCall(IRB);
709 return IRB.CreateXor(StackTag,
710 ConstantInt::get(IntptrTy, RetagMask(AllocaNo)));
711}
712
713Value *HWAddressSanitizer::getUARTag(IRBuilder<> &IRB, Value *StackTag) {
Alex Shlyapnikov788764c2018-06-29 20:20:17 +0000714 if (ClUARRetagToZero)
715 return ConstantInt::get(IntptrTy, 0);
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000716 if (ClGenerateTagsWithCalls)
717 return getNextTagWithCall(IRB);
718 return IRB.CreateXor(StackTag, ConstantInt::get(IntptrTy, 0xFFU));
719}
720
Evgeniy Stepanov80ccda22018-02-09 00:59:10 +0000721// Add a tag to an address.
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000722Value *HWAddressSanitizer::tagPointer(IRBuilder<> &IRB, Type *Ty,
723 Value *PtrLong, Value *Tag) {
Evgeniy Stepanov80ccda22018-02-09 00:59:10 +0000724 Value *TaggedPtrLong;
Andrey Konovalov1ba9d9c2018-04-13 18:05:21 +0000725 if (CompileKernel) {
Evgeniy Stepanov80ccda22018-02-09 00:59:10 +0000726 // Kernel addresses have 0xFF in the most significant byte.
727 Value *ShiftedTag = IRB.CreateOr(
728 IRB.CreateShl(Tag, kPointerTagShift),
729 ConstantInt::get(IntptrTy, (1ULL << kPointerTagShift) - 1));
730 TaggedPtrLong = IRB.CreateAnd(PtrLong, ShiftedTag);
731 } else {
732 // Userspace can simply do OR (tag << 56);
733 Value *ShiftedTag = IRB.CreateShl(Tag, kPointerTagShift);
734 TaggedPtrLong = IRB.CreateOr(PtrLong, ShiftedTag);
735 }
736 return IRB.CreateIntToPtr(TaggedPtrLong, Ty);
737}
738
Evgeniy Stepanov43271b12018-02-21 19:52:23 +0000739// Remove tag from an address.
740Value *HWAddressSanitizer::untagPointer(IRBuilder<> &IRB, Value *PtrLong) {
741 Value *UntaggedPtrLong;
Andrey Konovalov1ba9d9c2018-04-13 18:05:21 +0000742 if (CompileKernel) {
Evgeniy Stepanov43271b12018-02-21 19:52:23 +0000743 // Kernel addresses have 0xFF in the most significant byte.
744 UntaggedPtrLong = IRB.CreateOr(PtrLong,
745 ConstantInt::get(PtrLong->getType(), 0xFFULL << kPointerTagShift));
746 } else {
747 // Userspace addresses have 0x00.
748 UntaggedPtrLong = IRB.CreateAnd(PtrLong,
749 ConstantInt::get(PtrLong->getType(), ~(0xFFULL << kPointerTagShift)));
750 }
751 return UntaggedPtrLong;
752}
753
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000754Value *HWAddressSanitizer::getHwasanThreadSlotPtr(IRBuilder<> &IRB, Type *Ty) {
755 Module *M = IRB.GetInsertBlock()->getParent()->getParent();
756 if (TargetTriple.isAArch64() && TargetTriple.isAndroid()) {
757 Function *ThreadPointerFunc =
758 Intrinsic::getDeclaration(M, Intrinsic::thread_pointer);
759 Value *SlotPtr = IRB.CreatePointerCast(
Evgeniy Stepanoveb238ec2018-12-13 23:47:50 +0000760 IRB.CreateConstGEP1_32(IRB.CreateCall(ThreadPointerFunc), 0x40),
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000761 Ty->getPointerTo(0));
762 return SlotPtr;
763 }
764 if (ThreadPtrGlobal)
765 return ThreadPtrGlobal;
766
767
768 return nullptr;
769}
770
Kostya Serebryanyaf955972018-10-23 00:50:40 +0000771// Creates a string with a description of the stack frame (set of Allocas).
772// The string is intended to be human readable.
773// The current form is: Size1 Name1; Size2 Name2; ...
774std::string
775HWAddressSanitizer::createFrameString(ArrayRef<AllocaInst *> Allocas) {
776 std::ostringstream Descr;
777 for (auto AI : Allocas)
778 Descr << getAllocaSizeInBytes(*AI) << " " << AI->getName().str() << "; ";
779 return Descr.str();
780}
781
782// Creates a global in the frame section which consists of two pointers:
783// the function PC and the frame string constant.
784void HWAddressSanitizer::createFrameGlobal(Function &F,
785 const std::string &FrameString) {
786 Module &M = *F.getParent();
787 auto DescrGV = createPrivateGlobalForString(M, FrameString, true);
788 auto PtrPairTy = StructType::get(F.getType(), DescrGV->getType());
789 auto GV = new GlobalVariable(
790 M, PtrPairTy, /*isConstantGlobal*/ true, GlobalVariable::PrivateLinkage,
791 ConstantStruct::get(PtrPairTy, (Constant *)&F, (Constant *)DescrGV),
792 "__hwasan");
793 GV->setSection(getFrameSection());
794 appendToCompilerUsed(M, GV);
795 // Put GV into the F's Comadat so that if F is deleted GV can be deleted too.
Peter Collingbourned3a3e4b2018-12-17 22:56:34 +0000796 if (auto Comdat =
797 GetOrCreateFunctionComdat(F, TargetTriple, CurModuleUniqueId))
798 GV->setComdat(Comdat);
Kostya Serebryanyaf955972018-10-23 00:50:40 +0000799}
800
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000801Value *HWAddressSanitizer::emitPrologue(IRBuilder<> &IRB,
802 bool WithFrameRecord) {
803 if (!Mapping.InTls)
804 return getDynamicShadowNonTls(IRB);
805
806 Value *SlotPtr = getHwasanThreadSlotPtr(IRB, IntptrTy);
807 assert(SlotPtr);
808
809 Value *ThreadLong = IRB.CreateLoad(SlotPtr);
810 // Extract the address field from ThreadLong. Unnecessary on AArch64 with TBI.
811 Value *ThreadLongMaybeUntagged =
812 TargetTriple.isAArch64() ? ThreadLong : untagPointer(IRB, ThreadLong);
813
814 if (WithFrameRecord) {
815 // Prepare ring buffer data.
816 Function *F = IRB.GetInsertBlock()->getParent();
817 auto PC = IRB.CreatePtrToInt(F, IntptrTy);
818 auto GetStackPointerFn =
819 Intrinsic::getDeclaration(F->getParent(), Intrinsic::frameaddress);
820 Value *SP = IRB.CreatePtrToInt(
821 IRB.CreateCall(GetStackPointerFn,
822 {Constant::getNullValue(IRB.getInt32Ty())}),
823 IntptrTy);
824 // Mix SP and PC. TODO: also add the tag to the mix.
825 // Assumptions:
826 // PC is 0x0000PPPPPPPPPPPP (48 bits are meaningful, others are zero)
827 // SP is 0xsssssssssssSSSS0 (4 lower bits are zero)
828 // We only really need ~20 lower non-zero bits (SSSS), so we mix like this:
829 // 0xSSSSPPPPPPPPPPPP
830 SP = IRB.CreateShl(SP, 44);
831
832 // Store data to ring buffer.
833 Value *RecordPtr =
834 IRB.CreateIntToPtr(ThreadLongMaybeUntagged, IntptrTy->getPointerTo(0));
835 IRB.CreateStore(IRB.CreateOr(PC, SP), RecordPtr);
836
837 // Update the ring buffer. Top byte of ThreadLong defines the size of the
838 // buffer in pages, it must be a power of two, and the start of the buffer
839 // must be aligned by twice that much. Therefore wrap around of the ring
840 // buffer is simply Addr &= ~((ThreadLong >> 56) << 12).
841 // The use of AShr instead of LShr is due to
842 // https://bugs.llvm.org/show_bug.cgi?id=39030
843 // Runtime library makes sure not to use the highest bit.
844 Value *WrapMask = IRB.CreateXor(
845 IRB.CreateShl(IRB.CreateAShr(ThreadLong, 56), 12, "", true, true),
846 ConstantInt::get(IntptrTy, (uint64_t)-1));
847 Value *ThreadLongNew = IRB.CreateAnd(
848 IRB.CreateAdd(ThreadLong, ConstantInt::get(IntptrTy, 8)), WrapMask);
849 IRB.CreateStore(ThreadLongNew, SlotPtr);
850 }
851
852 // Get shadow base address by aligning RecordPtr up.
853 // Note: this is not correct if the pointer is already aligned.
854 // Runtime library will make sure this never happens.
855 Value *ShadowBase = IRB.CreateAdd(
856 IRB.CreateOr(
857 ThreadLongMaybeUntagged,
858 ConstantInt::get(IntptrTy, (1ULL << kShadowBaseAlignment) - 1)),
859 ConstantInt::get(IntptrTy, 1), "hwasan.shadow");
860 return ShadowBase;
861}
862
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000863bool HWAddressSanitizer::instrumentStack(
864 SmallVectorImpl<AllocaInst *> &Allocas,
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000865 SmallVectorImpl<Instruction *> &RetVec, Value *StackTag) {
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000866 // Ideally, we want to calculate tagged stack base pointer, and rewrite all
867 // alloca addresses using that. Unfortunately, offsets are not known yet
868 // (unless we use ASan-style mega-alloca). Instead we keep the base tag in a
869 // temp, shift-OR it into each alloca address and xor with the retag mask.
870 // This generates one extra instruction per alloca use.
871 for (unsigned N = 0; N < Allocas.size(); ++N) {
872 auto *AI = Allocas[N];
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000873 IRBuilder<> IRB(AI->getNextNode());
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000874
875 // Replace uses of the alloca with tagged address.
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000876 Value *Tag = getAllocaTag(IRB, StackTag, AI, N);
877 Value *AILong = IRB.CreatePointerCast(AI, IntptrTy);
Evgeniy Stepanov80ccda22018-02-09 00:59:10 +0000878 Value *Replacement = tagPointer(IRB, AI->getType(), AILong, Tag);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000879 std::string Name =
880 AI->hasName() ? AI->getName().str() : "alloca." + itostr(N);
Evgeniy Stepanov80ccda22018-02-09 00:59:10 +0000881 Replacement->setName(Name + ".hwasan");
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000882
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000883 for (auto UI = AI->use_begin(), UE = AI->use_end(); UI != UE;) {
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000884 Use &U = *UI++;
885 if (U.getUser() != AILong)
886 U.set(Replacement);
887 }
888
889 tagAlloca(IRB, AI, Tag);
890
891 for (auto RI : RetVec) {
892 IRB.SetInsertPoint(RI);
893
894 // Re-tag alloca memory with the special UAR tag.
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000895 Value *Tag = getUARTag(IRB, StackTag);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000896 tagAlloca(IRB, AI, Tag);
897 }
898 }
899
900 return true;
901}
902
903bool HWAddressSanitizer::isInterestingAlloca(const AllocaInst &AI) {
904 return (AI.getAllocatedType()->isSized() &&
905 // FIXME: instrument dynamic allocas, too
906 AI.isStaticAlloca() &&
907 // alloca() may be called with 0 size, ignore it.
908 getAllocaSizeInBytes(AI) > 0 &&
909 // We are only interested in allocas not promotable to registers.
910 // Promotable allocas are common under -O0.
911 !isAllocaPromotable(&AI) &&
912 // inalloca allocas are not treated as static, and we don't want
913 // dynamic alloca instrumentation for them as well.
914 !AI.isUsedWithInAlloca() &&
915 // swifterror allocas are register promoted by ISel
916 !AI.isSwiftError());
917}
918
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000919bool HWAddressSanitizer::runOnFunction(Function &F) {
920 if (&F == HwasanCtorFunction)
921 return false;
922
923 if (!F.hasFnAttribute(Attribute::SanitizeHWAddress))
924 return false;
925
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000926 LLVM_DEBUG(dbgs() << "Function: " << F.getName() << "\n");
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000927
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000928 SmallVector<Instruction*, 16> ToInstrument;
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000929 SmallVector<AllocaInst*, 8> AllocasToInstrument;
930 SmallVector<Instruction*, 8> RetVec;
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000931 for (auto &BB : F) {
932 for (auto &Inst : BB) {
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000933 if (ClInstrumentStack)
934 if (AllocaInst *AI = dyn_cast<AllocaInst>(&Inst)) {
935 // Realign all allocas. We don't want small uninteresting allocas to
936 // hide in instrumented alloca's padding.
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000937 if (AI->getAlignment() < Mapping.getAllocaAlignment())
938 AI->setAlignment(Mapping.getAllocaAlignment());
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000939 // Instrument some of them.
940 if (isInterestingAlloca(*AI))
941 AllocasToInstrument.push_back(AI);
942 continue;
943 }
944
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000945 if (isa<ReturnInst>(Inst) || isa<ResumeInst>(Inst) ||
946 isa<CleanupReturnInst>(Inst))
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000947 RetVec.push_back(&Inst);
948
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000949 Value *MaybeMask = nullptr;
950 bool IsWrite;
951 unsigned Alignment;
952 uint64_t TypeSize;
953 Value *Addr = isInterestingMemoryAccess(&Inst, &IsWrite, &TypeSize,
954 &Alignment, &MaybeMask);
955 if (Addr || isa<MemIntrinsic>(Inst))
956 ToInstrument.push_back(&Inst);
957 }
958 }
959
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000960 if (AllocasToInstrument.empty() && ToInstrument.empty())
961 return false;
962
Kostya Serebryanyaf955972018-10-23 00:50:40 +0000963 if (ClCreateFrameDescriptions && !AllocasToInstrument.empty())
964 createFrameGlobal(F, createFrameString(AllocasToInstrument));
965
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000966 initializeCallbacks(*F.getParent());
967
968 assert(!LocalDynamicShadow);
969
970 Instruction *InsertPt = &*F.getEntryBlock().begin();
971 IRBuilder<> EntryIRB(InsertPt);
972 LocalDynamicShadow = emitPrologue(EntryIRB,
973 /*WithFrameRecord*/ ClRecordStackHistory &&
974 !AllocasToInstrument.empty());
975
976 bool Changed = false;
977 if (!AllocasToInstrument.empty()) {
978 Value *StackTag =
979 ClGenerateTagsWithCalls ? nullptr : getStackBaseTag(EntryIRB);
980 Changed |= instrumentStack(AllocasToInstrument, RetVec, StackTag);
981 }
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000982
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000983 for (auto Inst : ToInstrument)
984 Changed |= instrumentMemAccess(Inst);
985
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000986 LocalDynamicShadow = nullptr;
987
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000988 return Changed;
989}
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000990
991void HWAddressSanitizer::ShadowMapping::init(Triple &TargetTriple) {
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000992 Scale = kDefaultShadowScale;
Evgeniy Stepanov453e7ac2018-08-10 16:21:37 +0000993 if (ClMappingOffset.getNumOccurrences() > 0) {
994 InGlobal = false;
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000995 InTls = false;
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000996 Offset = ClMappingOffset;
Evgeniy Stepanov453e7ac2018-08-10 16:21:37 +0000997 } else if (ClEnableKhwasan || ClInstrumentWithCalls) {
998 InGlobal = false;
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000999 InTls = false;
Evgeniy Stepanov453e7ac2018-08-10 16:21:37 +00001000 Offset = 0;
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +00001001 } else if (ClWithIfunc) {
Evgeniy Stepanov453e7ac2018-08-10 16:21:37 +00001002 InGlobal = true;
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +00001003 InTls = false;
1004 Offset = kDynamicShadowSentinel;
1005 } else if (ClWithTls) {
1006 InGlobal = false;
1007 InTls = true;
Evgeniy Stepanov453e7ac2018-08-10 16:21:37 +00001008 Offset = kDynamicShadowSentinel;
1009 } else {
1010 InGlobal = false;
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +00001011 InTls = false;
Evgeniy Stepanov453e7ac2018-08-10 16:21:37 +00001012 Offset = kDynamicShadowSentinel;
1013 }
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +00001014}