1 : // Copyright 2012 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : #include "syzygy/instrument/transforms/asan_transform.h"
16 :
17 : #include <algorithm>
18 : #include <list>
19 : #include <vector>
20 :
21 : #include "base/logging.h"
22 : #include "base/rand_util.h"
23 : #include "base/memory/ref_counted.h"
24 : #include "base/memory/scoped_vector.h"
25 : #include "base/strings/string_util.h"
26 : #include "base/strings/stringprintf.h"
27 : #include "syzygy/block_graph/basic_block.h"
28 : #include "syzygy/block_graph/basic_block_assembler.h"
29 : #include "syzygy/block_graph/block_builder.h"
30 : #include "syzygy/block_graph/block_util.h"
31 : #include "syzygy/block_graph/typed_block.h"
32 : #include "syzygy/common/defs.h"
33 : #include "syzygy/instrument/transforms/asan_intercepts.h"
34 : #include "syzygy/instrument/transforms/entry_thunk_transform.h"
35 : #include "syzygy/pe/pe_utils.h"
36 : #include "syzygy/pe/transforms/add_hot_patching_metadata_transform.h"
37 : #include "syzygy/pe/transforms/coff_add_imports_transform.h"
38 : #include "syzygy/pe/transforms/coff_rename_symbols_transform.h"
39 : #include "syzygy/pe/transforms/pe_hot_patching_basic_block_transform.h"
40 : #include "third_party/distorm/files/include/mnemonics.h"
41 : #include "third_party/distorm/files/src/x86defs.h"
42 :
43 : namespace instrument {
44 : namespace transforms {
45 : namespace {
46 :
47 : using block_graph::BasicBlock;
48 : using block_graph::BasicCodeBlock;
49 : using block_graph::BasicBlockAssembler;
50 : using block_graph::BasicBlockSubGraph;
51 : using block_graph::BasicBlockReference;
52 : using block_graph::BlockBuilder;
53 : using block_graph::BlockGraph;
54 : using block_graph::Displacement;
55 : using block_graph::Immediate;
56 : using block_graph::Instruction;
57 : using block_graph::Operand;
58 : using block_graph::TransformPolicyInterface;
59 : using block_graph::TypedBlock;
60 : using block_graph::analysis::LivenessAnalysis;
61 : using block_graph::analysis::MemoryAccessAnalysis;
62 : using assm::Register32;
63 : using pe::transforms::CoffAddImportsTransform;
64 : using pe::transforms::ImportedModule;
65 : using pe::transforms::PEAddImportsTransform;
66 : using pe::transforms::PECoffAddImportsTransform;
67 :
68 : // A simple struct that can be used to let us access strings using TypedBlock.
69 : struct StringStruct {
70 : const char string[1];
71 : };
72 :
73 : typedef AsanBasicBlockTransform::MemoryAccessMode AsanMemoryAccessMode;
74 : typedef AsanBasicBlockTransform::AsanHookMap HookMap;
75 : typedef std::vector<AsanBasicBlockTransform::AsanHookMapEntryKey>
76 : AccessHookParamVector;
77 : typedef TypedBlock<IMAGE_IMPORT_DESCRIPTOR> ImageImportDescriptor;
78 : typedef TypedBlock<StringStruct> String;
79 :
80 : // The timestamp 1 corresponds to Thursday, 01 Jan 1970 00:00:01 GMT. Setting
81 : // the timestamp of the image import descriptor to this value allows us to
82 : // temporarily bind the library until the loader finishes loading this module.
83 : // As the value is far in the past this means that the entries in the IAT for
84 : // this module will all be replaced by pointers into the actual library.
85 : // We need to bind the IAT for our module to make sure the stub is used until
86 : // the sandbox lets the loader finish patching the IAT entries.
87 : static const size_t kDateInThePast = 1;
88 :
89 : // Returns true iff opcode should be instrumented.
90 E : bool ShouldInstrumentOpcode(uint16_t opcode) {
91 E : switch (opcode) {
92 : // LEA does not actually access memory.
93 : case I_LEA:
94 E : return false;
95 :
96 : // We can ignore the prefetch and clflush instructions. The instrumentation
97 : // will detect memory errors if and when the memory is actually accessed.
98 : case I_CLFLUSH:
99 : case I_PREFETCH:
100 : case I_PREFETCHNTA:
101 : case I_PREFETCHT0:
102 : case I_PREFETCHT1:
103 : case I_PREFETCHT2:
104 : case I_PREFETCHW:
105 i : return false;
106 : }
107 E : return true;
108 E : }
109 :
110 : // Computes the correct displacement, if any, for operand
111 : // number @p operand of @p instr.
112 : BasicBlockAssembler::Displacement ComputeDisplacementForOperand(
113 E : const Instruction& instr, size_t operand) {
114 E : const _DInst& repr = instr.representation();
115 :
116 E : DCHECK(repr.ops[operand].type == O_SMEM ||
117 : repr.ops[operand].type == O_MEM);
118 :
119 E : size_t access_size_bytes = repr.ops[operand].size / 8;
120 E : if (repr.dispSize == 0)
121 E : return Displacement(access_size_bytes - 1);
122 :
123 E : BasicBlockReference reference;
124 E : if (instr.FindOperandReference(operand, &reference)) {
125 E : if (reference.referred_type() == BasicBlockReference::REFERRED_TYPE_BLOCK) {
126 E : return Displacement(reference.block(),
127 : reference.offset() + access_size_bytes - 1);
128 i : } else {
129 E : return Displacement(reference.basic_block());
130 : }
131 i : } else {
132 E : return Displacement(repr.disp + access_size_bytes - 1);
133 : }
134 E : }
135 :
136 : // Returns true if operand @p op is instrumentable, e.g.
137 : // if it implies a memory access.
138 E : bool IsInstrumentable(const _Operand& op) {
139 E : switch (op.type) {
140 : case O_SMEM:
141 : case O_MEM:
142 E : return true;
143 :
144 : default:
145 E : return false;
146 : }
147 E : }
148 :
149 : // Returns true if opcode @p opcode is a special instruction.
150 : // Memory checks for special instructions (string instructions, instructions
151 : // with prefix, etc) are handled by calling specialized functions rather than
152 : // the standard memory checks.
153 E : bool IsSpecialInstruction(uint16_t opcode) {
154 E : switch (opcode) {
155 : case I_CMPS:
156 : case I_STOS:
157 : case I_MOVS:
158 E : return true;
159 :
160 : default:
161 E : return false;
162 : }
163 E : }
164 :
165 : // Decodes the first O_MEM or O_SMEM operand of @p instr, if any to the
166 : // corresponding Operand.
167 : bool DecodeMemoryAccess(const Instruction& instr,
168 : BasicBlockAssembler::Operand* access,
169 E : AsanBasicBlockTransform::MemoryAccessInfo* info) {
170 E : DCHECK(access != NULL);
171 E : DCHECK(info != NULL);
172 E : const _DInst& repr = instr.representation();
173 :
174 : // Don't instrument NOP instructions. These can often make reference to
175 : // registers, but their contents aren't actually meaningful.
176 E : if (core::IsNop(repr))
177 E : return false;
178 :
179 : // Figure out which operand we're instrumenting.
180 E : size_t mem_op_id = SIZE_MAX;
181 E : if (IsInstrumentable(repr.ops[0]) && IsInstrumentable(repr.ops[1])) {
182 : // This happens with instructions like: MOVS [EDI], [ESI].
183 E : DCHECK(repr.ops[0].size == repr.ops[1].size);
184 E : mem_op_id = 0;
185 E : } else if (IsInstrumentable(repr.ops[0])) {
186 : // The first operand is instrumentable.
187 E : mem_op_id = 0;
188 E : } else if (IsInstrumentable(repr.ops[1])) {
189 : // The second operand is instrumentable.
190 E : mem_op_id = 1;
191 E : } else {
192 : // Neither of the first two operands is instrumentable.
193 E : return false;
194 : }
195 :
196 : // Determine the size of the access.
197 E : info->size = repr.ops[mem_op_id].size / 8;
198 :
199 : // Determine the kind of access (read/write/instr/repz).
200 E : if (FLAG_GET_PREFIX(repr.flags) & FLAG_REPNZ) {
201 i : info->mode = AsanBasicBlockTransform::kRepnzAccess;
202 E : } else if (FLAG_GET_PREFIX(repr.flags) & FLAG_REP) {
203 E : info->mode = AsanBasicBlockTransform::kRepzAccess;
204 E : } else if (IsSpecialInstruction(instr.opcode())) {
205 E : info->mode = AsanBasicBlockTransform::kInstrAccess;
206 E : } else if ((repr.flags & FLAG_DST_WR) && mem_op_id == 0) {
207 : // The first operand is written to.
208 E : info->mode = AsanBasicBlockTransform::kWriteAccess;
209 E : } else {
210 E : info->mode = AsanBasicBlockTransform::kReadAccess;
211 : }
212 :
213 : // Determine the opcode of this instruction (when needed).
214 : if (info->mode == AsanBasicBlockTransform::kRepnzAccess ||
215 E : info->mode == AsanBasicBlockTransform::kRepzAccess ||
216 : info->mode == AsanBasicBlockTransform::kInstrAccess) {
217 E : info->opcode = instr.opcode();
218 : }
219 :
220 : // Determine operand of the access.
221 E : if (repr.ops[mem_op_id].type == O_SMEM) {
222 : // Simple memory dereference with optional displacement.
223 E : const Register32& base_reg = assm::CastAsRegister32(
224 : core::GetRegister(repr.ops[mem_op_id].index));
225 :
226 : // Get the displacement for the operand.
227 E : auto displ = ComputeDisplacementForOperand(instr, mem_op_id);
228 E : *access = Operand(base_reg, displ);
229 E : } else if (repr.ops[0].type == O_MEM || repr.ops[1].type == O_MEM) {
230 : // Complex memory dereference.
231 E : const Register32& index_reg = assm::CastAsRegister32(
232 : core::GetRegister(repr.ops[mem_op_id].index));
233 :
234 E : assm::ScaleFactor scale = assm::kTimes1;
235 E : switch (repr.scale) {
236 : case 2:
237 E : scale = assm::kTimes2;
238 E : break;
239 : case 4:
240 E : scale = assm::kTimes4;
241 E : break;
242 : case 8:
243 E : scale = assm::kTimes8;
244 : break;
245 : default:
246 : break;
247 : }
248 :
249 : // Get the displacement for the operand (if any).
250 E : auto displ = ComputeDisplacementForOperand(instr, mem_op_id);
251 :
252 : // Compute the full operand.
253 E : if (repr.base != R_NONE) {
254 E : const Register32& base_reg = assm::CastAsRegister32(
255 : core::GetRegister(repr.base));
256 :
257 E : if (displ.size() == assm::kSizeNone) {
258 : // No displacement, it's a [base + index * scale] access.
259 i : *access = Operand(base_reg, index_reg, scale);
260 i : } else {
261 : // This is a [base + index * scale + displ] access.
262 E : *access = Operand(base_reg, index_reg, scale, displ);
263 : }
264 E : } else {
265 : // No base, this is an [index * scale + displ] access.
266 : // TODO(siggi): AFAIK, there's no encoding for [index * scale] without
267 : // a displacement. If this assert fires, I'm proven wrong.
268 E : DCHECK_NE(assm::kSizeNone, displ.size());
269 :
270 E : *access = Operand(index_reg, scale, displ);
271 : }
272 E : } else {
273 i : NOTREACHED();
274 i : return false;
275 : }
276 :
277 E : return true;
278 E : }
279 :
280 : // Use @p bb_asm to inject a hook to @p hook to instrument the access to the
281 : // address stored in the operand @p op.
282 : void InjectAsanHook(BasicBlockAssembler* bb_asm,
283 : const AsanBasicBlockTransform::MemoryAccessInfo& info,
284 : const BasicBlockAssembler::Operand& op,
285 : BlockGraph::Reference* hook,
286 : const LivenessAnalysis::State& state,
287 E : BlockGraph::ImageFormat image_format) {
288 E : DCHECK(hook != NULL);
289 :
290 : // Determine which kind of probe to inject.
291 : // - The standard load/store probe assume the address is in EDX.
292 : // It restore the original version of EDX and cleanup the stack.
293 : // - The special instruction probe take addresses directly in registers.
294 : // The probe doesn't have any effects on stack, registers and flags.
295 E : if (info.mode == AsanBasicBlockTransform::kReadAccess ||
296 : info.mode == AsanBasicBlockTransform::kWriteAccess) {
297 : // Load/store probe.
298 E : bb_asm->push(assm::edx);
299 E : bb_asm->lea(assm::edx, op);
300 : }
301 :
302 : // Call the hook.
303 E : if (image_format == BlockGraph::PE_IMAGE) {
304 : // In PE images the hooks are brought in as imports, so they are indirect
305 : // references.
306 E : bb_asm->call(Operand(Displacement(hook->referenced(), hook->offset())));
307 E : } else {
308 E : DCHECK_EQ(BlockGraph::COFF_IMAGE, image_format);
309 : // In COFF images the hooks are brought in as symbols, so they are direct
310 : // references.
311 E : bb_asm->call(Immediate(hook->referenced(), hook->offset()));
312 : }
313 E : }
314 :
315 : // Get the name of an asan check access function for an @p access_mode access.
316 : // @param info The memory access information, e.g. the size on a load/store,
317 : // the instruction opcode and the kind of access.
318 : std::string GetAsanCheckAccessFunctionName(
319 : AsanBasicBlockTransform::MemoryAccessInfo info,
320 E : BlockGraph::ImageFormat image_format) {
321 E : DCHECK(info.mode != AsanBasicBlockTransform::kNoAccess);
322 E : DCHECK_NE(0U, info.size);
323 E : DCHECK(info.mode == AsanBasicBlockTransform::kReadAccess ||
324 : info.mode == AsanBasicBlockTransform::kWriteAccess ||
325 : info.opcode != 0);
326 :
327 E : const char* rep_str = NULL;
328 E : if (info.mode == AsanBasicBlockTransform::kRepzAccess)
329 E : rep_str = "_repz";
330 E : else if (info.mode == AsanBasicBlockTransform::kRepnzAccess)
331 i : rep_str = "_repnz";
332 i : else
333 E : rep_str = "";
334 :
335 E : const char* access_mode_str = NULL;
336 E : if (info.mode == AsanBasicBlockTransform::kReadAccess)
337 E : access_mode_str = "read";
338 E : else if (info.mode == AsanBasicBlockTransform::kWriteAccess)
339 E : access_mode_str = "write";
340 E : else
341 E : access_mode_str = reinterpret_cast<char*>(GET_MNEMONIC_NAME(info.opcode));
342 :
343 : // For COFF images we use the decorated function name, which contains a
344 : // leading underscore.
345 : std::string function_name =
346 E : base::StringPrintf("%sasan_check%s_%d_byte_%s_access%s",
347 : image_format == BlockGraph::PE_IMAGE ? "" : "_",
348 : rep_str,
349 : info.size,
350 : access_mode_str,
351 : info.save_flags ? "" : "_no_flags");
352 E : function_name = base::ToLowerASCII(function_name);
353 E : return function_name;
354 E : }
355 :
356 : // Add imports from the specified module to the block graph, altering the
357 : // contents of its header/special blocks.
358 : // @param policy the policy object restricting how the transform is applied.
359 : // @param block_graph the block graph to modify.
360 : // @param header_block the header block of @p block_graph.
361 : // @param module the module to import, with its symbols.
362 : // @returns true on success, or false on failure.
363 : bool AddImportsFromModule(const TransformPolicyInterface* policy,
364 : BlockGraph* block_graph,
365 : BlockGraph::Block* header_block,
366 E : ImportedModule* module) {
367 E : if (block_graph->image_format() == BlockGraph::PE_IMAGE) {
368 E : PEAddImportsTransform transform;
369 E : transform.AddModule(module);
370 E : if (!ApplyBlockGraphTransform(&transform, policy,
371 : block_graph, header_block)) {
372 i : return false;
373 : }
374 E : } else {
375 E : DCHECK_EQ(BlockGraph::COFF_IMAGE, block_graph->image_format());
376 E : CoffAddImportsTransform transform;
377 E : transform.AddModule(module);
378 E : if (!ApplyBlockGraphTransform(&transform, policy,
379 : block_graph, header_block)) {
380 i : return false;
381 : }
382 E : }
383 :
384 E : return true;
385 E : }
386 :
387 : // Add the imports for the asan check access hooks to the block-graph.
388 : // @param hooks_param_vector A vector of hook parameter values.
389 : // @param default_stub_map Stubs for the asan check access functions.
390 : // @param import_module The module for which the import should be added.
391 : // @param check_access_hook_map The map where the reference to the imports
392 : // should be stored.
393 : // @param policy The policy object restricting how the transform is applied.
394 : // @param block_graph The block-graph to populate.
395 : // @param header_block The block containing the module's DOS header of this
396 : // block-graph.
397 : // @returns True on success, false otherwise.
398 : bool AddAsanCheckAccessHooks(
399 : const AccessHookParamVector& hook_param_vector,
400 : const AsanBasicBlockTransform::AsanDefaultHookMap& default_stub_map,
401 : ImportedModule* import_module,
402 : HookMap* check_access_hook_map,
403 : const TransformPolicyInterface* policy,
404 : BlockGraph* block_graph,
405 E : BlockGraph::Block* header_block) {
406 E : DCHECK(import_module != NULL);
407 E : DCHECK(check_access_hook_map != NULL);
408 E : DCHECK(policy != NULL);
409 E : DCHECK(block_graph != NULL);
410 E : DCHECK(header_block != NULL);
411 :
412 : typedef std::map<AsanBasicBlockTransform::AsanHookMapEntryKey, size_t>
413 : HooksParamsToIdxMap;
414 E : HooksParamsToIdxMap hooks_params_to_idx;
415 :
416 : // Add the hooks to the import module.
417 E : AccessHookParamVector::const_iterator iter_params = hook_param_vector.begin();
418 E : for (; iter_params != hook_param_vector.end(); ++iter_params) {
419 E : size_t symbol_idx = import_module->AddSymbol(
420 : GetAsanCheckAccessFunctionName(*iter_params,
421 : block_graph->image_format()),
422 : ImportedModule::kAlwaysImport);
423 E : hooks_params_to_idx[*iter_params] = symbol_idx;
424 E : }
425 :
426 E : DCHECK_EQ(hooks_params_to_idx.size(), hook_param_vector.size());
427 :
428 : // Add the imports. This takes care of invoking the appropriate format
429 : // specific transform.
430 E : if (!AddImportsFromModule(policy, block_graph, header_block, import_module)) {
431 i : LOG(ERROR) << "Unable to add imports for Asan instrumentation DLL.";
432 i : return false;
433 : }
434 :
435 : // Get a reference to each hook and put it in the hooks map.
436 E : HooksParamsToIdxMap::iterator iter_hooks = hooks_params_to_idx.begin();
437 E : for (; iter_hooks != hooks_params_to_idx.end(); ++iter_hooks) {
438 E : BlockGraph::Reference import_reference;
439 E : if (!import_module->GetSymbolReference(iter_hooks->second,
440 : &import_reference)) {
441 i : LOG(ERROR) << "Unable to get import reference for Asan.";
442 i : return false;
443 : }
444 E : HookMap& hook_map = *check_access_hook_map;
445 E : hook_map[iter_hooks->first] = import_reference;
446 :
447 : // We only need dummy implementation stubs for PE images, as the hooks are
448 : // imported. COFF instrumented images contain the hooks directly.
449 E : if (block_graph->image_format() == BlockGraph::PE_IMAGE) {
450 : // In a Chrome sandboxed process the NtMapViewOfSection function is
451 : // intercepted by the sandbox agent. This causes execution in the
452 : // executable before imports have been resolved, as the ntdll patch
453 : // invokes into the executable while resolving imports. As the Asan
454 : // instrumentation directly refers to the IAT entries we need to
455 : // temporarily stub these function until the Asan imports are resolved. To
456 : // do this we need to make the IAT entries for those functions point to a
457 : // temporarily block and we need to mark the image import descriptor for
458 : // this DLL as bound.
459 : AsanBasicBlockTransform::AsanDefaultHookMap::const_iterator
460 E : stub_reference = default_stub_map.find(iter_hooks->first.mode);
461 E : if (stub_reference == default_stub_map.end()) {
462 i : LOG(ERROR) << "Could not find the default hook for "
463 : << GetAsanCheckAccessFunctionName(iter_hooks->first,
464 : BlockGraph::PE_IMAGE)
465 : << ".";
466 i : return false;
467 : }
468 :
469 E : import_reference.referenced()->SetReference(import_reference.offset(),
470 : stub_reference->second);
471 : }
472 E : }
473 :
474 E : return true;
475 E : }
476 :
477 : // Create a stub for the asan_check_access functions. For load/store, the stub
478 : // consists of a small block of code that restores the value of EDX and returns
479 : // to the caller. Otherwise, the stub do return.
480 : // @param block_graph The block-graph to populate with the stub.
481 : // @param stub_name The stub's name.
482 : // @param mode The kind of memory access.
483 : // @param reference Will receive the reference to the created hook.
484 : // @returns true on success, false otherwise.
485 : bool CreateHooksStub(BlockGraph* block_graph,
486 : const base::StringPiece& stub_name,
487 : AsanBasicBlockTransform::MemoryAccessMode mode,
488 E : BlockGraph::Reference* reference) {
489 E : DCHECK(reference != NULL);
490 :
491 : // Find or create the section we put our thunks in.
492 E : BlockGraph::Section* thunk_section = block_graph->FindOrAddSection(
493 : common::kThunkSectionName, pe::kCodeCharacteristics);
494 :
495 E : if (thunk_section == NULL) {
496 i : LOG(ERROR) << "Unable to find or create .thunks section.";
497 i : return false;
498 : }
499 :
500 E : std::string stub_name_with_id = base::StringPrintf(
501 : "%.*s%d", stub_name.length(), stub_name.data(), mode);
502 :
503 : // Create the thunk for standard "load/store" (received address in EDX).
504 E : BasicBlockSubGraph bbsg;
505 E : BasicBlockSubGraph::BlockDescription* block_desc = bbsg.AddBlockDescription(
506 : stub_name_with_id,
507 : thunk_section->name(),
508 : BlockGraph::CODE_BLOCK,
509 : thunk_section->id(),
510 : 1,
511 : 0);
512 :
513 E : BasicCodeBlock* bb = bbsg.AddBasicCodeBlock(stub_name_with_id);
514 E : block_desc->basic_block_order.push_back(bb);
515 E : BasicBlockAssembler assm(bb->instructions().begin(), &bb->instructions());
516 :
517 E : if (mode == AsanBasicBlockTransform::kReadAccess ||
518 : mode == AsanBasicBlockTransform::kWriteAccess) {
519 : // The thunk body restores the original value of EDX and cleans the stack on
520 : // return.
521 E : assm.mov(assm::edx, Operand(assm::esp, Displacement(4)));
522 E : assm.ret(4);
523 E : } else {
524 E : assm.ret();
525 : }
526 :
527 : // Condense into a block.
528 E : BlockBuilder block_builder(block_graph);
529 E : if (!block_builder.Merge(&bbsg)) {
530 i : LOG(ERROR) << "Failed to build thunk block.";
531 i : return NULL;
532 : }
533 :
534 : // Exactly one new block should have been created.
535 E : DCHECK_EQ(1u, block_builder.new_blocks().size());
536 E : BlockGraph::Block* thunk = block_builder.new_blocks().front();
537 :
538 E : *reference = BlockGraph::Reference(BlockGraph::ABSOLUTE_REF, 4, thunk, 0, 0);
539 :
540 E : return true;
541 E : }
542 :
543 : // Creates stubs for Asan check access hooks (PE only), imports them from the
544 : // runtime module and adds them to the block graph.
545 : // @param asan_hook_stub_name Name prefix of the stubs for the asan check access
546 : // functions.
547 : // @param use_liveness_analysis true iff we use liveness analysis.
548 : // @param import_module The module for which the import should be added.
549 : // @param check_access_hooks_ref The map where the reference to the imports
550 : // should be stored.
551 : // @param policy The policy object restricting how the transform is applied.
552 : // @param block_graph The block-graph to populate.
553 : // @param header_block The block containing the module's DOS header of this
554 : // block-graph.
555 : // @returns True on success, false otherwise.
556 : bool ImportAsanCheckAccessHooks(
557 : const char* asan_hook_stub_name,
558 : bool use_liveness_analysis,
559 : ImportedModule* import_module,
560 : AsanBasicBlockTransform::AsanHookMap* check_access_hooks_ref,
561 : const TransformPolicyInterface* policy,
562 : BlockGraph* block_graph,
563 E : BlockGraph::Block* header_block) {
564 : typedef AsanBasicBlockTransform::MemoryAccessInfo MemoryAccessInfo;
565 :
566 E : AccessHookParamVector access_hook_param_vec;
567 E : AsanBasicBlockTransform::AsanDefaultHookMap default_stub_map;
568 :
569 : // We only need to add stubs for PE images. COFF images use direct references,
570 : // and the linker takes care of dragging in the appropriate code for us.
571 : // Also, hot patching mode does not need the stubs as it will load them
572 : // dynamically at runtime.
573 E : if (block_graph->image_format() == BlockGraph::PE_IMAGE) {
574 : // Create the hook stub for read/write instructions.
575 E : BlockGraph::Reference read_write_hook;
576 E : if (!CreateHooksStub(block_graph, asan_hook_stub_name,
577 : AsanBasicBlockTransform::kReadAccess,
578 : &read_write_hook)) {
579 i : return false;
580 : }
581 :
582 : // Create the hook stub for strings instructions.
583 E : BlockGraph::Reference instr_hook;
584 E : if (!CreateHooksStub(block_graph, asan_hook_stub_name,
585 : AsanBasicBlockTransform::kInstrAccess,
586 : &instr_hook)) {
587 i : return false;
588 : }
589 :
590 : // Map each memory access kind to an appropriate stub.
591 E : default_stub_map[AsanBasicBlockTransform::kReadAccess] = read_write_hook;
592 E : default_stub_map[AsanBasicBlockTransform::kWriteAccess] = read_write_hook;
593 E : default_stub_map[AsanBasicBlockTransform::kInstrAccess] = instr_hook;
594 E : default_stub_map[AsanBasicBlockTransform::kRepzAccess] = instr_hook;
595 E : default_stub_map[AsanBasicBlockTransform::kRepnzAccess] = instr_hook;
596 : }
597 :
598 : // Import the hooks for the read/write accesses.
599 E : for (int access_size = 1; access_size <= 32; access_size *= 2) {
600 : MemoryAccessInfo read_info =
601 E : { AsanBasicBlockTransform::kReadAccess, access_size, 0, true };
602 E : access_hook_param_vec.push_back(read_info);
603 E : if (use_liveness_analysis) {
604 E : read_info.save_flags = false;
605 E : access_hook_param_vec.push_back(read_info);
606 : }
607 :
608 : MemoryAccessInfo write_info =
609 E : { AsanBasicBlockTransform::kWriteAccess, access_size, 0, true };
610 E : access_hook_param_vec.push_back(write_info);
611 E : if (use_liveness_analysis) {
612 E : write_info.save_flags = false;
613 E : access_hook_param_vec.push_back(write_info);
614 : }
615 E : }
616 :
617 : // Import the hooks for the read/write 10-byte accesses.
618 : MemoryAccessInfo read_info_10 =
619 E : { AsanBasicBlockTransform::kReadAccess, 10, 0, true };
620 E : access_hook_param_vec.push_back(read_info_10);
621 E : if (use_liveness_analysis) {
622 E : read_info_10.save_flags = false;
623 E : access_hook_param_vec.push_back(read_info_10);
624 : }
625 :
626 : MemoryAccessInfo write_info_10 =
627 E : { AsanBasicBlockTransform::kWriteAccess, 10, 0, true };
628 E : access_hook_param_vec.push_back(write_info_10);
629 E : if (use_liveness_analysis) {
630 E : write_info_10.save_flags = false;
631 E : access_hook_param_vec.push_back(write_info_10);
632 : }
633 :
634 : // Import the hooks for string/prefix memory accesses.
635 E : const _InstructionType strings[] = { I_CMPS, I_MOVS, I_STOS };
636 E : int strings_length = sizeof(strings)/sizeof(_InstructionType);
637 :
638 E : for (int access_size = 1; access_size <= 4; access_size *= 2) {
639 E : for (int inst = 0; inst < strings_length; ++inst) {
640 : MemoryAccessInfo repz_inst_info = {
641 E : AsanBasicBlockTransform::kRepzAccess,
642 E : access_size,
643 E : strings[inst],
644 E : true
645 : };
646 E : access_hook_param_vec.push_back(repz_inst_info);
647 :
648 : MemoryAccessInfo inst_info = {
649 E : AsanBasicBlockTransform::kInstrAccess,
650 E : access_size,
651 E : strings[inst],
652 E : true
653 : };
654 E : access_hook_param_vec.push_back(inst_info);
655 E : }
656 E : }
657 :
658 E : if (!AddAsanCheckAccessHooks(access_hook_param_vec,
659 : default_stub_map,
660 : import_module,
661 : check_access_hooks_ref,
662 : policy,
663 : block_graph,
664 : header_block)) {
665 i : return false;
666 : }
667 :
668 E : return true;
669 E : }
670 :
671 : // Create a thunk that does the following call:
672 : // ::HeapCreate(0, 0x1000, 0);
673 : //
674 : // This block has the same signature as the ::GetProcessHeap function.
675 : //
676 : // As the ::GetProcessHeap function is usually called via an indirect reference
677 : // (i.e. it's an entry in the IAT) this function returns also an indirect
678 : // reference to the replacement block. To do this it first creates a code block,
679 : // and then a data block containing a reference t it. It returns the data block.
680 : //
681 : // @param block_graph the block graph that should receive this thunk.
682 : // @param thunk_name The name of the thunk to create. This name will be used to
683 : // name the code block that gets created, the data block will append '_data'
684 : // to it.
685 : // @param heap_create_ref The reference to the heap create function.
686 : // @returns a pointer to a data block that contains a reference to this block,
687 : // nullptr otherwise.
688 : BlockGraph::Block* CreateGetProcessHeapReplacement(
689 : BlockGraph* block_graph,
690 : base::StringPiece thunk_name,
691 E : const BlockGraph::Reference& heap_create_ref) {
692 : // Find or create the section we put our thunks in.
693 E : BlockGraph::Section* thunk_section = block_graph->FindOrAddSection(
694 : common::kThunkSectionName, pe::kCodeCharacteristics);
695 :
696 E : if (thunk_section == NULL) {
697 i : LOG(ERROR) << "Unable to find or create .thunks section.";
698 i : return nullptr;
699 : }
700 :
701 E : BasicBlockSubGraph code_bbsg;
702 : BasicBlockSubGraph::BlockDescription* code_block_desc =
703 E : code_bbsg.AddBlockDescription(thunk_name,
704 : thunk_section->name(),
705 : BlockGraph::CODE_BLOCK,
706 : thunk_section->id(),
707 : 1,
708 : 0);
709 :
710 E : BasicCodeBlock* code_bb = code_bbsg.AddBasicCodeBlock(thunk_name);
711 E : code_block_desc->basic_block_order.push_back(code_bb);
712 E : BasicBlockAssembler assm(code_bb->instructions().begin(),
713 : &code_bb->instructions());
714 E : assm.push(Immediate(0U, assm::kSize32Bit));
715 E : assm.push(Immediate(0x1000U, assm::kSize32Bit));
716 E : assm.push(Immediate(0U, assm::kSize32Bit));
717 E : assm.call(Operand(Displacement(heap_create_ref.referenced(),
718 : heap_create_ref.offset())));
719 E : assm.ret();
720 :
721 : // Condense into a block.
722 E : BlockBuilder block_builder(block_graph);
723 E : if (!block_builder.Merge(&code_bbsg)) {
724 i : LOG(ERROR) << "Failed to build thunk block.";
725 i : return nullptr;
726 : }
727 :
728 : // Exactly one new block should have been created.
729 E : DCHECK_EQ(1u, block_builder.new_blocks().size());
730 E : BlockGraph::Block* code_block = block_builder.new_blocks().front();
731 :
732 : // Create a data block containing the address of the new code block, it'll be
733 : // use to call it via an indirect reference.
734 : std::string data_block_name =
735 E : base::StringPrintf("%s_data", thunk_name.data());
736 E : BlockGraph::Reference ref(BlockGraph::ABSOLUTE_REF, 4, code_block, 0, 0);
737 E : BlockGraph::Block* data_block = block_graph->AddBlock(BlockGraph::DATA_BLOCK,
738 : ref.size(),
739 : data_block_name);
740 E : data_block->set_section(thunk_section->id());
741 E : data_block->SetReference(0, ref);
742 :
743 E : return data_block;
744 E : }
745 :
746 : // Since MSVS 2012 the implementation of the CRT _heap_init function has
747 : // changed and as a result the CRT defers all its allocation to the process
748 : // heap. Since MSVS 2015 the function has changed names to
749 : // _acrt_heap_initialize.
750 : //
751 : // As we don't want to replace the process heap by an Asan heap we need to
752 : // patch this function to make it use ::HeapCreate instead of
753 : // ::GetProcessHeap.
754 : //
755 : // We do this by replacing the reference to ::GetProcessHeap by a reference
756 : // to a thunk that calls ::HeapCreate.
757 : //
758 : // TODO(sebmarchand): Also patch the _heap_term/_acrt_uninitialize_heap
759 : // functions. These functions arent't always present and is just used to
760 : // reset the crt_heap pointer and free the underlying heap. This isn't so
761 : // important in this case because it only happens when the process
762 : // terminates and the heap will be automatically freed when we unload the
763 : // SyzyAsan agent DLL.
764 : //
765 : // @param block_graph The block-graph to populate with the stub.
766 : // @param header_block the header block of @p block_graph.
767 : // @param policy the policy object restricting how the transform is applied.
768 : // @param heap_create_dll_name the name of the DLL exporting the ::HeapCreate
769 : // function, it is either kernel32.dll or the name of the agent DLL used
770 : // by this transform.
771 : // @param heap_create_function_name the name of the ::HeapCreate export in
772 : // |heap_create_dll_name|.
773 : // @param heap_init_blocks The heap initialization functions that we want to
774 : // patch.
775 : // @returns true on success, false otherwise.
776 : bool PatchCRTHeapInitialization(
777 : BlockGraph* block_graph,
778 : BlockGraph::Block* header_block,
779 : const TransformPolicyInterface* policy,
780 : base::StringPiece heap_create_dll_name,
781 : base::StringPiece heap_create_function_name,
782 E : const std::vector<BlockGraph::Block*>& heap_init_blocks) {
783 E : DCHECK_NE(static_cast<BlockGraph*>(nullptr), block_graph);
784 E : DCHECK_NE(static_cast<BlockGraph::Block*>(nullptr), header_block);
785 E : DCHECK_NE(static_cast<const TransformPolicyInterface*>(nullptr), policy);
786 :
787 : // Add the |heap_create_dll_name| module.
788 E : ImportedModule heap_create_module(heap_create_dll_name);
789 E : size_t heap_create_idx = heap_create_module.AddSymbol(
790 : heap_create_function_name, ImportedModule::kAlwaysImport);
791 :
792 : // Add the module containing the GetProcessHeap function.
793 E : ImportedModule* kernel32_module = nullptr;
794 : // This scoped pointer will only be used if we need to dynamically allocate
795 : // the kernel32 module to make sure that it gets correctly freed.
796 E : const char* kKernel32 = "kernel32.dll";
797 E : std::unique_ptr<ImportedModule> scoped_get_process_heap_module;
798 : if (base::CompareCaseInsensitiveASCII(heap_create_dll_name,
799 E : kKernel32) != 0) {
800 E : scoped_get_process_heap_module.reset(new ImportedModule(kKernel32));
801 E : kernel32_module = scoped_get_process_heap_module.get();
802 E : } else {
803 E : kernel32_module = &heap_create_module;
804 : }
805 E : size_t get_process_heap_idx = kernel32_module->AddSymbol(
806 : "GetProcessHeap", ImportedModule::kFindOnly);
807 :
808 : // Apply the AddImport transform to add or find the required modules.
809 E : PEAddImportsTransform transform;
810 E : transform.AddModule(&heap_create_module);
811 E : if (kernel32_module != &heap_create_module)
812 E : transform.AddModule(kernel32_module);
813 E : if (!ApplyBlockGraphTransform(&transform, policy,
814 : block_graph, header_block)) {
815 i : LOG(ERROR) << "Unable to add or find the imports required to patch the CRT "
816 : << "heap initialization.";
817 i : return false;
818 : }
819 :
820 E : BlockGraph::Reference heap_create_ref;
821 E : CHECK(heap_create_module.GetSymbolReference(heap_create_idx,
822 : &heap_create_ref));
823 :
824 : // Create the GetProcessHeap replacement function.
825 E : BlockGraph::Block* get_process_heap_stub = CreateGetProcessHeapReplacement(
826 : block_graph, "asan_get_process_heap_replacement", heap_create_ref);
827 :
828 E : BlockGraph::Reference get_process_heap_ref;
829 E : CHECK(kernel32_module->GetSymbolReference(get_process_heap_idx,
830 : &get_process_heap_ref));
831 :
832 E : BlockGraph::Reference new_ref(BlockGraph::ABSOLUTE_REF,
833 : get_process_heap_ref.size(),
834 : get_process_heap_stub, 0U, 0U);
835 : // Iterates over the list of blocks to patch.
836 E : for (auto iter : heap_init_blocks) {
837 E : VLOG(1) << "Patching " << iter->name() << ".";
838 E : for (const auto& ref : iter->references()) {
839 E : if (ref.second == get_process_heap_ref)
840 E : iter->SetReference(ref.first, new_ref);
841 E : }
842 E : }
843 E : return true;
844 E : }
845 :
846 : typedef std::map<std::string, size_t> ImportNameIndexMap;
847 :
848 : bool PeFindImportsToIntercept(bool use_interceptors,
849 : const AsanIntercept* intercepts,
850 : const TransformPolicyInterface* policy,
851 : BlockGraph* block_graph,
852 : BlockGraph::Block* header_block,
853 : ScopedVector<ImportedModule>* imported_modules,
854 : ImportNameIndexMap* import_name_index_map,
855 : ImportedModule* asan_rtl,
856 E : const char* asan_intercept_prefix) {
857 E : DCHECK_NE(reinterpret_cast<AsanIntercept*>(NULL), intercepts);
858 E : DCHECK_NE(reinterpret_cast<TransformPolicyInterface*>(NULL), policy);
859 E : DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), block_graph);
860 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), header_block);
861 E : DCHECK_NE(reinterpret_cast<ScopedVector<ImportedModule>*>(NULL),
862 E : imported_modules);
863 E : DCHECK_NE(reinterpret_cast<ImportNameIndexMap*>(NULL), import_name_index_map);
864 E : DCHECK_NE(reinterpret_cast<ImportedModule*>(NULL), asan_rtl);
865 :
866 : // Process all of the import intercepts.
867 E : PEAddImportsTransform find_imports;
868 E : ImportedModule* current_module = NULL;
869 E : const char* current_module_name = NULL;
870 E : const AsanIntercept* intercept = intercepts;
871 E : for (; intercept->undecorated_name != NULL; ++intercept) {
872 : // Create a new module to house these imports.
873 E : if (intercept->module != current_module_name) {
874 E : current_module_name = intercept->module;
875 E : current_module = NULL;
876 E : if (current_module_name) {
877 E : current_module = new ImportedModule(current_module_name);
878 E : imported_modules->push_back(current_module);
879 E : find_imports.AddModule(current_module);
880 : }
881 : }
882 :
883 : // If no module name is specified then this interception is not an import
884 : // interception.
885 E : if (current_module_name == NULL)
886 E : continue;
887 :
888 : // Don't process optional intercepts unless asked to.
889 E : if (!use_interceptors && intercept->optional)
890 E : continue;
891 :
892 E : current_module->AddSymbol(intercept->undecorated_name,
893 : ImportedModule::kFindOnly);
894 E : }
895 :
896 : // Query the imports to see which ones are present.
897 E : if (!find_imports.TransformBlockGraph(policy, block_graph, header_block)) {
898 i : LOG(ERROR) << "Unable to find imports for redirection.";
899 i : return false;
900 : }
901 :
902 : // Add Asan imports for those functions found in the import tables. These will
903 : // later be redirected.
904 E : for (const auto& module : *imported_modules) {
905 E : for (size_t i = 0; i < module->size(); ++i) {
906 E : if (!module->SymbolIsImported(i))
907 E : continue;
908 :
909 : // The function should not already be imported. If it is then the
910 : // intercepts data contains duplicates.
911 E : const std::string& function_name = module->GetSymbolName(i);
912 E : DCHECK(import_name_index_map->find(function_name) ==
913 : import_name_index_map->end());
914 :
915 E : std::string asan_function_name = asan_intercept_prefix;
916 E : asan_function_name += function_name;
917 E : size_t index = asan_rtl->AddSymbol(asan_function_name,
918 : ImportedModule::kAlwaysImport);
919 E : import_name_index_map->insert(std::make_pair(function_name, index));
920 E : }
921 E : }
922 :
923 E : return true;
924 E : }
925 :
926 : // Loads the intercepts for the statically linked functions that need to be
927 : // intercepted into the imported module and the import index map.
928 : // @param static_blocks The blocks containing the statically linked functions we
929 : // want to intercept.
930 : // @param import_name_index_map The import index map of the runtime library.
931 : // @param asan_rtl The module of the runtime library.
932 : void PeLoadInterceptsForStaticallyLinkedFunctions(
933 : const AsanTransform::BlockSet& static_blocks,
934 : ImportNameIndexMap* import_name_index_map,
935 : ImportedModule* asan_rtl,
936 E : const char* block_name_prefix) {
937 E : DCHECK_NE(static_cast<ImportNameIndexMap*>(nullptr), import_name_index_map);
938 E : DCHECK_NE(static_cast<ImportedModule*>(nullptr), asan_rtl);
939 :
940 E : for (BlockGraph::Block* block : static_blocks) {
941 : // Don't add an import entry for names that have already been processed.
942 E : if (import_name_index_map->find(block->name()) !=
943 : import_name_index_map->end()) {
944 i : continue;
945 : }
946 :
947 E : std::string name = block_name_prefix;
948 E : name += block->name();
949 E : size_t index = asan_rtl->AddSymbol(name, ImportedModule::kAlwaysImport);
950 E : import_name_index_map->insert(std::make_pair(block->name(), index));
951 E : }
952 E : }
953 :
954 : void PeGetRedirectsForInterceptedImports(
955 : const ScopedVector<ImportedModule>& imported_modules,
956 : const ImportNameIndexMap& import_name_index_map,
957 : const ImportedModule& asan_rtl,
958 E : pe::ReferenceMap* reference_redirect_map) {
959 E : DCHECK_NE(reinterpret_cast<pe::ReferenceMap*>(NULL), reference_redirect_map);
960 :
961 : // Register redirections related to the original.
962 E : for (const auto& module : imported_modules) {
963 E : for (size_t j = 0; j < module->size(); ++j) {
964 E : if (!module->SymbolIsImported(j))
965 E : continue;
966 :
967 : // Get a reference to the original import.
968 E : BlockGraph::Reference src;
969 E : CHECK(module->GetSymbolReference(j, &src));
970 :
971 : // Get a reference to the newly created import.
972 E : const std::string& name = module->GetSymbolName(j);
973 : ImportNameIndexMap::const_iterator import_it =
974 E : import_name_index_map.find(name);
975 E : DCHECK(import_it != import_name_index_map.end());
976 E : BlockGraph::Reference dst;
977 E : CHECK(asan_rtl.GetSymbolReference(import_it->second, &dst));
978 :
979 : // Record the reference mapping.
980 E : reference_redirect_map->insert(
981 : std::make_pair(pe::ReferenceDest(src.referenced(), src.offset()),
982 : pe::ReferenceDest(dst.referenced(), dst.offset())));
983 E : }
984 E : }
985 E : }
986 :
987 : bool PeGetRedirectsForStaticallyLinkedFunctions(
988 : const AsanTransform::BlockSet& static_blocks,
989 : const ImportNameIndexMap& import_name_index_map,
990 : const ImportedModule& asan_rtl,
991 : BlockGraph* block_graph,
992 : pe::ReferenceMap* reference_redirect_map,
993 E : const char* thunk_prefix) {
994 E : DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), block_graph);
995 E : DCHECK_NE(reinterpret_cast<pe::ReferenceMap*>(NULL), reference_redirect_map);
996 :
997 E : BlockGraph::Section* thunk_section = block_graph->FindOrAddSection(
998 : common::kThunkSectionName, pe::kCodeCharacteristics);
999 E : DCHECK_NE(reinterpret_cast<BlockGraph::Section*>(NULL), thunk_section);
1000 :
1001 : typedef std::map<std::string, BlockGraph::Block*> ThunkMap;
1002 E : ThunkMap thunk_map;
1003 E : for (BlockGraph::Block* block : static_blocks) {
1004 E : ThunkMap::iterator thunk_it = thunk_map.find(block->name());
1005 E : if (thunk_it == thunk_map.end()) {
1006 : // Generate the name of the thunk for this function.
1007 E : std::string thunk_name = thunk_prefix;
1008 E : thunk_name += block->name();
1009 E : thunk_name += "_thunk";
1010 :
1011 : // Get a reference to the newly created import.
1012 : ImportNameIndexMap::const_iterator import_it =
1013 E : import_name_index_map.find(block->name());
1014 E : DCHECK(import_it != import_name_index_map.end());
1015 E : BlockGraph::Reference import_ref;
1016 E : CHECK(asan_rtl.GetSymbolReference(import_it->second, &import_ref));
1017 :
1018 : // Generate a basic code block for this thunk.
1019 E : BasicBlockSubGraph bbsg;
1020 : BasicBlockSubGraph::BlockDescription* block_desc =
1021 E : bbsg.AddBlockDescription(thunk_name,
1022 : thunk_section->name(),
1023 : BlockGraph::CODE_BLOCK,
1024 : thunk_section->id(),
1025 : 1,
1026 : 0);
1027 :
1028 E : BasicCodeBlock* bb = bbsg.AddBasicCodeBlock(thunk_name);
1029 E : block_desc->basic_block_order.push_back(bb);
1030 E : BasicBlockAssembler assm(bb->instructions().begin(),
1031 : &bb->instructions());
1032 E : assm.jmp(Operand(Displacement(import_ref.referenced(),
1033 : import_ref.offset())));
1034 :
1035 : // Condense into a block.
1036 E : BlockBuilder block_builder(block_graph);
1037 E : if (!block_builder.Merge(&bbsg)) {
1038 i : LOG(ERROR) << "Failed to build thunk block \"" << thunk_name << "\".";
1039 i : return false;
1040 : }
1041 :
1042 : // Exactly one new block should have been created.
1043 E : DCHECK_EQ(1u, block_builder.new_blocks().size());
1044 E : BlockGraph::Block* thunk = block_builder.new_blocks().front();
1045 E : thunk_it = thunk_map.insert(std::make_pair(block->name(), thunk)).first;
1046 E : }
1047 E : DCHECK(thunk_it != thunk_map.end());
1048 :
1049 : // Register a redirection of references, from the original block to the
1050 : // newly created thunk.
1051 E : reference_redirect_map->insert(std::make_pair(
1052 : pe::ReferenceDest(block, 0),
1053 : pe::ReferenceDest(thunk_it->second, 0)));
1054 E : }
1055 :
1056 E : return true;
1057 E : }
1058 :
1059 : } // namespace
1060 :
1061 : const char AsanBasicBlockTransform::kTransformName[] =
1062 : "SyzyAsanBasicBlockTransform";
1063 :
1064 : bool AsanBasicBlockTransform::InstrumentBasicBlock(
1065 : BasicCodeBlock* basic_block,
1066 : StackAccessMode stack_mode,
1067 E : BlockGraph::ImageFormat image_format) {
1068 E : DCHECK_NE(reinterpret_cast<BasicCodeBlock*>(NULL), basic_block);
1069 :
1070 E : if (instrumentation_rate_ == 0.0)
1071 E : return true;
1072 :
1073 : // Pre-compute liveness information for each instruction.
1074 E : std::list<LivenessAnalysis::State> states;
1075 E : LivenessAnalysis::State state;
1076 E : if (use_liveness_analysis_) {
1077 E : liveness_.GetStateAtExitOf(basic_block, &state);
1078 :
1079 : BasicBlock::Instructions::reverse_iterator rev_iter_inst =
1080 E : basic_block->instructions().rbegin();
1081 : BasicBlock::Instructions::const_reverse_iterator rev_iter_inst_end =
1082 E : basic_block->instructions().rend();
1083 E : for (; rev_iter_inst != rev_iter_inst_end; ++rev_iter_inst) {
1084 E : const Instruction& instr = *rev_iter_inst;
1085 E : liveness_.PropagateBackward(instr, &state);
1086 E : states.push_front(state);
1087 E : }
1088 :
1089 E : DCHECK_EQ(states.size(), basic_block->instructions().size());
1090 : }
1091 :
1092 : // Get the memory accesses information for this basic block.
1093 E : MemoryAccessAnalysis::State memory_state;
1094 E : if (remove_redundant_checks_)
1095 E : memory_accesses_.GetStateAtEntryOf(basic_block, &memory_state);
1096 :
1097 : // Process each instruction and inject a call to Asan when we find an
1098 : // instrumentable memory access.
1099 : BasicBlock::Instructions::iterator iter_inst =
1100 E : basic_block->instructions().begin();
1101 E : std::list<LivenessAnalysis::State>::iterator iter_state = states.begin();
1102 E : for (; iter_inst != basic_block->instructions().end(); ++iter_inst) {
1103 E : auto operand(Operand(assm::eax));
1104 E : const Instruction& instr = *iter_inst;
1105 E : const _DInst& repr = instr.representation();
1106 :
1107 : MemoryAccessInfo info;
1108 E : info.mode = kNoAccess;
1109 E : info.size = 0;
1110 E : info.opcode = 0;
1111 E : info.save_flags = true;
1112 :
1113 : // Get current instruction liveness information.
1114 E : if (use_liveness_analysis_) {
1115 E : state = *iter_state;
1116 E : ++iter_state;
1117 : }
1118 :
1119 : // When activated, skip redundant memory access check.
1120 E : if (remove_redundant_checks_) {
1121 E : bool need_memory_access_check = false;
1122 E : if (memory_state.HasNonRedundantAccess(instr))
1123 E : need_memory_access_check = true;
1124 :
1125 : // Update the memory accesses information for the current instruction.
1126 E : memory_accesses_.PropagateForward(instr, &memory_state);
1127 :
1128 E : if (!need_memory_access_check)
1129 E : continue;
1130 : }
1131 :
1132 : // Insert hook for a standard instruction.
1133 E : if (!DecodeMemoryAccess(instr, &operand, &info))
1134 E : continue;
1135 :
1136 : // Bail if this is not a memory access.
1137 E : if (info.mode == kNoAccess)
1138 i : continue;
1139 :
1140 : // A basic block reference means that can be either a computed jump,
1141 : // or a load from a case table. In either case it doesn't make sense
1142 : // to instrument the access.
1143 E : if (operand.displacement().reference().referred_type() ==
1144 : BasicBlockReference::REFERRED_TYPE_BASIC_BLOCK) {
1145 E : continue;
1146 : }
1147 :
1148 : // A block reference means this instruction is reading or writing to
1149 : // a global variable or some such. It's viable to pad and align global
1150 : // variables and to red-zone the padding, but without that, there's nothing
1151 : // to gain by instrumenting these accesses.
1152 E : if (operand.displacement().reference().referred_type() ==
1153 : BasicBlockReference::REFERRED_TYPE_BLOCK) {
1154 E : continue;
1155 : }
1156 :
1157 : // Is this an instruction we should be instrumenting.
1158 E : if (!ShouldInstrumentOpcode(repr.opcode))
1159 E : continue;
1160 :
1161 : // If there are no unconventional manipulations of the stack frame, we can
1162 : // skip instrumenting stack-based memory access (based on ESP or EBP).
1163 : // Conventionally, accesses through ESP/EBP are always on stack.
1164 E : if (stack_mode == kSafeStackAccess &&
1165 : (operand.base() == assm::kRegisterEsp ||
1166 : operand.base() == assm::kRegisterEbp)) {
1167 E : continue;
1168 : }
1169 :
1170 : // We do not instrument memory accesses through special segments.
1171 : // FS is used for thread local specifics and GS for CPU info.
1172 E : uint8_t segment = SEGMENT_GET(repr.segment);
1173 E : if (segment == R_FS || segment == R_GS)
1174 E : continue;
1175 :
1176 : // Don't instrument any filtered instructions.
1177 E : if (IsFiltered(*iter_inst))
1178 E : continue;
1179 :
1180 : // Randomly sample to effect partial instrumentation.
1181 E : if (instrumentation_rate_ < 1.0 &&
1182 : base::RandDouble() >= instrumentation_rate_) {
1183 E : continue;
1184 : }
1185 :
1186 : // Create a BasicBlockAssembler to insert new instruction.
1187 E : BasicBlockAssembler bb_asm(iter_inst, &basic_block->instructions());
1188 :
1189 : // Configure the assembler to copy the SourceRange information of the
1190 : // current instrumented instruction into newly created instructions. This is
1191 : // a hack to allow valid stack walking and better error reporting, but
1192 : // breaks the 1:1 OMAP mapping and may confuse some debuggers.
1193 E : if (debug_friendly_)
1194 E : bb_asm.set_source_range(instr.source_range());
1195 :
1196 E : if (use_liveness_analysis_ &&
1197 : (info.mode == kReadAccess || info.mode == kWriteAccess)) {
1198 : // Use the liveness information to skip saving the flags if possible.
1199 E : info.save_flags = state.AreArithmeticFlagsLive();
1200 : }
1201 :
1202 : // Mark that an instrumentation will happen. Do this before selecting a
1203 : // hook so we can call a dry run without hooks present.
1204 E : instrumentation_happened_ = true;
1205 :
1206 E : if (!dry_run_) {
1207 : // Insert hook for standard instructions.
1208 E : AsanHookMap::iterator hook = check_access_hooks_->find(info);
1209 E : if (hook == check_access_hooks_->end()) {
1210 i : LOG(ERROR) << "Invalid access : "
1211 : << GetAsanCheckAccessFunctionName(info, image_format);
1212 i : return false;
1213 : }
1214 :
1215 : // Instrument this instruction.
1216 E : InjectAsanHook(
1217 : &bb_asm, info, operand, &hook->second, state, image_format);
1218 : }
1219 E : }
1220 :
1221 E : DCHECK(iter_state == states.end());
1222 :
1223 E : return true;
1224 E : }
1225 :
1226 : void AsanBasicBlockTransform::set_instrumentation_rate(
1227 E : double instrumentation_rate) {
1228 : // Set the instrumentation rate, capping it between 0 and 1.
1229 E : instrumentation_rate_ = std::max(0.0, std::min(1.0, instrumentation_rate));
1230 E : }
1231 :
1232 : bool AsanBasicBlockTransform::TransformBasicBlockSubGraph(
1233 : const TransformPolicyInterface* policy,
1234 : BlockGraph* block_graph,
1235 E : BasicBlockSubGraph* subgraph) {
1236 E : DCHECK(policy != NULL);
1237 E : DCHECK(block_graph != NULL);
1238 E : DCHECK(subgraph != NULL);
1239 :
1240 : // Perform a global liveness analysis.
1241 E : if (use_liveness_analysis_)
1242 E : liveness_.Analyze(subgraph);
1243 :
1244 : // Perform a redundant memory access analysis.
1245 E : if (remove_redundant_checks_)
1246 E : memory_accesses_.Analyze(subgraph);
1247 :
1248 : // Determines if this subgraph uses unconventional stack pointer
1249 : // manipulations.
1250 E : StackAccessMode stack_mode = kUnsafeStackAccess;
1251 E : if (!block_graph::HasUnexpectedStackFrameManipulation(subgraph))
1252 E : stack_mode = kSafeStackAccess;
1253 :
1254 : // Iterates through each basic block and instruments it.
1255 : BasicBlockSubGraph::BBCollection::iterator it =
1256 E : subgraph->basic_blocks().begin();
1257 E : for (; it != subgraph->basic_blocks().end(); ++it) {
1258 E : BasicCodeBlock* bb = BasicCodeBlock::Cast(*it);
1259 E : if (bb != NULL &&
1260 : !InstrumentBasicBlock(bb, stack_mode, block_graph->image_format())) {
1261 i : return false;
1262 : }
1263 E : }
1264 E : return true;
1265 E : }
1266 :
1267 : HotPatchingAsanBasicBlockTransform::HotPatchingAsanBasicBlockTransform(
1268 : AsanBasicBlockTransform* asan_bb_transform)
1269 E : : asan_bb_transform_(asan_bb_transform),
1270 E : prepared_for_hot_patching_(false) {
1271 E : DCHECK_NE(static_cast<AsanBasicBlockTransform*>(nullptr), asan_bb_transform);
1272 E : DCHECK(asan_bb_transform_->dry_run());
1273 E : }
1274 :
1275 : bool HotPatchingAsanBasicBlockTransform::TransformBasicBlockSubGraph(
1276 : const TransformPolicyInterface* policy,
1277 : BlockGraph* block_graph,
1278 E : BasicBlockSubGraph* basic_block_subgraph) {
1279 E : DCHECK_NE(static_cast<TransformPolicyInterface*>(nullptr), policy);
1280 E : DCHECK_NE(static_cast<BlockGraph*>(nullptr), block_graph);
1281 E : DCHECK_NE(static_cast<BasicBlockSubGraph*>(nullptr), basic_block_subgraph);
1282 :
1283 E : prepared_for_hot_patching_ = false;
1284 :
1285 : // Run Asan basic block transform in dry run mode.
1286 E : DCHECK(asan_bb_transform_->dry_run());
1287 E : asan_bb_transform_->TransformBasicBlockSubGraph(policy,
1288 : block_graph,
1289 : basic_block_subgraph);
1290 :
1291 : // Prepare the block for hot patching if needed.
1292 E : if (asan_bb_transform_->instrumentation_happened()) {
1293 E : pe::transforms::PEHotPatchingBasicBlockTransform hp_bb_transform;
1294 E : hp_bb_transform.TransformBasicBlockSubGraph(policy,
1295 : block_graph,
1296 : basic_block_subgraph);
1297 E : prepared_for_hot_patching_ = true;
1298 E : }
1299 :
1300 E : return true;
1301 E : }
1302 :
1303 : const char AsanTransform::kTransformName[] = "SyzyAsanTransform";
1304 :
1305 : const char AsanTransform::kAsanHookStubName[] = "asan_hook_stub";
1306 :
1307 : const char AsanTransform::kSyzyAsanDll[] = "syzyasan_rtl.dll";
1308 :
1309 : const char AsanTransform::kSyzyAsanHpDll[] = "syzyasan_hp.dll";
1310 :
1311 : AsanTransform::AsanTransform()
1312 E : : debug_friendly_(false),
1313 E : use_liveness_analysis_(false),
1314 E : remove_redundant_checks_(false),
1315 E : use_interceptors_(false),
1316 E : instrumentation_rate_(1.0),
1317 E : asan_parameters_(nullptr),
1318 E : check_access_hooks_ref_(),
1319 E : asan_parameters_block_(nullptr),
1320 E : hot_patching_(false) {
1321 E : }
1322 :
1323 E : AsanTransform::~AsanTransform() { }
1324 :
1325 E : void AsanTransform::set_instrumentation_rate(double instrumentation_rate) {
1326 : // Set the instrumentation rate, capping it between 0 and 1.
1327 E : instrumentation_rate_ = std::max(0.0, std::min(1.0, instrumentation_rate));
1328 E : }
1329 :
1330 : bool AsanTransform::PreBlockGraphIteration(
1331 : const TransformPolicyInterface* policy,
1332 : BlockGraph* block_graph,
1333 E : BlockGraph::Block* header_block) {
1334 E : DCHECK_NE(reinterpret_cast<TransformPolicyInterface*>(NULL), policy);
1335 E : DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), block_graph);
1336 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), header_block);
1337 E : DCHECK(block_graph->image_format() == BlockGraph::PE_IMAGE ||
1338 : block_graph->image_format() == BlockGraph::COFF_IMAGE);
1339 :
1340 : // Ensure that this image has not already been instrumented.
1341 E : if (block_graph->FindSection(common::kThunkSectionName)) {
1342 i : LOG(ERROR) << "The image is already instrumented.";
1343 i : return false;
1344 : }
1345 :
1346 : // Initialize heap initialization blocks.
1347 E : FindHeapInitAndCrtHeapBlocks(block_graph);
1348 :
1349 : // Add an import entry for the Asan runtime.
1350 E : ImportedModule import_module(instrument_dll_name(), kDateInThePast);
1351 :
1352 : // Find static intercepts in PE images before the transform so that OnBlock
1353 : // can skip them.
1354 E : if (block_graph->image_format() == BlockGraph::PE_IMAGE)
1355 E : PeFindStaticallyLinkedFunctionsToIntercept(kAsanIntercepts, block_graph);
1356 :
1357 : // We don't need to import any hooks in hot patching mode.
1358 E : if (!hot_patching_) {
1359 E : if (!ImportAsanCheckAccessHooks(kAsanHookStubName,
1360 : use_liveness_analysis(),
1361 : &import_module,
1362 : &check_access_hooks_ref_,
1363 : policy,
1364 : block_graph,
1365 : header_block)) {
1366 i : return false;
1367 : }
1368 : }
1369 :
1370 : // Redirect DllMain entry thunk in hot patching mode.
1371 E : if (hot_patching_) {
1372 E : EntryThunkTransform entry_thunk_tx;
1373 E : entry_thunk_tx.set_instrument_unsafe_references(false);
1374 E : entry_thunk_tx.set_only_instrument_module_entry(true);
1375 E : entry_thunk_tx.set_instrument_dll_name(instrument_dll_name());
1376 E : if (!block_graph::ApplyBlockGraphTransform(&entry_thunk_tx,
1377 : policy,
1378 : block_graph,
1379 : header_block)) {
1380 i : LOG(ERROR) << "Failed to rewrite DLL entry thunk.";
1381 i : return false;
1382 : }
1383 E : }
1384 :
1385 E : return true;
1386 E : }
1387 :
1388 : bool AsanTransform::OnBlock(const TransformPolicyInterface* policy,
1389 : BlockGraph* block_graph,
1390 E : BlockGraph::Block* block) {
1391 E : DCHECK(policy != NULL);
1392 E : DCHECK(block_graph != NULL);
1393 E : DCHECK(block != NULL);
1394 :
1395 E : if (ShouldSkipBlock(policy, block))
1396 E : return true;
1397 :
1398 : // Use the filter that was passed to us for our child transform.
1399 E : AsanBasicBlockTransform transform(&check_access_hooks_ref_);
1400 E : transform.set_debug_friendly(debug_friendly());
1401 E : transform.set_use_liveness_analysis(use_liveness_analysis());
1402 E : transform.set_remove_redundant_checks(remove_redundant_checks());
1403 E : transform.set_filter(filter());
1404 E : transform.set_instrumentation_rate(instrumentation_rate_);
1405 :
1406 E : if (!hot_patching_) {
1407 E : if (!ApplyBasicBlockSubGraphTransform(
1408 : &transform, policy, block_graph, block, NULL)) {
1409 i : return false;
1410 : }
1411 E : } else {
1412 : // If we run in hot patching mode we just want to check if the block would
1413 : // be instrumented.
1414 E : transform.set_dry_run(true);
1415 :
1416 E : HotPatchingAsanBasicBlockTransform hp_asan_bb_transform(&transform);
1417 :
1418 E : block_graph::BlockVector new_blocks;
1419 E : if (!ApplyBasicBlockSubGraphTransform(
1420 : &hp_asan_bb_transform, policy, block_graph, block, &new_blocks)) {
1421 i : return false;
1422 : }
1423 :
1424 : // Save the block to be inserted into the hot patching section.
1425 E : if (hp_asan_bb_transform.prepared_for_hot_patching()) {
1426 E : CHECK_EQ(1U, new_blocks.size());
1427 E : hot_patched_blocks_.push_back(new_blocks.front());
1428 : }
1429 E : }
1430 :
1431 E : return true;
1432 E : }
1433 :
1434 : bool AsanTransform::PostBlockGraphIteration(
1435 : const TransformPolicyInterface* policy,
1436 : BlockGraph* block_graph,
1437 E : BlockGraph::Block* header_block) {
1438 E : DCHECK(policy != NULL);
1439 E : DCHECK(block_graph != NULL);
1440 E : DCHECK(header_block != NULL);
1441 :
1442 E : if (block_graph->image_format() == BlockGraph::PE_IMAGE) {
1443 E : if (!PeInterceptFunctions(kAsanIntercepts, policy, block_graph,
1444 : header_block)) {
1445 i : return false;
1446 : }
1447 :
1448 E : if (!PeInjectAsanParameters(policy, block_graph, header_block))
1449 i : return false;
1450 E : } else {
1451 E : DCHECK_EQ(BlockGraph::COFF_IMAGE, block_graph->image_format());
1452 E : if (!CoffInterceptFunctions(kAsanIntercepts, policy, block_graph,
1453 : header_block)) {
1454 i : return false;
1455 : }
1456 : }
1457 :
1458 : // If the heap initialization blocks were encountered in the
1459 : // PreBlockGraphIteration, patch them now.
1460 E : if (!heap_init_blocks_.empty()) {
1461 : // We don't instrument HeapCreate in hot patching mode.
1462 : base::StringPiece heap_create_dll_name =
1463 E : !hot_patching_ ? instrument_dll_name() : "kernel32.dll";
1464 : base::StringPiece heap_create_function_name =
1465 E : !hot_patching_ ? "asan_HeapCreate" : "HeapCreate";
1466 E : if (!PatchCRTHeapInitialization(block_graph,
1467 : header_block,
1468 : policy,
1469 : heap_create_dll_name,
1470 : heap_create_function_name,
1471 : heap_init_blocks_)) {
1472 i : return false;
1473 : }
1474 : }
1475 :
1476 E : if (hot_patching_) {
1477 E : pe::transforms::AddHotPatchingMetadataTransform hp_metadata_transform;
1478 E : hp_metadata_transform.set_blocks_prepared(&hot_patched_blocks_);
1479 E : if (!block_graph::ApplyBlockGraphTransform(&hp_metadata_transform,
1480 : policy,
1481 : block_graph,
1482 : header_block)) {
1483 i : LOG(ERROR) << "Failed to insert hot patching metadata.";
1484 i : return false;
1485 : }
1486 E : }
1487 :
1488 E : return true;
1489 E : }
1490 :
1491 E : base::StringPiece AsanTransform::instrument_dll_name() const {
1492 E : if (asan_dll_name_.empty()) {
1493 E : if (!hot_patching_) {
1494 E : return kSyzyAsanDll;
1495 i : } else {
1496 E : return kSyzyAsanHpDll;
1497 : }
1498 i : } else {
1499 E : return asan_dll_name_.c_str();
1500 : }
1501 E : }
1502 :
1503 E : void AsanTransform::FindHeapInitAndCrtHeapBlocks(BlockGraph* block_graph) {
1504 E : for (auto& iter : block_graph->blocks_mutable()) {
1505 E : bool add_block = false;
1506 E : if (iter.second.name().find("_heap_init") != std::string::npos) {
1507 : // VS2012 CRT heap initialization.
1508 i : add_block = true;
1509 E : } else if (iter.second.name().find("_acrt_initialize_heap") !=
1510 : std::string::npos) {
1511 : // VS2015 CRT heap initialization.
1512 E : add_block = true;
1513 : }
1514 :
1515 E : if (add_block) {
1516 E : DCHECK(std::find(heap_init_blocks_.begin(),
1517 : heap_init_blocks_.end(), &(iter.second)) == heap_init_blocks_.end());
1518 E : heap_init_blocks_.push_back(&(iter.second));
1519 : }
1520 E : }
1521 E : }
1522 :
1523 : bool AsanTransform::ShouldSkipBlock(const TransformPolicyInterface* policy,
1524 E : BlockGraph::Block* block) {
1525 : // Heap initialization blocks and intercepted blocks must be skipped.
1526 : if (std::find(heap_init_blocks_.begin(),
1527 E : heap_init_blocks_.end(), block) != heap_init_blocks_.end()) {
1528 E : return true;
1529 : }
1530 E : if (static_intercepted_blocks_.count(block))
1531 E : return true;
1532 :
1533 : // Blocks that are not safe to basic block decompose should also be skipped.
1534 E : if (!policy->BlockIsSafeToBasicBlockDecompose(block))
1535 E : return true;
1536 :
1537 E : return false;
1538 E : }
1539 :
1540 : void AsanTransform::PeFindStaticallyLinkedFunctionsToIntercept(
1541 : const AsanIntercept* intercepts,
1542 E : BlockGraph* block_graph) {
1543 E : DCHECK_NE(static_cast<AsanIntercept*>(nullptr), intercepts);
1544 E : DCHECK_NE(static_cast<BlockGraph*>(nullptr), block_graph);
1545 E : DCHECK(static_intercepted_blocks_.empty());
1546 :
1547 : // Populate the filter with known hashes.
1548 E : AsanInterceptorFilter filter;
1549 E : filter.InitializeContentHashes(intercepts, use_interceptors_);
1550 E : if (filter.empty())
1551 E : return;
1552 :
1553 : // Discover statically linked functions that need to be intercepted.
1554 : BlockGraph::BlockMap::iterator block_it =
1555 E : block_graph->blocks_mutable().begin();
1556 E : for (; block_it != block_graph->blocks_mutable().end(); ++block_it) {
1557 E : BlockGraph::Block* block = &block_it->second;
1558 E : if (!filter.ShouldIntercept(block))
1559 E : continue;
1560 E : static_intercepted_blocks_.insert(block);
1561 E : }
1562 E : }
1563 :
1564 : bool AsanTransform::PeInterceptFunctions(
1565 : const AsanIntercept* intercepts,
1566 : const TransformPolicyInterface* policy,
1567 : BlockGraph* block_graph,
1568 E : BlockGraph::Block* header_block) {
1569 E : DCHECK_NE(reinterpret_cast<AsanIntercept*>(NULL), intercepts);
1570 E : DCHECK_NE(reinterpret_cast<TransformPolicyInterface*>(NULL), policy);
1571 E : DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), block_graph);
1572 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), header_block);
1573 E : DCHECK_EQ(BlockGraph::PE_IMAGE, block_graph->image_format());
1574 :
1575 : // This is used to keep track of the index of imports to the Asan RTL.
1576 E : ImportNameIndexMap import_name_index_map;
1577 :
1578 : // Keeps track of all imported modules with imports that we intercept.
1579 E : ScopedVector<ImportedModule> imported_modules;
1580 :
1581 E : ImportedModule asan_rtl(instrument_dll_name(), kDateInThePast);
1582 :
1583 E : const char* asan_intercept_prefix = nullptr;
1584 E : if (!hot_patching_) {
1585 E : asan_intercept_prefix = kUndecoratedAsanInterceptPrefix;
1586 E : } else {
1587 E : asan_intercept_prefix = kUndecoratedHotPatchingAsanInterceptPrefix;
1588 : }
1589 :
1590 : // Dynamic imports are only intercepted when hot patching is inactive.
1591 E : if (!hot_patching()) {
1592 : // Determines what PE imports need to be intercepted, adding them to
1593 : // |asan_rtl| and |import_name_index_map|.
1594 E : if (!PeFindImportsToIntercept(use_interceptors_,
1595 : intercepts,
1596 : policy,
1597 : block_graph,
1598 : header_block,
1599 : &imported_modules,
1600 : &import_name_index_map,
1601 : &asan_rtl,
1602 : asan_intercept_prefix)) {
1603 i : return false;
1604 : }
1605 : }
1606 :
1607 : // Add the intercepts of statically linked functions to |asan_rtl| and
1608 : // |import_name_index_map|.
1609 E : PeLoadInterceptsForStaticallyLinkedFunctions(static_intercepted_blocks_,
1610 : &import_name_index_map,
1611 : &asan_rtl,
1612 : asan_intercept_prefix);
1613 :
1614 : // Keep track of how many import redirections are to be performed. This allows
1615 : // a minor optimization later on when there are none to be performed.
1616 E : size_t import_redirection_count = asan_rtl.size();
1617 :
1618 : // If no imports were found at all, then there are no redirections to perform.
1619 E : if (asan_rtl.size() == 0)
1620 E : return true;
1621 :
1622 : // Add the Asan RTL imports to the image.
1623 E : PEAddImportsTransform add_imports_transform;
1624 E : add_imports_transform.AddModule(&asan_rtl);
1625 E : if (!add_imports_transform.TransformBlockGraph(
1626 : policy, block_graph, header_block)) {
1627 i : LOG(ERROR) << "Unable to add imports for redirection.";
1628 i : return false;
1629 : }
1630 :
1631 : // This keeps track of reference redirections that need to be performed.
1632 E : pe::ReferenceMap reference_redirect_map;
1633 :
1634 E : if (import_redirection_count > 0) {
1635 E : PeGetRedirectsForInterceptedImports(imported_modules,
1636 : import_name_index_map,
1637 : asan_rtl,
1638 : &reference_redirect_map);
1639 : }
1640 :
1641 : // Adds redirect information for any intercepted statically linked functions.
1642 E : if (!static_intercepted_blocks_.empty()) {
1643 E : if (!PeGetRedirectsForStaticallyLinkedFunctions(static_intercepted_blocks_,
1644 : import_name_index_map,
1645 : asan_rtl,
1646 : block_graph,
1647 : &reference_redirect_map,
1648 : asan_intercept_prefix)) {
1649 i : return false;
1650 : }
1651 : }
1652 :
1653 : // Finally, redirect all references to intercepted functions.
1654 E : pe::RedirectReferences(reference_redirect_map);
1655 :
1656 E : return true;
1657 E : }
1658 :
1659 : bool AsanTransform::PeInjectAsanParameters(
1660 : const TransformPolicyInterface* policy,
1661 : BlockGraph* block_graph,
1662 E : BlockGraph::Block* header_block) {
1663 E : DCHECK_NE(reinterpret_cast<TransformPolicyInterface*>(NULL), policy);
1664 E : DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), block_graph);
1665 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), header_block);
1666 E : DCHECK_EQ(BlockGraph::PE_IMAGE, block_graph->image_format());
1667 :
1668 : // If there are no parameters then do nothing.
1669 E : if (asan_parameters_ == NULL)
1670 E : return true;
1671 :
1672 : // Serialize the parameters into a new block.
1673 E : common::FlatAsanParameters fparams(*asan_parameters_);
1674 E : BlockGraph::Block* params_block = block_graph->AddBlock(
1675 : BlockGraph::DATA_BLOCK, fparams.data().size(), "AsanParameters");
1676 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), params_block);
1677 E : params_block->CopyData(fparams.data().size(), fparams.data().data());
1678 :
1679 : // Wire up any references that are required.
1680 : static_assert(14 == common::kAsanParametersVersion,
1681 : "Pointers in the params must be linked up here.");
1682 E : block_graph::TypedBlock<common::AsanParameters> params;
1683 E : CHECK(params.Init(0, params_block));
1684 E : if (fparams->ignored_stack_ids != NULL) {
1685 : size_t offset =
1686 E : reinterpret_cast<const uint8_t*>(fparams->ignored_stack_ids) -
1687 : reinterpret_cast<const uint8_t*>(&fparams.params());
1688 E : CHECK(params.SetReference(BlockGraph::ABSOLUTE_REF,
1689 : params->ignored_stack_ids,
1690 : params_block,
1691 : offset,
1692 : offset));
1693 : }
1694 :
1695 : // Create an appropriately named section and put the parameters there. The
1696 : // RTL looks for this named section to find the parameters.
1697 E : BlockGraph::Section* section = block_graph->FindOrAddSection(
1698 : common::kAsanParametersSectionName,
1699 : common::kAsanParametersSectionCharacteristics);
1700 E : DCHECK_NE(reinterpret_cast<BlockGraph::Section*>(NULL), section);
1701 E : params_block->set_section(section->id());
1702 :
1703 : // Remember the block containing the parameters. This is a unittesting seam.
1704 E : asan_parameters_block_ = params_block;
1705 :
1706 E : return true;
1707 E : }
1708 :
1709 : bool AsanTransform::CoffInterceptFunctions(
1710 : const AsanIntercept* intercepts,
1711 : const TransformPolicyInterface* policy,
1712 : BlockGraph* block_graph,
1713 E : BlockGraph::Block* header_block) {
1714 E : DCHECK_NE(reinterpret_cast<AsanIntercept*>(NULL), intercepts);
1715 E : DCHECK_NE(reinterpret_cast<TransformPolicyInterface*>(NULL), policy);
1716 E : DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), block_graph);
1717 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), header_block);
1718 :
1719 : // Extract the existing symbols.
1720 E : pe::CoffSymbolNameOffsetMap symbol_map;
1721 E : BlockGraph::Block* symbols_block = NULL;
1722 E : BlockGraph::Block* strings_block = NULL;
1723 E : if (!pe::FindCoffSpecialBlocks(block_graph, NULL, &symbols_block,
1724 : &strings_block)) {
1725 i : LOG(ERROR) << "Unable to find COFF header blocks.";
1726 i : return false;
1727 : }
1728 E : if (!pe::BuildCoffSymbolNameOffsetMap(block_graph, &symbol_map)) {
1729 i : LOG(ERROR) << "Unable to build symbol map.";
1730 i : return false;
1731 : }
1732 :
1733 : // Populate a COFF symbol rename transform for each function to be
1734 : // intercepted. We simply try to rename all possible symbols that may exist
1735 : // and allow the transform to ignore any that aren't present.
1736 E : pe::transforms::CoffRenameSymbolsTransform rename_tx;
1737 E : rename_tx.set_symbols_must_exist(false);
1738 E : const AsanIntercept* intercept = intercepts;
1739 E : bool defines_asan_functions = false;
1740 E : for (; intercept->undecorated_name != NULL; ++intercept) {
1741 : // Skip disabled optional functions.
1742 E : if (!use_interceptors_ && intercept->optional)
1743 i : continue;
1744 :
1745 : // Skip functions for which we have no decorated name.
1746 E : if (intercept->decorated_name == NULL)
1747 E : continue;
1748 :
1749 : // Build the name of the imported version of this symbol.
1750 E : std::string imp_name(kDecoratedImportPrefix);
1751 E : imp_name += intercept->decorated_name;
1752 :
1753 : // Build the name of the Asan instrumented version of this symbol.
1754 E : std::string asan_name(kDecoratedAsanInterceptPrefix);
1755 E : asan_name += intercept->decorated_name;
1756 :
1757 : // Build the name of the Asan instrumented imported version of this symbol.
1758 E : std::string imp_asan_name(kDecoratedImportPrefix);
1759 E : imp_asan_name += asan_name;
1760 :
1761 : // Build symbol rename mappings for the direct and indirect versions of the
1762 : // function.
1763 E : rename_tx.AddSymbolMapping(intercept->decorated_name, asan_name);
1764 E : rename_tx.AddSymbolMapping(imp_name, imp_asan_name);
1765 :
1766 : // We use the add imports transform to try to find names for the Asan
1767 : // implementation. If these already exist in the object file then our
1768 : // instrumentation will fail.
1769 E : const std::string* names[] = { &asan_name, &imp_asan_name };
1770 E : for (size_t i = 0; i < arraysize(names); ++i) {
1771 E : if (symbol_map.count(*names[i])) {
1772 i : LOG(ERROR) << "Object file being instrumented defines Asan function \""
1773 : << asan_name << "\".";
1774 i : defines_asan_functions = true;
1775 : }
1776 E : }
1777 E : }
1778 :
1779 E : if (defines_asan_functions)
1780 i : return false;
1781 :
1782 : // Apply the rename transform.
1783 E : if (!block_graph::ApplyBlockGraphTransform(&rename_tx,
1784 : policy,
1785 : block_graph,
1786 : header_block)) {
1787 i : LOG(ERROR) << "Failed to apply COFF symbol rename transform.";
1788 i : return false;
1789 : }
1790 :
1791 E : return true;
1792 E : }
1793 :
1794 : bool operator<(const AsanBasicBlockTransform::MemoryAccessInfo& left,
1795 E : const AsanBasicBlockTransform::MemoryAccessInfo& right) {
1796 E : if (left.mode != right.mode)
1797 E : return left.mode < right.mode;
1798 E : if (left.size != right.size)
1799 E : return left.size < right.size;
1800 E : if (left.save_flags != right.save_flags)
1801 E : return left.save_flags < right.save_flags;
1802 E : return left.opcode < right.opcode;
1803 E : }
1804 :
1805 : } // namespace transforms
1806 : } // namespace instrument
|