blob: a6ffff418db959bdbfb48db0625abf7262127e28 [file] [log] [blame]
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +00001//===- HWAddressSanitizer.cpp - detector of uninitialized reads -------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +00006//
7//===----------------------------------------------------------------------===//
8//
9/// \file
10/// This file is a part of HWAddressSanitizer, an address sanity checker
11/// based on tagged addressing.
12//===----------------------------------------------------------------------===//
13
14#include "llvm/ADT/SmallVector.h"
15#include "llvm/ADT/StringExtras.h"
16#include "llvm/ADT/StringRef.h"
17#include "llvm/ADT/Triple.h"
18#include "llvm/IR/Attributes.h"
19#include "llvm/IR/BasicBlock.h"
20#include "llvm/IR/Constant.h"
21#include "llvm/IR/Constants.h"
22#include "llvm/IR/DataLayout.h"
23#include "llvm/IR/DerivedTypes.h"
24#include "llvm/IR/Function.h"
25#include "llvm/IR/IRBuilder.h"
26#include "llvm/IR/InlineAsm.h"
27#include "llvm/IR/InstVisitor.h"
28#include "llvm/IR/Instruction.h"
29#include "llvm/IR/Instructions.h"
30#include "llvm/IR/IntrinsicInst.h"
31#include "llvm/IR/Intrinsics.h"
32#include "llvm/IR/LLVMContext.h"
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +000033#include "llvm/IR/MDBuilder.h"
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +000034#include "llvm/IR/Module.h"
35#include "llvm/IR/Type.h"
36#include "llvm/IR/Value.h"
37#include "llvm/Pass.h"
38#include "llvm/Support/Casting.h"
39#include "llvm/Support/CommandLine.h"
40#include "llvm/Support/Debug.h"
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +000041#include "llvm/Support/raw_ostream.h"
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +000042#include "llvm/Transforms/Instrumentation.h"
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +000043#include "llvm/Transforms/Utils/BasicBlockUtils.h"
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +000044#include "llvm/Transforms/Utils/ModuleUtils.h"
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +000045#include "llvm/Transforms/Utils/PromoteMemToReg.h"
Kostya Serebryanyaf955972018-10-23 00:50:40 +000046#include <sstream>
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +000047
48using namespace llvm;
49
50#define DEBUG_TYPE "hwasan"
51
52static const char *const kHwasanModuleCtorName = "hwasan.module_ctor";
53static const char *const kHwasanInitName = "__hwasan_init";
54
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +000055static const char *const kHwasanShadowMemoryDynamicAddress =
56 "__hwasan_shadow_memory_dynamic_address";
57
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +000058// Accesses sizes are powers of two: 1, 2, 4, 8, 16.
59static const size_t kNumberOfAccessSizes = 5;
60
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +000061static const size_t kDefaultShadowScale = 4;
62static const uint64_t kDynamicShadowSentinel =
63 std::numeric_limits<uint64_t>::max();
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +000064static const unsigned kPointerTagShift = 56;
65
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +000066static const unsigned kShadowBaseAlignment = 32;
67
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +000068static cl::opt<std::string> ClMemoryAccessCallbackPrefix(
69 "hwasan-memory-access-callback-prefix",
70 cl::desc("Prefix for memory access callbacks"), cl::Hidden,
71 cl::init("__hwasan_"));
72
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +000073static cl::opt<bool>
74 ClInstrumentWithCalls("hwasan-instrument-with-calls",
75 cl::desc("instrument reads and writes with callbacks"),
76 cl::Hidden, cl::init(false));
77
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +000078static cl::opt<bool> ClInstrumentReads("hwasan-instrument-reads",
79 cl::desc("instrument read instructions"),
80 cl::Hidden, cl::init(true));
81
82static cl::opt<bool> ClInstrumentWrites(
83 "hwasan-instrument-writes", cl::desc("instrument write instructions"),
84 cl::Hidden, cl::init(true));
85
86static cl::opt<bool> ClInstrumentAtomics(
87 "hwasan-instrument-atomics",
88 cl::desc("instrument atomic instructions (rmw, cmpxchg)"), cl::Hidden,
89 cl::init(true));
90
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +000091static cl::opt<bool> ClRecover(
92 "hwasan-recover",
93 cl::desc("Enable recovery mode (continue-after-error)."),
94 cl::Hidden, cl::init(false));
95
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +000096static cl::opt<bool> ClInstrumentStack("hwasan-instrument-stack",
97 cl::desc("instrument stack (allocas)"),
98 cl::Hidden, cl::init(true));
99
Alex Shlyapnikov788764c2018-06-29 20:20:17 +0000100static cl::opt<bool> ClUARRetagToZero(
101 "hwasan-uar-retag-to-zero",
102 cl::desc("Clear alloca tags before returning from the function to allow "
103 "non-instrumented and instrumented function calls mix. When set "
104 "to false, allocas are retagged before returning from the "
105 "function to detect use after return."),
106 cl::Hidden, cl::init(true));
107
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000108static cl::opt<bool> ClGenerateTagsWithCalls(
109 "hwasan-generate-tags-with-calls",
110 cl::desc("generate new tags with runtime library calls"), cl::Hidden,
111 cl::init(false));
112
Evgeniy Stepanov1f1a7a72018-04-04 20:44:59 +0000113static cl::opt<int> ClMatchAllTag(
114 "hwasan-match-all-tag",
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000115 cl::desc("don't report bad accesses via pointers with this tag"),
116 cl::Hidden, cl::init(-1));
Evgeniy Stepanov1f1a7a72018-04-04 20:44:59 +0000117
Evgeniy Stepanov5bd669d2018-01-17 23:24:38 +0000118static cl::opt<bool> ClEnableKhwasan(
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000119 "hwasan-kernel",
120 cl::desc("Enable KernelHWAddressSanitizer instrumentation"),
Evgeniy Stepanov5bd669d2018-01-17 23:24:38 +0000121 cl::Hidden, cl::init(false));
122
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000123// These flags allow to change the shadow mapping and control how shadow memory
124// is accessed. The shadow mapping looks like:
125// Shadow = (Mem >> scale) + offset
126
127static cl::opt<unsigned long long> ClMappingOffset(
128 "hwasan-mapping-offset",
129 cl::desc("HWASan shadow mapping offset [EXPERIMENTAL]"), cl::Hidden,
130 cl::init(0));
131
Evgeniy Stepanov453e7ac2018-08-10 16:21:37 +0000132static cl::opt<bool>
133 ClWithIfunc("hwasan-with-ifunc",
134 cl::desc("Access dynamic shadow through an ifunc global on "
135 "platforms that support this"),
136 cl::Hidden, cl::init(false));
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000137
138static cl::opt<bool> ClWithTls(
139 "hwasan-with-tls",
140 cl::desc("Access dynamic shadow through an thread-local pointer on "
141 "platforms that support this"),
142 cl::Hidden, cl::init(true));
143
144static cl::opt<bool>
145 ClRecordStackHistory("hwasan-record-stack-history",
146 cl::desc("Record stack frames with tagged allocations "
147 "in a thread-local ring buffer"),
148 cl::Hidden, cl::init(true));
Kostya Serebryanyaf955972018-10-23 00:50:40 +0000149static cl::opt<bool>
150 ClCreateFrameDescriptions("hwasan-create-frame-descriptions",
151 cl::desc("create static frame descriptions"),
152 cl::Hidden, cl::init(true));
153
Eugene Leviant2d98eb12018-12-20 09:04:33 +0000154static cl::opt<bool>
155 ClInstrumentMemIntrinsics("hwasan-instrument-mem-intrinsics",
156 cl::desc("instrument memory intrinsics"),
Eugene Leviant4dc3a3f2018-12-24 16:02:48 +0000157 cl::Hidden, cl::init(true));
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000158
159static cl::opt<bool> ClInlineAllChecks("hwasan-inline-all-checks",
160 cl::desc("inline all checks"),
161 cl::Hidden, cl::init(false));
162
Peter Collingbourne020ce3f2019-01-23 22:39:11 +0000163static cl::opt<bool> ClAllowIfunc("hwasan-allow-ifunc",
164 cl::desc("allow the use of ifunc"),
165 cl::Hidden, cl::init(false));
166
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000167namespace {
168
Adrian Prantl5f8f34e42018-05-01 15:54:18 +0000169/// An instrumentation pass implementing detection of addressability bugs
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000170/// using tagged pointers.
171class HWAddressSanitizer : public FunctionPass {
172public:
173 // Pass identification, replacement for typeid.
174 static char ID;
175
Andrey Konovalov1ba9d9c2018-04-13 18:05:21 +0000176 explicit HWAddressSanitizer(bool CompileKernel = false, bool Recover = false)
177 : FunctionPass(ID) {
178 this->Recover = ClRecover.getNumOccurrences() > 0 ? ClRecover : Recover;
179 this->CompileKernel = ClEnableKhwasan.getNumOccurrences() > 0 ?
180 ClEnableKhwasan : CompileKernel;
181 }
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000182
183 StringRef getPassName() const override { return "HWAddressSanitizer"; }
184
185 bool runOnFunction(Function &F) override;
186 bool doInitialization(Module &M) override;
187
188 void initializeCallbacks(Module &M);
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000189
Peter Collingbourne020ce3f2019-01-23 22:39:11 +0000190 Value *getDynamicShadowIfunc(IRBuilder<> &IRB);
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000191 Value *getDynamicShadowNonTls(IRBuilder<> &IRB);
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000192
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000193 void untagPointerOperand(Instruction *I, Value *Addr);
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000194 Value *shadowBase();
195 Value *memToShadow(Value *Shadow, IRBuilder<> &IRB);
196 void instrumentMemAccessInline(Value *Ptr, bool IsWrite,
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000197 unsigned AccessSizeIndex,
198 Instruction *InsertBefore);
Eugene Leviant2d98eb12018-12-20 09:04:33 +0000199 void instrumentMemIntrinsic(MemIntrinsic *MI);
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000200 bool instrumentMemAccess(Instruction *I);
201 Value *isInterestingMemoryAccess(Instruction *I, bool *IsWrite,
202 uint64_t *TypeSize, unsigned *Alignment,
203 Value **MaybeMask);
204
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000205 bool isInterestingAlloca(const AllocaInst &AI);
206 bool tagAlloca(IRBuilder<> &IRB, AllocaInst *AI, Value *Tag);
Evgeniy Stepanov80ccda22018-02-09 00:59:10 +0000207 Value *tagPointer(IRBuilder<> &IRB, Type *Ty, Value *PtrLong, Value *Tag);
Evgeniy Stepanov43271b12018-02-21 19:52:23 +0000208 Value *untagPointer(IRBuilder<> &IRB, Value *PtrLong);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000209 bool instrumentStack(SmallVectorImpl<AllocaInst *> &Allocas,
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000210 SmallVectorImpl<Instruction *> &RetVec, Value *StackTag);
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000211 Value *getNextTagWithCall(IRBuilder<> &IRB);
212 Value *getStackBaseTag(IRBuilder<> &IRB);
213 Value *getAllocaTag(IRBuilder<> &IRB, Value *StackTag, AllocaInst *AI,
214 unsigned AllocaNo);
215 Value *getUARTag(IRBuilder<> &IRB, Value *StackTag);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000216
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000217 Value *getHwasanThreadSlotPtr(IRBuilder<> &IRB, Type *Ty);
218 Value *emitPrologue(IRBuilder<> &IRB, bool WithFrameRecord);
219
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000220private:
221 LLVMContext *C;
Kostya Serebryanyaf955972018-10-23 00:50:40 +0000222 std::string CurModuleUniqueId;
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000223 Triple TargetTriple;
Eugene Leviant2d98eb12018-12-20 09:04:33 +0000224 Function *HWAsanMemmove, *HWAsanMemcpy, *HWAsanMemset;
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000225
Kostya Serebryanyaf955972018-10-23 00:50:40 +0000226 // Frame description is a way to pass names/sizes of local variables
227 // to the run-time w/o adding extra executable code in every function.
228 // We do this by creating a separate section with {PC,Descr} pairs and passing
229 // the section beg/end to __hwasan_init_frames() at module init time.
230 std::string createFrameString(ArrayRef<AllocaInst*> Allocas);
231 void createFrameGlobal(Function &F, const std::string &FrameString);
232 // Get the section name for frame descriptions. Currently ELF-only.
233 const char *getFrameSection() { return "__hwasan_frames"; }
234 const char *getFrameSectionBeg() { return "__start___hwasan_frames"; }
235 const char *getFrameSectionEnd() { return "__stop___hwasan_frames"; }
236 GlobalVariable *createFrameSectionBound(Module &M, Type *Ty,
237 const char *Name) {
238 auto GV = new GlobalVariable(M, Ty, false, GlobalVariable::ExternalLinkage,
239 nullptr, Name);
240 GV->setVisibility(GlobalValue::HiddenVisibility);
241 return GV;
242 }
243
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000244 /// This struct defines the shadow mapping using the rule:
245 /// shadow = (mem >> Scale) + Offset.
246 /// If InGlobal is true, then
247 /// extern char __hwasan_shadow[];
248 /// shadow = (mem >> Scale) + &__hwasan_shadow
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000249 /// If InTls is true, then
250 /// extern char *__hwasan_tls;
Kostya Serebryanyaf955972018-10-23 00:50:40 +0000251 /// shadow = (mem>>Scale) + align_up(__hwasan_shadow, kShadowBaseAlignment)
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000252 struct ShadowMapping {
253 int Scale;
254 uint64_t Offset;
255 bool InGlobal;
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000256 bool InTls;
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000257
258 void init(Triple &TargetTriple);
259 unsigned getAllocaAlignment() const { return 1U << Scale; }
260 };
261 ShadowMapping Mapping;
262
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000263 Type *IntptrTy;
Evgeniy Stepanova265a132018-08-15 00:39:35 +0000264 Type *Int8PtrTy;
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000265 Type *Int8Ty;
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000266 Type *Int32Ty;
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000267
Andrey Konovalov1ba9d9c2018-04-13 18:05:21 +0000268 bool CompileKernel;
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000269 bool Recover;
270
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000271 Function *HwasanCtorFunction;
272
273 Function *HwasanMemoryAccessCallback[2][kNumberOfAccessSizes];
274 Function *HwasanMemoryAccessCallbackSized[2];
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000275
276 Function *HwasanTagMemoryFunc;
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000277 Function *HwasanGenerateTagFunc;
Peter Collingbourne87f477b2019-01-04 19:27:04 +0000278 Function *HwasanThreadEnterFunc;
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000279
280 Constant *ShadowGlobal;
281
282 Value *LocalDynamicShadow = nullptr;
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000283 GlobalValue *ThreadPtrGlobal = nullptr;
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000284};
285
286} // end anonymous namespace
287
288char HWAddressSanitizer::ID = 0;
289
290INITIALIZE_PASS_BEGIN(
291 HWAddressSanitizer, "hwasan",
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000292 "HWAddressSanitizer: detect memory bugs using tagged addressing.", false,
293 false)
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000294INITIALIZE_PASS_END(
295 HWAddressSanitizer, "hwasan",
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000296 "HWAddressSanitizer: detect memory bugs using tagged addressing.", false,
297 false)
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000298
Andrey Konovalov1ba9d9c2018-04-13 18:05:21 +0000299FunctionPass *llvm::createHWAddressSanitizerPass(bool CompileKernel,
300 bool Recover) {
301 assert(!CompileKernel || Recover);
302 return new HWAddressSanitizer(CompileKernel, Recover);
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000303}
304
Adrian Prantl5f8f34e42018-05-01 15:54:18 +0000305/// Module-level initialization.
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000306///
307/// inserts a call to __hwasan_init to the module's constructor list.
308bool HWAddressSanitizer::doInitialization(Module &M) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000309 LLVM_DEBUG(dbgs() << "Init " << M.getName() << "\n");
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000310 auto &DL = M.getDataLayout();
311
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000312 TargetTriple = Triple(M.getTargetTriple());
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000313
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000314 Mapping.init(TargetTriple);
315
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000316 C = &(M.getContext());
Kostya Serebryanyaf955972018-10-23 00:50:40 +0000317 CurModuleUniqueId = getUniqueModuleId(&M);
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000318 IRBuilder<> IRB(*C);
319 IntptrTy = IRB.getIntPtrTy(DL);
Evgeniy Stepanova265a132018-08-15 00:39:35 +0000320 Int8PtrTy = IRB.getInt8PtrTy();
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000321 Int8Ty = IRB.getInt8Ty();
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000322 Int32Ty = IRB.getInt32Ty();
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000323
Benjamin Kramerbfc1d972018-01-18 14:19:04 +0000324 HwasanCtorFunction = nullptr;
Andrey Konovalov1ba9d9c2018-04-13 18:05:21 +0000325 if (!CompileKernel) {
Evgeniy Stepanov5bd669d2018-01-17 23:24:38 +0000326 std::tie(HwasanCtorFunction, std::ignore) =
327 createSanitizerCtorAndInitFunctions(M, kHwasanModuleCtorName,
328 kHwasanInitName,
329 /*InitArgTypes=*/{},
330 /*InitArgs=*/{});
Peter Collingbourned3a3e4b2018-12-17 22:56:34 +0000331 Comdat *CtorComdat = M.getOrInsertComdat(kHwasanModuleCtorName);
332 HwasanCtorFunction->setComdat(CtorComdat);
333 appendToGlobalCtors(M, HwasanCtorFunction, 0, HwasanCtorFunction);
Kostya Serebryanyaf955972018-10-23 00:50:40 +0000334
Peter Collingbourned3a3e4b2018-12-17 22:56:34 +0000335 // Create a zero-length global in __hwasan_frame so that the linker will
336 // always create start and stop symbols.
337 //
338 // N.B. If we ever start creating associated metadata in this pass this
339 // global will need to be associated with the ctor.
340 Type *Int8Arr0Ty = ArrayType::get(Int8Ty, 0);
341 auto GV =
342 new GlobalVariable(M, Int8Arr0Ty, /*isConstantGlobal*/ true,
343 GlobalVariable::PrivateLinkage,
344 Constant::getNullValue(Int8Arr0Ty), "__hwasan");
345 GV->setSection(getFrameSection());
346 GV->setComdat(CtorComdat);
347 appendToCompilerUsed(M, GV);
348
Kostya Serebryanyaf955972018-10-23 00:50:40 +0000349 IRBuilder<> IRBCtor(HwasanCtorFunction->getEntryBlock().getTerminator());
350 IRBCtor.CreateCall(
351 declareSanitizerInitFunction(M, "__hwasan_init_frames",
352 {Int8PtrTy, Int8PtrTy}),
353 {createFrameSectionBound(M, Int8Ty, getFrameSectionBeg()),
354 createFrameSectionBound(M, Int8Ty, getFrameSectionEnd())});
355 }
356
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000357 if (!TargetTriple.isAndroid())
358 appendToCompilerUsed(
359 M, ThreadPtrGlobal = new GlobalVariable(
360 M, IntptrTy, false, GlobalVariable::ExternalLinkage, nullptr,
361 "__hwasan_tls", nullptr, GlobalVariable::InitialExecTLSModel));
362
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000363 return true;
364}
365
366void HWAddressSanitizer::initializeCallbacks(Module &M) {
367 IRBuilder<> IRB(*C);
368 for (size_t AccessIsWrite = 0; AccessIsWrite <= 1; AccessIsWrite++) {
369 const std::string TypeStr = AccessIsWrite ? "store" : "load";
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000370 const std::string EndingStr = Recover ? "_noabort" : "";
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000371
372 HwasanMemoryAccessCallbackSized[AccessIsWrite] =
373 checkSanitizerInterfaceFunction(M.getOrInsertFunction(
Evgeniy Stepanovc07e0bd2018-01-16 23:15:08 +0000374 ClMemoryAccessCallbackPrefix + TypeStr + "N" + EndingStr,
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000375 FunctionType::get(IRB.getVoidTy(), {IntptrTy, IntptrTy}, false)));
376
377 for (size_t AccessSizeIndex = 0; AccessSizeIndex < kNumberOfAccessSizes;
378 AccessSizeIndex++) {
379 HwasanMemoryAccessCallback[AccessIsWrite][AccessSizeIndex] =
380 checkSanitizerInterfaceFunction(M.getOrInsertFunction(
381 ClMemoryAccessCallbackPrefix + TypeStr +
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000382 itostr(1ULL << AccessSizeIndex) + EndingStr,
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000383 FunctionType::get(IRB.getVoidTy(), {IntptrTy}, false)));
384 }
385 }
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000386
387 HwasanTagMemoryFunc = checkSanitizerInterfaceFunction(M.getOrInsertFunction(
Evgeniy Stepanova265a132018-08-15 00:39:35 +0000388 "__hwasan_tag_memory", IRB.getVoidTy(), Int8PtrTy, Int8Ty, IntptrTy));
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000389 HwasanGenerateTagFunc = checkSanitizerInterfaceFunction(
390 M.getOrInsertFunction("__hwasan_generate_tag", Int8Ty));
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000391
Peter Collingbourne020ce3f2019-01-23 22:39:11 +0000392 ShadowGlobal = M.getOrInsertGlobal("__hwasan_shadow",
393 ArrayType::get(IRB.getInt8Ty(), 0));
Eugene Leviant2d98eb12018-12-20 09:04:33 +0000394
395 const std::string MemIntrinCallbackPrefix =
396 CompileKernel ? std::string("") : ClMemoryAccessCallbackPrefix;
397 HWAsanMemmove = checkSanitizerInterfaceFunction(M.getOrInsertFunction(
398 MemIntrinCallbackPrefix + "memmove", IRB.getInt8PtrTy(),
399 IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), IntptrTy));
400 HWAsanMemcpy = checkSanitizerInterfaceFunction(M.getOrInsertFunction(
401 MemIntrinCallbackPrefix + "memcpy", IRB.getInt8PtrTy(),
402 IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), IntptrTy));
403 HWAsanMemset = checkSanitizerInterfaceFunction(M.getOrInsertFunction(
404 MemIntrinCallbackPrefix + "memset", IRB.getInt8PtrTy(),
405 IRB.getInt8PtrTy(), IRB.getInt32Ty(), IntptrTy));
Peter Collingbourne87f477b2019-01-04 19:27:04 +0000406
407 HwasanThreadEnterFunc = checkSanitizerInterfaceFunction(
408 M.getOrInsertFunction("__hwasan_thread_enter", IRB.getVoidTy()));
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000409}
410
Peter Collingbourne020ce3f2019-01-23 22:39:11 +0000411Value *HWAddressSanitizer::getDynamicShadowIfunc(IRBuilder<> &IRB) {
412 // An empty inline asm with input reg == output reg.
413 // An opaque no-op cast, basically.
414 InlineAsm *Asm = InlineAsm::get(
415 FunctionType::get(Int8PtrTy, {ShadowGlobal->getType()}, false),
416 StringRef(""), StringRef("=r,0"),
417 /*hasSideEffects=*/false);
418 return IRB.CreateCall(Asm, {ShadowGlobal}, ".hwasan.shadow");
419}
420
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000421Value *HWAddressSanitizer::getDynamicShadowNonTls(IRBuilder<> &IRB) {
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000422 // Generate code only when dynamic addressing is needed.
423 if (Mapping.Offset != kDynamicShadowSentinel)
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000424 return nullptr;
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000425
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000426 if (Mapping.InGlobal) {
Peter Collingbourne020ce3f2019-01-23 22:39:11 +0000427 return getDynamicShadowIfunc(IRB);
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000428 } else {
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000429 Value *GlobalDynamicAddress =
430 IRB.GetInsertBlock()->getParent()->getParent()->getOrInsertGlobal(
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000431 kHwasanShadowMemoryDynamicAddress, Int8PtrTy);
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000432 return IRB.CreateLoad(GlobalDynamicAddress);
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000433 }
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000434}
435
436Value *HWAddressSanitizer::isInterestingMemoryAccess(Instruction *I,
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000437 bool *IsWrite,
438 uint64_t *TypeSize,
439 unsigned *Alignment,
440 Value **MaybeMask) {
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000441 // Skip memory accesses inserted by another instrumentation.
442 if (I->getMetadata("nosanitize")) return nullptr;
443
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000444 // Do not instrument the load fetching the dynamic shadow address.
445 if (LocalDynamicShadow == I)
446 return nullptr;
447
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000448 Value *PtrOperand = nullptr;
449 const DataLayout &DL = I->getModule()->getDataLayout();
450 if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
451 if (!ClInstrumentReads) return nullptr;
452 *IsWrite = false;
453 *TypeSize = DL.getTypeStoreSizeInBits(LI->getType());
454 *Alignment = LI->getAlignment();
455 PtrOperand = LI->getPointerOperand();
456 } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
457 if (!ClInstrumentWrites) return nullptr;
458 *IsWrite = true;
459 *TypeSize = DL.getTypeStoreSizeInBits(SI->getValueOperand()->getType());
460 *Alignment = SI->getAlignment();
461 PtrOperand = SI->getPointerOperand();
462 } else if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(I)) {
463 if (!ClInstrumentAtomics) return nullptr;
464 *IsWrite = true;
465 *TypeSize = DL.getTypeStoreSizeInBits(RMW->getValOperand()->getType());
466 *Alignment = 0;
467 PtrOperand = RMW->getPointerOperand();
468 } else if (AtomicCmpXchgInst *XCHG = dyn_cast<AtomicCmpXchgInst>(I)) {
469 if (!ClInstrumentAtomics) return nullptr;
470 *IsWrite = true;
471 *TypeSize = DL.getTypeStoreSizeInBits(XCHG->getCompareOperand()->getType());
472 *Alignment = 0;
473 PtrOperand = XCHG->getPointerOperand();
474 }
475
476 if (PtrOperand) {
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000477 // Do not instrument accesses from different address spaces; we cannot deal
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000478 // with them.
479 Type *PtrTy = cast<PointerType>(PtrOperand->getType()->getScalarType());
480 if (PtrTy->getPointerAddressSpace() != 0)
481 return nullptr;
482
483 // Ignore swifterror addresses.
484 // swifterror memory addresses are mem2reg promoted by instruction
485 // selection. As such they cannot have regular uses like an instrumentation
486 // function and it makes no sense to track them as memory.
487 if (PtrOperand->isSwiftError())
488 return nullptr;
489 }
490
491 return PtrOperand;
492}
493
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000494static unsigned getPointerOperandIndex(Instruction *I) {
495 if (LoadInst *LI = dyn_cast<LoadInst>(I))
496 return LI->getPointerOperandIndex();
497 if (StoreInst *SI = dyn_cast<StoreInst>(I))
498 return SI->getPointerOperandIndex();
499 if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(I))
500 return RMW->getPointerOperandIndex();
501 if (AtomicCmpXchgInst *XCHG = dyn_cast<AtomicCmpXchgInst>(I))
502 return XCHG->getPointerOperandIndex();
503 report_fatal_error("Unexpected instruction");
504 return -1;
505}
506
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000507static size_t TypeSizeToSizeIndex(uint32_t TypeSize) {
508 size_t Res = countTrailingZeros(TypeSize / 8);
509 assert(Res < kNumberOfAccessSizes);
510 return Res;
511}
512
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000513void HWAddressSanitizer::untagPointerOperand(Instruction *I, Value *Addr) {
514 if (TargetTriple.isAArch64())
515 return;
516
517 IRBuilder<> IRB(I);
518 Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy);
519 Value *UntaggedPtr =
520 IRB.CreateIntToPtr(untagPointer(IRB, AddrLong), Addr->getType());
521 I->setOperand(getPointerOperandIndex(I), UntaggedPtr);
522}
523
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000524Value *HWAddressSanitizer::shadowBase() {
525 if (LocalDynamicShadow)
526 return LocalDynamicShadow;
527 return ConstantExpr::getIntToPtr(ConstantInt::get(IntptrTy, Mapping.Offset),
528 Int8PtrTy);
529}
530
531Value *HWAddressSanitizer::memToShadow(Value *Mem, IRBuilder<> &IRB) {
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000532 // Mem >> Scale
533 Value *Shadow = IRB.CreateLShr(Mem, Mapping.Scale);
534 if (Mapping.Offset == 0)
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000535 return IRB.CreateIntToPtr(Shadow, Int8PtrTy);
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000536 // (Mem >> Scale) + Offset
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000537 return IRB.CreateGEP(Int8Ty, shadowBase(), Shadow);
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000538}
539
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000540void HWAddressSanitizer::instrumentMemAccessInline(Value *Ptr, bool IsWrite,
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000541 unsigned AccessSizeIndex,
542 Instruction *InsertBefore) {
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000543 const int64_t AccessInfo = Recover * 0x20 + IsWrite * 0x10 + AccessSizeIndex;
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000544 IRBuilder<> IRB(InsertBefore);
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000545
546 if (!ClInlineAllChecks && TargetTriple.isAArch64() &&
547 TargetTriple.isOSBinFormatELF() && !Recover) {
548 Module *M = IRB.GetInsertBlock()->getParent()->getParent();
549 Ptr = IRB.CreateBitCast(Ptr, Int8PtrTy);
550 IRB.CreateCall(
551 Intrinsic::getDeclaration(M, Intrinsic::hwasan_check_memaccess),
552 {shadowBase(), Ptr, ConstantInt::get(Int32Ty, AccessInfo)});
553 return;
554 }
555
556 Value *PtrLong = IRB.CreatePointerCast(Ptr, IntptrTy);
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000557 Value *PtrTag = IRB.CreateTrunc(IRB.CreateLShr(PtrLong, kPointerTagShift),
558 IRB.getInt8Ty());
Evgeniy Stepanov43271b12018-02-21 19:52:23 +0000559 Value *AddrLong = untagPointer(IRB, PtrLong);
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000560 Value *Shadow = memToShadow(AddrLong, IRB);
561 Value *MemTag = IRB.CreateLoad(Shadow);
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000562 Value *TagMismatch = IRB.CreateICmpNE(PtrTag, MemTag);
563
Andrey Konovalov1ba9d9c2018-04-13 18:05:21 +0000564 int matchAllTag = ClMatchAllTag.getNumOccurrences() > 0 ?
565 ClMatchAllTag : (CompileKernel ? 0xFF : -1);
566 if (matchAllTag != -1) {
Evgeniy Stepanov1f1a7a72018-04-04 20:44:59 +0000567 Value *TagNotIgnored = IRB.CreateICmpNE(PtrTag,
Andrey Konovalov1ba9d9c2018-04-13 18:05:21 +0000568 ConstantInt::get(PtrTag->getType(), matchAllTag));
Evgeniy Stepanov1f1a7a72018-04-04 20:44:59 +0000569 TagMismatch = IRB.CreateAnd(TagMismatch, TagNotIgnored);
570 }
571
Chandler Carruth4a2d58e2018-10-15 09:34:05 +0000572 Instruction *CheckTerm =
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000573 SplitBlockAndInsertIfThen(TagMismatch, InsertBefore, !Recover,
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000574 MDBuilder(*C).createBranchWeights(1, 100000));
575
576 IRB.SetInsertPoint(CheckTerm);
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000577 InlineAsm *Asm;
578 switch (TargetTriple.getArch()) {
579 case Triple::x86_64:
580 // The signal handler will find the data address in rdi.
581 Asm = InlineAsm::get(
582 FunctionType::get(IRB.getVoidTy(), {PtrLong->getType()}, false),
583 "int3\nnopl " + itostr(0x40 + AccessInfo) + "(%rax)",
584 "{rdi}",
585 /*hasSideEffects=*/true);
586 break;
587 case Triple::aarch64:
588 case Triple::aarch64_be:
589 // The signal handler will find the data address in x0.
590 Asm = InlineAsm::get(
591 FunctionType::get(IRB.getVoidTy(), {PtrLong->getType()}, false),
592 "brk #" + itostr(0x900 + AccessInfo),
593 "{x0}",
594 /*hasSideEffects=*/true);
595 break;
596 default:
597 report_fatal_error("unsupported architecture");
598 }
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000599 IRB.CreateCall(Asm, PtrLong);
600}
601
Eugene Leviant2d98eb12018-12-20 09:04:33 +0000602void HWAddressSanitizer::instrumentMemIntrinsic(MemIntrinsic *MI) {
603 IRBuilder<> IRB(MI);
604 if (isa<MemTransferInst>(MI)) {
605 IRB.CreateCall(
606 isa<MemMoveInst>(MI) ? HWAsanMemmove : HWAsanMemcpy,
607 {IRB.CreatePointerCast(MI->getOperand(0), IRB.getInt8PtrTy()),
608 IRB.CreatePointerCast(MI->getOperand(1), IRB.getInt8PtrTy()),
609 IRB.CreateIntCast(MI->getOperand(2), IntptrTy, false)});
610 } else if (isa<MemSetInst>(MI)) {
611 IRB.CreateCall(
612 HWAsanMemset,
613 {IRB.CreatePointerCast(MI->getOperand(0), IRB.getInt8PtrTy()),
614 IRB.CreateIntCast(MI->getOperand(1), IRB.getInt32Ty(), false),
615 IRB.CreateIntCast(MI->getOperand(2), IntptrTy, false)});
616 }
617 MI->eraseFromParent();
618}
619
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000620bool HWAddressSanitizer::instrumentMemAccess(Instruction *I) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000621 LLVM_DEBUG(dbgs() << "Instrumenting: " << *I << "\n");
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000622 bool IsWrite = false;
623 unsigned Alignment = 0;
624 uint64_t TypeSize = 0;
625 Value *MaybeMask = nullptr;
Eugene Leviant2d98eb12018-12-20 09:04:33 +0000626
627 if (ClInstrumentMemIntrinsics && isa<MemIntrinsic>(I)) {
628 instrumentMemIntrinsic(cast<MemIntrinsic>(I));
629 return true;
630 }
631
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000632 Value *Addr =
633 isInterestingMemoryAccess(I, &IsWrite, &TypeSize, &Alignment, &MaybeMask);
634
635 if (!Addr)
636 return false;
637
638 if (MaybeMask)
639 return false; //FIXME
640
641 IRBuilder<> IRB(I);
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000642 if (isPowerOf2_64(TypeSize) &&
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000643 (TypeSize / 8 <= (1UL << (kNumberOfAccessSizes - 1))) &&
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000644 (Alignment >= (1UL << Mapping.Scale) || Alignment == 0 ||
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000645 Alignment >= TypeSize / 8)) {
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000646 size_t AccessSizeIndex = TypeSizeToSizeIndex(TypeSize);
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000647 if (ClInstrumentWithCalls) {
648 IRB.CreateCall(HwasanMemoryAccessCallback[IsWrite][AccessSizeIndex],
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000649 IRB.CreatePointerCast(Addr, IntptrTy));
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000650 } else {
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000651 instrumentMemAccessInline(Addr, IsWrite, AccessSizeIndex, I);
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000652 }
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000653 } else {
654 IRB.CreateCall(HwasanMemoryAccessCallbackSized[IsWrite],
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000655 {IRB.CreatePointerCast(Addr, IntptrTy),
656 ConstantInt::get(IntptrTy, TypeSize / 8)});
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000657 }
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000658 untagPointerOperand(I, Addr);
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000659
660 return true;
661}
662
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000663static uint64_t getAllocaSizeInBytes(const AllocaInst &AI) {
664 uint64_t ArraySize = 1;
665 if (AI.isArrayAllocation()) {
666 const ConstantInt *CI = dyn_cast<ConstantInt>(AI.getArraySize());
667 assert(CI && "non-constant array size");
668 ArraySize = CI->getZExtValue();
669 }
670 Type *Ty = AI.getAllocatedType();
671 uint64_t SizeInBytes = AI.getModule()->getDataLayout().getTypeAllocSize(Ty);
672 return SizeInBytes * ArraySize;
673}
674
675bool HWAddressSanitizer::tagAlloca(IRBuilder<> &IRB, AllocaInst *AI,
676 Value *Tag) {
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000677 size_t Size = (getAllocaSizeInBytes(*AI) + Mapping.getAllocaAlignment() - 1) &
678 ~(Mapping.getAllocaAlignment() - 1);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000679
680 Value *JustTag = IRB.CreateTrunc(Tag, IRB.getInt8Ty());
681 if (ClInstrumentWithCalls) {
682 IRB.CreateCall(HwasanTagMemoryFunc,
Evgeniy Stepanova265a132018-08-15 00:39:35 +0000683 {IRB.CreatePointerCast(AI, Int8PtrTy), JustTag,
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000684 ConstantInt::get(IntptrTy, Size)});
685 } else {
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000686 size_t ShadowSize = Size >> Mapping.Scale;
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000687 Value *ShadowPtr = memToShadow(IRB.CreatePointerCast(AI, IntptrTy), IRB);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000688 // If this memset is not inlined, it will be intercepted in the hwasan
689 // runtime library. That's OK, because the interceptor skips the checks if
690 // the address is in the shadow region.
691 // FIXME: the interceptor is not as fast as real memset. Consider lowering
692 // llvm.memset right here into either a sequence of stores, or a call to
693 // hwasan_tag_memory.
694 IRB.CreateMemSet(ShadowPtr, JustTag, ShadowSize, /*Align=*/1);
695 }
696 return true;
697}
698
699static unsigned RetagMask(unsigned AllocaNo) {
700 // A list of 8-bit numbers that have at most one run of non-zero bits.
701 // x = x ^ (mask << 56) can be encoded as a single armv8 instruction for these
702 // masks.
703 // The list does not include the value 255, which is used for UAR.
704 static unsigned FastMasks[] = {
705 0, 1, 2, 3, 4, 6, 7, 8, 12, 14, 15, 16, 24,
706 28, 30, 31, 32, 48, 56, 60, 62, 63, 64, 96, 112, 120,
707 124, 126, 127, 128, 192, 224, 240, 248, 252, 254};
708 return FastMasks[AllocaNo % (sizeof(FastMasks) / sizeof(FastMasks[0]))];
709}
710
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000711Value *HWAddressSanitizer::getNextTagWithCall(IRBuilder<> &IRB) {
712 return IRB.CreateZExt(IRB.CreateCall(HwasanGenerateTagFunc), IntptrTy);
713}
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000714
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000715Value *HWAddressSanitizer::getStackBaseTag(IRBuilder<> &IRB) {
716 if (ClGenerateTagsWithCalls)
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000717 return getNextTagWithCall(IRB);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000718 // FIXME: use addressofreturnaddress (but implement it in aarch64 backend
719 // first).
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000720 Module *M = IRB.GetInsertBlock()->getParent()->getParent();
721 auto GetStackPointerFn =
722 Intrinsic::getDeclaration(M, Intrinsic::frameaddress);
723 Value *StackPointer = IRB.CreateCall(
724 GetStackPointerFn, {Constant::getNullValue(IRB.getInt32Ty())});
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000725
726 // Extract some entropy from the stack pointer for the tags.
727 // Take bits 20..28 (ASLR entropy) and xor with bits 0..8 (these differ
728 // between functions).
729 Value *StackPointerLong = IRB.CreatePointerCast(StackPointer, IntptrTy);
730 Value *StackTag =
731 IRB.CreateXor(StackPointerLong, IRB.CreateLShr(StackPointerLong, 20),
732 "hwasan.stack.base.tag");
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000733 return StackTag;
734}
735
736Value *HWAddressSanitizer::getAllocaTag(IRBuilder<> &IRB, Value *StackTag,
737 AllocaInst *AI, unsigned AllocaNo) {
738 if (ClGenerateTagsWithCalls)
739 return getNextTagWithCall(IRB);
740 return IRB.CreateXor(StackTag,
741 ConstantInt::get(IntptrTy, RetagMask(AllocaNo)));
742}
743
744Value *HWAddressSanitizer::getUARTag(IRBuilder<> &IRB, Value *StackTag) {
Alex Shlyapnikov788764c2018-06-29 20:20:17 +0000745 if (ClUARRetagToZero)
746 return ConstantInt::get(IntptrTy, 0);
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000747 if (ClGenerateTagsWithCalls)
748 return getNextTagWithCall(IRB);
749 return IRB.CreateXor(StackTag, ConstantInt::get(IntptrTy, 0xFFU));
750}
751
Evgeniy Stepanov80ccda22018-02-09 00:59:10 +0000752// Add a tag to an address.
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000753Value *HWAddressSanitizer::tagPointer(IRBuilder<> &IRB, Type *Ty,
754 Value *PtrLong, Value *Tag) {
Evgeniy Stepanov80ccda22018-02-09 00:59:10 +0000755 Value *TaggedPtrLong;
Andrey Konovalov1ba9d9c2018-04-13 18:05:21 +0000756 if (CompileKernel) {
Evgeniy Stepanov80ccda22018-02-09 00:59:10 +0000757 // Kernel addresses have 0xFF in the most significant byte.
758 Value *ShiftedTag = IRB.CreateOr(
759 IRB.CreateShl(Tag, kPointerTagShift),
760 ConstantInt::get(IntptrTy, (1ULL << kPointerTagShift) - 1));
761 TaggedPtrLong = IRB.CreateAnd(PtrLong, ShiftedTag);
762 } else {
763 // Userspace can simply do OR (tag << 56);
764 Value *ShiftedTag = IRB.CreateShl(Tag, kPointerTagShift);
765 TaggedPtrLong = IRB.CreateOr(PtrLong, ShiftedTag);
766 }
767 return IRB.CreateIntToPtr(TaggedPtrLong, Ty);
768}
769
Evgeniy Stepanov43271b12018-02-21 19:52:23 +0000770// Remove tag from an address.
771Value *HWAddressSanitizer::untagPointer(IRBuilder<> &IRB, Value *PtrLong) {
772 Value *UntaggedPtrLong;
Andrey Konovalov1ba9d9c2018-04-13 18:05:21 +0000773 if (CompileKernel) {
Evgeniy Stepanov43271b12018-02-21 19:52:23 +0000774 // Kernel addresses have 0xFF in the most significant byte.
775 UntaggedPtrLong = IRB.CreateOr(PtrLong,
776 ConstantInt::get(PtrLong->getType(), 0xFFULL << kPointerTagShift));
777 } else {
778 // Userspace addresses have 0x00.
779 UntaggedPtrLong = IRB.CreateAnd(PtrLong,
780 ConstantInt::get(PtrLong->getType(), ~(0xFFULL << kPointerTagShift)));
781 }
782 return UntaggedPtrLong;
783}
784
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000785Value *HWAddressSanitizer::getHwasanThreadSlotPtr(IRBuilder<> &IRB, Type *Ty) {
786 Module *M = IRB.GetInsertBlock()->getParent()->getParent();
787 if (TargetTriple.isAArch64() && TargetTriple.isAndroid()) {
Evgeniy Stepanov0184c532019-01-05 00:44:58 +0000788 // Android provides a fixed TLS slot for sanitizers. See TLS_SLOT_SANITIZER
789 // in Bionic's libc/private/bionic_tls.h.
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000790 Function *ThreadPointerFunc =
791 Intrinsic::getDeclaration(M, Intrinsic::thread_pointer);
792 Value *SlotPtr = IRB.CreatePointerCast(
Evgeniy Stepanov0184c532019-01-05 00:44:58 +0000793 IRB.CreateConstGEP1_32(IRB.CreateCall(ThreadPointerFunc), 0x30),
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000794 Ty->getPointerTo(0));
795 return SlotPtr;
796 }
797 if (ThreadPtrGlobal)
798 return ThreadPtrGlobal;
799
800
801 return nullptr;
802}
803
Kostya Serebryanyaf955972018-10-23 00:50:40 +0000804// Creates a string with a description of the stack frame (set of Allocas).
805// The string is intended to be human readable.
806// The current form is: Size1 Name1; Size2 Name2; ...
807std::string
808HWAddressSanitizer::createFrameString(ArrayRef<AllocaInst *> Allocas) {
809 std::ostringstream Descr;
810 for (auto AI : Allocas)
811 Descr << getAllocaSizeInBytes(*AI) << " " << AI->getName().str() << "; ";
812 return Descr.str();
813}
814
815// Creates a global in the frame section which consists of two pointers:
816// the function PC and the frame string constant.
817void HWAddressSanitizer::createFrameGlobal(Function &F,
818 const std::string &FrameString) {
819 Module &M = *F.getParent();
820 auto DescrGV = createPrivateGlobalForString(M, FrameString, true);
821 auto PtrPairTy = StructType::get(F.getType(), DescrGV->getType());
822 auto GV = new GlobalVariable(
823 M, PtrPairTy, /*isConstantGlobal*/ true, GlobalVariable::PrivateLinkage,
824 ConstantStruct::get(PtrPairTy, (Constant *)&F, (Constant *)DescrGV),
825 "__hwasan");
826 GV->setSection(getFrameSection());
827 appendToCompilerUsed(M, GV);
828 // 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 +0000829 if (auto Comdat =
830 GetOrCreateFunctionComdat(F, TargetTriple, CurModuleUniqueId))
831 GV->setComdat(Comdat);
Kostya Serebryanyaf955972018-10-23 00:50:40 +0000832}
833
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000834Value *HWAddressSanitizer::emitPrologue(IRBuilder<> &IRB,
835 bool WithFrameRecord) {
836 if (!Mapping.InTls)
837 return getDynamicShadowNonTls(IRB);
838
Peter Collingbourne020ce3f2019-01-23 22:39:11 +0000839 if (ClAllowIfunc && !WithFrameRecord && TargetTriple.isAndroid())
840 return getDynamicShadowIfunc(IRB);
841
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000842 Value *SlotPtr = getHwasanThreadSlotPtr(IRB, IntptrTy);
843 assert(SlotPtr);
844
Peter Collingbourne87f477b2019-01-04 19:27:04 +0000845 Instruction *ThreadLong = IRB.CreateLoad(SlotPtr);
846
847 Function *F = IRB.GetInsertBlock()->getParent();
848 if (F->getFnAttribute("hwasan-abi").getValueAsString() == "interceptor") {
849 Value *ThreadLongEqZero =
850 IRB.CreateICmpEQ(ThreadLong, ConstantInt::get(IntptrTy, 0));
851 auto *Br = cast<BranchInst>(SplitBlockAndInsertIfThen(
852 ThreadLongEqZero, cast<Instruction>(ThreadLongEqZero)->getNextNode(),
853 false, MDBuilder(*C).createBranchWeights(1, 100000)));
854
855 IRB.SetInsertPoint(Br);
856 // FIXME: This should call a new runtime function with a custom calling
857 // convention to avoid needing to spill all arguments here.
858 IRB.CreateCall(HwasanThreadEnterFunc);
859 LoadInst *ReloadThreadLong = IRB.CreateLoad(SlotPtr);
860
861 IRB.SetInsertPoint(&*Br->getSuccessor(0)->begin());
862 PHINode *ThreadLongPhi = IRB.CreatePHI(IntptrTy, 2);
863 ThreadLongPhi->addIncoming(ThreadLong, ThreadLong->getParent());
864 ThreadLongPhi->addIncoming(ReloadThreadLong, ReloadThreadLong->getParent());
865 ThreadLong = ThreadLongPhi;
866 }
867
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000868 // Extract the address field from ThreadLong. Unnecessary on AArch64 with TBI.
869 Value *ThreadLongMaybeUntagged =
870 TargetTriple.isAArch64() ? ThreadLong : untagPointer(IRB, ThreadLong);
871
872 if (WithFrameRecord) {
873 // Prepare ring buffer data.
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000874 auto PC = IRB.CreatePtrToInt(F, IntptrTy);
875 auto GetStackPointerFn =
876 Intrinsic::getDeclaration(F->getParent(), Intrinsic::frameaddress);
877 Value *SP = IRB.CreatePtrToInt(
878 IRB.CreateCall(GetStackPointerFn,
879 {Constant::getNullValue(IRB.getInt32Ty())}),
880 IntptrTy);
881 // Mix SP and PC. TODO: also add the tag to the mix.
882 // Assumptions:
883 // PC is 0x0000PPPPPPPPPPPP (48 bits are meaningful, others are zero)
884 // SP is 0xsssssssssssSSSS0 (4 lower bits are zero)
885 // We only really need ~20 lower non-zero bits (SSSS), so we mix like this:
886 // 0xSSSSPPPPPPPPPPPP
887 SP = IRB.CreateShl(SP, 44);
888
889 // Store data to ring buffer.
890 Value *RecordPtr =
891 IRB.CreateIntToPtr(ThreadLongMaybeUntagged, IntptrTy->getPointerTo(0));
892 IRB.CreateStore(IRB.CreateOr(PC, SP), RecordPtr);
893
894 // Update the ring buffer. Top byte of ThreadLong defines the size of the
895 // buffer in pages, it must be a power of two, and the start of the buffer
896 // must be aligned by twice that much. Therefore wrap around of the ring
897 // buffer is simply Addr &= ~((ThreadLong >> 56) << 12).
898 // The use of AShr instead of LShr is due to
899 // https://bugs.llvm.org/show_bug.cgi?id=39030
900 // Runtime library makes sure not to use the highest bit.
901 Value *WrapMask = IRB.CreateXor(
902 IRB.CreateShl(IRB.CreateAShr(ThreadLong, 56), 12, "", true, true),
903 ConstantInt::get(IntptrTy, (uint64_t)-1));
904 Value *ThreadLongNew = IRB.CreateAnd(
905 IRB.CreateAdd(ThreadLong, ConstantInt::get(IntptrTy, 8)), WrapMask);
906 IRB.CreateStore(ThreadLongNew, SlotPtr);
907 }
908
909 // Get shadow base address by aligning RecordPtr up.
910 // Note: this is not correct if the pointer is already aligned.
911 // Runtime library will make sure this never happens.
912 Value *ShadowBase = IRB.CreateAdd(
913 IRB.CreateOr(
914 ThreadLongMaybeUntagged,
915 ConstantInt::get(IntptrTy, (1ULL << kShadowBaseAlignment) - 1)),
916 ConstantInt::get(IntptrTy, 1), "hwasan.shadow");
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000917 ShadowBase = IRB.CreateIntToPtr(ShadowBase, Int8PtrTy);
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000918 return ShadowBase;
919}
920
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000921bool HWAddressSanitizer::instrumentStack(
922 SmallVectorImpl<AllocaInst *> &Allocas,
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000923 SmallVectorImpl<Instruction *> &RetVec, Value *StackTag) {
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000924 // Ideally, we want to calculate tagged stack base pointer, and rewrite all
925 // alloca addresses using that. Unfortunately, offsets are not known yet
926 // (unless we use ASan-style mega-alloca). Instead we keep the base tag in a
927 // temp, shift-OR it into each alloca address and xor with the retag mask.
928 // This generates one extra instruction per alloca use.
929 for (unsigned N = 0; N < Allocas.size(); ++N) {
930 auto *AI = Allocas[N];
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000931 IRBuilder<> IRB(AI->getNextNode());
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000932
933 // Replace uses of the alloca with tagged address.
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000934 Value *Tag = getAllocaTag(IRB, StackTag, AI, N);
935 Value *AILong = IRB.CreatePointerCast(AI, IntptrTy);
Evgeniy Stepanov80ccda22018-02-09 00:59:10 +0000936 Value *Replacement = tagPointer(IRB, AI->getType(), AILong, Tag);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000937 std::string Name =
938 AI->hasName() ? AI->getName().str() : "alloca." + itostr(N);
Evgeniy Stepanov80ccda22018-02-09 00:59:10 +0000939 Replacement->setName(Name + ".hwasan");
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000940
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000941 for (auto UI = AI->use_begin(), UE = AI->use_end(); UI != UE;) {
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000942 Use &U = *UI++;
943 if (U.getUser() != AILong)
944 U.set(Replacement);
945 }
946
947 tagAlloca(IRB, AI, Tag);
948
949 for (auto RI : RetVec) {
950 IRB.SetInsertPoint(RI);
951
952 // Re-tag alloca memory with the special UAR tag.
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000953 Value *Tag = getUARTag(IRB, StackTag);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000954 tagAlloca(IRB, AI, Tag);
955 }
956 }
957
958 return true;
959}
960
961bool HWAddressSanitizer::isInterestingAlloca(const AllocaInst &AI) {
962 return (AI.getAllocatedType()->isSized() &&
963 // FIXME: instrument dynamic allocas, too
964 AI.isStaticAlloca() &&
965 // alloca() may be called with 0 size, ignore it.
966 getAllocaSizeInBytes(AI) > 0 &&
967 // We are only interested in allocas not promotable to registers.
968 // Promotable allocas are common under -O0.
969 !isAllocaPromotable(&AI) &&
970 // inalloca allocas are not treated as static, and we don't want
971 // dynamic alloca instrumentation for them as well.
972 !AI.isUsedWithInAlloca() &&
973 // swifterror allocas are register promoted by ISel
974 !AI.isSwiftError());
975}
976
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000977bool HWAddressSanitizer::runOnFunction(Function &F) {
978 if (&F == HwasanCtorFunction)
979 return false;
980
981 if (!F.hasFnAttribute(Attribute::SanitizeHWAddress))
982 return false;
983
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000984 LLVM_DEBUG(dbgs() << "Function: " << F.getName() << "\n");
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000985
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000986 SmallVector<Instruction*, 16> ToInstrument;
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000987 SmallVector<AllocaInst*, 8> AllocasToInstrument;
988 SmallVector<Instruction*, 8> RetVec;
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000989 for (auto &BB : F) {
990 for (auto &Inst : BB) {
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000991 if (ClInstrumentStack)
992 if (AllocaInst *AI = dyn_cast<AllocaInst>(&Inst)) {
993 // Realign all allocas. We don't want small uninteresting allocas to
994 // hide in instrumented alloca's padding.
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000995 if (AI->getAlignment() < Mapping.getAllocaAlignment())
996 AI->setAlignment(Mapping.getAllocaAlignment());
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000997 // Instrument some of them.
998 if (isInterestingAlloca(*AI))
999 AllocasToInstrument.push_back(AI);
1000 continue;
1001 }
1002
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +00001003 if (isa<ReturnInst>(Inst) || isa<ResumeInst>(Inst) ||
1004 isa<CleanupReturnInst>(Inst))
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +00001005 RetVec.push_back(&Inst);
1006
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +00001007 Value *MaybeMask = nullptr;
1008 bool IsWrite;
1009 unsigned Alignment;
1010 uint64_t TypeSize;
1011 Value *Addr = isInterestingMemoryAccess(&Inst, &IsWrite, &TypeSize,
1012 &Alignment, &MaybeMask);
1013 if (Addr || isa<MemIntrinsic>(Inst))
1014 ToInstrument.push_back(&Inst);
1015 }
1016 }
1017
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +00001018 if (AllocasToInstrument.empty() && ToInstrument.empty())
1019 return false;
1020
Kostya Serebryanyaf955972018-10-23 00:50:40 +00001021 if (ClCreateFrameDescriptions && !AllocasToInstrument.empty())
1022 createFrameGlobal(F, createFrameString(AllocasToInstrument));
1023
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +00001024 initializeCallbacks(*F.getParent());
1025
1026 assert(!LocalDynamicShadow);
1027
1028 Instruction *InsertPt = &*F.getEntryBlock().begin();
1029 IRBuilder<> EntryIRB(InsertPt);
1030 LocalDynamicShadow = emitPrologue(EntryIRB,
1031 /*WithFrameRecord*/ ClRecordStackHistory &&
1032 !AllocasToInstrument.empty());
1033
1034 bool Changed = false;
1035 if (!AllocasToInstrument.empty()) {
1036 Value *StackTag =
1037 ClGenerateTagsWithCalls ? nullptr : getStackBaseTag(EntryIRB);
1038 Changed |= instrumentStack(AllocasToInstrument, RetVec, StackTag);
1039 }
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +00001040
Peter Collingbourne1a8acfb2019-01-25 02:08:46 +00001041 // If we split the entry block, move any allocas that were originally in the
1042 // entry block back into the entry block so that they aren't treated as
1043 // dynamic allocas.
1044 if (EntryIRB.GetInsertBlock() != &F.getEntryBlock()) {
1045 InsertPt = &*F.getEntryBlock().begin();
1046 for (auto II = EntryIRB.GetInsertBlock()->begin(),
1047 IE = EntryIRB.GetInsertBlock()->end();
1048 II != IE;) {
1049 Instruction *I = &*II++;
1050 if (auto *AI = dyn_cast<AllocaInst>(I))
1051 if (isa<ConstantInt>(AI->getArraySize()))
1052 I->moveBefore(InsertPt);
1053 }
1054 }
1055
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +00001056 for (auto Inst : ToInstrument)
1057 Changed |= instrumentMemAccess(Inst);
1058
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +00001059 LocalDynamicShadow = nullptr;
1060
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +00001061 return Changed;
1062}
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +00001063
1064void HWAddressSanitizer::ShadowMapping::init(Triple &TargetTriple) {
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +00001065 Scale = kDefaultShadowScale;
Evgeniy Stepanov453e7ac2018-08-10 16:21:37 +00001066 if (ClMappingOffset.getNumOccurrences() > 0) {
1067 InGlobal = false;
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +00001068 InTls = false;
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +00001069 Offset = ClMappingOffset;
Evgeniy Stepanov453e7ac2018-08-10 16:21:37 +00001070 } else if (ClEnableKhwasan || ClInstrumentWithCalls) {
1071 InGlobal = false;
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +00001072 InTls = false;
Evgeniy Stepanov453e7ac2018-08-10 16:21:37 +00001073 Offset = 0;
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +00001074 } else if (ClWithIfunc) {
Evgeniy Stepanov453e7ac2018-08-10 16:21:37 +00001075 InGlobal = true;
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +00001076 InTls = false;
1077 Offset = kDynamicShadowSentinel;
1078 } else if (ClWithTls) {
1079 InGlobal = false;
1080 InTls = true;
Evgeniy Stepanov453e7ac2018-08-10 16:21:37 +00001081 Offset = kDynamicShadowSentinel;
1082 } else {
1083 InGlobal = false;
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +00001084 InTls = false;
Evgeniy Stepanov453e7ac2018-08-10 16:21:37 +00001085 Offset = kDynamicShadowSentinel;
1086 }
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +00001087}