1*03ce13f7SAndroid Build Coastguard Worker //===- subzero/src/IceASanInstrumentation.cpp - ASan ------------*- C++ -*-===//
2*03ce13f7SAndroid Build Coastguard Worker //
3*03ce13f7SAndroid Build Coastguard Worker // The Subzero Code Generator
4*03ce13f7SAndroid Build Coastguard Worker //
5*03ce13f7SAndroid Build Coastguard Worker // This file is distributed under the University of Illinois Open Source
6*03ce13f7SAndroid Build Coastguard Worker // License. See LICENSE.TXT for details.
7*03ce13f7SAndroid Build Coastguard Worker //
8*03ce13f7SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
9*03ce13f7SAndroid Build Coastguard Worker ///
10*03ce13f7SAndroid Build Coastguard Worker /// \file
11*03ce13f7SAndroid Build Coastguard Worker /// \brief Implements the AddressSanitizer instrumentation class.
12*03ce13f7SAndroid Build Coastguard Worker ///
13*03ce13f7SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
14*03ce13f7SAndroid Build Coastguard Worker
15*03ce13f7SAndroid Build Coastguard Worker #include "IceASanInstrumentation.h"
16*03ce13f7SAndroid Build Coastguard Worker
17*03ce13f7SAndroid Build Coastguard Worker #include "IceBuildDefs.h"
18*03ce13f7SAndroid Build Coastguard Worker #include "IceCfg.h"
19*03ce13f7SAndroid Build Coastguard Worker #include "IceCfgNode.h"
20*03ce13f7SAndroid Build Coastguard Worker #include "IceGlobalInits.h"
21*03ce13f7SAndroid Build Coastguard Worker #include "IceInst.h"
22*03ce13f7SAndroid Build Coastguard Worker #include "IceTargetLowering.h"
23*03ce13f7SAndroid Build Coastguard Worker #include "IceTypes.h"
24*03ce13f7SAndroid Build Coastguard Worker
25*03ce13f7SAndroid Build Coastguard Worker #include <sstream>
26*03ce13f7SAndroid Build Coastguard Worker #include <unordered_map>
27*03ce13f7SAndroid Build Coastguard Worker #include <unordered_set>
28*03ce13f7SAndroid Build Coastguard Worker #include <vector>
29*03ce13f7SAndroid Build Coastguard Worker
30*03ce13f7SAndroid Build Coastguard Worker namespace Ice {
31*03ce13f7SAndroid Build Coastguard Worker
32*03ce13f7SAndroid Build Coastguard Worker namespace {
33*03ce13f7SAndroid Build Coastguard Worker
34*03ce13f7SAndroid Build Coastguard Worker constexpr SizeT BytesPerWord = sizeof(uint32_t);
35*03ce13f7SAndroid Build Coastguard Worker constexpr SizeT RzSize = 32;
36*03ce13f7SAndroid Build Coastguard Worker constexpr SizeT ShadowScaleLog2 = 3;
37*03ce13f7SAndroid Build Coastguard Worker constexpr SizeT ShadowScale = 1 << ShadowScaleLog2;
38*03ce13f7SAndroid Build Coastguard Worker constexpr SizeT ShadowLength32 = 1 << (32 - ShadowScaleLog2);
39*03ce13f7SAndroid Build Coastguard Worker constexpr int32_t StackPoisonVal = -1;
40*03ce13f7SAndroid Build Coastguard Worker constexpr const char *ASanPrefix = "__asan";
41*03ce13f7SAndroid Build Coastguard Worker constexpr const char *RzPrefix = "__$rz";
42*03ce13f7SAndroid Build Coastguard Worker constexpr const char *RzArrayName = "__$rz_array";
43*03ce13f7SAndroid Build Coastguard Worker constexpr const char *RzSizesName = "__$rz_sizes";
44*03ce13f7SAndroid Build Coastguard Worker const llvm::NaClBitcodeRecord::RecordVector RzContents =
45*03ce13f7SAndroid Build Coastguard Worker llvm::NaClBitcodeRecord::RecordVector(RzSize, 'R');
46*03ce13f7SAndroid Build Coastguard Worker
47*03ce13f7SAndroid Build Coastguard Worker // In order to instrument the code correctly, the .pexe must not have had its
48*03ce13f7SAndroid Build Coastguard Worker // symbols stripped.
49*03ce13f7SAndroid Build Coastguard Worker using StringMap = std::unordered_map<std::string, std::string>;
50*03ce13f7SAndroid Build Coastguard Worker using StringSet = std::unordered_set<std::string>;
51*03ce13f7SAndroid Build Coastguard Worker // TODO(tlively): Handle all allocation functions
52*03ce13f7SAndroid Build Coastguard Worker const StringMap FuncSubstitutions = {{"malloc", "__asan_malloc"},
53*03ce13f7SAndroid Build Coastguard Worker {"free", "__asan_free"},
54*03ce13f7SAndroid Build Coastguard Worker {"calloc", "__asan_calloc"},
55*03ce13f7SAndroid Build Coastguard Worker {"__asan_dummy_calloc", "__asan_calloc"},
56*03ce13f7SAndroid Build Coastguard Worker {"realloc", "__asan_realloc"}};
57*03ce13f7SAndroid Build Coastguard Worker const StringSet FuncIgnoreList = {"_Balloc"};
58*03ce13f7SAndroid Build Coastguard Worker
sizeToByteVec(SizeT Size)59*03ce13f7SAndroid Build Coastguard Worker llvm::NaClBitcodeRecord::RecordVector sizeToByteVec(SizeT Size) {
60*03ce13f7SAndroid Build Coastguard Worker llvm::NaClBitcodeRecord::RecordVector SizeContents;
61*03ce13f7SAndroid Build Coastguard Worker for (unsigned i = 0; i < sizeof(Size); ++i) {
62*03ce13f7SAndroid Build Coastguard Worker SizeContents.emplace_back(Size % (1 << CHAR_BIT));
63*03ce13f7SAndroid Build Coastguard Worker Size >>= CHAR_BIT;
64*03ce13f7SAndroid Build Coastguard Worker }
65*03ce13f7SAndroid Build Coastguard Worker return SizeContents;
66*03ce13f7SAndroid Build Coastguard Worker }
67*03ce13f7SAndroid Build Coastguard Worker
68*03ce13f7SAndroid Build Coastguard Worker } // end of anonymous namespace
69*03ce13f7SAndroid Build Coastguard Worker
70*03ce13f7SAndroid Build Coastguard Worker ICE_TLS_DEFINE_FIELD(VarSizeMap *, ASanInstrumentation, LocalVars);
71*03ce13f7SAndroid Build Coastguard Worker ICE_TLS_DEFINE_FIELD(std::vector<InstStore *> *, ASanInstrumentation,
72*03ce13f7SAndroid Build Coastguard Worker LocalDtors);
73*03ce13f7SAndroid Build Coastguard Worker ICE_TLS_DEFINE_FIELD(CfgNode *, ASanInstrumentation, CurNode);
74*03ce13f7SAndroid Build Coastguard Worker ICE_TLS_DEFINE_FIELD(VarSizeMap *, ASanInstrumentation, CheckedVars);
75*03ce13f7SAndroid Build Coastguard Worker
isInstrumentable(Cfg * Func)76*03ce13f7SAndroid Build Coastguard Worker bool ASanInstrumentation::isInstrumentable(Cfg *Func) {
77*03ce13f7SAndroid Build Coastguard Worker std::string FuncName = Func->getFunctionName().toStringOrEmpty();
78*03ce13f7SAndroid Build Coastguard Worker return FuncName == "" || (FuncIgnoreList.count(FuncName) == 0 &&
79*03ce13f7SAndroid Build Coastguard Worker FuncName.find(ASanPrefix) != 0);
80*03ce13f7SAndroid Build Coastguard Worker }
81*03ce13f7SAndroid Build Coastguard Worker
82*03ce13f7SAndroid Build Coastguard Worker // Create redzones around all global variables, ensuring that the initializer
83*03ce13f7SAndroid Build Coastguard Worker // types of the redzones and their associated globals match so that they are
84*03ce13f7SAndroid Build Coastguard Worker // laid out together in memory.
instrumentGlobals(VariableDeclarationList & Globals)85*03ce13f7SAndroid Build Coastguard Worker void ASanInstrumentation::instrumentGlobals(VariableDeclarationList &Globals) {
86*03ce13f7SAndroid Build Coastguard Worker std::unique_lock<std::mutex> _(GlobalsMutex);
87*03ce13f7SAndroid Build Coastguard Worker if (DidProcessGlobals)
88*03ce13f7SAndroid Build Coastguard Worker return;
89*03ce13f7SAndroid Build Coastguard Worker VariableDeclarationList NewGlobals;
90*03ce13f7SAndroid Build Coastguard Worker // Global holding pointers to all redzones
91*03ce13f7SAndroid Build Coastguard Worker auto *RzArray = VariableDeclaration::create(&NewGlobals);
92*03ce13f7SAndroid Build Coastguard Worker // Global holding sizes of all redzones
93*03ce13f7SAndroid Build Coastguard Worker auto *RzSizes = VariableDeclaration::create(&NewGlobals);
94*03ce13f7SAndroid Build Coastguard Worker
95*03ce13f7SAndroid Build Coastguard Worker RzArray->setName(Ctx, RzArrayName);
96*03ce13f7SAndroid Build Coastguard Worker RzSizes->setName(Ctx, RzSizesName);
97*03ce13f7SAndroid Build Coastguard Worker RzArray->setIsConstant(true);
98*03ce13f7SAndroid Build Coastguard Worker RzSizes->setIsConstant(true);
99*03ce13f7SAndroid Build Coastguard Worker NewGlobals.push_back(RzArray);
100*03ce13f7SAndroid Build Coastguard Worker NewGlobals.push_back(RzSizes);
101*03ce13f7SAndroid Build Coastguard Worker
102*03ce13f7SAndroid Build Coastguard Worker using PrototypeMap = std::unordered_map<std::string, FunctionDeclaration *>;
103*03ce13f7SAndroid Build Coastguard Worker PrototypeMap ProtoSubstitutions;
104*03ce13f7SAndroid Build Coastguard Worker for (VariableDeclaration *Global : Globals) {
105*03ce13f7SAndroid Build Coastguard Worker assert(Global->getAlignment() <= RzSize);
106*03ce13f7SAndroid Build Coastguard Worker VariableDeclaration *RzLeft = VariableDeclaration::create(&NewGlobals);
107*03ce13f7SAndroid Build Coastguard Worker VariableDeclaration *NewGlobal = Global;
108*03ce13f7SAndroid Build Coastguard Worker VariableDeclaration *RzRight = VariableDeclaration::create(&NewGlobals);
109*03ce13f7SAndroid Build Coastguard Worker RzLeft->setName(Ctx, nextRzName());
110*03ce13f7SAndroid Build Coastguard Worker RzRight->setName(Ctx, nextRzName());
111*03ce13f7SAndroid Build Coastguard Worker SizeT Alignment = std::max(RzSize, Global->getAlignment());
112*03ce13f7SAndroid Build Coastguard Worker SizeT RzLeftSize = Alignment;
113*03ce13f7SAndroid Build Coastguard Worker SizeT RzRightSize =
114*03ce13f7SAndroid Build Coastguard Worker RzSize + Utils::OffsetToAlignment(Global->getNumBytes(), Alignment);
115*03ce13f7SAndroid Build Coastguard Worker if (!Global->hasNonzeroInitializer()) {
116*03ce13f7SAndroid Build Coastguard Worker RzLeft->addInitializer(VariableDeclaration::ZeroInitializer::create(
117*03ce13f7SAndroid Build Coastguard Worker &NewGlobals, RzLeftSize));
118*03ce13f7SAndroid Build Coastguard Worker RzRight->addInitializer(VariableDeclaration::ZeroInitializer::create(
119*03ce13f7SAndroid Build Coastguard Worker &NewGlobals, RzRightSize));
120*03ce13f7SAndroid Build Coastguard Worker } else {
121*03ce13f7SAndroid Build Coastguard Worker RzLeft->addInitializer(VariableDeclaration::DataInitializer::create(
122*03ce13f7SAndroid Build Coastguard Worker &NewGlobals, llvm::NaClBitcodeRecord::RecordVector(RzLeftSize, 'R')));
123*03ce13f7SAndroid Build Coastguard Worker RzRight->addInitializer(VariableDeclaration::DataInitializer::create(
124*03ce13f7SAndroid Build Coastguard Worker &NewGlobals,
125*03ce13f7SAndroid Build Coastguard Worker llvm::NaClBitcodeRecord::RecordVector(RzRightSize, 'R')));
126*03ce13f7SAndroid Build Coastguard Worker
127*03ce13f7SAndroid Build Coastguard Worker // replace any pointers to allocator functions
128*03ce13f7SAndroid Build Coastguard Worker NewGlobal = VariableDeclaration::create(&NewGlobals);
129*03ce13f7SAndroid Build Coastguard Worker NewGlobal->setName(Global->getName());
130*03ce13f7SAndroid Build Coastguard Worker std::vector<VariableDeclaration::Initializer *> GlobalInits =
131*03ce13f7SAndroid Build Coastguard Worker Global->getInitializers();
132*03ce13f7SAndroid Build Coastguard Worker for (VariableDeclaration::Initializer *Init : GlobalInits) {
133*03ce13f7SAndroid Build Coastguard Worker auto *RelocInit =
134*03ce13f7SAndroid Build Coastguard Worker llvm::dyn_cast<VariableDeclaration::RelocInitializer>(Init);
135*03ce13f7SAndroid Build Coastguard Worker if (RelocInit == nullptr) {
136*03ce13f7SAndroid Build Coastguard Worker NewGlobal->addInitializer(Init);
137*03ce13f7SAndroid Build Coastguard Worker continue;
138*03ce13f7SAndroid Build Coastguard Worker }
139*03ce13f7SAndroid Build Coastguard Worker const GlobalDeclaration *TargetDecl = RelocInit->getDeclaration();
140*03ce13f7SAndroid Build Coastguard Worker const auto *TargetFunc =
141*03ce13f7SAndroid Build Coastguard Worker llvm::dyn_cast<FunctionDeclaration>(TargetDecl);
142*03ce13f7SAndroid Build Coastguard Worker if (TargetFunc == nullptr) {
143*03ce13f7SAndroid Build Coastguard Worker NewGlobal->addInitializer(Init);
144*03ce13f7SAndroid Build Coastguard Worker continue;
145*03ce13f7SAndroid Build Coastguard Worker }
146*03ce13f7SAndroid Build Coastguard Worker std::string TargetName = TargetDecl->getName().toStringOrEmpty();
147*03ce13f7SAndroid Build Coastguard Worker StringMap::const_iterator Subst = FuncSubstitutions.find(TargetName);
148*03ce13f7SAndroid Build Coastguard Worker if (Subst == FuncSubstitutions.end()) {
149*03ce13f7SAndroid Build Coastguard Worker NewGlobal->addInitializer(Init);
150*03ce13f7SAndroid Build Coastguard Worker continue;
151*03ce13f7SAndroid Build Coastguard Worker }
152*03ce13f7SAndroid Build Coastguard Worker std::string SubstName = Subst->second;
153*03ce13f7SAndroid Build Coastguard Worker PrototypeMap::iterator SubstProtoEntry =
154*03ce13f7SAndroid Build Coastguard Worker ProtoSubstitutions.find(SubstName);
155*03ce13f7SAndroid Build Coastguard Worker FunctionDeclaration *SubstProto;
156*03ce13f7SAndroid Build Coastguard Worker if (SubstProtoEntry != ProtoSubstitutions.end())
157*03ce13f7SAndroid Build Coastguard Worker SubstProto = SubstProtoEntry->second;
158*03ce13f7SAndroid Build Coastguard Worker else {
159*03ce13f7SAndroid Build Coastguard Worker constexpr bool IsProto = true;
160*03ce13f7SAndroid Build Coastguard Worker SubstProto = FunctionDeclaration::create(
161*03ce13f7SAndroid Build Coastguard Worker Ctx, TargetFunc->getSignature(), TargetFunc->getCallingConv(),
162*03ce13f7SAndroid Build Coastguard Worker llvm::GlobalValue::ExternalLinkage, IsProto);
163*03ce13f7SAndroid Build Coastguard Worker SubstProto->setName(Ctx, SubstName);
164*03ce13f7SAndroid Build Coastguard Worker ProtoSubstitutions.insert({SubstName, SubstProto});
165*03ce13f7SAndroid Build Coastguard Worker }
166*03ce13f7SAndroid Build Coastguard Worker
167*03ce13f7SAndroid Build Coastguard Worker NewGlobal->addInitializer(VariableDeclaration::RelocInitializer::create(
168*03ce13f7SAndroid Build Coastguard Worker &NewGlobals, SubstProto, RelocOffsetArray(0)));
169*03ce13f7SAndroid Build Coastguard Worker }
170*03ce13f7SAndroid Build Coastguard Worker }
171*03ce13f7SAndroid Build Coastguard Worker
172*03ce13f7SAndroid Build Coastguard Worker RzLeft->setIsConstant(Global->getIsConstant());
173*03ce13f7SAndroid Build Coastguard Worker NewGlobal->setIsConstant(Global->getIsConstant());
174*03ce13f7SAndroid Build Coastguard Worker RzRight->setIsConstant(Global->getIsConstant());
175*03ce13f7SAndroid Build Coastguard Worker RzLeft->setAlignment(Alignment);
176*03ce13f7SAndroid Build Coastguard Worker NewGlobal->setAlignment(Alignment);
177*03ce13f7SAndroid Build Coastguard Worker RzRight->setAlignment(1);
178*03ce13f7SAndroid Build Coastguard Worker RzArray->addInitializer(VariableDeclaration::RelocInitializer::create(
179*03ce13f7SAndroid Build Coastguard Worker &NewGlobals, RzLeft, RelocOffsetArray(0)));
180*03ce13f7SAndroid Build Coastguard Worker RzArray->addInitializer(VariableDeclaration::RelocInitializer::create(
181*03ce13f7SAndroid Build Coastguard Worker &NewGlobals, RzRight, RelocOffsetArray(0)));
182*03ce13f7SAndroid Build Coastguard Worker RzSizes->addInitializer(VariableDeclaration::DataInitializer::create(
183*03ce13f7SAndroid Build Coastguard Worker &NewGlobals, sizeToByteVec(RzLeftSize)));
184*03ce13f7SAndroid Build Coastguard Worker RzSizes->addInitializer(VariableDeclaration::DataInitializer::create(
185*03ce13f7SAndroid Build Coastguard Worker &NewGlobals, sizeToByteVec(RzRightSize)));
186*03ce13f7SAndroid Build Coastguard Worker
187*03ce13f7SAndroid Build Coastguard Worker NewGlobals.push_back(RzLeft);
188*03ce13f7SAndroid Build Coastguard Worker NewGlobals.push_back(NewGlobal);
189*03ce13f7SAndroid Build Coastguard Worker NewGlobals.push_back(RzRight);
190*03ce13f7SAndroid Build Coastguard Worker RzGlobalsNum += 2;
191*03ce13f7SAndroid Build Coastguard Worker
192*03ce13f7SAndroid Build Coastguard Worker GlobalSizes.insert({NewGlobal->getName(), NewGlobal->getNumBytes()});
193*03ce13f7SAndroid Build Coastguard Worker }
194*03ce13f7SAndroid Build Coastguard Worker
195*03ce13f7SAndroid Build Coastguard Worker // Replace old list of globals, without messing up arena allocators
196*03ce13f7SAndroid Build Coastguard Worker Globals.clear();
197*03ce13f7SAndroid Build Coastguard Worker Globals.merge(&NewGlobals);
198*03ce13f7SAndroid Build Coastguard Worker DidProcessGlobals = true;
199*03ce13f7SAndroid Build Coastguard Worker
200*03ce13f7SAndroid Build Coastguard Worker // Log the new set of globals
201*03ce13f7SAndroid Build Coastguard Worker if (BuildDefs::dump() && (getFlags().getVerbose() & IceV_GlobalInit)) {
202*03ce13f7SAndroid Build Coastguard Worker OstreamLocker _(Ctx);
203*03ce13f7SAndroid Build Coastguard Worker Ctx->getStrDump() << "========= Instrumented Globals =========\n";
204*03ce13f7SAndroid Build Coastguard Worker for (VariableDeclaration *Global : Globals) {
205*03ce13f7SAndroid Build Coastguard Worker Global->dump(Ctx->getStrDump());
206*03ce13f7SAndroid Build Coastguard Worker }
207*03ce13f7SAndroid Build Coastguard Worker }
208*03ce13f7SAndroid Build Coastguard Worker }
209*03ce13f7SAndroid Build Coastguard Worker
nextRzName()210*03ce13f7SAndroid Build Coastguard Worker std::string ASanInstrumentation::nextRzName() {
211*03ce13f7SAndroid Build Coastguard Worker std::stringstream Name;
212*03ce13f7SAndroid Build Coastguard Worker Name << RzPrefix << RzNum++;
213*03ce13f7SAndroid Build Coastguard Worker return Name.str();
214*03ce13f7SAndroid Build Coastguard Worker }
215*03ce13f7SAndroid Build Coastguard Worker
216*03ce13f7SAndroid Build Coastguard Worker // Check for an alloca signaling the presence of local variables and add a
217*03ce13f7SAndroid Build Coastguard Worker // redzone if it is found
instrumentFuncStart(LoweringContext & Context)218*03ce13f7SAndroid Build Coastguard Worker void ASanInstrumentation::instrumentFuncStart(LoweringContext &Context) {
219*03ce13f7SAndroid Build Coastguard Worker if (ICE_TLS_GET_FIELD(LocalDtors) == nullptr) {
220*03ce13f7SAndroid Build Coastguard Worker ICE_TLS_SET_FIELD(LocalDtors, new std::vector<InstStore *>());
221*03ce13f7SAndroid Build Coastguard Worker ICE_TLS_SET_FIELD(LocalVars, new VarSizeMap());
222*03ce13f7SAndroid Build Coastguard Worker }
223*03ce13f7SAndroid Build Coastguard Worker Cfg *Func = Context.getNode()->getCfg();
224*03ce13f7SAndroid Build Coastguard Worker using Entry = std::pair<SizeT, int32_t>;
225*03ce13f7SAndroid Build Coastguard Worker std::vector<InstAlloca *> NewAllocas;
226*03ce13f7SAndroid Build Coastguard Worker std::vector<Entry> PoisonVals;
227*03ce13f7SAndroid Build Coastguard Worker Variable *FirstShadowLocVar;
228*03ce13f7SAndroid Build Coastguard Worker InstArithmetic *ShadowIndexCalc;
229*03ce13f7SAndroid Build Coastguard Worker InstArithmetic *ShadowLocCalc;
230*03ce13f7SAndroid Build Coastguard Worker InstAlloca *Cur;
231*03ce13f7SAndroid Build Coastguard Worker ConstantInteger32 *VarSizeOp;
232*03ce13f7SAndroid Build Coastguard Worker while (!Context.atEnd()) {
233*03ce13f7SAndroid Build Coastguard Worker Cur = llvm::dyn_cast<InstAlloca>(iteratorToInst(Context.getCur()));
234*03ce13f7SAndroid Build Coastguard Worker VarSizeOp = (Cur == nullptr)
235*03ce13f7SAndroid Build Coastguard Worker ? nullptr
236*03ce13f7SAndroid Build Coastguard Worker : llvm::dyn_cast<ConstantInteger32>(Cur->getSizeInBytes());
237*03ce13f7SAndroid Build Coastguard Worker if (Cur == nullptr || VarSizeOp == nullptr) {
238*03ce13f7SAndroid Build Coastguard Worker Context.advanceCur();
239*03ce13f7SAndroid Build Coastguard Worker Context.advanceNext();
240*03ce13f7SAndroid Build Coastguard Worker continue;
241*03ce13f7SAndroid Build Coastguard Worker }
242*03ce13f7SAndroid Build Coastguard Worker
243*03ce13f7SAndroid Build Coastguard Worker Cur->setDeleted();
244*03ce13f7SAndroid Build Coastguard Worker
245*03ce13f7SAndroid Build Coastguard Worker if (PoisonVals.empty()) {
246*03ce13f7SAndroid Build Coastguard Worker // insert leftmost redzone
247*03ce13f7SAndroid Build Coastguard Worker auto *LastRzVar = Func->makeVariable(IceType_i32);
248*03ce13f7SAndroid Build Coastguard Worker LastRzVar->setName(Func, nextRzName());
249*03ce13f7SAndroid Build Coastguard Worker auto *ByteCount = ConstantInteger32::create(Ctx, IceType_i32, RzSize);
250*03ce13f7SAndroid Build Coastguard Worker constexpr SizeT Alignment = 8;
251*03ce13f7SAndroid Build Coastguard Worker NewAllocas.emplace_back(
252*03ce13f7SAndroid Build Coastguard Worker InstAlloca::create(Func, LastRzVar, ByteCount, Alignment));
253*03ce13f7SAndroid Build Coastguard Worker PoisonVals.emplace_back(Entry{RzSize >> ShadowScaleLog2, StackPoisonVal});
254*03ce13f7SAndroid Build Coastguard Worker
255*03ce13f7SAndroid Build Coastguard Worker // Calculate starting address for poisoning
256*03ce13f7SAndroid Build Coastguard Worker FirstShadowLocVar = Func->makeVariable(IceType_i32);
257*03ce13f7SAndroid Build Coastguard Worker FirstShadowLocVar->setName(Func, "firstShadowLoc");
258*03ce13f7SAndroid Build Coastguard Worker auto *ShadowIndexVar = Func->makeVariable(IceType_i32);
259*03ce13f7SAndroid Build Coastguard Worker ShadowIndexVar->setName(Func, "shadowIndex");
260*03ce13f7SAndroid Build Coastguard Worker
261*03ce13f7SAndroid Build Coastguard Worker auto *ShadowScaleLog2Const =
262*03ce13f7SAndroid Build Coastguard Worker ConstantInteger32::create(Ctx, IceType_i32, ShadowScaleLog2);
263*03ce13f7SAndroid Build Coastguard Worker auto *ShadowMemLocConst =
264*03ce13f7SAndroid Build Coastguard Worker ConstantInteger32::create(Ctx, IceType_i32, ShadowLength32);
265*03ce13f7SAndroid Build Coastguard Worker
266*03ce13f7SAndroid Build Coastguard Worker ShadowIndexCalc =
267*03ce13f7SAndroid Build Coastguard Worker InstArithmetic::create(Func, InstArithmetic::Lshr, ShadowIndexVar,
268*03ce13f7SAndroid Build Coastguard Worker LastRzVar, ShadowScaleLog2Const);
269*03ce13f7SAndroid Build Coastguard Worker ShadowLocCalc =
270*03ce13f7SAndroid Build Coastguard Worker InstArithmetic::create(Func, InstArithmetic::Add, FirstShadowLocVar,
271*03ce13f7SAndroid Build Coastguard Worker ShadowIndexVar, ShadowMemLocConst);
272*03ce13f7SAndroid Build Coastguard Worker }
273*03ce13f7SAndroid Build Coastguard Worker
274*03ce13f7SAndroid Build Coastguard Worker // create the new alloca that includes a redzone
275*03ce13f7SAndroid Build Coastguard Worker SizeT VarSize = VarSizeOp->getValue();
276*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Cur->getDest();
277*03ce13f7SAndroid Build Coastguard Worker ICE_TLS_GET_FIELD(LocalVars)->insert({Dest, VarSize});
278*03ce13f7SAndroid Build Coastguard Worker SizeT RzPadding = RzSize + Utils::OffsetToAlignment(VarSize, RzSize);
279*03ce13f7SAndroid Build Coastguard Worker auto *ByteCount =
280*03ce13f7SAndroid Build Coastguard Worker ConstantInteger32::create(Ctx, IceType_i32, VarSize + RzPadding);
281*03ce13f7SAndroid Build Coastguard Worker constexpr SizeT Alignment = 8;
282*03ce13f7SAndroid Build Coastguard Worker NewAllocas.emplace_back(
283*03ce13f7SAndroid Build Coastguard Worker InstAlloca::create(Func, Dest, ByteCount, Alignment));
284*03ce13f7SAndroid Build Coastguard Worker
285*03ce13f7SAndroid Build Coastguard Worker const SizeT Zeros = VarSize >> ShadowScaleLog2;
286*03ce13f7SAndroid Build Coastguard Worker const SizeT Offset = VarSize % ShadowScale;
287*03ce13f7SAndroid Build Coastguard Worker const SizeT PoisonBytes =
288*03ce13f7SAndroid Build Coastguard Worker ((VarSize + RzPadding) >> ShadowScaleLog2) - Zeros - 1;
289*03ce13f7SAndroid Build Coastguard Worker if (Zeros > 0)
290*03ce13f7SAndroid Build Coastguard Worker PoisonVals.emplace_back(Entry{Zeros, 0});
291*03ce13f7SAndroid Build Coastguard Worker PoisonVals.emplace_back(Entry{1, (Offset == 0) ? StackPoisonVal : Offset});
292*03ce13f7SAndroid Build Coastguard Worker PoisonVals.emplace_back(Entry{PoisonBytes, StackPoisonVal});
293*03ce13f7SAndroid Build Coastguard Worker Context.advanceCur();
294*03ce13f7SAndroid Build Coastguard Worker Context.advanceNext();
295*03ce13f7SAndroid Build Coastguard Worker }
296*03ce13f7SAndroid Build Coastguard Worker
297*03ce13f7SAndroid Build Coastguard Worker Context.rewind();
298*03ce13f7SAndroid Build Coastguard Worker if (PoisonVals.empty()) {
299*03ce13f7SAndroid Build Coastguard Worker Context.advanceNext();
300*03ce13f7SAndroid Build Coastguard Worker return;
301*03ce13f7SAndroid Build Coastguard Worker }
302*03ce13f7SAndroid Build Coastguard Worker for (InstAlloca *RzAlloca : NewAllocas) {
303*03ce13f7SAndroid Build Coastguard Worker Context.insert(RzAlloca);
304*03ce13f7SAndroid Build Coastguard Worker }
305*03ce13f7SAndroid Build Coastguard Worker Context.insert(ShadowIndexCalc);
306*03ce13f7SAndroid Build Coastguard Worker Context.insert(ShadowLocCalc);
307*03ce13f7SAndroid Build Coastguard Worker
308*03ce13f7SAndroid Build Coastguard Worker // Poison redzones
309*03ce13f7SAndroid Build Coastguard Worker std::vector<Entry>::iterator Iter = PoisonVals.begin();
310*03ce13f7SAndroid Build Coastguard Worker for (SizeT Offset = 0; Iter != PoisonVals.end(); Offset += BytesPerWord) {
311*03ce13f7SAndroid Build Coastguard Worker int32_t CurVals[BytesPerWord] = {0};
312*03ce13f7SAndroid Build Coastguard Worker for (uint32_t i = 0; i < BytesPerWord; ++i) {
313*03ce13f7SAndroid Build Coastguard Worker if (Iter == PoisonVals.end())
314*03ce13f7SAndroid Build Coastguard Worker break;
315*03ce13f7SAndroid Build Coastguard Worker Entry Val = *Iter;
316*03ce13f7SAndroid Build Coastguard Worker CurVals[i] = Val.second;
317*03ce13f7SAndroid Build Coastguard Worker --Val.first;
318*03ce13f7SAndroid Build Coastguard Worker if (Val.first > 0)
319*03ce13f7SAndroid Build Coastguard Worker *Iter = Val;
320*03ce13f7SAndroid Build Coastguard Worker else
321*03ce13f7SAndroid Build Coastguard Worker ++Iter;
322*03ce13f7SAndroid Build Coastguard Worker }
323*03ce13f7SAndroid Build Coastguard Worker int32_t Poison = ((CurVals[3] & 0xff) << 24) | ((CurVals[2] & 0xff) << 16) |
324*03ce13f7SAndroid Build Coastguard Worker ((CurVals[1] & 0xff) << 8) | (CurVals[0] & 0xff);
325*03ce13f7SAndroid Build Coastguard Worker if (Poison == 0)
326*03ce13f7SAndroid Build Coastguard Worker continue;
327*03ce13f7SAndroid Build Coastguard Worker auto *PoisonConst = ConstantInteger32::create(Ctx, IceType_i32, Poison);
328*03ce13f7SAndroid Build Coastguard Worker auto *ZeroConst = ConstantInteger32::create(Ctx, IceType_i32, 0);
329*03ce13f7SAndroid Build Coastguard Worker auto *OffsetConst = ConstantInteger32::create(Ctx, IceType_i32, Offset);
330*03ce13f7SAndroid Build Coastguard Worker auto *PoisonAddrVar = Func->makeVariable(IceType_i32);
331*03ce13f7SAndroid Build Coastguard Worker Context.insert(InstArithmetic::create(Func, InstArithmetic::Add,
332*03ce13f7SAndroid Build Coastguard Worker PoisonAddrVar, FirstShadowLocVar,
333*03ce13f7SAndroid Build Coastguard Worker OffsetConst));
334*03ce13f7SAndroid Build Coastguard Worker Context.insert(InstStore::create(Func, PoisonConst, PoisonAddrVar));
335*03ce13f7SAndroid Build Coastguard Worker ICE_TLS_GET_FIELD(LocalDtors)
336*03ce13f7SAndroid Build Coastguard Worker ->emplace_back(InstStore::create(Func, ZeroConst, PoisonAddrVar));
337*03ce13f7SAndroid Build Coastguard Worker }
338*03ce13f7SAndroid Build Coastguard Worker Context.advanceNext();
339*03ce13f7SAndroid Build Coastguard Worker }
340*03ce13f7SAndroid Build Coastguard Worker
instrumentCall(LoweringContext & Context,InstCall * Instr)341*03ce13f7SAndroid Build Coastguard Worker void ASanInstrumentation::instrumentCall(LoweringContext &Context,
342*03ce13f7SAndroid Build Coastguard Worker InstCall *Instr) {
343*03ce13f7SAndroid Build Coastguard Worker auto *CallTarget =
344*03ce13f7SAndroid Build Coastguard Worker llvm::dyn_cast<ConstantRelocatable>(Instr->getCallTarget());
345*03ce13f7SAndroid Build Coastguard Worker if (CallTarget == nullptr)
346*03ce13f7SAndroid Build Coastguard Worker return;
347*03ce13f7SAndroid Build Coastguard Worker
348*03ce13f7SAndroid Build Coastguard Worker std::string TargetName = CallTarget->getName().toStringOrEmpty();
349*03ce13f7SAndroid Build Coastguard Worker auto Subst = FuncSubstitutions.find(TargetName);
350*03ce13f7SAndroid Build Coastguard Worker if (Subst == FuncSubstitutions.end())
351*03ce13f7SAndroid Build Coastguard Worker return;
352*03ce13f7SAndroid Build Coastguard Worker
353*03ce13f7SAndroid Build Coastguard Worker std::string SubName = Subst->second;
354*03ce13f7SAndroid Build Coastguard Worker Constant *NewFunc = Ctx->getConstantExternSym(Ctx->getGlobalString(SubName));
355*03ce13f7SAndroid Build Coastguard Worker auto *NewCall =
356*03ce13f7SAndroid Build Coastguard Worker InstCall::create(Context.getNode()->getCfg(), Instr->getNumArgs(),
357*03ce13f7SAndroid Build Coastguard Worker Instr->getDest(), NewFunc, Instr->isTailcall());
358*03ce13f7SAndroid Build Coastguard Worker for (SizeT I = 0, Args = Instr->getNumArgs(); I < Args; ++I)
359*03ce13f7SAndroid Build Coastguard Worker NewCall->addArg(Instr->getArg(I));
360*03ce13f7SAndroid Build Coastguard Worker Context.insert(NewCall);
361*03ce13f7SAndroid Build Coastguard Worker Instr->setDeleted();
362*03ce13f7SAndroid Build Coastguard Worker }
363*03ce13f7SAndroid Build Coastguard Worker
instrumentLoad(LoweringContext & Context,InstLoad * Instr)364*03ce13f7SAndroid Build Coastguard Worker void ASanInstrumentation::instrumentLoad(LoweringContext &Context,
365*03ce13f7SAndroid Build Coastguard Worker InstLoad *Instr) {
366*03ce13f7SAndroid Build Coastguard Worker Operand *Src = Instr->getLoadAddress();
367*03ce13f7SAndroid Build Coastguard Worker if (auto *Reloc = llvm::dyn_cast<ConstantRelocatable>(Src)) {
368*03ce13f7SAndroid Build Coastguard Worker auto *NewLoad = InstLoad::create(Context.getNode()->getCfg(),
369*03ce13f7SAndroid Build Coastguard Worker Instr->getDest(), instrumentReloc(Reloc));
370*03ce13f7SAndroid Build Coastguard Worker Instr->setDeleted();
371*03ce13f7SAndroid Build Coastguard Worker Context.insert(NewLoad);
372*03ce13f7SAndroid Build Coastguard Worker Instr = NewLoad;
373*03ce13f7SAndroid Build Coastguard Worker }
374*03ce13f7SAndroid Build Coastguard Worker Constant *Func =
375*03ce13f7SAndroid Build Coastguard Worker Ctx->getConstantExternSym(Ctx->getGlobalString("__asan_check_load"));
376*03ce13f7SAndroid Build Coastguard Worker instrumentAccess(Context, Instr->getLoadAddress(),
377*03ce13f7SAndroid Build Coastguard Worker typeWidthInBytes(Instr->getDest()->getType()), Func);
378*03ce13f7SAndroid Build Coastguard Worker }
379*03ce13f7SAndroid Build Coastguard Worker
instrumentStore(LoweringContext & Context,InstStore * Instr)380*03ce13f7SAndroid Build Coastguard Worker void ASanInstrumentation::instrumentStore(LoweringContext &Context,
381*03ce13f7SAndroid Build Coastguard Worker InstStore *Instr) {
382*03ce13f7SAndroid Build Coastguard Worker Operand *Data = Instr->getData();
383*03ce13f7SAndroid Build Coastguard Worker if (auto *Reloc = llvm::dyn_cast<ConstantRelocatable>(Data)) {
384*03ce13f7SAndroid Build Coastguard Worker auto *NewStore =
385*03ce13f7SAndroid Build Coastguard Worker InstStore::create(Context.getNode()->getCfg(), instrumentReloc(Reloc),
386*03ce13f7SAndroid Build Coastguard Worker Instr->getStoreAddress());
387*03ce13f7SAndroid Build Coastguard Worker Instr->setDeleted();
388*03ce13f7SAndroid Build Coastguard Worker Context.insert(NewStore);
389*03ce13f7SAndroid Build Coastguard Worker Instr = NewStore;
390*03ce13f7SAndroid Build Coastguard Worker }
391*03ce13f7SAndroid Build Coastguard Worker Constant *Func =
392*03ce13f7SAndroid Build Coastguard Worker Ctx->getConstantExternSym(Ctx->getGlobalString("__asan_check_store"));
393*03ce13f7SAndroid Build Coastguard Worker instrumentAccess(Context, Instr->getStoreAddress(),
394*03ce13f7SAndroid Build Coastguard Worker typeWidthInBytes(Instr->getData()->getType()), Func);
395*03ce13f7SAndroid Build Coastguard Worker }
396*03ce13f7SAndroid Build Coastguard Worker
397*03ce13f7SAndroid Build Coastguard Worker ConstantRelocatable *
instrumentReloc(ConstantRelocatable * Reloc)398*03ce13f7SAndroid Build Coastguard Worker ASanInstrumentation::instrumentReloc(ConstantRelocatable *Reloc) {
399*03ce13f7SAndroid Build Coastguard Worker std::string DataName = Reloc->getName().toString();
400*03ce13f7SAndroid Build Coastguard Worker StringMap::const_iterator DataSub = FuncSubstitutions.find(DataName);
401*03ce13f7SAndroid Build Coastguard Worker if (DataSub != FuncSubstitutions.end()) {
402*03ce13f7SAndroid Build Coastguard Worker return ConstantRelocatable::create(
403*03ce13f7SAndroid Build Coastguard Worker Ctx, Reloc->getType(),
404*03ce13f7SAndroid Build Coastguard Worker RelocatableTuple(Reloc->getOffset(), RelocOffsetArray(0),
405*03ce13f7SAndroid Build Coastguard Worker Ctx->getGlobalString(DataSub->second),
406*03ce13f7SAndroid Build Coastguard Worker Reloc->getEmitString()));
407*03ce13f7SAndroid Build Coastguard Worker }
408*03ce13f7SAndroid Build Coastguard Worker return Reloc;
409*03ce13f7SAndroid Build Coastguard Worker }
410*03ce13f7SAndroid Build Coastguard Worker
instrumentAccess(LoweringContext & Context,Operand * Op,SizeT Size,Constant * CheckFunc)411*03ce13f7SAndroid Build Coastguard Worker void ASanInstrumentation::instrumentAccess(LoweringContext &Context,
412*03ce13f7SAndroid Build Coastguard Worker Operand *Op, SizeT Size,
413*03ce13f7SAndroid Build Coastguard Worker Constant *CheckFunc) {
414*03ce13f7SAndroid Build Coastguard Worker // Skip redundant checks within basic blocks
415*03ce13f7SAndroid Build Coastguard Worker VarSizeMap *Checked = ICE_TLS_GET_FIELD(CheckedVars);
416*03ce13f7SAndroid Build Coastguard Worker if (ICE_TLS_GET_FIELD(CurNode) != Context.getNode()) {
417*03ce13f7SAndroid Build Coastguard Worker ICE_TLS_SET_FIELD(CurNode, Context.getNode());
418*03ce13f7SAndroid Build Coastguard Worker if (Checked == NULL) {
419*03ce13f7SAndroid Build Coastguard Worker Checked = new VarSizeMap();
420*03ce13f7SAndroid Build Coastguard Worker ICE_TLS_SET_FIELD(CheckedVars, Checked);
421*03ce13f7SAndroid Build Coastguard Worker }
422*03ce13f7SAndroid Build Coastguard Worker Checked->clear();
423*03ce13f7SAndroid Build Coastguard Worker }
424*03ce13f7SAndroid Build Coastguard Worker VarSizeMap::iterator PrevCheck = Checked->find(Op);
425*03ce13f7SAndroid Build Coastguard Worker if (PrevCheck != Checked->end() && PrevCheck->second >= Size)
426*03ce13f7SAndroid Build Coastguard Worker return;
427*03ce13f7SAndroid Build Coastguard Worker else
428*03ce13f7SAndroid Build Coastguard Worker Checked->insert({Op, Size});
429*03ce13f7SAndroid Build Coastguard Worker
430*03ce13f7SAndroid Build Coastguard Worker // check for known good local access
431*03ce13f7SAndroid Build Coastguard Worker VarSizeMap::iterator LocalSize = ICE_TLS_GET_FIELD(LocalVars)->find(Op);
432*03ce13f7SAndroid Build Coastguard Worker if (LocalSize != ICE_TLS_GET_FIELD(LocalVars)->end() &&
433*03ce13f7SAndroid Build Coastguard Worker LocalSize->second >= Size)
434*03ce13f7SAndroid Build Coastguard Worker return;
435*03ce13f7SAndroid Build Coastguard Worker if (isOkGlobalAccess(Op, Size))
436*03ce13f7SAndroid Build Coastguard Worker return;
437*03ce13f7SAndroid Build Coastguard Worker constexpr SizeT NumArgs = 2;
438*03ce13f7SAndroid Build Coastguard Worker constexpr Variable *Void = nullptr;
439*03ce13f7SAndroid Build Coastguard Worker constexpr bool NoTailCall = false;
440*03ce13f7SAndroid Build Coastguard Worker auto *Call = InstCall::create(Context.getNode()->getCfg(), NumArgs, Void,
441*03ce13f7SAndroid Build Coastguard Worker CheckFunc, NoTailCall);
442*03ce13f7SAndroid Build Coastguard Worker Call->addArg(Op);
443*03ce13f7SAndroid Build Coastguard Worker Call->addArg(ConstantInteger32::create(Ctx, IceType_i32, Size));
444*03ce13f7SAndroid Build Coastguard Worker // play games to insert the call before the access instruction
445*03ce13f7SAndroid Build Coastguard Worker InstList::iterator Next = Context.getNext();
446*03ce13f7SAndroid Build Coastguard Worker Context.setInsertPoint(Context.getCur());
447*03ce13f7SAndroid Build Coastguard Worker Context.insert(Call);
448*03ce13f7SAndroid Build Coastguard Worker Context.setNext(Next);
449*03ce13f7SAndroid Build Coastguard Worker }
450*03ce13f7SAndroid Build Coastguard Worker
451*03ce13f7SAndroid Build Coastguard Worker // TODO(tlively): Trace back load and store addresses to find their real offsets
isOkGlobalAccess(Operand * Op,SizeT Size)452*03ce13f7SAndroid Build Coastguard Worker bool ASanInstrumentation::isOkGlobalAccess(Operand *Op, SizeT Size) {
453*03ce13f7SAndroid Build Coastguard Worker auto *Reloc = llvm::dyn_cast<ConstantRelocatable>(Op);
454*03ce13f7SAndroid Build Coastguard Worker if (Reloc == nullptr)
455*03ce13f7SAndroid Build Coastguard Worker return false;
456*03ce13f7SAndroid Build Coastguard Worker RelocOffsetT Offset = Reloc->getOffset();
457*03ce13f7SAndroid Build Coastguard Worker GlobalSizeMap::iterator GlobalSize = GlobalSizes.find(Reloc->getName());
458*03ce13f7SAndroid Build Coastguard Worker return GlobalSize != GlobalSizes.end() && GlobalSize->second - Offset >= Size;
459*03ce13f7SAndroid Build Coastguard Worker }
460*03ce13f7SAndroid Build Coastguard Worker
instrumentRet(LoweringContext & Context,InstRet *)461*03ce13f7SAndroid Build Coastguard Worker void ASanInstrumentation::instrumentRet(LoweringContext &Context, InstRet *) {
462*03ce13f7SAndroid Build Coastguard Worker Cfg *Func = Context.getNode()->getCfg();
463*03ce13f7SAndroid Build Coastguard Worker Context.setInsertPoint(Context.getCur());
464*03ce13f7SAndroid Build Coastguard Worker for (InstStore *RzUnpoison : *ICE_TLS_GET_FIELD(LocalDtors)) {
465*03ce13f7SAndroid Build Coastguard Worker Context.insert(InstStore::create(Func, RzUnpoison->getData(),
466*03ce13f7SAndroid Build Coastguard Worker RzUnpoison->getStoreAddress()));
467*03ce13f7SAndroid Build Coastguard Worker }
468*03ce13f7SAndroid Build Coastguard Worker Context.advanceCur();
469*03ce13f7SAndroid Build Coastguard Worker Context.advanceNext();
470*03ce13f7SAndroid Build Coastguard Worker }
471*03ce13f7SAndroid Build Coastguard Worker
instrumentStart(Cfg * Func)472*03ce13f7SAndroid Build Coastguard Worker void ASanInstrumentation::instrumentStart(Cfg *Func) {
473*03ce13f7SAndroid Build Coastguard Worker Constant *ShadowMemInit =
474*03ce13f7SAndroid Build Coastguard Worker Ctx->getConstantExternSym(Ctx->getGlobalString("__asan_init"));
475*03ce13f7SAndroid Build Coastguard Worker constexpr SizeT NumArgs = 3;
476*03ce13f7SAndroid Build Coastguard Worker constexpr Variable *Void = nullptr;
477*03ce13f7SAndroid Build Coastguard Worker constexpr bool NoTailCall = false;
478*03ce13f7SAndroid Build Coastguard Worker auto *Call = InstCall::create(Func, NumArgs, Void, ShadowMemInit, NoTailCall);
479*03ce13f7SAndroid Build Coastguard Worker Func->getEntryNode()->getInsts().push_front(Call);
480*03ce13f7SAndroid Build Coastguard Worker
481*03ce13f7SAndroid Build Coastguard Worker instrumentGlobals(*getGlobals());
482*03ce13f7SAndroid Build Coastguard Worker
483*03ce13f7SAndroid Build Coastguard Worker Call->addArg(ConstantInteger32::create(Ctx, IceType_i32, RzGlobalsNum));
484*03ce13f7SAndroid Build Coastguard Worker Call->addArg(Ctx->getConstantSym(0, Ctx->getGlobalString(RzArrayName)));
485*03ce13f7SAndroid Build Coastguard Worker Call->addArg(Ctx->getConstantSym(0, Ctx->getGlobalString(RzSizesName)));
486*03ce13f7SAndroid Build Coastguard Worker }
487*03ce13f7SAndroid Build Coastguard Worker
488*03ce13f7SAndroid Build Coastguard Worker // TODO(tlively): make this more efficient with swap idiom
finishFunc(Cfg *)489*03ce13f7SAndroid Build Coastguard Worker void ASanInstrumentation::finishFunc(Cfg *) {
490*03ce13f7SAndroid Build Coastguard Worker ICE_TLS_GET_FIELD(LocalVars)->clear();
491*03ce13f7SAndroid Build Coastguard Worker ICE_TLS_GET_FIELD(LocalDtors)->clear();
492*03ce13f7SAndroid Build Coastguard Worker }
493*03ce13f7SAndroid Build Coastguard Worker
494*03ce13f7SAndroid Build Coastguard Worker } // end of namespace Ice
495