Coverage for /Syzygy/agent/asan/iat_patcher.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
65.9%27410.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/agent/asan/iat_patcher.h"
  16    :  
  17    :  #include <vector>
  18    :  
  19    :  #include "base/logging.h"
  20    :  #include "base/win/iat_patch_function.h"
  21    :  #include "base/win/pe_image.h"
  22    :  #include "syzygy/agent/asan/scoped_page_protections.h"
  23    :  #include "syzygy/common/align.h"
  24    :  #include "syzygy/common/com_utils.h"
  25    :  
  26    :  namespace agent {
  27    :  namespace asan {
  28    :  
  29    :  namespace {
  30    :  
  31    :  bool UpdateImportThunk(volatile PIMAGE_THUNK_DATA iat,
  32  i :                         FunctionPointer function) {
  33    :    // Writing to an IAT is inherently racy, as there may be other parties also
  34    :    // writing the same page at the same time. This gets ugly where multiple
  35    :    // parties mess with page protections, as VirtualProtect causes surprising
  36    :    // serialization. We therefore proceed with an abundance of caution, by
  37    :    // running inside an exception handler and using a compare-and-swap to
  38    :    // detect races on VM operations as well as on assignment.
  39    :  
  40  i :    __try {
  41  i :      DWORD old_fn = iat->u1.Function;
  42  i :      DWORD new_fn = reinterpret_cast<DWORD>(function);
  43    :      DWORD prev_fn =
  44  i :          ::InterlockedCompareExchange(&iat->u1.Function, new_fn, old_fn);
  45    :      // Check whether we collided on the assignment.
  46  i :      if (prev_fn != old_fn)
  47  i :        return false;
  48  i :    } __except(EXCEPTION_EXECUTE_HANDLER) {
  49    :      // We took an exception, that goes down as failure.
  50  i :      return false;
  51  i :    }
  52    :  
  53    :    // All shiny!
  54  i :    return true;
  55  i :  }
  56    :  
  57    :  class IATPatchWorker {
  58    :   public:
  59    :    explicit IATPatchWorker(const IATPatchMap& patch);
  60    :  
  61    :    bool PatchImage(base::win::PEImage* image);
  62    :  
  63    :   private:
  64    :    static bool VisitImport(const base::win::PEImage &image, LPCSTR module,
  65    :                            DWORD ordinal, LPCSTR name, DWORD hint,
  66    :                            PIMAGE_THUNK_DATA iat, PVOID cookie);
  67    :    bool OnImport(const char* name, PIMAGE_THUNK_DATA iat);
  68    :  
  69    :    ScopedPageProtections scoped_page_protections_;
  70    :    const IATPatchMap& patch_;
  71    :  
  72    :    DISALLOW_COPY_AND_ASSIGN(IATPatchWorker);
  73    :  };
  74    :  
  75  E :  IATPatchWorker::IATPatchWorker(const IATPatchMap& patch) : patch_(patch) {
  76  E :  }
  77    :  
  78  E :  bool IATPatchWorker::PatchImage(base::win::PEImage* image) {
  79  E :    DCHECK_NE(static_cast<base::win::PEImage*>(nullptr), image);
  80    :  
  81    :    // The IAT patching takes place during enumeration.
  82  E :    bool ret = image->EnumAllImports(&VisitImport, this);
  83    :  
  84    :    // Clean up whatever we soiled, success or failure be damned.
  85  E :    scoped_page_protections_.RestorePageProtections();
  86    :  
  87  E :    return ret;
  88  E :  }
  89    :  
  90    :  bool IATPatchWorker::VisitImport(
  91    :      const base::win::PEImage &image, LPCSTR module, DWORD ordinal,
  92  E :      LPCSTR name, DWORD hint, PIMAGE_THUNK_DATA iat, PVOID cookie) {
  93  E :    if (!name)
  94  E :      return true;
  95    :  
  96  E :    IATPatchWorker* worker = reinterpret_cast<IATPatchWorker*>(cookie);
  97  E :    return worker->OnImport(name, iat);
  98  E :  }
  99    :  
 100  E :  bool IATPatchWorker::OnImport(const char* name, PIMAGE_THUNK_DATA iat) {
 101  E :    auto it = patch_.find(name);
 102    :    // See whether this is a function we care about.
 103  E :    if (it == patch_.end())
 104  E :      return true;
 105    :  
 106    :    // Make the containing page writable.
 107    :    if (!scoped_page_protections_.EnsureContainingPagesWritable(
 108  E :            iat, sizeof(IMAGE_THUNK_DATA))) {
 109  i :      return false;
 110    :    }
 111    :  
 112  E :    return UpdateImportThunk(iat, it->second);
 113  E :  }
 114    :  
 115    :  }  // namespace
 116    :  
 117  E :  bool PatchIATForModule(HMODULE module, const IATPatchMap& patch_map) {
 118  E :    base::win::PEImage image(module);
 119    :  
 120  E :    if (!image.VerifyMagic())
 121  i :      return false;
 122    :  
 123  E :    IATPatchWorker worker(patch_map);
 124    :  
 125  E :    return worker.PatchImage(&image);
 126  E :  }
 127    :  
 128    :  }  // namespace asan
 129    :  }  // namespace agent

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