blob: caa383b57f9789262ce8f188302890405d68e762 [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;
Peter Collingbourne87f477b2019-01-04 19:27:04 +0000267 Function *HwasanThreadEnterFunc;
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000268
269 Constant *ShadowGlobal;
270
271 Value *LocalDynamicShadow = nullptr;
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000272 GlobalValue *ThreadPtrGlobal = nullptr;
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000273};
274
275} // end anonymous namespace
276
277char HWAddressSanitizer::ID = 0;
278
279INITIALIZE_PASS_BEGIN(
280 HWAddressSanitizer, "hwasan",
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000281 "HWAddressSanitizer: detect memory bugs using tagged addressing.", false,
282 false)
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000283INITIALIZE_PASS_END(
284 HWAddressSanitizer, "hwasan",
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000285 "HWAddressSanitizer: detect memory bugs using tagged addressing.", false,
286 false)
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000287
Andrey Konovalov1ba9d9c2018-04-13 18:05:21 +0000288FunctionPass *llvm::createHWAddressSanitizerPass(bool CompileKernel,
289 bool Recover) {
290 assert(!CompileKernel || Recover);
291 return new HWAddressSanitizer(CompileKernel, Recover);
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000292}
293
Adrian Prantl5f8f34e42018-05-01 15:54:18 +0000294/// Module-level initialization.
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000295///
296/// inserts a call to __hwasan_init to the module's constructor list.
297bool HWAddressSanitizer::doInitialization(Module &M) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000298 LLVM_DEBUG(dbgs() << "Init " << M.getName() << "\n");
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000299 auto &DL = M.getDataLayout();
300
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000301 TargetTriple = Triple(M.getTargetTriple());
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000302
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000303 Mapping.init(TargetTriple);
304
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000305 C = &(M.getContext());
Kostya Serebryanyaf955972018-10-23 00:50:40 +0000306 CurModuleUniqueId = getUniqueModuleId(&M);
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000307 IRBuilder<> IRB(*C);
308 IntptrTy = IRB.getIntPtrTy(DL);
Evgeniy Stepanova265a132018-08-15 00:39:35 +0000309 Int8PtrTy = IRB.getInt8PtrTy();
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000310 Int8Ty = IRB.getInt8Ty();
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000311
Benjamin Kramerbfc1d972018-01-18 14:19:04 +0000312 HwasanCtorFunction = nullptr;
Andrey Konovalov1ba9d9c2018-04-13 18:05:21 +0000313 if (!CompileKernel) {
Evgeniy Stepanov5bd669d2018-01-17 23:24:38 +0000314 std::tie(HwasanCtorFunction, std::ignore) =
315 createSanitizerCtorAndInitFunctions(M, kHwasanModuleCtorName,
316 kHwasanInitName,
317 /*InitArgTypes=*/{},
318 /*InitArgs=*/{});
Peter Collingbourned3a3e4b2018-12-17 22:56:34 +0000319 Comdat *CtorComdat = M.getOrInsertComdat(kHwasanModuleCtorName);
320 HwasanCtorFunction->setComdat(CtorComdat);
321 appendToGlobalCtors(M, HwasanCtorFunction, 0, HwasanCtorFunction);
Kostya Serebryanyaf955972018-10-23 00:50:40 +0000322
Peter Collingbourned3a3e4b2018-12-17 22:56:34 +0000323 // Create a zero-length global in __hwasan_frame so that the linker will
324 // always create start and stop symbols.
325 //
326 // N.B. If we ever start creating associated metadata in this pass this
327 // global will need to be associated with the ctor.
328 Type *Int8Arr0Ty = ArrayType::get(Int8Ty, 0);
329 auto GV =
330 new GlobalVariable(M, Int8Arr0Ty, /*isConstantGlobal*/ true,
331 GlobalVariable::PrivateLinkage,
332 Constant::getNullValue(Int8Arr0Ty), "__hwasan");
333 GV->setSection(getFrameSection());
334 GV->setComdat(CtorComdat);
335 appendToCompilerUsed(M, GV);
336
Kostya Serebryanyaf955972018-10-23 00:50:40 +0000337 IRBuilder<> IRBCtor(HwasanCtorFunction->getEntryBlock().getTerminator());
338 IRBCtor.CreateCall(
339 declareSanitizerInitFunction(M, "__hwasan_init_frames",
340 {Int8PtrTy, Int8PtrTy}),
341 {createFrameSectionBound(M, Int8Ty, getFrameSectionBeg()),
342 createFrameSectionBound(M, Int8Ty, getFrameSectionEnd())});
343 }
344
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000345 if (!TargetTriple.isAndroid())
346 appendToCompilerUsed(
347 M, ThreadPtrGlobal = new GlobalVariable(
348 M, IntptrTy, false, GlobalVariable::ExternalLinkage, nullptr,
349 "__hwasan_tls", nullptr, GlobalVariable::InitialExecTLSModel));
350
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000351 return true;
352}
353
354void HWAddressSanitizer::initializeCallbacks(Module &M) {
355 IRBuilder<> IRB(*C);
356 for (size_t AccessIsWrite = 0; AccessIsWrite <= 1; AccessIsWrite++) {
357 const std::string TypeStr = AccessIsWrite ? "store" : "load";
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000358 const std::string EndingStr = Recover ? "_noabort" : "";
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000359
360 HwasanMemoryAccessCallbackSized[AccessIsWrite] =
361 checkSanitizerInterfaceFunction(M.getOrInsertFunction(
Evgeniy Stepanovc07e0bd2018-01-16 23:15:08 +0000362 ClMemoryAccessCallbackPrefix + TypeStr + "N" + EndingStr,
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000363 FunctionType::get(IRB.getVoidTy(), {IntptrTy, IntptrTy}, false)));
364
365 for (size_t AccessSizeIndex = 0; AccessSizeIndex < kNumberOfAccessSizes;
366 AccessSizeIndex++) {
367 HwasanMemoryAccessCallback[AccessIsWrite][AccessSizeIndex] =
368 checkSanitizerInterfaceFunction(M.getOrInsertFunction(
369 ClMemoryAccessCallbackPrefix + TypeStr +
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000370 itostr(1ULL << AccessSizeIndex) + EndingStr,
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000371 FunctionType::get(IRB.getVoidTy(), {IntptrTy}, false)));
372 }
373 }
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000374
375 HwasanTagMemoryFunc = checkSanitizerInterfaceFunction(M.getOrInsertFunction(
Evgeniy Stepanova265a132018-08-15 00:39:35 +0000376 "__hwasan_tag_memory", IRB.getVoidTy(), Int8PtrTy, Int8Ty, IntptrTy));
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000377 HwasanGenerateTagFunc = checkSanitizerInterfaceFunction(
378 M.getOrInsertFunction("__hwasan_generate_tag", Int8Ty));
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000379
380 if (Mapping.InGlobal)
381 ShadowGlobal = M.getOrInsertGlobal("__hwasan_shadow",
382 ArrayType::get(IRB.getInt8Ty(), 0));
Eugene Leviant2d98eb12018-12-20 09:04:33 +0000383
384 const std::string MemIntrinCallbackPrefix =
385 CompileKernel ? std::string("") : ClMemoryAccessCallbackPrefix;
386 HWAsanMemmove = checkSanitizerInterfaceFunction(M.getOrInsertFunction(
387 MemIntrinCallbackPrefix + "memmove", IRB.getInt8PtrTy(),
388 IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), IntptrTy));
389 HWAsanMemcpy = checkSanitizerInterfaceFunction(M.getOrInsertFunction(
390 MemIntrinCallbackPrefix + "memcpy", IRB.getInt8PtrTy(),
391 IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), IntptrTy));
392 HWAsanMemset = checkSanitizerInterfaceFunction(M.getOrInsertFunction(
393 MemIntrinCallbackPrefix + "memset", IRB.getInt8PtrTy(),
394 IRB.getInt8PtrTy(), IRB.getInt32Ty(), IntptrTy));
Peter Collingbourne87f477b2019-01-04 19:27:04 +0000395
396 HwasanThreadEnterFunc = checkSanitizerInterfaceFunction(
397 M.getOrInsertFunction("__hwasan_thread_enter", IRB.getVoidTy()));
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000398}
399
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000400Value *HWAddressSanitizer::getDynamicShadowNonTls(IRBuilder<> &IRB) {
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000401 // Generate code only when dynamic addressing is needed.
402 if (Mapping.Offset != kDynamicShadowSentinel)
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000403 return nullptr;
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000404
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000405 if (Mapping.InGlobal) {
406 // An empty inline asm with input reg == output reg.
407 // An opaque pointer-to-int cast, basically.
408 InlineAsm *Asm = InlineAsm::get(
409 FunctionType::get(IntptrTy, {ShadowGlobal->getType()}, false),
410 StringRef(""), StringRef("=r,0"),
411 /*hasSideEffects=*/false);
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000412 return IRB.CreateCall(Asm, {ShadowGlobal}, ".hwasan.shadow");
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000413 } else {
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000414 Value *GlobalDynamicAddress =
415 IRB.GetInsertBlock()->getParent()->getParent()->getOrInsertGlobal(
416 kHwasanShadowMemoryDynamicAddress, IntptrTy);
417 return IRB.CreateLoad(GlobalDynamicAddress);
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000418 }
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000419}
420
421Value *HWAddressSanitizer::isInterestingMemoryAccess(Instruction *I,
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000422 bool *IsWrite,
423 uint64_t *TypeSize,
424 unsigned *Alignment,
425 Value **MaybeMask) {
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000426 // Skip memory accesses inserted by another instrumentation.
427 if (I->getMetadata("nosanitize")) return nullptr;
428
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000429 // Do not instrument the load fetching the dynamic shadow address.
430 if (LocalDynamicShadow == I)
431 return nullptr;
432
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000433 Value *PtrOperand = nullptr;
434 const DataLayout &DL = I->getModule()->getDataLayout();
435 if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
436 if (!ClInstrumentReads) return nullptr;
437 *IsWrite = false;
438 *TypeSize = DL.getTypeStoreSizeInBits(LI->getType());
439 *Alignment = LI->getAlignment();
440 PtrOperand = LI->getPointerOperand();
441 } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
442 if (!ClInstrumentWrites) return nullptr;
443 *IsWrite = true;
444 *TypeSize = DL.getTypeStoreSizeInBits(SI->getValueOperand()->getType());
445 *Alignment = SI->getAlignment();
446 PtrOperand = SI->getPointerOperand();
447 } else if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(I)) {
448 if (!ClInstrumentAtomics) return nullptr;
449 *IsWrite = true;
450 *TypeSize = DL.getTypeStoreSizeInBits(RMW->getValOperand()->getType());
451 *Alignment = 0;
452 PtrOperand = RMW->getPointerOperand();
453 } else if (AtomicCmpXchgInst *XCHG = dyn_cast<AtomicCmpXchgInst>(I)) {
454 if (!ClInstrumentAtomics) return nullptr;
455 *IsWrite = true;
456 *TypeSize = DL.getTypeStoreSizeInBits(XCHG->getCompareOperand()->getType());
457 *Alignment = 0;
458 PtrOperand = XCHG->getPointerOperand();
459 }
460
461 if (PtrOperand) {
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000462 // Do not instrument accesses from different address spaces; we cannot deal
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000463 // with them.
464 Type *PtrTy = cast<PointerType>(PtrOperand->getType()->getScalarType());
465 if (PtrTy->getPointerAddressSpace() != 0)
466 return nullptr;
467
468 // Ignore swifterror addresses.
469 // swifterror memory addresses are mem2reg promoted by instruction
470 // selection. As such they cannot have regular uses like an instrumentation
471 // function and it makes no sense to track them as memory.
472 if (PtrOperand->isSwiftError())
473 return nullptr;
474 }
475
476 return PtrOperand;
477}
478
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000479static unsigned getPointerOperandIndex(Instruction *I) {
480 if (LoadInst *LI = dyn_cast<LoadInst>(I))
481 return LI->getPointerOperandIndex();
482 if (StoreInst *SI = dyn_cast<StoreInst>(I))
483 return SI->getPointerOperandIndex();
484 if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(I))
485 return RMW->getPointerOperandIndex();
486 if (AtomicCmpXchgInst *XCHG = dyn_cast<AtomicCmpXchgInst>(I))
487 return XCHG->getPointerOperandIndex();
488 report_fatal_error("Unexpected instruction");
489 return -1;
490}
491
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000492static size_t TypeSizeToSizeIndex(uint32_t TypeSize) {
493 size_t Res = countTrailingZeros(TypeSize / 8);
494 assert(Res < kNumberOfAccessSizes);
495 return Res;
496}
497
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000498void HWAddressSanitizer::untagPointerOperand(Instruction *I, Value *Addr) {
499 if (TargetTriple.isAArch64())
500 return;
501
502 IRBuilder<> IRB(I);
503 Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy);
504 Value *UntaggedPtr =
505 IRB.CreateIntToPtr(untagPointer(IRB, AddrLong), Addr->getType());
506 I->setOperand(getPointerOperandIndex(I), UntaggedPtr);
507}
508
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000509Value *HWAddressSanitizer::memToShadow(Value *Mem, Type *Ty, IRBuilder<> &IRB) {
510 // Mem >> Scale
511 Value *Shadow = IRB.CreateLShr(Mem, Mapping.Scale);
512 if (Mapping.Offset == 0)
513 return Shadow;
514 // (Mem >> Scale) + Offset
515 Value *ShadowBase;
516 if (LocalDynamicShadow)
517 ShadowBase = LocalDynamicShadow;
518 else
519 ShadowBase = ConstantInt::get(Ty, Mapping.Offset);
520 return IRB.CreateAdd(Shadow, ShadowBase);
521}
522
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000523void HWAddressSanitizer::instrumentMemAccessInline(Value *PtrLong, bool IsWrite,
524 unsigned AccessSizeIndex,
525 Instruction *InsertBefore) {
526 IRBuilder<> IRB(InsertBefore);
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000527 Value *PtrTag = IRB.CreateTrunc(IRB.CreateLShr(PtrLong, kPointerTagShift),
528 IRB.getInt8Ty());
Evgeniy Stepanov43271b12018-02-21 19:52:23 +0000529 Value *AddrLong = untagPointer(IRB, PtrLong);
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000530 Value *ShadowLong = memToShadow(AddrLong, PtrLong->getType(), IRB);
Evgeniy Stepanova265a132018-08-15 00:39:35 +0000531 Value *MemTag = IRB.CreateLoad(IRB.CreateIntToPtr(ShadowLong, Int8PtrTy));
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000532 Value *TagMismatch = IRB.CreateICmpNE(PtrTag, MemTag);
533
Andrey Konovalov1ba9d9c2018-04-13 18:05:21 +0000534 int matchAllTag = ClMatchAllTag.getNumOccurrences() > 0 ?
535 ClMatchAllTag : (CompileKernel ? 0xFF : -1);
536 if (matchAllTag != -1) {
Evgeniy Stepanov1f1a7a72018-04-04 20:44:59 +0000537 Value *TagNotIgnored = IRB.CreateICmpNE(PtrTag,
Andrey Konovalov1ba9d9c2018-04-13 18:05:21 +0000538 ConstantInt::get(PtrTag->getType(), matchAllTag));
Evgeniy Stepanov1f1a7a72018-04-04 20:44:59 +0000539 TagMismatch = IRB.CreateAnd(TagMismatch, TagNotIgnored);
540 }
541
Chandler Carruth4a2d58e2018-10-15 09:34:05 +0000542 Instruction *CheckTerm =
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000543 SplitBlockAndInsertIfThen(TagMismatch, InsertBefore, !Recover,
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000544 MDBuilder(*C).createBranchWeights(1, 100000));
545
546 IRB.SetInsertPoint(CheckTerm);
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000547 const int64_t AccessInfo = Recover * 0x20 + IsWrite * 0x10 + AccessSizeIndex;
548 InlineAsm *Asm;
549 switch (TargetTriple.getArch()) {
550 case Triple::x86_64:
551 // The signal handler will find the data address in rdi.
552 Asm = InlineAsm::get(
553 FunctionType::get(IRB.getVoidTy(), {PtrLong->getType()}, false),
554 "int3\nnopl " + itostr(0x40 + AccessInfo) + "(%rax)",
555 "{rdi}",
556 /*hasSideEffects=*/true);
557 break;
558 case Triple::aarch64:
559 case Triple::aarch64_be:
560 // The signal handler will find the data address in x0.
561 Asm = InlineAsm::get(
562 FunctionType::get(IRB.getVoidTy(), {PtrLong->getType()}, false),
563 "brk #" + itostr(0x900 + AccessInfo),
564 "{x0}",
565 /*hasSideEffects=*/true);
566 break;
567 default:
568 report_fatal_error("unsupported architecture");
569 }
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000570 IRB.CreateCall(Asm, PtrLong);
571}
572
Eugene Leviant2d98eb12018-12-20 09:04:33 +0000573void HWAddressSanitizer::instrumentMemIntrinsic(MemIntrinsic *MI) {
574 IRBuilder<> IRB(MI);
575 if (isa<MemTransferInst>(MI)) {
576 IRB.CreateCall(
577 isa<MemMoveInst>(MI) ? HWAsanMemmove : HWAsanMemcpy,
578 {IRB.CreatePointerCast(MI->getOperand(0), IRB.getInt8PtrTy()),
579 IRB.CreatePointerCast(MI->getOperand(1), IRB.getInt8PtrTy()),
580 IRB.CreateIntCast(MI->getOperand(2), IntptrTy, false)});
581 } else if (isa<MemSetInst>(MI)) {
582 IRB.CreateCall(
583 HWAsanMemset,
584 {IRB.CreatePointerCast(MI->getOperand(0), IRB.getInt8PtrTy()),
585 IRB.CreateIntCast(MI->getOperand(1), IRB.getInt32Ty(), false),
586 IRB.CreateIntCast(MI->getOperand(2), IntptrTy, false)});
587 }
588 MI->eraseFromParent();
589}
590
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000591bool HWAddressSanitizer::instrumentMemAccess(Instruction *I) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000592 LLVM_DEBUG(dbgs() << "Instrumenting: " << *I << "\n");
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000593 bool IsWrite = false;
594 unsigned Alignment = 0;
595 uint64_t TypeSize = 0;
596 Value *MaybeMask = nullptr;
Eugene Leviant2d98eb12018-12-20 09:04:33 +0000597
598 if (ClInstrumentMemIntrinsics && isa<MemIntrinsic>(I)) {
599 instrumentMemIntrinsic(cast<MemIntrinsic>(I));
600 return true;
601 }
602
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000603 Value *Addr =
604 isInterestingMemoryAccess(I, &IsWrite, &TypeSize, &Alignment, &MaybeMask);
605
606 if (!Addr)
607 return false;
608
609 if (MaybeMask)
610 return false; //FIXME
611
612 IRBuilder<> IRB(I);
613 Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy);
614 if (isPowerOf2_64(TypeSize) &&
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000615 (TypeSize / 8 <= (1UL << (kNumberOfAccessSizes - 1))) &&
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000616 (Alignment >= (1UL << Mapping.Scale) || Alignment == 0 ||
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000617 Alignment >= TypeSize / 8)) {
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000618 size_t AccessSizeIndex = TypeSizeToSizeIndex(TypeSize);
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000619 if (ClInstrumentWithCalls) {
620 IRB.CreateCall(HwasanMemoryAccessCallback[IsWrite][AccessSizeIndex],
621 AddrLong);
622 } else {
623 instrumentMemAccessInline(AddrLong, IsWrite, AccessSizeIndex, I);
624 }
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000625 } else {
626 IRB.CreateCall(HwasanMemoryAccessCallbackSized[IsWrite],
627 {AddrLong, ConstantInt::get(IntptrTy, TypeSize / 8)});
628 }
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000629 untagPointerOperand(I, Addr);
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000630
631 return true;
632}
633
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000634static uint64_t getAllocaSizeInBytes(const AllocaInst &AI) {
635 uint64_t ArraySize = 1;
636 if (AI.isArrayAllocation()) {
637 const ConstantInt *CI = dyn_cast<ConstantInt>(AI.getArraySize());
638 assert(CI && "non-constant array size");
639 ArraySize = CI->getZExtValue();
640 }
641 Type *Ty = AI.getAllocatedType();
642 uint64_t SizeInBytes = AI.getModule()->getDataLayout().getTypeAllocSize(Ty);
643 return SizeInBytes * ArraySize;
644}
645
646bool HWAddressSanitizer::tagAlloca(IRBuilder<> &IRB, AllocaInst *AI,
647 Value *Tag) {
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000648 size_t Size = (getAllocaSizeInBytes(*AI) + Mapping.getAllocaAlignment() - 1) &
649 ~(Mapping.getAllocaAlignment() - 1);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000650
651 Value *JustTag = IRB.CreateTrunc(Tag, IRB.getInt8Ty());
652 if (ClInstrumentWithCalls) {
653 IRB.CreateCall(HwasanTagMemoryFunc,
Evgeniy Stepanova265a132018-08-15 00:39:35 +0000654 {IRB.CreatePointerCast(AI, Int8PtrTy), JustTag,
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000655 ConstantInt::get(IntptrTy, Size)});
656 } else {
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000657 size_t ShadowSize = Size >> Mapping.Scale;
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000658 Value *ShadowPtr = IRB.CreateIntToPtr(
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000659 memToShadow(IRB.CreatePointerCast(AI, IntptrTy), AI->getType(), IRB),
Evgeniy Stepanova265a132018-08-15 00:39:35 +0000660 Int8PtrTy);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000661 // If this memset is not inlined, it will be intercepted in the hwasan
662 // runtime library. That's OK, because the interceptor skips the checks if
663 // the address is in the shadow region.
664 // FIXME: the interceptor is not as fast as real memset. Consider lowering
665 // llvm.memset right here into either a sequence of stores, or a call to
666 // hwasan_tag_memory.
667 IRB.CreateMemSet(ShadowPtr, JustTag, ShadowSize, /*Align=*/1);
668 }
669 return true;
670}
671
672static unsigned RetagMask(unsigned AllocaNo) {
673 // A list of 8-bit numbers that have at most one run of non-zero bits.
674 // x = x ^ (mask << 56) can be encoded as a single armv8 instruction for these
675 // masks.
676 // The list does not include the value 255, which is used for UAR.
677 static unsigned FastMasks[] = {
678 0, 1, 2, 3, 4, 6, 7, 8, 12, 14, 15, 16, 24,
679 28, 30, 31, 32, 48, 56, 60, 62, 63, 64, 96, 112, 120,
680 124, 126, 127, 128, 192, 224, 240, 248, 252, 254};
681 return FastMasks[AllocaNo % (sizeof(FastMasks) / sizeof(FastMasks[0]))];
682}
683
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000684Value *HWAddressSanitizer::getNextTagWithCall(IRBuilder<> &IRB) {
685 return IRB.CreateZExt(IRB.CreateCall(HwasanGenerateTagFunc), IntptrTy);
686}
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000687
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000688Value *HWAddressSanitizer::getStackBaseTag(IRBuilder<> &IRB) {
689 if (ClGenerateTagsWithCalls)
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000690 return getNextTagWithCall(IRB);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000691 // FIXME: use addressofreturnaddress (but implement it in aarch64 backend
692 // first).
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000693 Module *M = IRB.GetInsertBlock()->getParent()->getParent();
694 auto GetStackPointerFn =
695 Intrinsic::getDeclaration(M, Intrinsic::frameaddress);
696 Value *StackPointer = IRB.CreateCall(
697 GetStackPointerFn, {Constant::getNullValue(IRB.getInt32Ty())});
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000698
699 // Extract some entropy from the stack pointer for the tags.
700 // Take bits 20..28 (ASLR entropy) and xor with bits 0..8 (these differ
701 // between functions).
702 Value *StackPointerLong = IRB.CreatePointerCast(StackPointer, IntptrTy);
703 Value *StackTag =
704 IRB.CreateXor(StackPointerLong, IRB.CreateLShr(StackPointerLong, 20),
705 "hwasan.stack.base.tag");
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000706 return StackTag;
707}
708
709Value *HWAddressSanitizer::getAllocaTag(IRBuilder<> &IRB, Value *StackTag,
710 AllocaInst *AI, unsigned AllocaNo) {
711 if (ClGenerateTagsWithCalls)
712 return getNextTagWithCall(IRB);
713 return IRB.CreateXor(StackTag,
714 ConstantInt::get(IntptrTy, RetagMask(AllocaNo)));
715}
716
717Value *HWAddressSanitizer::getUARTag(IRBuilder<> &IRB, Value *StackTag) {
Alex Shlyapnikov788764c2018-06-29 20:20:17 +0000718 if (ClUARRetagToZero)
719 return ConstantInt::get(IntptrTy, 0);
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000720 if (ClGenerateTagsWithCalls)
721 return getNextTagWithCall(IRB);
722 return IRB.CreateXor(StackTag, ConstantInt::get(IntptrTy, 0xFFU));
723}
724
Evgeniy Stepanov80ccda22018-02-09 00:59:10 +0000725// Add a tag to an address.
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000726Value *HWAddressSanitizer::tagPointer(IRBuilder<> &IRB, Type *Ty,
727 Value *PtrLong, Value *Tag) {
Evgeniy Stepanov80ccda22018-02-09 00:59:10 +0000728 Value *TaggedPtrLong;
Andrey Konovalov1ba9d9c2018-04-13 18:05:21 +0000729 if (CompileKernel) {
Evgeniy Stepanov80ccda22018-02-09 00:59:10 +0000730 // Kernel addresses have 0xFF in the most significant byte.
731 Value *ShiftedTag = IRB.CreateOr(
732 IRB.CreateShl(Tag, kPointerTagShift),
733 ConstantInt::get(IntptrTy, (1ULL << kPointerTagShift) - 1));
734 TaggedPtrLong = IRB.CreateAnd(PtrLong, ShiftedTag);
735 } else {
736 // Userspace can simply do OR (tag << 56);
737 Value *ShiftedTag = IRB.CreateShl(Tag, kPointerTagShift);
738 TaggedPtrLong = IRB.CreateOr(PtrLong, ShiftedTag);
739 }
740 return IRB.CreateIntToPtr(TaggedPtrLong, Ty);
741}
742
Evgeniy Stepanov43271b12018-02-21 19:52:23 +0000743// Remove tag from an address.
744Value *HWAddressSanitizer::untagPointer(IRBuilder<> &IRB, Value *PtrLong) {
745 Value *UntaggedPtrLong;
Andrey Konovalov1ba9d9c2018-04-13 18:05:21 +0000746 if (CompileKernel) {
Evgeniy Stepanov43271b12018-02-21 19:52:23 +0000747 // Kernel addresses have 0xFF in the most significant byte.
748 UntaggedPtrLong = IRB.CreateOr(PtrLong,
749 ConstantInt::get(PtrLong->getType(), 0xFFULL << kPointerTagShift));
750 } else {
751 // Userspace addresses have 0x00.
752 UntaggedPtrLong = IRB.CreateAnd(PtrLong,
753 ConstantInt::get(PtrLong->getType(), ~(0xFFULL << kPointerTagShift)));
754 }
755 return UntaggedPtrLong;
756}
757
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000758Value *HWAddressSanitizer::getHwasanThreadSlotPtr(IRBuilder<> &IRB, Type *Ty) {
759 Module *M = IRB.GetInsertBlock()->getParent()->getParent();
760 if (TargetTriple.isAArch64() && TargetTriple.isAndroid()) {
761 Function *ThreadPointerFunc =
762 Intrinsic::getDeclaration(M, Intrinsic::thread_pointer);
763 Value *SlotPtr = IRB.CreatePointerCast(
Evgeniy Stepanoveb238ec2018-12-13 23:47:50 +0000764 IRB.CreateConstGEP1_32(IRB.CreateCall(ThreadPointerFunc), 0x40),
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000765 Ty->getPointerTo(0));
766 return SlotPtr;
767 }
768 if (ThreadPtrGlobal)
769 return ThreadPtrGlobal;
770
771
772 return nullptr;
773}
774
Kostya Serebryanyaf955972018-10-23 00:50:40 +0000775// Creates a string with a description of the stack frame (set of Allocas).
776// The string is intended to be human readable.
777// The current form is: Size1 Name1; Size2 Name2; ...
778std::string
779HWAddressSanitizer::createFrameString(ArrayRef<AllocaInst *> Allocas) {
780 std::ostringstream Descr;
781 for (auto AI : Allocas)
782 Descr << getAllocaSizeInBytes(*AI) << " " << AI->getName().str() << "; ";
783 return Descr.str();
784}
785
786// Creates a global in the frame section which consists of two pointers:
787// the function PC and the frame string constant.
788void HWAddressSanitizer::createFrameGlobal(Function &F,
789 const std::string &FrameString) {
790 Module &M = *F.getParent();
791 auto DescrGV = createPrivateGlobalForString(M, FrameString, true);
792 auto PtrPairTy = StructType::get(F.getType(), DescrGV->getType());
793 auto GV = new GlobalVariable(
794 M, PtrPairTy, /*isConstantGlobal*/ true, GlobalVariable::PrivateLinkage,
795 ConstantStruct::get(PtrPairTy, (Constant *)&F, (Constant *)DescrGV),
796 "__hwasan");
797 GV->setSection(getFrameSection());
798 appendToCompilerUsed(M, GV);
799 // 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 +0000800 if (auto Comdat =
801 GetOrCreateFunctionComdat(F, TargetTriple, CurModuleUniqueId))
802 GV->setComdat(Comdat);
Kostya Serebryanyaf955972018-10-23 00:50:40 +0000803}
804
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000805Value *HWAddressSanitizer::emitPrologue(IRBuilder<> &IRB,
806 bool WithFrameRecord) {
807 if (!Mapping.InTls)
808 return getDynamicShadowNonTls(IRB);
809
810 Value *SlotPtr = getHwasanThreadSlotPtr(IRB, IntptrTy);
811 assert(SlotPtr);
812
Peter Collingbourne87f477b2019-01-04 19:27:04 +0000813 Instruction *ThreadLong = IRB.CreateLoad(SlotPtr);
814
815 Function *F = IRB.GetInsertBlock()->getParent();
816 if (F->getFnAttribute("hwasan-abi").getValueAsString() == "interceptor") {
817 Value *ThreadLongEqZero =
818 IRB.CreateICmpEQ(ThreadLong, ConstantInt::get(IntptrTy, 0));
819 auto *Br = cast<BranchInst>(SplitBlockAndInsertIfThen(
820 ThreadLongEqZero, cast<Instruction>(ThreadLongEqZero)->getNextNode(),
821 false, MDBuilder(*C).createBranchWeights(1, 100000)));
822
823 IRB.SetInsertPoint(Br);
824 // FIXME: This should call a new runtime function with a custom calling
825 // convention to avoid needing to spill all arguments here.
826 IRB.CreateCall(HwasanThreadEnterFunc);
827 LoadInst *ReloadThreadLong = IRB.CreateLoad(SlotPtr);
828
829 IRB.SetInsertPoint(&*Br->getSuccessor(0)->begin());
830 PHINode *ThreadLongPhi = IRB.CreatePHI(IntptrTy, 2);
831 ThreadLongPhi->addIncoming(ThreadLong, ThreadLong->getParent());
832 ThreadLongPhi->addIncoming(ReloadThreadLong, ReloadThreadLong->getParent());
833 ThreadLong = ThreadLongPhi;
834 }
835
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000836 // Extract the address field from ThreadLong. Unnecessary on AArch64 with TBI.
837 Value *ThreadLongMaybeUntagged =
838 TargetTriple.isAArch64() ? ThreadLong : untagPointer(IRB, ThreadLong);
839
840 if (WithFrameRecord) {
841 // Prepare ring buffer data.
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000842 auto PC = IRB.CreatePtrToInt(F, IntptrTy);
843 auto GetStackPointerFn =
844 Intrinsic::getDeclaration(F->getParent(), Intrinsic::frameaddress);
845 Value *SP = IRB.CreatePtrToInt(
846 IRB.CreateCall(GetStackPointerFn,
847 {Constant::getNullValue(IRB.getInt32Ty())}),
848 IntptrTy);
849 // Mix SP and PC. TODO: also add the tag to the mix.
850 // Assumptions:
851 // PC is 0x0000PPPPPPPPPPPP (48 bits are meaningful, others are zero)
852 // SP is 0xsssssssssssSSSS0 (4 lower bits are zero)
853 // We only really need ~20 lower non-zero bits (SSSS), so we mix like this:
854 // 0xSSSSPPPPPPPPPPPP
855 SP = IRB.CreateShl(SP, 44);
856
857 // Store data to ring buffer.
858 Value *RecordPtr =
859 IRB.CreateIntToPtr(ThreadLongMaybeUntagged, IntptrTy->getPointerTo(0));
860 IRB.CreateStore(IRB.CreateOr(PC, SP), RecordPtr);
861
862 // Update the ring buffer. Top byte of ThreadLong defines the size of the
863 // buffer in pages, it must be a power of two, and the start of the buffer
864 // must be aligned by twice that much. Therefore wrap around of the ring
865 // buffer is simply Addr &= ~((ThreadLong >> 56) << 12).
866 // The use of AShr instead of LShr is due to
867 // https://bugs.llvm.org/show_bug.cgi?id=39030
868 // Runtime library makes sure not to use the highest bit.
869 Value *WrapMask = IRB.CreateXor(
870 IRB.CreateShl(IRB.CreateAShr(ThreadLong, 56), 12, "", true, true),
871 ConstantInt::get(IntptrTy, (uint64_t)-1));
872 Value *ThreadLongNew = IRB.CreateAnd(
873 IRB.CreateAdd(ThreadLong, ConstantInt::get(IntptrTy, 8)), WrapMask);
874 IRB.CreateStore(ThreadLongNew, SlotPtr);
875 }
876
877 // Get shadow base address by aligning RecordPtr up.
878 // Note: this is not correct if the pointer is already aligned.
879 // Runtime library will make sure this never happens.
880 Value *ShadowBase = IRB.CreateAdd(
881 IRB.CreateOr(
882 ThreadLongMaybeUntagged,
883 ConstantInt::get(IntptrTy, (1ULL << kShadowBaseAlignment) - 1)),
884 ConstantInt::get(IntptrTy, 1), "hwasan.shadow");
885 return ShadowBase;
886}
887
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000888bool HWAddressSanitizer::instrumentStack(
889 SmallVectorImpl<AllocaInst *> &Allocas,
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000890 SmallVectorImpl<Instruction *> &RetVec, Value *StackTag) {
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000891 // Ideally, we want to calculate tagged stack base pointer, and rewrite all
892 // alloca addresses using that. Unfortunately, offsets are not known yet
893 // (unless we use ASan-style mega-alloca). Instead we keep the base tag in a
894 // temp, shift-OR it into each alloca address and xor with the retag mask.
895 // This generates one extra instruction per alloca use.
896 for (unsigned N = 0; N < Allocas.size(); ++N) {
897 auto *AI = Allocas[N];
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000898 IRBuilder<> IRB(AI->getNextNode());
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000899
900 // Replace uses of the alloca with tagged address.
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000901 Value *Tag = getAllocaTag(IRB, StackTag, AI, N);
902 Value *AILong = IRB.CreatePointerCast(AI, IntptrTy);
Evgeniy Stepanov80ccda22018-02-09 00:59:10 +0000903 Value *Replacement = tagPointer(IRB, AI->getType(), AILong, Tag);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000904 std::string Name =
905 AI->hasName() ? AI->getName().str() : "alloca." + itostr(N);
Evgeniy Stepanov80ccda22018-02-09 00:59:10 +0000906 Replacement->setName(Name + ".hwasan");
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000907
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000908 for (auto UI = AI->use_begin(), UE = AI->use_end(); UI != UE;) {
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000909 Use &U = *UI++;
910 if (U.getUser() != AILong)
911 U.set(Replacement);
912 }
913
914 tagAlloca(IRB, AI, Tag);
915
916 for (auto RI : RetVec) {
917 IRB.SetInsertPoint(RI);
918
919 // Re-tag alloca memory with the special UAR tag.
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000920 Value *Tag = getUARTag(IRB, StackTag);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000921 tagAlloca(IRB, AI, Tag);
922 }
923 }
924
925 return true;
926}
927
928bool HWAddressSanitizer::isInterestingAlloca(const AllocaInst &AI) {
929 return (AI.getAllocatedType()->isSized() &&
930 // FIXME: instrument dynamic allocas, too
931 AI.isStaticAlloca() &&
932 // alloca() may be called with 0 size, ignore it.
933 getAllocaSizeInBytes(AI) > 0 &&
934 // We are only interested in allocas not promotable to registers.
935 // Promotable allocas are common under -O0.
936 !isAllocaPromotable(&AI) &&
937 // inalloca allocas are not treated as static, and we don't want
938 // dynamic alloca instrumentation for them as well.
939 !AI.isUsedWithInAlloca() &&
940 // swifterror allocas are register promoted by ISel
941 !AI.isSwiftError());
942}
943
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000944bool HWAddressSanitizer::runOnFunction(Function &F) {
945 if (&F == HwasanCtorFunction)
946 return false;
947
948 if (!F.hasFnAttribute(Attribute::SanitizeHWAddress))
949 return false;
950
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000951 LLVM_DEBUG(dbgs() << "Function: " << F.getName() << "\n");
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000952
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000953 SmallVector<Instruction*, 16> ToInstrument;
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000954 SmallVector<AllocaInst*, 8> AllocasToInstrument;
955 SmallVector<Instruction*, 8> RetVec;
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000956 for (auto &BB : F) {
957 for (auto &Inst : BB) {
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000958 if (ClInstrumentStack)
959 if (AllocaInst *AI = dyn_cast<AllocaInst>(&Inst)) {
960 // Realign all allocas. We don't want small uninteresting allocas to
961 // hide in instrumented alloca's padding.
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000962 if (AI->getAlignment() < Mapping.getAllocaAlignment())
963 AI->setAlignment(Mapping.getAllocaAlignment());
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000964 // Instrument some of them.
965 if (isInterestingAlloca(*AI))
966 AllocasToInstrument.push_back(AI);
967 continue;
968 }
969
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000970 if (isa<ReturnInst>(Inst) || isa<ResumeInst>(Inst) ||
971 isa<CleanupReturnInst>(Inst))
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000972 RetVec.push_back(&Inst);
973
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000974 Value *MaybeMask = nullptr;
975 bool IsWrite;
976 unsigned Alignment;
977 uint64_t TypeSize;
978 Value *Addr = isInterestingMemoryAccess(&Inst, &IsWrite, &TypeSize,
979 &Alignment, &MaybeMask);
980 if (Addr || isa<MemIntrinsic>(Inst))
981 ToInstrument.push_back(&Inst);
982 }
983 }
984
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000985 if (AllocasToInstrument.empty() && ToInstrument.empty())
986 return false;
987
Kostya Serebryanyaf955972018-10-23 00:50:40 +0000988 if (ClCreateFrameDescriptions && !AllocasToInstrument.empty())
989 createFrameGlobal(F, createFrameString(AllocasToInstrument));
990
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000991 initializeCallbacks(*F.getParent());
992
993 assert(!LocalDynamicShadow);
994
995 Instruction *InsertPt = &*F.getEntryBlock().begin();
996 IRBuilder<> EntryIRB(InsertPt);
997 LocalDynamicShadow = emitPrologue(EntryIRB,
998 /*WithFrameRecord*/ ClRecordStackHistory &&
999 !AllocasToInstrument.empty());
1000
1001 bool Changed = false;
1002 if (!AllocasToInstrument.empty()) {
1003 Value *StackTag =
1004 ClGenerateTagsWithCalls ? nullptr : getStackBaseTag(EntryIRB);
1005 Changed |= instrumentStack(AllocasToInstrument, RetVec, StackTag);
1006 }
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +00001007
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +00001008 for (auto Inst : ToInstrument)
1009 Changed |= instrumentMemAccess(Inst);
1010
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +00001011 LocalDynamicShadow = nullptr;
1012
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +00001013 return Changed;
1014}
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +00001015
1016void HWAddressSanitizer::ShadowMapping::init(Triple &TargetTriple) {
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +00001017 Scale = kDefaultShadowScale;
Evgeniy Stepanov453e7ac2018-08-10 16:21:37 +00001018 if (ClMappingOffset.getNumOccurrences() > 0) {
1019 InGlobal = false;
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +00001020 InTls = false;
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +00001021 Offset = ClMappingOffset;
Evgeniy Stepanov453e7ac2018-08-10 16:21:37 +00001022 } else if (ClEnableKhwasan || ClInstrumentWithCalls) {
1023 InGlobal = false;
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +00001024 InTls = false;
Evgeniy Stepanov453e7ac2018-08-10 16:21:37 +00001025 Offset = 0;
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +00001026 } else if (ClWithIfunc) {
Evgeniy Stepanov453e7ac2018-08-10 16:21:37 +00001027 InGlobal = true;
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +00001028 InTls = false;
1029 Offset = kDynamicShadowSentinel;
1030 } else if (ClWithTls) {
1031 InGlobal = false;
1032 InTls = true;
Evgeniy Stepanov453e7ac2018-08-10 16:21:37 +00001033 Offset = kDynamicShadowSentinel;
1034 } else {
1035 InGlobal = false;
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +00001036 InTls = false;
Evgeniy Stepanov453e7ac2018-08-10 16:21:37 +00001037 Offset = kDynamicShadowSentinel;
1038 }
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +00001039}