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

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
76.5%39510.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    :  // Declares a helper class for use in performing hot-patching operations.
  16    :  // The class takes care of modifying page protections as the patcher works.
  17    :  
  18    :  #include "syzygy/agent/asan/scoped_page_protections.h"
  19    :  
  20    :  #include "base/logging.h"
  21    :  #include "syzygy/agent/asan/constants.h"
  22    :  #include "syzygy/common/align.h"
  23    :  #include "syzygy/common/com_utils.h"
  24    :  
  25    :  namespace agent {
  26    :  namespace asan {
  27    :  
  28  E :  ScopedPageProtections::~ScopedPageProtections() {
  29  E :    RestorePageProtections();
  30  E :  }
  31    :  
  32    :  bool ScopedPageProtections::EnsureContainingPagesWritable(void* addr,
  33  E :                                                            size_t size) {
  34    :    // Ensure the entire space of pages covered by the provided range is
  35    :    // writable.
  36  E :    uint8* cursor = reinterpret_cast<uint8*>(addr);
  37  E :    uint8* page_begin = common::AlignDown(cursor, GetPageSize());
  38  E :    uint8* page_end = common::AlignUp(cursor + size, GetPageSize());
  39  E :    while (page_begin < page_end) {
  40  E :      if (!EnsurePageWritable(page_begin))
  41  i :        return false;
  42  E :      page_begin += GetPageSize();
  43  E :    }
  44    :  
  45  E :    return true;
  46  E :  }
  47    :  
  48  E :  bool ScopedPageProtections::RestorePageProtections() {
  49    :    // Grab the list of pages to unprotect.
  50  E :    UnprotectedPages to_unprotect;
  51  E :    unprotected_pages_.swap(to_unprotect);
  52    :  
  53    :    // Best-effort restore the old page protections, and remember pages for
  54    :    // which the effort failed.
  55  E :    bool did_succeed = true;
  56  E :    for (const auto& unprotected_page : to_unprotect) {
  57  E :      DWORD old_prot = 0;
  58    :      if (!::VirtualProtect(unprotected_page.first, GetPageSize(),
  59  E :                            unprotected_page.second, &old_prot)) {
  60  i :        DWORD error = ::GetLastError();
  61  i :        LOG(ERROR) << "VirtualProtect failed: " << common::LogWe(error);
  62    :  
  63    :        // Pages that failed to be unprotected are reinserted into the set of
  64    :        // pages being tracked.
  65  i :        bool inserted = unprotected_pages_.insert(unprotected_page).second;
  66  i :        DCHECK(inserted);
  67    :  
  68  i :        did_succeed = false;
  69    :      }
  70  E :    }
  71    :  
  72  E :    return did_succeed;
  73  E :  }
  74    :  
  75  E :  bool ScopedPageProtections::EnsurePageWritable(void* page) {
  76  E :    DCHECK(common::IsAligned(page, GetPageSize()));
  77    :  
  78    :    // Check whether we've already unprotected this page.
  79  E :    if (unprotected_pages_.find(page) != unprotected_pages_.end())
  80  E :      return true;
  81    :  
  82    :    // We didn't unprotect this yet, make the page writable.
  83  E :    MEMORY_BASIC_INFORMATION memory_info{};
  84  E :    if (!::VirtualQuery(page, &memory_info, sizeof(memory_info))) {
  85  i :      DWORD error = ::GetLastError();
  86  i :      LOG(ERROR) << "VirtualQuery failed: " << common::LogWe(error);
  87  i :      return false;
  88    :    }
  89    :  
  90    :    // Preserve executable status while patching.
  91    :    DWORD is_executable = (PAGE_EXECUTE | PAGE_EXECUTE_READ |
  92    :                           PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY) &
  93  E :                          memory_info.Protect;
  94  E :    DWORD new_prot = PAGE_READWRITE;
  95  E :    if (is_executable)
  96  E :      new_prot = PAGE_EXECUTE_READWRITE;
  97    :  
  98  E :    DWORD old_prot = 0;
  99  E :    if (!::VirtualProtect(page, GetPageSize(), new_prot, &old_prot)) {
 100  i :      DWORD error = ::GetLastError();
 101  i :      LOG(ERROR) << "VirtualProtect failed: " << common::LogWe(error);
 102  i :      return false;
 103    :    }
 104    :  
 105    :    // Make a note that we modified this page, as well as its original settings.
 106    :    bool inserted =
 107  E :        unprotected_pages_.insert(std::make_pair(page, old_prot)).second;
 108  E :    DCHECK(inserted);
 109    :  
 110  E :    return true;
 111  E :  }
 112    :  
 113    :  }  // namespace asan
 114    :  }  // namespace agent

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