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

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
91.2%7227920.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_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

Coverage information generated Fri Jul 29 11:00:21 2016.