blob: a00070e34aa7c228f8b5b38eb01c1228d53c138f [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
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000163namespace {
164
Adrian Prantl5f8f34e42018-05-01 15:54:18 +0000165/// An instrumentation pass implementing detection of addressability bugs
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000166/// using tagged pointers.
167class HWAddressSanitizer : public FunctionPass {
168public:
169 // Pass identification, replacement for typeid.
170 static char ID;
171
Andrey Konovalov1ba9d9c2018-04-13 18:05:21 +0000172 explicit HWAddressSanitizer(bool CompileKernel = false, bool Recover = false)
173 : FunctionPass(ID) {
174 this->Recover = ClRecover.getNumOccurrences() > 0 ? ClRecover : Recover;
175 this->CompileKernel = ClEnableKhwasan.getNumOccurrences() > 0 ?
176 ClEnableKhwasan : CompileKernel;
177 }
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000178
179 StringRef getPassName() const override { return "HWAddressSanitizer"; }
180
181 bool runOnFunction(Function &F) override;
182 bool doInitialization(Module &M) override;
183
184 void initializeCallbacks(Module &M);
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000185
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000186 Value *getDynamicShadowNonTls(IRBuilder<> &IRB);
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000187
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000188 void untagPointerOperand(Instruction *I, Value *Addr);
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000189 Value *shadowBase();
190 Value *memToShadow(Value *Shadow, IRBuilder<> &IRB);
191 void instrumentMemAccessInline(Value *Ptr, bool IsWrite,
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000192 unsigned AccessSizeIndex,
193 Instruction *InsertBefore);
Eugene Leviant2d98eb12018-12-20 09:04:33 +0000194 void instrumentMemIntrinsic(MemIntrinsic *MI);
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000195 bool instrumentMemAccess(Instruction *I);
196 Value *isInterestingMemoryAccess(Instruction *I, bool *IsWrite,
197 uint64_t *TypeSize, unsigned *Alignment,
198 Value **MaybeMask);
199
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000200 bool isInterestingAlloca(const AllocaInst &AI);
201 bool tagAlloca(IRBuilder<> &IRB, AllocaInst *AI, Value *Tag);
Evgeniy Stepanov80ccda22018-02-09 00:59:10 +0000202 Value *tagPointer(IRBuilder<> &IRB, Type *Ty, Value *PtrLong, Value *Tag);
Evgeniy Stepanov43271b12018-02-21 19:52:23 +0000203 Value *untagPointer(IRBuilder<> &IRB, Value *PtrLong);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000204 bool instrumentStack(SmallVectorImpl<AllocaInst *> &Allocas,
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000205 SmallVectorImpl<Instruction *> &RetVec, Value *StackTag);
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000206 Value *getNextTagWithCall(IRBuilder<> &IRB);
207 Value *getStackBaseTag(IRBuilder<> &IRB);
208 Value *getAllocaTag(IRBuilder<> &IRB, Value *StackTag, AllocaInst *AI,
209 unsigned AllocaNo);
210 Value *getUARTag(IRBuilder<> &IRB, Value *StackTag);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000211
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000212 Value *getHwasanThreadSlotPtr(IRBuilder<> &IRB, Type *Ty);
213 Value *emitPrologue(IRBuilder<> &IRB, bool WithFrameRecord);
214
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000215private:
216 LLVMContext *C;
Kostya Serebryanyaf955972018-10-23 00:50:40 +0000217 std::string CurModuleUniqueId;
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000218 Triple TargetTriple;
Eugene Leviant2d98eb12018-12-20 09:04:33 +0000219 Function *HWAsanMemmove, *HWAsanMemcpy, *HWAsanMemset;
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000220
Kostya Serebryanyaf955972018-10-23 00:50:40 +0000221 // Frame description is a way to pass names/sizes of local variables
222 // to the run-time w/o adding extra executable code in every function.
223 // We do this by creating a separate section with {PC,Descr} pairs and passing
224 // the section beg/end to __hwasan_init_frames() at module init time.
225 std::string createFrameString(ArrayRef<AllocaInst*> Allocas);
226 void createFrameGlobal(Function &F, const std::string &FrameString);
227 // Get the section name for frame descriptions. Currently ELF-only.
228 const char *getFrameSection() { return "__hwasan_frames"; }
229 const char *getFrameSectionBeg() { return "__start___hwasan_frames"; }
230 const char *getFrameSectionEnd() { return "__stop___hwasan_frames"; }
231 GlobalVariable *createFrameSectionBound(Module &M, Type *Ty,
232 const char *Name) {
233 auto GV = new GlobalVariable(M, Ty, false, GlobalVariable::ExternalLinkage,
234 nullptr, Name);
235 GV->setVisibility(GlobalValue::HiddenVisibility);
236 return GV;
237 }
238
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000239 /// This struct defines the shadow mapping using the rule:
240 /// shadow = (mem >> Scale) + Offset.
241 /// If InGlobal is true, then
242 /// extern char __hwasan_shadow[];
243 /// shadow = (mem >> Scale) + &__hwasan_shadow
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000244 /// If InTls is true, then
245 /// extern char *__hwasan_tls;
Kostya Serebryanyaf955972018-10-23 00:50:40 +0000246 /// shadow = (mem>>Scale) + align_up(__hwasan_shadow, kShadowBaseAlignment)
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000247 struct ShadowMapping {
248 int Scale;
249 uint64_t Offset;
250 bool InGlobal;
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000251 bool InTls;
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000252
253 void init(Triple &TargetTriple);
254 unsigned getAllocaAlignment() const { return 1U << Scale; }
255 };
256 ShadowMapping Mapping;
257
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000258 Type *IntptrTy;
Evgeniy Stepanova265a132018-08-15 00:39:35 +0000259 Type *Int8PtrTy;
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000260 Type *Int8Ty;
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000261 Type *Int32Ty;
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000262
Andrey Konovalov1ba9d9c2018-04-13 18:05:21 +0000263 bool CompileKernel;
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000264 bool Recover;
265
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000266 Function *HwasanCtorFunction;
267
268 Function *HwasanMemoryAccessCallback[2][kNumberOfAccessSizes];
269 Function *HwasanMemoryAccessCallbackSized[2];
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000270
271 Function *HwasanTagMemoryFunc;
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000272 Function *HwasanGenerateTagFunc;
Peter Collingbourne87f477b2019-01-04 19:27:04 +0000273 Function *HwasanThreadEnterFunc;
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000274
275 Constant *ShadowGlobal;
276
277 Value *LocalDynamicShadow = nullptr;
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000278 GlobalValue *ThreadPtrGlobal = nullptr;
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000279};
280
281} // end anonymous namespace
282
283char HWAddressSanitizer::ID = 0;
284
285INITIALIZE_PASS_BEGIN(
286 HWAddressSanitizer, "hwasan",
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000287 "HWAddressSanitizer: detect memory bugs using tagged addressing.", false,
288 false)
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000289INITIALIZE_PASS_END(
290 HWAddressSanitizer, "hwasan",
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000291 "HWAddressSanitizer: detect memory bugs using tagged addressing.", false,
292 false)
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000293
Andrey Konovalov1ba9d9c2018-04-13 18:05:21 +0000294FunctionPass *llvm::createHWAddressSanitizerPass(bool CompileKernel,
295 bool Recover) {
296 assert(!CompileKernel || Recover);
297 return new HWAddressSanitizer(CompileKernel, Recover);
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000298}
299
Adrian Prantl5f8f34e42018-05-01 15:54:18 +0000300/// Module-level initialization.
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000301///
302/// inserts a call to __hwasan_init to the module's constructor list.
303bool HWAddressSanitizer::doInitialization(Module &M) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000304 LLVM_DEBUG(dbgs() << "Init " << M.getName() << "\n");
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000305 auto &DL = M.getDataLayout();
306
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000307 TargetTriple = Triple(M.getTargetTriple());
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000308
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000309 Mapping.init(TargetTriple);
310
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000311 C = &(M.getContext());
Kostya Serebryanyaf955972018-10-23 00:50:40 +0000312 CurModuleUniqueId = getUniqueModuleId(&M);
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000313 IRBuilder<> IRB(*C);
314 IntptrTy = IRB.getIntPtrTy(DL);
Evgeniy Stepanova265a132018-08-15 00:39:35 +0000315 Int8PtrTy = IRB.getInt8PtrTy();
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000316 Int8Ty = IRB.getInt8Ty();
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000317 Int32Ty = IRB.getInt32Ty();
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000318
Benjamin Kramerbfc1d972018-01-18 14:19:04 +0000319 HwasanCtorFunction = nullptr;
Andrey Konovalov1ba9d9c2018-04-13 18:05:21 +0000320 if (!CompileKernel) {
Evgeniy Stepanov5bd669d2018-01-17 23:24:38 +0000321 std::tie(HwasanCtorFunction, std::ignore) =
322 createSanitizerCtorAndInitFunctions(M, kHwasanModuleCtorName,
323 kHwasanInitName,
324 /*InitArgTypes=*/{},
325 /*InitArgs=*/{});
Peter Collingbourned3a3e4b2018-12-17 22:56:34 +0000326 Comdat *CtorComdat = M.getOrInsertComdat(kHwasanModuleCtorName);
327 HwasanCtorFunction->setComdat(CtorComdat);
328 appendToGlobalCtors(M, HwasanCtorFunction, 0, HwasanCtorFunction);
Kostya Serebryanyaf955972018-10-23 00:50:40 +0000329
Peter Collingbourned3a3e4b2018-12-17 22:56:34 +0000330 // Create a zero-length global in __hwasan_frame so that the linker will
331 // always create start and stop symbols.
332 //
333 // N.B. If we ever start creating associated metadata in this pass this
334 // global will need to be associated with the ctor.
335 Type *Int8Arr0Ty = ArrayType::get(Int8Ty, 0);
336 auto GV =
337 new GlobalVariable(M, Int8Arr0Ty, /*isConstantGlobal*/ true,
338 GlobalVariable::PrivateLinkage,
339 Constant::getNullValue(Int8Arr0Ty), "__hwasan");
340 GV->setSection(getFrameSection());
341 GV->setComdat(CtorComdat);
342 appendToCompilerUsed(M, GV);
343
Kostya Serebryanyaf955972018-10-23 00:50:40 +0000344 IRBuilder<> IRBCtor(HwasanCtorFunction->getEntryBlock().getTerminator());
345 IRBCtor.CreateCall(
346 declareSanitizerInitFunction(M, "__hwasan_init_frames",
347 {Int8PtrTy, Int8PtrTy}),
348 {createFrameSectionBound(M, Int8Ty, getFrameSectionBeg()),
349 createFrameSectionBound(M, Int8Ty, getFrameSectionEnd())});
350 }
351
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000352 if (!TargetTriple.isAndroid())
353 appendToCompilerUsed(
354 M, ThreadPtrGlobal = new GlobalVariable(
355 M, IntptrTy, false, GlobalVariable::ExternalLinkage, nullptr,
356 "__hwasan_tls", nullptr, GlobalVariable::InitialExecTLSModel));
357
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000358 return true;
359}
360
361void HWAddressSanitizer::initializeCallbacks(Module &M) {
362 IRBuilder<> IRB(*C);
363 for (size_t AccessIsWrite = 0; AccessIsWrite <= 1; AccessIsWrite++) {
364 const std::string TypeStr = AccessIsWrite ? "store" : "load";
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000365 const std::string EndingStr = Recover ? "_noabort" : "";
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000366
367 HwasanMemoryAccessCallbackSized[AccessIsWrite] =
368 checkSanitizerInterfaceFunction(M.getOrInsertFunction(
Evgeniy Stepanovc07e0bd2018-01-16 23:15:08 +0000369 ClMemoryAccessCallbackPrefix + TypeStr + "N" + EndingStr,
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000370 FunctionType::get(IRB.getVoidTy(), {IntptrTy, IntptrTy}, false)));
371
372 for (size_t AccessSizeIndex = 0; AccessSizeIndex < kNumberOfAccessSizes;
373 AccessSizeIndex++) {
374 HwasanMemoryAccessCallback[AccessIsWrite][AccessSizeIndex] =
375 checkSanitizerInterfaceFunction(M.getOrInsertFunction(
376 ClMemoryAccessCallbackPrefix + TypeStr +
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000377 itostr(1ULL << AccessSizeIndex) + EndingStr,
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000378 FunctionType::get(IRB.getVoidTy(), {IntptrTy}, false)));
379 }
380 }
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000381
382 HwasanTagMemoryFunc = checkSanitizerInterfaceFunction(M.getOrInsertFunction(
Evgeniy Stepanova265a132018-08-15 00:39:35 +0000383 "__hwasan_tag_memory", IRB.getVoidTy(), Int8PtrTy, Int8Ty, IntptrTy));
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000384 HwasanGenerateTagFunc = checkSanitizerInterfaceFunction(
385 M.getOrInsertFunction("__hwasan_generate_tag", Int8Ty));
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000386
387 if (Mapping.InGlobal)
388 ShadowGlobal = M.getOrInsertGlobal("__hwasan_shadow",
389 ArrayType::get(IRB.getInt8Ty(), 0));
Eugene Leviant2d98eb12018-12-20 09:04:33 +0000390
391 const std::string MemIntrinCallbackPrefix =
392 CompileKernel ? std::string("") : ClMemoryAccessCallbackPrefix;
393 HWAsanMemmove = checkSanitizerInterfaceFunction(M.getOrInsertFunction(
394 MemIntrinCallbackPrefix + "memmove", IRB.getInt8PtrTy(),
395 IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), IntptrTy));
396 HWAsanMemcpy = checkSanitizerInterfaceFunction(M.getOrInsertFunction(
397 MemIntrinCallbackPrefix + "memcpy", IRB.getInt8PtrTy(),
398 IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), IntptrTy));
399 HWAsanMemset = checkSanitizerInterfaceFunction(M.getOrInsertFunction(
400 MemIntrinCallbackPrefix + "memset", IRB.getInt8PtrTy(),
401 IRB.getInt8PtrTy(), IRB.getInt32Ty(), IntptrTy));
Peter Collingbourne87f477b2019-01-04 19:27:04 +0000402
403 HwasanThreadEnterFunc = checkSanitizerInterfaceFunction(
404 M.getOrInsertFunction("__hwasan_thread_enter", IRB.getVoidTy()));
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000405}
406
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000407Value *HWAddressSanitizer::getDynamicShadowNonTls(IRBuilder<> &IRB) {
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000408 // Generate code only when dynamic addressing is needed.
409 if (Mapping.Offset != kDynamicShadowSentinel)
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000410 return nullptr;
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000411
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000412 if (Mapping.InGlobal) {
413 // An empty inline asm with input reg == output reg.
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000414 // An opaque no-op cast, basically.
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000415 InlineAsm *Asm = InlineAsm::get(
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000416 FunctionType::get(Int8PtrTy, {ShadowGlobal->getType()}, false),
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000417 StringRef(""), StringRef("=r,0"),
418 /*hasSideEffects=*/false);
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000419 return IRB.CreateCall(Asm, {ShadowGlobal}, ".hwasan.shadow");
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000420 } else {
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000421 Value *GlobalDynamicAddress =
422 IRB.GetInsertBlock()->getParent()->getParent()->getOrInsertGlobal(
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000423 kHwasanShadowMemoryDynamicAddress, Int8PtrTy);
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000424 return IRB.CreateLoad(GlobalDynamicAddress);
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000425 }
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000426}
427
428Value *HWAddressSanitizer::isInterestingMemoryAccess(Instruction *I,
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000429 bool *IsWrite,
430 uint64_t *TypeSize,
431 unsigned *Alignment,
432 Value **MaybeMask) {
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000433 // Skip memory accesses inserted by another instrumentation.
434 if (I->getMetadata("nosanitize")) return nullptr;
435
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000436 // Do not instrument the load fetching the dynamic shadow address.
437 if (LocalDynamicShadow == I)
438 return nullptr;
439
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000440 Value *PtrOperand = nullptr;
441 const DataLayout &DL = I->getModule()->getDataLayout();
442 if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
443 if (!ClInstrumentReads) return nullptr;
444 *IsWrite = false;
445 *TypeSize = DL.getTypeStoreSizeInBits(LI->getType());
446 *Alignment = LI->getAlignment();
447 PtrOperand = LI->getPointerOperand();
448 } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
449 if (!ClInstrumentWrites) return nullptr;
450 *IsWrite = true;
451 *TypeSize = DL.getTypeStoreSizeInBits(SI->getValueOperand()->getType());
452 *Alignment = SI->getAlignment();
453 PtrOperand = SI->getPointerOperand();
454 } else if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(I)) {
455 if (!ClInstrumentAtomics) return nullptr;
456 *IsWrite = true;
457 *TypeSize = DL.getTypeStoreSizeInBits(RMW->getValOperand()->getType());
458 *Alignment = 0;
459 PtrOperand = RMW->getPointerOperand();
460 } else if (AtomicCmpXchgInst *XCHG = dyn_cast<AtomicCmpXchgInst>(I)) {
461 if (!ClInstrumentAtomics) return nullptr;
462 *IsWrite = true;
463 *TypeSize = DL.getTypeStoreSizeInBits(XCHG->getCompareOperand()->getType());
464 *Alignment = 0;
465 PtrOperand = XCHG->getPointerOperand();
466 }
467
468 if (PtrOperand) {
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000469 // Do not instrument accesses from different address spaces; we cannot deal
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000470 // with them.
471 Type *PtrTy = cast<PointerType>(PtrOperand->getType()->getScalarType());
472 if (PtrTy->getPointerAddressSpace() != 0)
473 return nullptr;
474
475 // Ignore swifterror addresses.
476 // swifterror memory addresses are mem2reg promoted by instruction
477 // selection. As such they cannot have regular uses like an instrumentation
478 // function and it makes no sense to track them as memory.
479 if (PtrOperand->isSwiftError())
480 return nullptr;
481 }
482
483 return PtrOperand;
484}
485
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000486static unsigned getPointerOperandIndex(Instruction *I) {
487 if (LoadInst *LI = dyn_cast<LoadInst>(I))
488 return LI->getPointerOperandIndex();
489 if (StoreInst *SI = dyn_cast<StoreInst>(I))
490 return SI->getPointerOperandIndex();
491 if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(I))
492 return RMW->getPointerOperandIndex();
493 if (AtomicCmpXchgInst *XCHG = dyn_cast<AtomicCmpXchgInst>(I))
494 return XCHG->getPointerOperandIndex();
495 report_fatal_error("Unexpected instruction");
496 return -1;
497}
498
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000499static size_t TypeSizeToSizeIndex(uint32_t TypeSize) {
500 size_t Res = countTrailingZeros(TypeSize / 8);
501 assert(Res < kNumberOfAccessSizes);
502 return Res;
503}
504
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000505void HWAddressSanitizer::untagPointerOperand(Instruction *I, Value *Addr) {
506 if (TargetTriple.isAArch64())
507 return;
508
509 IRBuilder<> IRB(I);
510 Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy);
511 Value *UntaggedPtr =
512 IRB.CreateIntToPtr(untagPointer(IRB, AddrLong), Addr->getType());
513 I->setOperand(getPointerOperandIndex(I), UntaggedPtr);
514}
515
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000516Value *HWAddressSanitizer::shadowBase() {
517 if (LocalDynamicShadow)
518 return LocalDynamicShadow;
519 return ConstantExpr::getIntToPtr(ConstantInt::get(IntptrTy, Mapping.Offset),
520 Int8PtrTy);
521}
522
523Value *HWAddressSanitizer::memToShadow(Value *Mem, IRBuilder<> &IRB) {
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000524 // Mem >> Scale
525 Value *Shadow = IRB.CreateLShr(Mem, Mapping.Scale);
526 if (Mapping.Offset == 0)
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000527 return IRB.CreateIntToPtr(Shadow, Int8PtrTy);
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000528 // (Mem >> Scale) + Offset
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000529 return IRB.CreateGEP(Int8Ty, shadowBase(), Shadow);
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000530}
531
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000532void HWAddressSanitizer::instrumentMemAccessInline(Value *Ptr, bool IsWrite,
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000533 unsigned AccessSizeIndex,
534 Instruction *InsertBefore) {
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000535 const int64_t AccessInfo = Recover * 0x20 + IsWrite * 0x10 + AccessSizeIndex;
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000536 IRBuilder<> IRB(InsertBefore);
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000537
538 if (!ClInlineAllChecks && TargetTriple.isAArch64() &&
539 TargetTriple.isOSBinFormatELF() && !Recover) {
540 Module *M = IRB.GetInsertBlock()->getParent()->getParent();
541 Ptr = IRB.CreateBitCast(Ptr, Int8PtrTy);
542 IRB.CreateCall(
543 Intrinsic::getDeclaration(M, Intrinsic::hwasan_check_memaccess),
544 {shadowBase(), Ptr, ConstantInt::get(Int32Ty, AccessInfo)});
545 return;
546 }
547
548 Value *PtrLong = IRB.CreatePointerCast(Ptr, IntptrTy);
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000549 Value *PtrTag = IRB.CreateTrunc(IRB.CreateLShr(PtrLong, kPointerTagShift),
550 IRB.getInt8Ty());
Evgeniy Stepanov43271b12018-02-21 19:52:23 +0000551 Value *AddrLong = untagPointer(IRB, PtrLong);
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000552 Value *Shadow = memToShadow(AddrLong, IRB);
553 Value *MemTag = IRB.CreateLoad(Shadow);
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000554 Value *TagMismatch = IRB.CreateICmpNE(PtrTag, MemTag);
555
Andrey Konovalov1ba9d9c2018-04-13 18:05:21 +0000556 int matchAllTag = ClMatchAllTag.getNumOccurrences() > 0 ?
557 ClMatchAllTag : (CompileKernel ? 0xFF : -1);
558 if (matchAllTag != -1) {
Evgeniy Stepanov1f1a7a72018-04-04 20:44:59 +0000559 Value *TagNotIgnored = IRB.CreateICmpNE(PtrTag,
Andrey Konovalov1ba9d9c2018-04-13 18:05:21 +0000560 ConstantInt::get(PtrTag->getType(), matchAllTag));
Evgeniy Stepanov1f1a7a72018-04-04 20:44:59 +0000561 TagMismatch = IRB.CreateAnd(TagMismatch, TagNotIgnored);
562 }
563
Chandler Carruth4a2d58e2018-10-15 09:34:05 +0000564 Instruction *CheckTerm =
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000565 SplitBlockAndInsertIfThen(TagMismatch, InsertBefore, !Recover,
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000566 MDBuilder(*C).createBranchWeights(1, 100000));
567
568 IRB.SetInsertPoint(CheckTerm);
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000569 InlineAsm *Asm;
570 switch (TargetTriple.getArch()) {
571 case Triple::x86_64:
572 // The signal handler will find the data address in rdi.
573 Asm = InlineAsm::get(
574 FunctionType::get(IRB.getVoidTy(), {PtrLong->getType()}, false),
575 "int3\nnopl " + itostr(0x40 + AccessInfo) + "(%rax)",
576 "{rdi}",
577 /*hasSideEffects=*/true);
578 break;
579 case Triple::aarch64:
580 case Triple::aarch64_be:
581 // The signal handler will find the data address in x0.
582 Asm = InlineAsm::get(
583 FunctionType::get(IRB.getVoidTy(), {PtrLong->getType()}, false),
584 "brk #" + itostr(0x900 + AccessInfo),
585 "{x0}",
586 /*hasSideEffects=*/true);
587 break;
588 default:
589 report_fatal_error("unsupported architecture");
590 }
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000591 IRB.CreateCall(Asm, PtrLong);
592}
593
Eugene Leviant2d98eb12018-12-20 09:04:33 +0000594void HWAddressSanitizer::instrumentMemIntrinsic(MemIntrinsic *MI) {
595 IRBuilder<> IRB(MI);
596 if (isa<MemTransferInst>(MI)) {
597 IRB.CreateCall(
598 isa<MemMoveInst>(MI) ? HWAsanMemmove : HWAsanMemcpy,
599 {IRB.CreatePointerCast(MI->getOperand(0), IRB.getInt8PtrTy()),
600 IRB.CreatePointerCast(MI->getOperand(1), IRB.getInt8PtrTy()),
601 IRB.CreateIntCast(MI->getOperand(2), IntptrTy, false)});
602 } else if (isa<MemSetInst>(MI)) {
603 IRB.CreateCall(
604 HWAsanMemset,
605 {IRB.CreatePointerCast(MI->getOperand(0), IRB.getInt8PtrTy()),
606 IRB.CreateIntCast(MI->getOperand(1), IRB.getInt32Ty(), false),
607 IRB.CreateIntCast(MI->getOperand(2), IntptrTy, false)});
608 }
609 MI->eraseFromParent();
610}
611
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000612bool HWAddressSanitizer::instrumentMemAccess(Instruction *I) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000613 LLVM_DEBUG(dbgs() << "Instrumenting: " << *I << "\n");
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000614 bool IsWrite = false;
615 unsigned Alignment = 0;
616 uint64_t TypeSize = 0;
617 Value *MaybeMask = nullptr;
Eugene Leviant2d98eb12018-12-20 09:04:33 +0000618
619 if (ClInstrumentMemIntrinsics && isa<MemIntrinsic>(I)) {
620 instrumentMemIntrinsic(cast<MemIntrinsic>(I));
621 return true;
622 }
623
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000624 Value *Addr =
625 isInterestingMemoryAccess(I, &IsWrite, &TypeSize, &Alignment, &MaybeMask);
626
627 if (!Addr)
628 return false;
629
630 if (MaybeMask)
631 return false; //FIXME
632
633 IRBuilder<> IRB(I);
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000634 if (isPowerOf2_64(TypeSize) &&
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000635 (TypeSize / 8 <= (1UL << (kNumberOfAccessSizes - 1))) &&
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000636 (Alignment >= (1UL << Mapping.Scale) || Alignment == 0 ||
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000637 Alignment >= TypeSize / 8)) {
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000638 size_t AccessSizeIndex = TypeSizeToSizeIndex(TypeSize);
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000639 if (ClInstrumentWithCalls) {
640 IRB.CreateCall(HwasanMemoryAccessCallback[IsWrite][AccessSizeIndex],
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000641 IRB.CreatePointerCast(Addr, IntptrTy));
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000642 } else {
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000643 instrumentMemAccessInline(Addr, IsWrite, AccessSizeIndex, I);
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000644 }
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000645 } else {
646 IRB.CreateCall(HwasanMemoryAccessCallbackSized[IsWrite],
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000647 {IRB.CreatePointerCast(Addr, IntptrTy),
648 ConstantInt::get(IntptrTy, TypeSize / 8)});
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000649 }
Alex Shlyapnikov83e78412018-03-23 17:57:54 +0000650 untagPointerOperand(I, Addr);
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000651
652 return true;
653}
654
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000655static uint64_t getAllocaSizeInBytes(const AllocaInst &AI) {
656 uint64_t ArraySize = 1;
657 if (AI.isArrayAllocation()) {
658 const ConstantInt *CI = dyn_cast<ConstantInt>(AI.getArraySize());
659 assert(CI && "non-constant array size");
660 ArraySize = CI->getZExtValue();
661 }
662 Type *Ty = AI.getAllocatedType();
663 uint64_t SizeInBytes = AI.getModule()->getDataLayout().getTypeAllocSize(Ty);
664 return SizeInBytes * ArraySize;
665}
666
667bool HWAddressSanitizer::tagAlloca(IRBuilder<> &IRB, AllocaInst *AI,
668 Value *Tag) {
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000669 size_t Size = (getAllocaSizeInBytes(*AI) + Mapping.getAllocaAlignment() - 1) &
670 ~(Mapping.getAllocaAlignment() - 1);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000671
672 Value *JustTag = IRB.CreateTrunc(Tag, IRB.getInt8Ty());
673 if (ClInstrumentWithCalls) {
674 IRB.CreateCall(HwasanTagMemoryFunc,
Evgeniy Stepanova265a132018-08-15 00:39:35 +0000675 {IRB.CreatePointerCast(AI, Int8PtrTy), JustTag,
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000676 ConstantInt::get(IntptrTy, Size)});
677 } else {
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000678 size_t ShadowSize = Size >> Mapping.Scale;
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000679 Value *ShadowPtr = memToShadow(IRB.CreatePointerCast(AI, IntptrTy), IRB);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000680 // If this memset is not inlined, it will be intercepted in the hwasan
681 // runtime library. That's OK, because the interceptor skips the checks if
682 // the address is in the shadow region.
683 // FIXME: the interceptor is not as fast as real memset. Consider lowering
684 // llvm.memset right here into either a sequence of stores, or a call to
685 // hwasan_tag_memory.
686 IRB.CreateMemSet(ShadowPtr, JustTag, ShadowSize, /*Align=*/1);
687 }
688 return true;
689}
690
691static unsigned RetagMask(unsigned AllocaNo) {
692 // A list of 8-bit numbers that have at most one run of non-zero bits.
693 // x = x ^ (mask << 56) can be encoded as a single armv8 instruction for these
694 // masks.
695 // The list does not include the value 255, which is used for UAR.
696 static unsigned FastMasks[] = {
697 0, 1, 2, 3, 4, 6, 7, 8, 12, 14, 15, 16, 24,
698 28, 30, 31, 32, 48, 56, 60, 62, 63, 64, 96, 112, 120,
699 124, 126, 127, 128, 192, 224, 240, 248, 252, 254};
700 return FastMasks[AllocaNo % (sizeof(FastMasks) / sizeof(FastMasks[0]))];
701}
702
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000703Value *HWAddressSanitizer::getNextTagWithCall(IRBuilder<> &IRB) {
704 return IRB.CreateZExt(IRB.CreateCall(HwasanGenerateTagFunc), IntptrTy);
705}
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000706
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000707Value *HWAddressSanitizer::getStackBaseTag(IRBuilder<> &IRB) {
708 if (ClGenerateTagsWithCalls)
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000709 return getNextTagWithCall(IRB);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000710 // FIXME: use addressofreturnaddress (but implement it in aarch64 backend
711 // first).
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000712 Module *M = IRB.GetInsertBlock()->getParent()->getParent();
713 auto GetStackPointerFn =
714 Intrinsic::getDeclaration(M, Intrinsic::frameaddress);
715 Value *StackPointer = IRB.CreateCall(
716 GetStackPointerFn, {Constant::getNullValue(IRB.getInt32Ty())});
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000717
718 // Extract some entropy from the stack pointer for the tags.
719 // Take bits 20..28 (ASLR entropy) and xor with bits 0..8 (these differ
720 // between functions).
721 Value *StackPointerLong = IRB.CreatePointerCast(StackPointer, IntptrTy);
722 Value *StackTag =
723 IRB.CreateXor(StackPointerLong, IRB.CreateLShr(StackPointerLong, 20),
724 "hwasan.stack.base.tag");
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000725 return StackTag;
726}
727
728Value *HWAddressSanitizer::getAllocaTag(IRBuilder<> &IRB, Value *StackTag,
729 AllocaInst *AI, unsigned AllocaNo) {
730 if (ClGenerateTagsWithCalls)
731 return getNextTagWithCall(IRB);
732 return IRB.CreateXor(StackTag,
733 ConstantInt::get(IntptrTy, RetagMask(AllocaNo)));
734}
735
736Value *HWAddressSanitizer::getUARTag(IRBuilder<> &IRB, Value *StackTag) {
Alex Shlyapnikov788764c2018-06-29 20:20:17 +0000737 if (ClUARRetagToZero)
738 return ConstantInt::get(IntptrTy, 0);
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000739 if (ClGenerateTagsWithCalls)
740 return getNextTagWithCall(IRB);
741 return IRB.CreateXor(StackTag, ConstantInt::get(IntptrTy, 0xFFU));
742}
743
Evgeniy Stepanov80ccda22018-02-09 00:59:10 +0000744// Add a tag to an address.
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000745Value *HWAddressSanitizer::tagPointer(IRBuilder<> &IRB, Type *Ty,
746 Value *PtrLong, Value *Tag) {
Evgeniy Stepanov80ccda22018-02-09 00:59:10 +0000747 Value *TaggedPtrLong;
Andrey Konovalov1ba9d9c2018-04-13 18:05:21 +0000748 if (CompileKernel) {
Evgeniy Stepanov80ccda22018-02-09 00:59:10 +0000749 // Kernel addresses have 0xFF in the most significant byte.
750 Value *ShiftedTag = IRB.CreateOr(
751 IRB.CreateShl(Tag, kPointerTagShift),
752 ConstantInt::get(IntptrTy, (1ULL << kPointerTagShift) - 1));
753 TaggedPtrLong = IRB.CreateAnd(PtrLong, ShiftedTag);
754 } else {
755 // Userspace can simply do OR (tag << 56);
756 Value *ShiftedTag = IRB.CreateShl(Tag, kPointerTagShift);
757 TaggedPtrLong = IRB.CreateOr(PtrLong, ShiftedTag);
758 }
759 return IRB.CreateIntToPtr(TaggedPtrLong, Ty);
760}
761
Evgeniy Stepanov43271b12018-02-21 19:52:23 +0000762// Remove tag from an address.
763Value *HWAddressSanitizer::untagPointer(IRBuilder<> &IRB, Value *PtrLong) {
764 Value *UntaggedPtrLong;
Andrey Konovalov1ba9d9c2018-04-13 18:05:21 +0000765 if (CompileKernel) {
Evgeniy Stepanov43271b12018-02-21 19:52:23 +0000766 // Kernel addresses have 0xFF in the most significant byte.
767 UntaggedPtrLong = IRB.CreateOr(PtrLong,
768 ConstantInt::get(PtrLong->getType(), 0xFFULL << kPointerTagShift));
769 } else {
770 // Userspace addresses have 0x00.
771 UntaggedPtrLong = IRB.CreateAnd(PtrLong,
772 ConstantInt::get(PtrLong->getType(), ~(0xFFULL << kPointerTagShift)));
773 }
774 return UntaggedPtrLong;
775}
776
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000777Value *HWAddressSanitizer::getHwasanThreadSlotPtr(IRBuilder<> &IRB, Type *Ty) {
778 Module *M = IRB.GetInsertBlock()->getParent()->getParent();
779 if (TargetTriple.isAArch64() && TargetTriple.isAndroid()) {
Evgeniy Stepanov0184c532019-01-05 00:44:58 +0000780 // Android provides a fixed TLS slot for sanitizers. See TLS_SLOT_SANITIZER
781 // in Bionic's libc/private/bionic_tls.h.
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000782 Function *ThreadPointerFunc =
783 Intrinsic::getDeclaration(M, Intrinsic::thread_pointer);
784 Value *SlotPtr = IRB.CreatePointerCast(
Evgeniy Stepanov0184c532019-01-05 00:44:58 +0000785 IRB.CreateConstGEP1_32(IRB.CreateCall(ThreadPointerFunc), 0x30),
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000786 Ty->getPointerTo(0));
787 return SlotPtr;
788 }
789 if (ThreadPtrGlobal)
790 return ThreadPtrGlobal;
791
792
793 return nullptr;
794}
795
Kostya Serebryanyaf955972018-10-23 00:50:40 +0000796// Creates a string with a description of the stack frame (set of Allocas).
797// The string is intended to be human readable.
798// The current form is: Size1 Name1; Size2 Name2; ...
799std::string
800HWAddressSanitizer::createFrameString(ArrayRef<AllocaInst *> Allocas) {
801 std::ostringstream Descr;
802 for (auto AI : Allocas)
803 Descr << getAllocaSizeInBytes(*AI) << " " << AI->getName().str() << "; ";
804 return Descr.str();
805}
806
807// Creates a global in the frame section which consists of two pointers:
808// the function PC and the frame string constant.
809void HWAddressSanitizer::createFrameGlobal(Function &F,
810 const std::string &FrameString) {
811 Module &M = *F.getParent();
812 auto DescrGV = createPrivateGlobalForString(M, FrameString, true);
813 auto PtrPairTy = StructType::get(F.getType(), DescrGV->getType());
814 auto GV = new GlobalVariable(
815 M, PtrPairTy, /*isConstantGlobal*/ true, GlobalVariable::PrivateLinkage,
816 ConstantStruct::get(PtrPairTy, (Constant *)&F, (Constant *)DescrGV),
817 "__hwasan");
818 GV->setSection(getFrameSection());
819 appendToCompilerUsed(M, GV);
820 // 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 +0000821 if (auto Comdat =
822 GetOrCreateFunctionComdat(F, TargetTriple, CurModuleUniqueId))
823 GV->setComdat(Comdat);
Kostya Serebryanyaf955972018-10-23 00:50:40 +0000824}
825
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000826Value *HWAddressSanitizer::emitPrologue(IRBuilder<> &IRB,
827 bool WithFrameRecord) {
828 if (!Mapping.InTls)
829 return getDynamicShadowNonTls(IRB);
830
831 Value *SlotPtr = getHwasanThreadSlotPtr(IRB, IntptrTy);
832 assert(SlotPtr);
833
Peter Collingbourne87f477b2019-01-04 19:27:04 +0000834 Instruction *ThreadLong = IRB.CreateLoad(SlotPtr);
835
836 Function *F = IRB.GetInsertBlock()->getParent();
837 if (F->getFnAttribute("hwasan-abi").getValueAsString() == "interceptor") {
838 Value *ThreadLongEqZero =
839 IRB.CreateICmpEQ(ThreadLong, ConstantInt::get(IntptrTy, 0));
840 auto *Br = cast<BranchInst>(SplitBlockAndInsertIfThen(
841 ThreadLongEqZero, cast<Instruction>(ThreadLongEqZero)->getNextNode(),
842 false, MDBuilder(*C).createBranchWeights(1, 100000)));
843
844 IRB.SetInsertPoint(Br);
845 // FIXME: This should call a new runtime function with a custom calling
846 // convention to avoid needing to spill all arguments here.
847 IRB.CreateCall(HwasanThreadEnterFunc);
848 LoadInst *ReloadThreadLong = IRB.CreateLoad(SlotPtr);
849
850 IRB.SetInsertPoint(&*Br->getSuccessor(0)->begin());
851 PHINode *ThreadLongPhi = IRB.CreatePHI(IntptrTy, 2);
852 ThreadLongPhi->addIncoming(ThreadLong, ThreadLong->getParent());
853 ThreadLongPhi->addIncoming(ReloadThreadLong, ReloadThreadLong->getParent());
854 ThreadLong = ThreadLongPhi;
855 }
856
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000857 // Extract the address field from ThreadLong. Unnecessary on AArch64 with TBI.
858 Value *ThreadLongMaybeUntagged =
859 TargetTriple.isAArch64() ? ThreadLong : untagPointer(IRB, ThreadLong);
860
861 if (WithFrameRecord) {
862 // Prepare ring buffer data.
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000863 auto PC = IRB.CreatePtrToInt(F, IntptrTy);
864 auto GetStackPointerFn =
865 Intrinsic::getDeclaration(F->getParent(), Intrinsic::frameaddress);
866 Value *SP = IRB.CreatePtrToInt(
867 IRB.CreateCall(GetStackPointerFn,
868 {Constant::getNullValue(IRB.getInt32Ty())}),
869 IntptrTy);
870 // Mix SP and PC. TODO: also add the tag to the mix.
871 // Assumptions:
872 // PC is 0x0000PPPPPPPPPPPP (48 bits are meaningful, others are zero)
873 // SP is 0xsssssssssssSSSS0 (4 lower bits are zero)
874 // We only really need ~20 lower non-zero bits (SSSS), so we mix like this:
875 // 0xSSSSPPPPPPPPPPPP
876 SP = IRB.CreateShl(SP, 44);
877
878 // Store data to ring buffer.
879 Value *RecordPtr =
880 IRB.CreateIntToPtr(ThreadLongMaybeUntagged, IntptrTy->getPointerTo(0));
881 IRB.CreateStore(IRB.CreateOr(PC, SP), RecordPtr);
882
883 // Update the ring buffer. Top byte of ThreadLong defines the size of the
884 // buffer in pages, it must be a power of two, and the start of the buffer
885 // must be aligned by twice that much. Therefore wrap around of the ring
886 // buffer is simply Addr &= ~((ThreadLong >> 56) << 12).
887 // The use of AShr instead of LShr is due to
888 // https://bugs.llvm.org/show_bug.cgi?id=39030
889 // Runtime library makes sure not to use the highest bit.
890 Value *WrapMask = IRB.CreateXor(
891 IRB.CreateShl(IRB.CreateAShr(ThreadLong, 56), 12, "", true, true),
892 ConstantInt::get(IntptrTy, (uint64_t)-1));
893 Value *ThreadLongNew = IRB.CreateAnd(
894 IRB.CreateAdd(ThreadLong, ConstantInt::get(IntptrTy, 8)), WrapMask);
895 IRB.CreateStore(ThreadLongNew, SlotPtr);
896 }
897
898 // Get shadow base address by aligning RecordPtr up.
899 // Note: this is not correct if the pointer is already aligned.
900 // Runtime library will make sure this never happens.
901 Value *ShadowBase = IRB.CreateAdd(
902 IRB.CreateOr(
903 ThreadLongMaybeUntagged,
904 ConstantInt::get(IntptrTy, (1ULL << kShadowBaseAlignment) - 1)),
905 ConstantInt::get(IntptrTy, 1), "hwasan.shadow");
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000906 ShadowBase = IRB.CreateIntToPtr(ShadowBase, Int8PtrTy);
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000907 return ShadowBase;
908}
909
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000910bool HWAddressSanitizer::instrumentStack(
911 SmallVectorImpl<AllocaInst *> &Allocas,
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000912 SmallVectorImpl<Instruction *> &RetVec, Value *StackTag) {
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000913 // Ideally, we want to calculate tagged stack base pointer, and rewrite all
914 // alloca addresses using that. Unfortunately, offsets are not known yet
915 // (unless we use ASan-style mega-alloca). Instead we keep the base tag in a
916 // temp, shift-OR it into each alloca address and xor with the retag mask.
917 // This generates one extra instruction per alloca use.
918 for (unsigned N = 0; N < Allocas.size(); ++N) {
919 auto *AI = Allocas[N];
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +0000920 IRBuilder<> IRB(AI->getNextNode());
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000921
922 // Replace uses of the alloca with tagged address.
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000923 Value *Tag = getAllocaTag(IRB, StackTag, AI, N);
924 Value *AILong = IRB.CreatePointerCast(AI, IntptrTy);
Evgeniy Stepanov80ccda22018-02-09 00:59:10 +0000925 Value *Replacement = tagPointer(IRB, AI->getType(), AILong, Tag);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000926 std::string Name =
927 AI->hasName() ? AI->getName().str() : "alloca." + itostr(N);
Evgeniy Stepanov80ccda22018-02-09 00:59:10 +0000928 Replacement->setName(Name + ".hwasan");
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000929
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000930 for (auto UI = AI->use_begin(), UE = AI->use_end(); UI != UE;) {
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000931 Use &U = *UI++;
932 if (U.getUser() != AILong)
933 U.set(Replacement);
934 }
935
936 tagAlloca(IRB, AI, Tag);
937
938 for (auto RI : RetVec) {
939 IRB.SetInsertPoint(RI);
940
941 // Re-tag alloca memory with the special UAR tag.
Evgeniy Stepanov080e0d42018-01-13 01:32:15 +0000942 Value *Tag = getUARTag(IRB, StackTag);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000943 tagAlloca(IRB, AI, Tag);
944 }
945 }
946
947 return true;
948}
949
950bool HWAddressSanitizer::isInterestingAlloca(const AllocaInst &AI) {
951 return (AI.getAllocatedType()->isSized() &&
952 // FIXME: instrument dynamic allocas, too
953 AI.isStaticAlloca() &&
954 // alloca() may be called with 0 size, ignore it.
955 getAllocaSizeInBytes(AI) > 0 &&
956 // We are only interested in allocas not promotable to registers.
957 // Promotable allocas are common under -O0.
958 !isAllocaPromotable(&AI) &&
959 // inalloca allocas are not treated as static, and we don't want
960 // dynamic alloca instrumentation for them as well.
961 !AI.isUsedWithInAlloca() &&
962 // swifterror allocas are register promoted by ISel
963 !AI.isSwiftError());
964}
965
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000966bool HWAddressSanitizer::runOnFunction(Function &F) {
967 if (&F == HwasanCtorFunction)
968 return false;
969
970 if (!F.hasFnAttribute(Attribute::SanitizeHWAddress))
971 return false;
972
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000973 LLVM_DEBUG(dbgs() << "Function: " << F.getName() << "\n");
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000974
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000975 SmallVector<Instruction*, 16> ToInstrument;
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000976 SmallVector<AllocaInst*, 8> AllocasToInstrument;
977 SmallVector<Instruction*, 8> RetVec;
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000978 for (auto &BB : F) {
979 for (auto &Inst : BB) {
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000980 if (ClInstrumentStack)
981 if (AllocaInst *AI = dyn_cast<AllocaInst>(&Inst)) {
982 // Realign all allocas. We don't want small uninteresting allocas to
983 // hide in instrumented alloca's padding.
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000984 if (AI->getAlignment() < Mapping.getAllocaAlignment())
985 AI->setAlignment(Mapping.getAllocaAlignment());
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000986 // Instrument some of them.
987 if (isInterestingAlloca(*AI))
988 AllocasToInstrument.push_back(AI);
989 continue;
990 }
991
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +0000992 if (isa<ReturnInst>(Inst) || isa<ResumeInst>(Inst) ||
993 isa<CleanupReturnInst>(Inst))
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000994 RetVec.push_back(&Inst);
995
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000996 Value *MaybeMask = nullptr;
997 bool IsWrite;
998 unsigned Alignment;
999 uint64_t TypeSize;
1000 Value *Addr = isInterestingMemoryAccess(&Inst, &IsWrite, &TypeSize,
1001 &Alignment, &MaybeMask);
1002 if (Addr || isa<MemIntrinsic>(Inst))
1003 ToInstrument.push_back(&Inst);
1004 }
1005 }
1006
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +00001007 if (AllocasToInstrument.empty() && ToInstrument.empty())
1008 return false;
1009
Kostya Serebryanyaf955972018-10-23 00:50:40 +00001010 if (ClCreateFrameDescriptions && !AllocasToInstrument.empty())
1011 createFrameGlobal(F, createFrameString(AllocasToInstrument));
1012
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +00001013 initializeCallbacks(*F.getParent());
1014
1015 assert(!LocalDynamicShadow);
1016
1017 Instruction *InsertPt = &*F.getEntryBlock().begin();
1018 IRBuilder<> EntryIRB(InsertPt);
1019 LocalDynamicShadow = emitPrologue(EntryIRB,
1020 /*WithFrameRecord*/ ClRecordStackHistory &&
1021 !AllocasToInstrument.empty());
1022
1023 bool Changed = false;
1024 if (!AllocasToInstrument.empty()) {
1025 Value *StackTag =
1026 ClGenerateTagsWithCalls ? nullptr : getStackBaseTag(EntryIRB);
1027 Changed |= instrumentStack(AllocasToInstrument, RetVec, StackTag);
1028 }
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +00001029
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +00001030 for (auto Inst : ToInstrument)
1031 Changed |= instrumentMemAccess(Inst);
1032
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +00001033 LocalDynamicShadow = nullptr;
1034
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +00001035 return Changed;
1036}
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +00001037
1038void HWAddressSanitizer::ShadowMapping::init(Triple &TargetTriple) {
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +00001039 Scale = kDefaultShadowScale;
Evgeniy Stepanov453e7ac2018-08-10 16:21:37 +00001040 if (ClMappingOffset.getNumOccurrences() > 0) {
1041 InGlobal = false;
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +00001042 InTls = false;
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +00001043 Offset = ClMappingOffset;
Evgeniy Stepanov453e7ac2018-08-10 16:21:37 +00001044 } else if (ClEnableKhwasan || ClInstrumentWithCalls) {
1045 InGlobal = false;
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +00001046 InTls = false;
Evgeniy Stepanov453e7ac2018-08-10 16:21:37 +00001047 Offset = 0;
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +00001048 } else if (ClWithIfunc) {
Evgeniy Stepanov453e7ac2018-08-10 16:21:37 +00001049 InGlobal = true;
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +00001050 InTls = false;
1051 Offset = kDynamicShadowSentinel;
1052 } else if (ClWithTls) {
1053 InGlobal = false;
1054 InTls = true;
Evgeniy Stepanov453e7ac2018-08-10 16:21:37 +00001055 Offset = kDynamicShadowSentinel;
1056 } else {
1057 InGlobal = false;
Evgeniy Stepanov090f0f92018-09-24 23:03:34 +00001058 InTls = false;
Evgeniy Stepanov453e7ac2018-08-10 16:21:37 +00001059 Offset = kDynamicShadowSentinel;
1060 }
Alex Shlyapnikov99cf54b2018-04-20 20:04:04 +00001061}