Coverage for /Syzygy/instrument/transforms/asan_transform.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
91.0%6987670.C++source

Line-by-line coverage:

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

Coverage information generated Thu Jan 14 17:40:38 2016.