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

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
91.1%4705160.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 <vector>
  18    :  
  19    :  #include "base/logging.h"
  20    :  #include "base/string_util.h"
  21    :  #include "base/stringprintf.h"
  22    :  #include "base/memory/ref_counted.h"
  23    :  #include "syzygy/block_graph/basic_block.h"
  24    :  #include "syzygy/block_graph/basic_block_assembler.h"
  25    :  #include "syzygy/block_graph/block_builder.h"
  26    :  #include "syzygy/block_graph/block_util.h"
  27    :  #include "syzygy/common/defs.h"
  28    :  #include "syzygy/pe/pe_utils.h"
  29    :  #include "third_party/distorm/files/include/mnemonics.h"
  30    :  #include "third_party/distorm/files/src/x86defs.h"
  31    :  
  32    :  namespace instrument {
  33    :  namespace transforms {
  34    :  namespace {
  35    :  
  36    :  using block_graph::BasicBlock;
  37    :  using block_graph::BasicCodeBlock;
  38    :  using block_graph::BasicBlockAssembler;
  39    :  using block_graph::BasicBlockSubGraph;
  40    :  using block_graph::BasicBlockReference;
  41    :  using block_graph::BlockBuilder;
  42    :  using block_graph::BlockGraph;
  43    :  using block_graph::Displacement;
  44    :  using block_graph::Immediate;
  45    :  using block_graph::Instruction;
  46    :  using block_graph::Operand;
  47    :  using block_graph::TransformPolicyInterface;
  48    :  using block_graph::TypedBlock;
  49    :  using block_graph::Value;
  50    :  using block_graph::analysis::LivenessAnalysis;
  51    :  using block_graph::analysis::MemoryAccessAnalysis;
  52    :  using core::Register32;
  53    :  using pe::transforms::PEAddImportsTransform;
  54    :  
  55    :  // A simple struct that can be used to let us access strings using TypedBlock.
  56    :  struct StringStruct {
  57    :    const char string[1];
  58    :  };
  59    :  
  60    :  typedef pe::transforms::ImportedModule ImportedModule;
  61    :  typedef AsanBasicBlockTransform::MemoryAccessMode AsanMemoryAccessMode;
  62    :  typedef AsanBasicBlockTransform::AsanHookMap HookMap;
  63    :  typedef std::vector<AsanBasicBlockTransform::AsanHookMapEntryKey>
  64    :      AccessHookParamVector;
  65    :  typedef TypedBlock<IMAGE_IMPORT_DESCRIPTOR> ImageImportDescriptor;
  66    :  typedef TypedBlock<StringStruct> String;
  67    :  
  68    :  // Returns true iff opcode should be instrumented.
  69  E :  bool ShouldInstrumentOpcode(uint16 opcode) {
  70  E :    switch (opcode) {
  71    :      // LEA does not actually access memory.
  72    :      case I_LEA:
  73  E :        return false;
  74    :  
  75    :      // We can ignore the prefetch and clflush instructions. The instrumentation
  76    :      // will detect memory errors if and when the memory is actually accessed.
  77    :      case I_CLFLUSH:
  78    :      case I_PREFETCH:
  79    :      case I_PREFETCHNTA:
  80    :      case I_PREFETCHT0:
  81    :      case I_PREFETCHT1:
  82    :      case I_PREFETCHT2:
  83    :      case I_PREFETCHW:
  84  i :        return false;
  85    :    }
  86  E :    return true;
  87  E :  }
  88    :  
  89    :  // Computes the correct displacement, if any, for operand
  90    :  // number @p operand of @p instr.
  91    :  Displacement ComputeDisplacementForOperand(const Instruction& instr,
  92  E :                                             size_t operand) {
  93  E :    const _DInst& repr = instr.representation();
  94    :  
  95    :    DCHECK(repr.ops[operand].type == O_SMEM ||
  96  E :           repr.ops[operand].type == O_MEM);
  97    :  
  98  E :    size_t access_size_bytes = repr.ops[operand].size / 8;
  99  E :    if (repr.dispSize == 0)
 100  E :      return Displacement(access_size_bytes - 1);
 101    :  
 102  E :    BasicBlockReference reference;
 103  E :    if (instr.FindOperandReference(operand, &reference)) {
 104  E :      if (reference.referred_type() == BasicBlockReference::REFERRED_TYPE_BLOCK) {
 105    :        return Displacement(reference.block(),
 106  E :                            reference.offset() + access_size_bytes - 1);
 107  i :      } else {
 108  E :        return Displacement(reference.basic_block());
 109    :      }
 110  i :    } else {
 111  E :      return Displacement(repr.disp + access_size_bytes - 1);
 112    :    }
 113  E :  }
 114    :  
 115    :  // Returns true if operand @p op is instrumentable, e.g.
 116    :  // if it implies a memory access.
 117  E :  bool IsInstrumentable(const _Operand& op) {
 118  E :    switch (op.type) {
 119    :      case O_SMEM:
 120    :      case O_MEM:
 121  E :        return true;
 122    :  
 123    :      default:
 124  E :        return false;
 125    :    }
 126  E :  }
 127    :  
 128    :  // Returns true if opcode @p opcode is a special instruction.
 129    :  // Memory checks for special instructions (string instructions, instructions
 130    :  // with prefix, etc) are handled by calling specialized functions rather than
 131    :  // the standard memory checks.
 132  E :  bool IsSpecialInstruction(uint16_t opcode) {
 133  E :    switch (opcode) {
 134    :      case I_CMPS:
 135    :      case I_STOS:
 136    :      case I_MOVS:
 137  E :        return true;
 138    :  
 139    :      default:
 140  E :        return false;
 141    :    }
 142  E :  }
 143    :  
 144    :  // Decodes the first O_MEM or O_SMEM operand of @p instr, if any to the
 145    :  // corresponding Operand.
 146    :  bool DecodeMemoryAccess(const Instruction& instr,
 147    :      Operand* access,
 148  E :      AsanBasicBlockTransform::MemoryAccessInfo* info) {
 149  E :    DCHECK(access != NULL);
 150  E :    DCHECK(info != NULL);
 151  E :    const _DInst& repr = instr.representation();
 152    :  
 153    :    // Figure out which operand we're instrumenting.
 154  E :    size_t mem_op_id = -1;
 155  E :    if (IsInstrumentable(repr.ops[0]) && IsInstrumentable(repr.ops[1])) {
 156    :      // This happens with instructions like: MOVS [EDI], [ESI].
 157  E :      DCHECK(repr.ops[0].size == repr.ops[1].size);
 158  E :      mem_op_id = 0;
 159  E :    } else if (IsInstrumentable(repr.ops[0])) {
 160    :      // The first operand is instrumentable.
 161  E :      mem_op_id = 0;
 162  E :    } else if (IsInstrumentable(repr.ops[1])) {
 163    :      // The second operand is instrumentable.
 164  E :      mem_op_id = 1;
 165  E :    } else {
 166    :      // Neither of the first two operands is instrumentable.
 167  E :      return false;
 168    :    }
 169    :  
 170    :    // Determine the size of the access.
 171  E :    info->size = repr.ops[mem_op_id].size / 8;
 172    :  
 173    :    // Determine the kind of access (read/write/instr/repz).
 174  E :    if (FLAG_GET_PREFIX(repr.flags) & FLAG_REPNZ)
 175  i :      info->mode = AsanBasicBlockTransform::kRepnzAccess;
 176  E :    else if (FLAG_GET_PREFIX(repr.flags) & FLAG_REP)
 177  E :      info->mode = AsanBasicBlockTransform::kRepzAccess;
 178  E :    else if (IsSpecialInstruction(instr.opcode()))
 179  E :      info->mode = AsanBasicBlockTransform::kInstrAccess;
 180  E :    else if ((repr.flags & FLAG_DST_WR) && mem_op_id == 0) {
 181    :      // The first operand is written to.
 182  E :      info->mode = AsanBasicBlockTransform::kWriteAccess;
 183  E :    } else {
 184  E :      info->mode = AsanBasicBlockTransform::kReadAccess;
 185    :    }
 186    :  
 187    :    // Determine the opcode of this instruction (when needed).
 188    :    if (info->mode == AsanBasicBlockTransform::kRepnzAccess ||
 189    :        info->mode == AsanBasicBlockTransform::kRepzAccess ||
 190  E :        info->mode == AsanBasicBlockTransform::kInstrAccess) {
 191  E :      info->opcode = instr.opcode();
 192    :    }
 193    :  
 194    :    // Determine operand of the access.
 195  E :    if (repr.ops[mem_op_id].type == O_SMEM) {
 196    :      // Simple memory dereference with optional displacement.
 197    :      const Register32& base_reg = core::CastAsRegister32(
 198  E :          core::GetRegister(repr.ops[mem_op_id].index));
 199    :  
 200    :      // Get the displacement for the operand.
 201  E :      Displacement displ = ComputeDisplacementForOperand(instr, mem_op_id);
 202  E :      *access = Operand(base_reg, displ);
 203  E :    } else if (repr.ops[0].type == O_MEM || repr.ops[1].type == O_MEM) {
 204    :      // Complex memory dereference.
 205    :      const Register32& index_reg = core::CastAsRegister32(
 206  E :          core::GetRegister(repr.ops[mem_op_id].index));
 207    :  
 208  E :      core::ScaleFactor scale = core::kTimes1;
 209  E :      switch (repr.scale) {
 210    :        case 2:
 211  E :          scale = core::kTimes2;
 212  E :          break;
 213    :        case 4:
 214  E :          scale = core::kTimes4;
 215  E :          break;
 216    :        case 8:
 217  E :          scale = core::kTimes8;
 218    :          break;
 219    :        default:
 220    :          break;
 221    :      }
 222    :  
 223    :      // Get the displacement for the operand (if any).
 224  E :      Displacement displ = ComputeDisplacementForOperand(instr, mem_op_id);
 225    :  
 226    :      // Compute the full operand.
 227  E :      if (repr.base != R_NONE) {
 228    :        const Register32& base_reg = core::CastAsRegister32(
 229  E :            core::GetRegister(repr.base));
 230    :  
 231  E :        if (displ.size() == core::kSizeNone) {
 232    :          // No displacement, it's a [base + index * scale] access.
 233  i :          *access = Operand(base_reg, index_reg, scale);
 234  i :        } else {
 235    :          // This is a [base + index * scale + displ] access.
 236  E :          *access = Operand(base_reg, index_reg, scale, displ);
 237    :        }
 238  E :      } else {
 239    :        // No base, this is an [index * scale + displ] access.
 240    :        // TODO(siggi): AFAIK, there's no encoding for [index * scale] without
 241    :        //    a displacement. If this assert fires, I'm proven wrong.
 242  E :        DCHECK_NE(core::kSizeNone, displ.size());
 243    :  
 244  E :        *access = Operand(index_reg, scale, displ);
 245    :      }
 246  E :    } else {
 247  i :      NOTREACHED();
 248  i :      return false;
 249    :    }
 250    :  
 251  E :    return true;
 252  E :  }
 253    :  
 254    :  // Use @p bb_asm to inject a hook to @p hook to instrument the access to the
 255    :  // address stored in the operand @p op.
 256    :  void InjectAsanHook(BasicBlockAssembler* bb_asm,
 257    :                      const AsanBasicBlockTransform::MemoryAccessInfo& info,
 258    :                      const Operand& op,
 259    :                      BlockGraph::Reference* hook,
 260  E :                      const LivenessAnalysis::State& state) {
 261  E :    DCHECK(hook != NULL);
 262    :  
 263    :    // Determine which kind of probe to inject.
 264    :    if (info.mode == AsanBasicBlockTransform::kReadAccess ||
 265  E :        info.mode == AsanBasicBlockTransform::kWriteAccess) {
 266    :      // The standard load/store probe assume the address is in EDX.
 267    :      // It restore the original version of EDX and cleanup the stack.
 268  E :      bb_asm->push(core::edx);
 269  E :      bb_asm->lea(core::edx, op);
 270  E :      bb_asm->call(Operand(Displacement(hook->referenced(), hook->offset())));
 271  E :    } else {
 272    :      // The special instruction probe take addresses directly in registers.
 273    :      // The probe doesn't have any effects on stack, registers and flags.
 274  E :      bb_asm->call(Operand(Displacement(hook->referenced(), hook->offset())));
 275    :    }
 276  E :  }
 277    :  
 278    :  typedef std::pair<BlockGraph::Block*, BlockGraph::Offset> ReferenceDest;
 279    :  typedef std::map<ReferenceDest, ReferenceDest> ReferenceMap;
 280    :  typedef std::set<BlockGraph::Block*> BlockSet;
 281    :  
 282    :  // For every block referencing @p dst_blocks, redirects any reference "ref" in
 283    :  // @p redirects to @p redirects[ref].
 284    :  void RedirectReferences(const BlockSet& dst_blocks,
 285  E :                          const ReferenceMap& redirects) {
 286    :    // For each block referenced by any source reference.
 287  E :    BlockSet::const_iterator dst_block_it = dst_blocks.begin();
 288  E :    for (; dst_block_it != dst_blocks.end(); ++dst_block_it) {
 289    :      // Iterate over all their referrers.
 290  E :      BlockGraph::Block* referred_block = *dst_block_it;
 291  E :      BlockGraph::Block::ReferrerSet referrers = referred_block->referrers();
 292  E :      BlockGraph::Block::ReferrerSet::iterator referrer_it = referrers.begin();
 293  E :      for (; referrer_it != referrers.end(); ++referrer_it) {
 294  E :        BlockGraph::Block* referrer = referrer_it->first;
 295    :  
 296    :        // Don't redirect references from PE parsed blocks. This actually ends up
 297    :        // redirecting the IAT entries as well in the worst case.
 298  E :        if (referrer->attributes() & BlockGraph::PE_PARSED)
 299  E :          continue;
 300    :  
 301    :        // And redirect any references that happen to match a source reference.
 302    :        BlockGraph::Block::ReferenceMap::const_iterator reference_it =
 303  E :            referrer->references().begin();
 304    :  
 305  E :        for (; reference_it != referrer->references().end(); ++reference_it) {
 306  E :          const BlockGraph::Reference& ref(reference_it->second);
 307  E :          ReferenceDest dest(std::make_pair(ref.referenced(), ref.offset()));
 308    :  
 309  E :          ReferenceMap::const_iterator it(redirects.find(dest));
 310  E :          if (it != redirects.end()) {
 311    :            BlockGraph::Reference new_reference(ref.type(),
 312    :                                                ref.size(),
 313    :                                                it->second.first,
 314    :                                                it->second.second,
 315  E :                                                0);
 316    :  
 317  E :            referrer->SetReference(reference_it->first, new_reference);
 318    :          }
 319  E :        }
 320  E :      }
 321  E :    }
 322  E :  }
 323    :  
 324    :  // Get the name of an asan check access function for an @p access_mode access.
 325    :  // @param info The memory access information, e.g. the size on a load/store,
 326    :  //     the instruction opcode and the kind of access.
 327    :  std::string GetAsanCheckAccessFunctionName(
 328  E :      AsanBasicBlockTransform::MemoryAccessInfo info) {
 329  E :    DCHECK(info.mode != AsanBasicBlockTransform::kNoAccess);
 330  E :    DCHECK_NE(0U, info.size);
 331    :    DCHECK(info.mode == AsanBasicBlockTransform::kReadAccess ||
 332    :           info.mode == AsanBasicBlockTransform::kWriteAccess ||
 333  E :           info.opcode != 0);
 334    :  
 335  E :    const char* rep_str = NULL;
 336  E :    if (info.mode == AsanBasicBlockTransform::kRepzAccess)
 337  E :      rep_str = "_repz";
 338  E :    else if (info.mode == AsanBasicBlockTransform::kRepnzAccess)
 339  i :      rep_str = "_repnz";
 340  i :    else
 341  E :      rep_str = "";
 342    :  
 343  E :    const char* access_mode_str = NULL;
 344  E :    if (info.mode == AsanBasicBlockTransform::kReadAccess)
 345  E :      access_mode_str = "read";
 346  E :    else if (info.mode == AsanBasicBlockTransform::kWriteAccess)
 347  E :      access_mode_str = "write";
 348  E :    else
 349  E :      access_mode_str = reinterpret_cast<char*>(GET_MNEMONIC_NAME(info.opcode));
 350    :  
 351    :    std::string function_name =
 352    :        base::StringPrintf("asan_check%s_%d_byte_%s_access%s",
 353    :                            rep_str,
 354    :                            info.size,
 355    :                            access_mode_str,
 356  E :                            info.save_flags ? "" : "_no_flags");
 357  E :    StringToLowerASCII(&function_name);
 358  E :    return function_name;
 359  E :  }
 360    :  
 361    :  // Add the imports for the asan check access hooks to the block-graph.
 362    :  // @param hooks_param_vector A vector of hook parameter values.
 363    :  // @param default_stub_map Stubs for the asan check access functions.
 364    :  // @param import_module The module for which the import should be added.
 365    :  // @param check_access_hook_map The map where the reference to the imports
 366    :  //     should be stored.
 367    :  // @param policy The policy object restricting how the transform is applied.
 368    :  // @param block_graph The block-graph to populate.
 369    :  // @param header_block The block containing the module's DOS header of this
 370    :  //     block-graph.
 371    :  // @returns True on success, false otherwise.
 372    :  bool AddAsanCheckAccessHooks(
 373    :      const AccessHookParamVector& hook_param_vector,
 374    :      const AsanBasicBlockTransform::AsanDefaultHookMap& default_stub_map,
 375    :      ImportedModule* import_module,
 376    :      HookMap* check_access_hook_map,
 377    :      const TransformPolicyInterface* policy,
 378    :      BlockGraph* block_graph,
 379  E :      BlockGraph::Block* header_block) {
 380  E :    DCHECK(import_module != NULL);
 381  E :    DCHECK(check_access_hook_map != NULL);
 382  E :    DCHECK(policy != NULL);
 383  E :    DCHECK(block_graph != NULL);
 384  E :    DCHECK(header_block != NULL);
 385    :  
 386    :    // Add the hooks to the import module.
 387    :  
 388    :    typedef std::map<AsanBasicBlockTransform::AsanHookMapEntryKey, size_t>
 389    :        HooksParamsToIdxMap;
 390  E :    HooksParamsToIdxMap hooks_params_to_idx;
 391    :  
 392  E :    AccessHookParamVector::const_iterator iter_params = hook_param_vector.begin();
 393  E :    for (; iter_params != hook_param_vector.end(); ++iter_params) {
 394    :      size_t symbol_idx = import_module->AddSymbol(
 395    :          GetAsanCheckAccessFunctionName(*iter_params),
 396  E :          ImportedModule::kAlwaysImport);
 397  E :      hooks_params_to_idx[*iter_params] = symbol_idx;
 398  E :    }
 399    :  
 400  E :    DCHECK_EQ(hooks_params_to_idx.size(), hook_param_vector.size());
 401    :  
 402    :    // Transforms the block-graph.
 403    :  
 404  E :    PEAddImportsTransform add_imports_transform;
 405  E :    add_imports_transform.AddModule(import_module);
 406    :  
 407    :    if (!add_imports_transform.TransformBlockGraph(
 408  E :            policy, block_graph, header_block)) {
 409  i :      LOG(ERROR) << "Unable to add imports for Asan instrumentation DLL.";
 410  i :      return false;
 411    :    }
 412    :  
 413    :    // Get a reference to each hook and put it in the hooks map.
 414  E :    HooksParamsToIdxMap::iterator iter_hooks = hooks_params_to_idx.begin();
 415  E :    for (; iter_hooks != hooks_params_to_idx.end(); ++iter_hooks) {
 416  E :      BlockGraph::Reference import_reference;
 417    :      if (!import_module->GetSymbolReference(iter_hooks->second,
 418  E :                                             &import_reference)) {
 419  i :        LOG(ERROR) << "Unable to get import reference for Asan.";
 420  i :        return false;
 421    :      }
 422  E :      HookMap& hook_map = *check_access_hook_map;
 423  E :      hook_map[iter_hooks->first] = import_reference;
 424    :  
 425    :      // In a Chrome sandboxed process the NtMapViewOfSection function is
 426    :      // intercepted by the sandbox agent. This causes execution in the executable
 427    :      // before imports have been resolved, as the ntdll patch invokes into the
 428    :      // executable while resolving imports. As the Asan instrumentation directly
 429    :      // refers to the IAT entries we need to temporarily stub these function
 430    :      // until the Asan imports are resolved. To do this we need to make the IAT
 431    :      // entries for those functions point to a temporarily block and we need to
 432    :      // mark the image import descriptor for this DLL as bound.
 433    :      AsanBasicBlockTransform::AsanDefaultHookMap::const_iterator stub_reference =
 434  E :          default_stub_map.find(iter_hooks->first.mode);
 435  E :      if (stub_reference == default_stub_map.end()) {
 436  i :         LOG(ERROR) << "Could not find the default hook for "
 437    :                    << GetAsanCheckAccessFunctionName(iter_hooks->first)
 438    :                    << ".";
 439  i :        return false;
 440    :      }
 441    :  
 442    :      import_reference.referenced()->SetReference(import_reference.offset(),
 443  E :                                                  stub_reference->second);
 444  E :    }
 445    :  
 446  E :    return true;
 447  E :  }
 448    :  
 449    :  // Create a stub for the asan_check_access functions. For load/store, the stub
 450    :  // consists of a small block of code that restores the value of EDX and returns
 451    :  // to the caller. Otherwise, the stub do return.
 452    :  // @param block_graph The block-graph to populate with the stub.
 453    :  // @param stub_name The stub's name.
 454    :  // @param mode The kind of memory access.
 455    :  // @param reference Will receive the reference to the created hook.
 456    :  // @returns true on success, false otherwise.
 457    :  bool CreateHooksStub(BlockGraph* block_graph,
 458    :                       const base::StringPiece& stub_name,
 459    :                       AsanBasicBlockTransform::MemoryAccessMode mode,
 460  E :                       BlockGraph::Reference* reference) {
 461  E :    DCHECK(reference != NULL);
 462    :  
 463    :    // Find or create the section we put our thunks in.
 464    :    BlockGraph::Section* thunk_section = block_graph->FindOrAddSection(
 465  E :        common::kThunkSectionName, pe::kCodeCharacteristics);
 466    :  
 467  E :    if (thunk_section == NULL) {
 468  i :      LOG(ERROR) << "Unable to find or create .thunks section.";
 469  i :      return false;
 470    :    }
 471    :  
 472    :    std::string stub_name_with_id = base::StringPrintf(
 473  E :        "%.*s%d", stub_name.length(), stub_name.data(), mode);
 474    :  
 475    :    // Create the thunk for standard "load/store" (received address in EDX).
 476  E :    BasicBlockSubGraph bbsg;
 477    :    BasicBlockSubGraph::BlockDescription* block_desc = bbsg.AddBlockDescription(
 478    :        stub_name_with_id,
 479    :        thunk_section->name(),
 480    :        BlockGraph::CODE_BLOCK,
 481    :        thunk_section->id(),
 482    :        1,
 483  E :        0);
 484    :  
 485  E :    BasicCodeBlock* bb = bbsg.AddBasicCodeBlock(stub_name_with_id);
 486  E :    block_desc->basic_block_order.push_back(bb);
 487  E :    BasicBlockAssembler assm(bb->instructions().begin(), &bb->instructions());
 488    :  
 489    :    if (mode == AsanBasicBlockTransform::kReadAccess ||
 490  E :        mode == AsanBasicBlockTransform::kWriteAccess) {
 491    :      // The thunk body restores the original value of EDX and cleans the stack on
 492    :      // return.
 493  E :      assm.mov(core::edx, Operand(core::esp, Displacement(4)));
 494  E :      assm.ret(4);
 495  E :    } else {
 496  E :      assm.ret();
 497    :    }
 498    :  
 499    :    // Condense into a block.
 500  E :    BlockBuilder block_builder(block_graph);
 501  E :    if (!block_builder.Merge(&bbsg)) {
 502  i :      LOG(ERROR) << "Failed to build thunk block.";
 503  i :      return NULL;
 504    :    }
 505    :  
 506    :    // Exactly one new block should have been created.
 507  E :    DCHECK_EQ(1u, block_builder.new_blocks().size());
 508  E :    BlockGraph::Block* thunk = block_builder.new_blocks().front();
 509    :  
 510  E :    *reference = BlockGraph::Reference(BlockGraph::ABSOLUTE_REF, 4, thunk, 0, 0);
 511    :  
 512  E :    return true;
 513  E :  }
 514    :  
 515    :  }  // namespace
 516    :  
 517    :  const char AsanBasicBlockTransform::kTransformName[] =
 518    :      "SyzyAsanBasicBlockTransform";
 519    :  
 520    :  bool AsanBasicBlockTransform::InstrumentBasicBlock(
 521  E :      BasicCodeBlock* basic_block, StackAccessMode stack_mode) {
 522  E :    DCHECK(basic_block != NULL);
 523    :  
 524    :    // Pre-compute liveness information for each instruction.
 525  E :    std::list<LivenessAnalysis::State> states;
 526  E :    LivenessAnalysis::State state;
 527  E :    if (use_liveness_analysis_) {
 528  E :      liveness_.GetStateAtExitOf(basic_block, &state);
 529    :  
 530    :      BasicBlock::Instructions::reverse_iterator rev_iter_inst =
 531  E :          basic_block->instructions().rbegin();
 532    :      BasicBlock::Instructions::const_reverse_iterator rev_iter_inst_end =
 533  E :          basic_block->instructions().rend();
 534  E :      for (; rev_iter_inst != rev_iter_inst_end; ++rev_iter_inst) {
 535  E :        const Instruction& instr = *rev_iter_inst;
 536  E :        liveness_.PropagateBackward(instr, &state);
 537  E :        states.push_front(state);
 538  E :      }
 539    :  
 540  E :      DCHECK_EQ(states.size(), basic_block->instructions().size());
 541    :    }
 542    :  
 543    :    // Get the memory accesses information for this basic block.
 544  E :    MemoryAccessAnalysis::State memory_state;
 545  E :    if (remove_redundant_checks_)
 546  E :      memory_accesses_.GetStateAtEntryOf(basic_block, &memory_state);
 547    :  
 548    :    // Process each instruction and inject a call to Asan when we find an
 549    :    // instrumentable memory access.
 550    :    BasicBlock::Instructions::iterator iter_inst =
 551  E :        basic_block->instructions().begin();
 552  E :    std::list<LivenessAnalysis::State>::iterator iter_state = states.begin();
 553  E :    for (; iter_inst != basic_block->instructions().end(); ++iter_inst) {
 554  E :      Operand operand(core::eax);
 555  E :      const Instruction& instr = *iter_inst;
 556  E :      const _DInst& repr = instr.representation();
 557    :  
 558    :      MemoryAccessInfo info;
 559  E :      info.mode = kNoAccess;
 560  E :      info.size = 0;
 561  E :      info.opcode = 0;
 562  E :      info.save_flags = true;
 563    :  
 564    :      // Get current instruction liveness information.
 565  E :      if (use_liveness_analysis_) {
 566  E :        state = *iter_state;
 567  E :        ++iter_state;
 568    :      }
 569    :  
 570    :      // When activated, skip redundant memory access check.
 571  E :      if (remove_redundant_checks_) {
 572  E :        bool need_memory_access_check = false;
 573  E :        if (memory_state.HasNonRedundantAccess(instr))
 574  E :          need_memory_access_check = true;
 575    :  
 576    :        // Update the memory accesses information for the current instruction.
 577  E :        memory_accesses_.PropagateForward(instr, &memory_state);
 578    :  
 579  E :        if (!need_memory_access_check)
 580  E :          continue;
 581    :      }
 582    :  
 583    :      // Insert hook for a standard instruction.
 584  E :      if (!DecodeMemoryAccess(instr, &operand, &info))
 585  E :        continue;
 586    :  
 587    :      // Bail if this is not a memory access.
 588  E :      if (info.mode == kNoAccess)
 589  i :        continue;
 590    :  
 591    :      // A basic block reference means that can be either a computed jump,
 592    :      // or a load from a case table. In either case it doesn't make sense
 593    :      // to instrument the access.
 594    :      if (operand.displacement().reference().referred_type() ==
 595  E :          BasicBlockReference::REFERRED_TYPE_BASIC_BLOCK) {
 596  E :        continue;
 597    :      }
 598    :  
 599    :      // A block reference means this instruction is reading or writing to
 600    :      // a global variable or some such. It's viable to pad and align global
 601    :      // variables and to red-zone the padding, but without that, there's nothing
 602    :      // to gain by instrumenting these accesses.
 603    :      if (operand.displacement().reference().referred_type() ==
 604  E :          BasicBlockReference::REFERRED_TYPE_BLOCK) {
 605  E :        continue;
 606    :      }
 607    :  
 608    :      // Is this an instruction we should be instrumenting.
 609  E :      if (!ShouldInstrumentOpcode(repr.opcode))
 610  E :        continue;
 611    :  
 612    :      // If there are no unconventional manipulations of the stack frame, we can
 613    :      // skip instrumenting stack-based memory access (based on ESP or EBP).
 614    :      // Conventionally, accesses through ESP/EBP are always on stack.
 615    :      if (stack_mode == kSafeStackAccess &&
 616    :          (operand.base() == core::kRegisterEsp ||
 617  E :           operand.base() == core::kRegisterEbp)) {
 618  E :        continue;
 619    :      }
 620    :  
 621    :      // We do not instrument memory accesses through special segments.
 622    :      // FS is used for thread local specifics and GS for CPU info.
 623  E :      uint8_t segment = SEGMENT_GET(repr.segment);
 624  E :      if (segment == R_FS || segment == R_GS)
 625  E :        continue;
 626    :  
 627    :      // Finally, don't instrument any filtered instructions.
 628  E :      if (IsFiltered(*iter_inst))
 629  E :        continue;
 630    :  
 631    :      // Create a BasicBlockAssembler to insert new instruction.
 632  E :      BasicBlockAssembler bb_asm(iter_inst, &basic_block->instructions());
 633    :  
 634    :      // Configure the assembler to copy the SourceRange information of the
 635    :      // current instrumented instruction into newly created instructions. This is
 636    :      // a hack to allow valid stack walking and better error reporting, but
 637    :      // breaks the 1:1 OMAP mapping and may confuse some debuggers.
 638  E :      if (debug_friendly_)
 639  E :        bb_asm.set_source_range(instr.source_range());
 640    :  
 641    :      if (use_liveness_analysis_ &&
 642  E :          (info.mode == kReadAccess || info.mode == kWriteAccess)) {
 643    :        // Use the liveness information to skip saving the flags if possible.
 644  E :        info.save_flags = state.AreArithmeticFlagsLive();
 645    :      }
 646    :  
 647    :      // Insert hook for standard instructions.
 648  E :      AsanHookMap::iterator hook = check_access_hooks_->find(info);
 649  E :      if (hook == check_access_hooks_->end()) {
 650  i :        LOG(ERROR) << "Invalid access : " << GetAsanCheckAccessFunctionName(info);
 651  i :        return false;
 652    :      }
 653    :  
 654    :      // Instrument this instruction.
 655  E :      InjectAsanHook(&bb_asm, info, operand, &hook->second, state);
 656  E :    }
 657    :  
 658  E :    DCHECK(iter_state == states.end());
 659    :  
 660  E :    return true;
 661  E :  }
 662    :  
 663    :  bool AsanBasicBlockTransform::TransformBasicBlockSubGraph(
 664    :      const TransformPolicyInterface* policy,
 665    :      BlockGraph* block_graph,
 666  E :      BasicBlockSubGraph* subgraph) {
 667  E :    DCHECK(policy != NULL);
 668  E :    DCHECK(block_graph != NULL);
 669  E :    DCHECK(subgraph != NULL);
 670    :  
 671    :    // Perform a global liveness analysis.
 672  E :    if (use_liveness_analysis_)
 673  E :      liveness_.Analyze(subgraph);
 674    :  
 675    :    // Perform a redundant memory access analysis.
 676  E :    if (remove_redundant_checks_)
 677  E :      memory_accesses_.Analyze(subgraph);
 678    :  
 679    :    // Determines if this subgraph uses unconventional stack pointer
 680    :    // manipulations.
 681  E :    StackAccessMode stack_mode = kUnsafeStackAccess;
 682  E :    if (!block_graph::HasUnexpectedStackFrameManipulation(subgraph))
 683  E :      stack_mode = kSafeStackAccess;
 684    :  
 685    :    // Iterates through each basic block and instruments it.
 686    :    BasicBlockSubGraph::BBCollection::iterator it =
 687  E :        subgraph->basic_blocks().begin();
 688  E :    for (; it != subgraph->basic_blocks().end(); ++it) {
 689  E :      BasicCodeBlock* bb = BasicCodeBlock::Cast(*it);
 690  E :      if (bb != NULL && !InstrumentBasicBlock(bb, stack_mode))
 691  i :        return false;
 692  E :    }
 693  E :    return true;
 694  E :  }
 695    :  
 696    :  const char AsanTransform::kTransformName[] = "SyzyAsanTransform";
 697    :  
 698    :  const char AsanTransform::kAsanHookStubName[] = "asan_hook_stub";
 699    :  
 700    :  const char AsanTransform::kSyzyAsanDll[] = "syzyasan_rtl.dll";
 701    :  
 702    :  AsanTransform::AsanTransform()
 703    :      : asan_dll_name_(kSyzyAsanDll),
 704    :        debug_friendly_(false),
 705    :        use_liveness_analysis_(false),
 706    :        remove_redundant_checks_(false),
 707    :        use_interceptors_(false),
 708  E :        check_access_hooks_ref_() {
 709  E :  }
 710    :  
 711    :  bool AsanTransform::PreBlockGraphIteration(
 712    :      const TransformPolicyInterface* policy,
 713    :      BlockGraph* block_graph,
 714  E :      BlockGraph::Block* header_block) {
 715  E :    DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), block_graph);
 716  E :    DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), header_block);
 717    :  
 718    :    // Ensure that this image has not already been instrumented.
 719  E :    if (block_graph->FindSection(common::kThunkSectionName)) {
 720  i :      LOG(ERROR) << "The image is already instrumented.";
 721  i :      return false;
 722    :    }
 723    :  
 724  E :    AccessHookParamVector access_hook_param_vec;
 725  E :    AsanBasicBlockTransform::AsanDefaultHookMap default_stub_map;
 726    :  
 727    :    // Create the hook stub for read/write instructions.
 728  E :    BlockGraph::Reference read_write_hook;
 729    :    if (!CreateHooksStub(block_graph, kAsanHookStubName,
 730    :                         AsanBasicBlockTransform::kReadAccess,
 731  E :                         &read_write_hook)) {
 732  i :      return false;
 733    :    }
 734    :  
 735    :    // Create the hook stub for strings instructions.
 736  E :    BlockGraph::Reference instr_hook;
 737    :    if (!CreateHooksStub(block_graph, kAsanHookStubName,
 738    :                         AsanBasicBlockTransform::kInstrAccess,
 739  E :                         &instr_hook)) {
 740  i :      return false;
 741    :    }
 742    :  
 743    :    // Map each memory access kind to an appropriate stub.
 744  E :    default_stub_map[AsanBasicBlockTransform::kReadAccess] = read_write_hook;
 745  E :    default_stub_map[AsanBasicBlockTransform::kWriteAccess] = read_write_hook;
 746  E :    default_stub_map[AsanBasicBlockTransform::kInstrAccess] = instr_hook;
 747  E :    default_stub_map[AsanBasicBlockTransform::kRepzAccess] = instr_hook;
 748  E :    default_stub_map[AsanBasicBlockTransform::kRepnzAccess] = instr_hook;
 749    :  
 750    :    // Add an import entry for the ASAN runtime.
 751  E :    ImportedModule import_module(asan_dll_name_);
 752    :  
 753    :    // Import the hooks for the read/write accesses.
 754  E :    for (int access_size = 1; access_size <= 32; access_size *= 2) {
 755    :      MemoryAccessInfo read_info =
 756  E :          { AsanBasicBlockTransform::kReadAccess, access_size, 0, true };
 757  E :      access_hook_param_vec.push_back(read_info);
 758  E :      if (use_liveness_analysis()) {
 759  E :        read_info.save_flags = false;
 760  E :        access_hook_param_vec.push_back(read_info);
 761    :      }
 762    :  
 763    :      MemoryAccessInfo write_info =
 764  E :          { AsanBasicBlockTransform::kWriteAccess, access_size, 0, true };
 765  E :      access_hook_param_vec.push_back(write_info);
 766  E :      if (use_liveness_analysis()) {
 767  E :        write_info.save_flags = false;
 768  E :        access_hook_param_vec.push_back(write_info);
 769    :      }
 770  E :    }
 771    :  
 772    :    // Import the hooks for the read/write 10-bytes accesses.
 773    :    MemoryAccessInfo read_info_10 =
 774  E :        { AsanBasicBlockTransform::kReadAccess, 10, 0, true };
 775  E :    access_hook_param_vec.push_back(read_info_10);
 776  E :    if (use_liveness_analysis()) {
 777  E :      read_info_10.save_flags = false;
 778  E :      access_hook_param_vec.push_back(read_info_10);
 779    :    }
 780    :  
 781    :    MemoryAccessInfo write_info_10 =
 782  E :        { AsanBasicBlockTransform::kWriteAccess, 10, 0, true };
 783  E :    access_hook_param_vec.push_back(write_info_10);
 784  E :    if (use_liveness_analysis()) {
 785  E :      write_info_10.save_flags = false;
 786  E :      access_hook_param_vec.push_back(write_info_10);
 787    :    }
 788    :  
 789    :    // Import the hooks for strings/prefix memory accesses.
 790  E :    const _InstructionType strings[] = { I_CMPS, I_MOVS, I_STOS };
 791  E :    int strings_length = sizeof(strings)/sizeof(_InstructionType);
 792    :  
 793  E :    for (int access_size = 1; access_size <= 4; access_size *= 2) {
 794  E :      for (int inst = 0; inst < strings_length; ++inst) {
 795    :        MemoryAccessInfo repz_inst_info = {
 796  E :           AsanBasicBlockTransform::kRepzAccess,
 797  E :           access_size,
 798  E :           strings[inst],
 799    :           true
 800  E :        };
 801  E :        access_hook_param_vec.push_back(repz_inst_info);
 802    :  
 803    :        MemoryAccessInfo inst_info = {
 804  E :            AsanBasicBlockTransform::kInstrAccess,
 805  E :            access_size,
 806  E :            strings[inst],
 807    :            true
 808  E :        };
 809  E :        access_hook_param_vec.push_back(inst_info);
 810  E :      }
 811  E :    }
 812    :  
 813    :    if (!AddAsanCheckAccessHooks(access_hook_param_vec,
 814    :                                 default_stub_map,
 815    :                                 &import_module,
 816    :                                 &check_access_hooks_ref_,
 817    :                                 policy,
 818    :                                 block_graph,
 819  E :                                 header_block)) {
 820  i :      return false;
 821    :    }
 822  E :    return true;
 823  E :  }
 824    :  
 825    :  bool AsanTransform::OnBlock(const TransformPolicyInterface* policy,
 826    :                              BlockGraph* block_graph,
 827  E :                              BlockGraph::Block* block) {
 828  E :    DCHECK(policy != NULL);
 829  E :    DCHECK(block_graph != NULL);
 830  E :    DCHECK(block != NULL);
 831    :  
 832  E :    if (!policy->BlockIsSafeToBasicBlockDecompose(block))
 833  E :      return true;
 834    :  
 835    :    // Use the filter that was passed to us for our child transform.
 836  E :    AsanBasicBlockTransform transform(&check_access_hooks_ref_);
 837  E :    transform.set_debug_friendly(debug_friendly());
 838  E :    transform.set_use_liveness_analysis(use_liveness_analysis());
 839  E :    transform.set_remove_redundant_checks(remove_redundant_checks());
 840  E :    transform.set_filter(filter());
 841    :  
 842    :    if (!ApplyBasicBlockSubGraphTransform(
 843  E :            &transform, policy, block_graph, block, NULL)) {
 844  i :      return false;
 845    :    }
 846    :  
 847  E :    return true;
 848  E :  }
 849    :  
 850    :  bool AsanTransform::PostBlockGraphIteration(
 851    :      const TransformPolicyInterface* policy,
 852    :      BlockGraph* block_graph,
 853  E :      BlockGraph::Block* header_block) {
 854  E :    DCHECK(policy != NULL);
 855  E :    DCHECK(block_graph != NULL);
 856  E :    DCHECK(header_block != NULL);
 857    :  
 858    :    // This function redirects the heap-related kernel32 imports to point to a set
 859    :    // of "override" imports in the ASAN runtime.
 860    :  
 861    :    static const size_t kInvalidIndex = -1;
 862    :  
 863    :    static const char* kKernel32RedirectionPrefix = "asan_";
 864    :    struct Kernel32ImportRedirect {
 865    :      const char* import_name;
 866    :      std::pair<size_t, size_t> override_indexes;
 867    :    };
 868  E :    static const Kernel32ImportRedirect kKernel32HeapRedirects[] = {
 869  E :      { "HeapCreate" },
 870  E :      { "HeapDestroy" },
 871  E :      { "HeapAlloc" },
 872  E :      { "HeapReAlloc" },
 873  E :      { "HeapFree" },
 874  E :      { "HeapSize" },
 875  E :      { "HeapValidate" },
 876  E :      { "HeapCompact" },
 877  E :      { "HeapLock" },
 878  E :      { "HeapUnlock" },
 879  E :      { "HeapWalk" },
 880  E :      { "HeapSetInformation" },
 881  E :      { "HeapQueryInformation" },
 882    :    };
 883  E :    static const Kernel32ImportRedirect kKernel32FunctionRedirects[] = {
 884  E :      { "ReadFile" },
 885  E :      { "WriteFile" },
 886    :    };
 887    :  
 888    :    // TODO(sebmarchand): Use the RedirectImport transform when it's ready.
 889  E :    std::vector<Kernel32ImportRedirect> kernel32_redirects;
 890  E :    for (size_t i = 0; i < arraysize(kKernel32HeapRedirects); ++i)
 891  E :      kernel32_redirects.push_back(kKernel32HeapRedirects[i]);
 892    :  
 893  E :    if (use_interceptors_) {
 894  E :      for (size_t i = 0; i < arraysize(kKernel32FunctionRedirects); ++i)
 895  E :        kernel32_redirects.push_back(kKernel32FunctionRedirects[i]);
 896    :    }
 897    :  
 898    :    // Initialize the module info for querying kernel32 imports.
 899  E :    ImportedModule module_kernel32("kernel32.dll");
 900    :    std::vector<Kernel32ImportRedirect>::iterator iter =
 901  E :        kernel32_redirects.begin();
 902  E :    for (; iter != kernel32_redirects.end(); ++iter) {
 903    :      size_t kernel32_index =
 904    :          module_kernel32.AddSymbol(iter->import_name,
 905  E :                                    ImportedModule::kFindOnly);
 906  E :      iter->override_indexes = std::make_pair(kernel32_index, kInvalidIndex);
 907  E :    }
 908    :  
 909    :    // Query the kernel32 imports.
 910  E :    PEAddImportsTransform find_kernel_imports;
 911  E :    find_kernel_imports.AddModule(&module_kernel32);
 912    :    if (!find_kernel_imports.TransformBlockGraph(
 913  E :            policy, block_graph, header_block)) {
 914  i :      LOG(ERROR) << "Unable to find kernel32 imports for redirection.";
 915  i :      return false;
 916    :    }
 917    :  
 918    :    // The timestamp 1 corresponds to Thursday, 01 Jan 1970 00:00:01 GMT. Setting
 919    :    // the timestamp of the image import descriptor to this value allows us to
 920    :    // temporarily bind the library until the loader finishes loading this module.
 921    :    // As the value is far in the past this means that the entries in the IAT for
 922    :    // this module will all be replaced by pointers into the actual library.
 923    :    // We need to bind the IAT for our module to make sure the stub is used until
 924    :    // the sandbox lets the loader finish patching the IAT entries.
 925    :    static const size_t kDateInThePast = 1;
 926    :  
 927    :    // Add ASAN imports for those kernel32 functions we found. These will later
 928    :    // be redirected.
 929  E :    ImportedModule module_asan(asan_dll_name_, kDateInThePast);
 930  E :    iter = kernel32_redirects.begin();
 931  E :    for (; iter != kernel32_redirects.end(); ++iter) {
 932  E :      size_t kernel32_index = iter->override_indexes.first;
 933  E :      if (module_kernel32.SymbolIsImported(kernel32_index)) {
 934    :        size_t asan_index = module_asan.AddSymbol(
 935    :            base::StringPrintf("%s%s",
 936    :                               kKernel32RedirectionPrefix,
 937    :                               iter->import_name),
 938  E :            ImportedModule::kAlwaysImport);
 939  E :        DCHECK_EQ(kInvalidIndex, iter->override_indexes.second);
 940  E :        iter->override_indexes.second = asan_index;
 941    :      }
 942  E :    }
 943    :  
 944    :    // Another transform can safely be run without invalidating the results
 945    :    // stored in module_kernel32, as additions to the IAT will strictly be
 946    :    // performed at the end.
 947  E :    PEAddImportsTransform add_imports_transform;
 948  E :    add_imports_transform.AddModule(&module_asan);
 949    :    if (!add_imports_transform.TransformBlockGraph(
 950  E :            policy, block_graph, header_block)) {
 951  i :      LOG(ERROR) << "Unable to add imports for import redirection.";
 952  i :      return false;
 953    :    }
 954    :  
 955    :    // Keeps track of all the blocks referenced by the original references.
 956  E :    BlockSet dst_blocks;
 957    :    // Stores the reference mapping we want to rewrite.
 958  E :    ReferenceMap reference_redirect_map;
 959    :  
 960  E :    iter = kernel32_redirects.begin();
 961  E :    for (; iter != kernel32_redirects.end(); ++iter) {
 962    :      // Symbols that aren't imported don't need to be redirected.
 963  E :      size_t kernel32_index = iter->override_indexes.first;
 964  E :      size_t asan_index = iter->override_indexes.second;
 965  E :      if (!module_kernel32.SymbolIsImported(kernel32_index)) {
 966  E :        DCHECK_EQ(kInvalidIndex, asan_index);
 967  E :        continue;
 968    :      }
 969    :  
 970  E :      DCHECK_NE(kInvalidIndex, asan_index);
 971  E :      BlockGraph::Reference src;
 972  E :      BlockGraph::Reference dst;
 973    :      if (!module_kernel32.GetSymbolReference(kernel32_index, &src) ||
 974  E :          !module_asan.GetSymbolReference(asan_index, &dst)) {
 975  i :         NOTREACHED() << "Unable to get references after a successful transform.";
 976  i :        return false;
 977    :      }
 978    :  
 979    :      // Add the destination block to the set of referred blocks.
 980  E :      dst_blocks.insert(src.referenced());
 981    :      reference_redirect_map.insert(
 982    :          std::make_pair(ReferenceDest(src.referenced(), src.offset()),
 983  E :                         ReferenceDest(dst.referenced(), dst.offset())));
 984  E :    }
 985    :  
 986  E :    RedirectReferences(dst_blocks, reference_redirect_map);
 987    :  
 988  E :    if (use_interceptors_) {
 989  E :      FunctionInterceptionSet interception_set;
 990  E :      interception_set.insert("memchr");
 991  E :      interception_set.insert("memcpy");
 992  E :      interception_set.insert("memmove");
 993  E :      interception_set.insert("memset");
 994  E :      interception_set.insert("strcspn");
 995  E :      interception_set.insert("strlen");
 996  E :      interception_set.insert("strrchr");
 997  E :      interception_set.insert("strcmp");
 998  E :      interception_set.insert("strpbrk");
 999  E :      interception_set.insert("strstr");
1000  E :      interception_set.insert("strspn");
1001  E :      interception_set.insert("strncpy");
1002  E :      interception_set.insert("strncat");
1003    :      InterceptFunctions(&module_asan,
1004    :                         policy,
1005    :                         block_graph,
1006    :                         header_block,
1007  E :                         interception_set);
1008  E :    }
1009    :  
1010  E :    return true;
1011  E :  }
1012    :  
1013    :  bool AsanTransform::InterceptFunctions(
1014    :      ImportedModule* import_module,
1015    :      const TransformPolicyInterface* policy,
1016    :      BlockGraph* block_graph,
1017    :      BlockGraph::Block* header_block,
1018  E :      const FunctionInterceptionSet& functions_set) {
1019  E :    DCHECK(import_module != NULL);
1020  E :    DCHECK(block_graph != NULL);
1021  E :    DCHECK(header_block != NULL);
1022    :  
1023    :    // The map containing the information about the functions that we want to
1024    :    // intercept.
1025  E :    FunctionInterceptionInfoMap function_redirection_info_map;
1026    :  
1027    :    // Find the blocks that we want to intercept. This is O(N log(M)), with N
1028    :    // being the number of blocks in the image and M the number of functions that
1029    :    // we want to intercept.
1030    :    block_graph::BlockGraph::BlockMap::iterator iter_blocks =
1031  E :        block_graph->blocks_mutable().begin();
1032  E :    for (; iter_blocks != block_graph->blocks_mutable().end(); ++iter_blocks) {
1033  E :      if (functions_set.find(iter_blocks->second.name()) == functions_set.end())
1034  E :        continue;
1035    :  
1036    :      // Generate the name of the hook for this function and add it to the image.
1037    :      std::string hook_name = base::StringPrintf("asan_%s",
1038  E :          iter_blocks->second.name().c_str());
1039    :      size_t symbol_index =
1040  E :          import_module->AddSymbol(hook_name, ImportedModule::kAlwaysImport);
1041    :  
1042    :      // Save the information about this block.
1043    :      function_redirection_info_map[
1044  E :          iter_blocks->second.name()].asan_symbol_index = symbol_index;
1045    :      function_redirection_info_map[iter_blocks->second.name()].function_block =
1046  E :          &iter_blocks->second;
1047  E :    }
1048    :  
1049    :    // Transforms the block-graph.
1050  E :    PEAddImportsTransform add_imports_transform;
1051  E :    add_imports_transform.AddModule(import_module);
1052    :    if (!add_imports_transform.TransformBlockGraph(
1053  E :            policy, block_graph, header_block)) {
1054  i :      LOG(ERROR) << "Unable to add imports for Asan instrumentation DLL.";
1055  i :      return false;
1056    :    }
1057    :  
1058    :    // Find or create the section we put our thunks in.
1059    :    BlockGraph::Section* thunk_section = block_graph->FindOrAddSection(
1060  E :        common::kThunkSectionName, pe::kCodeCharacteristics);
1061    :  
1062  E :    if (thunk_section == NULL) {
1063  i :      LOG(ERROR) << "Unable to find or create " << common::kThunkSectionName
1064    :                 << " section.";
1065  i :      return false;
1066    :    }
1067    :  
1068    :    // For every function that we want to intercept we create a thunk that'll
1069    :    // verify the parameters and call the original function.
1070    :    FunctionInterceptionInfoMap::iterator iter_redirection_info =
1071  E :        function_redirection_info_map.begin();
1072  E :    for (; iter_redirection_info != function_redirection_info_map.end();
1073  E :         ++iter_redirection_info) {
1074  E :      DCHECK(iter_redirection_info->second.function_block != NULL);
1075  E :      DCHECK_NE(~0U, iter_redirection_info->second.asan_symbol_index);
1076  E :      BlockGraph::Reference import_reference;
1077    :      if (!import_module->GetSymbolReference(
1078    :              iter_redirection_info->second.asan_symbol_index,
1079  E :              &import_reference)) {
1080  i :        LOG(ERROR) << "Unable to get import reference for Asan.";
1081  i :        return false;
1082    :      }
1083    :  
1084    :      // Generate the name of the thunk for this function.
1085    :      std::string thunk_name = base::StringPrintf("asan_%s_thunk",
1086  E :          iter_redirection_info->first.data());
1087    :  
1088    :      // Generate a basic code block for this thunk.
1089  E :      BasicBlockSubGraph bbsg;
1090    :      BasicBlockSubGraph::BlockDescription* block_desc = bbsg.AddBlockDescription(
1091    :          thunk_name,
1092    :          thunk_section->name(),
1093    :          BlockGraph::CODE_BLOCK,
1094    :          thunk_section->id(),
1095    :          1,
1096  E :          0);
1097  E :      BasicCodeBlock* bb = bbsg.AddBasicCodeBlock(thunk_name);
1098  E :      block_desc->basic_block_order.push_back(bb);
1099  E :      BasicBlockAssembler assm(bb->instructions().begin(), &bb->instructions());
1100    :      assm.jmp(Operand(Displacement(import_reference.referenced(),
1101  E :                                    import_reference.offset())));
1102    :  
1103    :      // Condense into a block.
1104  E :      BlockBuilder block_builder(block_graph);
1105  E :      if (!block_builder.Merge(&bbsg)) {
1106  i :        LOG(ERROR) << "Failed to build thunk block.";
1107  i :        return false;
1108    :      }
1109    :  
1110    :      // Exactly one new block should have been created.
1111  E :      DCHECK_EQ(1u, block_builder.new_blocks().size());
1112  E :      BlockGraph::Block* thunk = block_builder.new_blocks().front();
1113    :  
1114    :      // Transfer the references to the original block to the thunk.
1115    :      if (!iter_redirection_info->second.function_block->TransferReferrers(0,
1116  E :              thunk, BlockGraph::Block::kSkipInternalReferences)) {
1117  i :        LOG(ERROR) << "Failed to redirect the reference during the interception "
1118    :                   << "of a function.";
1119  i :        return false;
1120    :      }
1121    :  
1122    :      // Temporarily make the interceptor imports point to their original
1123    :      // function. These references will be ... has been loaded. This is necessary
1124    :      // so that Chrome sandbox code (which runs under the loader lock before all
1125    :      // imports have been resolved) doesn't crash.
1126    :      import_reference.referenced()->SetReference(import_reference.offset(),
1127    :          BlockGraph::Reference(BlockGraph::ABSOLUTE_REF, 4,
1128  E :              iter_redirection_info->second.function_block, 0, 0));
1129  E :    }
1130    :  
1131  E :    return true;
1132  E :  }
1133    :  
1134    :  bool operator<(const AsanBasicBlockTransform::MemoryAccessInfo& left,
1135  E :                 const AsanBasicBlockTransform::MemoryAccessInfo& right) {
1136  E :    if (left.mode != right.mode)
1137  E :      return left.mode < right.mode;
1138  E :    if (left.size != right.size)
1139  E :      return left.size < right.size;
1140  E :    if (left.save_flags != right.save_flags)
1141  E :      return left.save_flags < right.save_flags;
1142  E :    return left.opcode < right.opcode;
1143  E :  }
1144    :  
1145    :  }  // namespace transforms
1146    :  }  // namespace instrument

Coverage information generated Wed Dec 11 11:34:16 2013.