Coverage for /Syzygy/refinery/validators/vftable_ptr_validator.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
0.0%00128.C++source

Line-by-line coverage:

   1    :  // Copyright 2015 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/refinery/validators/vftable_ptr_validator.h"
  16    :  
  17    :  #include <string>
  18    :  
  19    :  #include "base/strings/stringprintf.h"
  20    :  #include "syzygy/refinery/process_state/process_state_util.h"
  21    :  #include "syzygy/refinery/process_state/refinery.pb.h"
  22    :  #include "syzygy/refinery/types/type.h"
  23    :  
  24  m :  namespace refinery {
  25    :  
  26  m :  namespace {
  27    :  
  28  m :  TypePtr RecoverType(ModuleLayerAccessor* accessor,
  29  m :                      SymbolProvider* provider,
  30  m :                      const TypedBlock& typedblock) {
  31  m :    DCHECK(accessor);
  32  m :    DCHECK(provider);
  33    :  
  34  m :    pe::PEFile::Signature signature;
  35  m :    if (!accessor->GetModuleSignature(typedblock.module_id(), &signature))
  36  m :      return nullptr;
  37    :  
  38  m :    scoped_refptr<TypeRepository> type_repository;
  39  m :    if (!provider->FindOrCreateTypeRepository(signature, &type_repository))
  40  m :      return nullptr;
  41    :  
  42  m :    return type_repository->GetType(typedblock.type_id());
  43  m :  }
  44    :  
  45  m :  void AddViolation(const TypedData& typed_data, ValidationReport* report) {
  46  m :    DCHECK(typed_data.IsValid());
  47  m :    DCHECK(report);
  48    :  
  49  m :    Violation* violation = report->add_error();
  50  m :    violation->set_type(VIOLATION_VFPTR);
  51    :  
  52  m :    std::string description = base::StringPrintf(
  53  m :        "Type %ls at address %08X has an incorrect vfptr.",
  54  m :        typed_data.type()->GetName().c_str(), typed_data.GetRange().start());
  55  m :    violation->set_description(description);
  56  m :  }
  57    :  
  58  m :  }  // namespace
  59    :  
  60  m :  VftablePtrValidator::VftablePtrValidator(
  61  m :      scoped_refptr<SymbolProvider> symbol_provider)
  62  m :      : symbol_provider_(symbol_provider) {
  63  m :    DCHECK(symbol_provider);
  64  m :  }
  65    :  
  66  m :  Validator::ValidationResult VftablePtrValidator::Validate(
  67  m :      ProcessState* process_state,
  68  m :      ValidationReport* report) {
  69  m :    DCHECK(process_state);
  70  m :    DCHECK(report);
  71    :  
  72    :    // Analyzers that build content for the bytes and typed block layer must have
  73    :    // already run. We use the existence of a bytes layer and a typed block layer
  74    :    // as a proxy for this.
  75  m :    BytesLayerPtr bytes_layer;
  76  m :    if (!process_state->FindLayer(&bytes_layer)) {
  77  m :      LOG(ERROR) << "Missing bytes layer.";
  78  m :      return VALIDATION_ERROR;
  79  m :    }
  80  m :    TypedBlockLayerPtr typed_layer;
  81  m :    if (!process_state->FindLayer(&typed_layer)) {
  82  m :      LOG(ERROR) << "Missing typed block layer.";
  83  m :      return VALIDATION_ERROR;
  84  m :    }
  85    :  
  86    :    // Get the set of valid vftable ptrs.
  87    :    // Go through the typed block layer for validation.
  88  m :    base::hash_set<Address> vftable_vas;
  89  m :    if (!GetVFTableVAs(process_state, symbol_provider_.get(), &vftable_vas)) {
  90  m :      LOG(ERROR) << "Failed to get vfptr VAs.";
  91  m :      return VALIDATION_ERROR;
  92  m :    }
  93    :  
  94    :    // Validate each typed block.
  95  m :    ModuleLayerAccessor accessor(process_state);
  96  m :    for (TypedBlockRecordPtr rec : *typed_layer) {
  97  m :      TypePtr type = RecoverType(&accessor, symbol_provider_.get(), rec->data());
  98  m :      if (type == nullptr)
  99  m :        return VALIDATION_ERROR;
 100    :  
 101  m :      TypedData typed_data(process_state, type, rec->range().start());
 102  m :      ValidateTypedData(typed_data, vftable_vas, report);
 103  m :    }
 104    :  
 105  m :    return VALIDATION_COMPLETE;
 106  m :  }
 107    :  
 108  m :  bool VftablePtrValidator::GetVFTableVAs(
 109  m :      ProcessState* process_state,
 110  m :      SymbolProvider* symbol_provider,
 111  m :      base::hash_set<RelativeAddress>* vftable_vas) {
 112  m :    DCHECK(process_state);
 113  m :    DCHECK(symbol_provider);
 114  m :    DCHECK(vftable_vas);
 115    :  
 116  m :    ModuleLayerPtr layer;
 117  m :    if (!process_state->FindLayer(&layer))
 118  m :      return false;  // We expect to find a module layer (though possibly empty).
 119  m :    ModuleLayerAccessor accessor(process_state);
 120    :  
 121    :    // Note: no optimisation for multiples instances of the same module.
 122  m :    for (ModuleRecordPtr record : *layer) {
 123  m :      pe::PEFile::Signature signature;
 124  m :      if (!accessor.GetModuleSignature(record->data().module_id(), &signature))
 125  m :        return false;
 126    :  
 127  m :      base::hash_set<Address> vftable_rvas;
 128  m :      if (!symbol_provider->GetVFTableRVAs(signature, &vftable_rvas))
 129  m :        return false;
 130    :  
 131  m :      Address module_base = record->range().start();
 132  m :      for (Address rva : vftable_rvas) {
 133  m :        base::CheckedNumeric<Address> virtual_address = module_base;
 134  m :        virtual_address += rva;
 135  m :        if (!virtual_address.IsValid())
 136  m :          return false;
 137    :  
 138  m :        vftable_vas->insert(virtual_address.ValueOrDie());
 139  m :      }
 140  m :    }
 141    :  
 142  m :    return true;
 143  m :  }
 144    :  
 145  m :  bool VftablePtrValidator::ValidateTypedData(
 146  m :      const TypedData& typed_data,
 147  m :      const base::hash_set<Address>& vftable_vas,
 148  m :      ValidationReport* report) {
 149  m :    DCHECK(typed_data.IsValid());
 150  m :    DCHECK(report);
 151    :  
 152    :    // Restrict to UDTs.
 153  m :    if (!typed_data.IsUserDefinedType())
 154  m :      return false;
 155    :  
 156  m :    size_t field_cnt;
 157  m :    if (!typed_data.GetFieldCount(&field_cnt))
 158  m :      return false;
 159    :  
 160  m :    for (size_t i = 0; i < field_cnt; ++i) {
 161  m :      FieldPtr field;
 162  m :      if (!typed_data.GetField(i, &field))
 163  m :        return false;
 164  m :      TypedData field_data;
 165  m :      if (!typed_data.GetField(i, &field_data))
 166  m :        return false;
 167    :  
 168  m :      switch (field->kind()) {
 169  m :        case UserDefinedType::Field::VFPTR_KIND: {
 170  m :          Address vfptr;
 171  m :          if (field_data.GetPointerValue(&vfptr) &&
 172  m :              vftable_vas.find(vfptr) == vftable_vas.end()) {
 173    :            // The value of the vfptr was retrieved but it's not in the allowed
 174    :            // set. Add a violation.
 175  m :            AddViolation(typed_data, report);
 176  m :          }
 177  m :          break;
 178  m :        }
 179  m :        case UserDefinedType::Field::BASE_CLASS_KIND:
 180  m :        case UserDefinedType::Field::MEMBER_KIND: {
 181    :          // Recurse on "nested" UDTs (base classes and members).
 182  m :          if (!ValidateTypedData(field_data, vftable_vas, report))
 183  m :            return false;
 184  m :          break;
 185  m :        }
 186  m :      }
 187  m :    }
 188    :  
 189  m :    return true;
 190  m :  }
 191    :  
 192  m :  }  // namespace refinery

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