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

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
100.0%1031030.C++test

Line-by-line coverage:

   1    :  // Copyright 2014 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/heap_checker.h"
  16    :  
  17    :  #include "base/rand_util.h"
  18    :  #include "gtest/gtest.h"
  19    :  #include "syzygy/agent/asan/logger.h"
  20    :  #include "syzygy/agent/asan/page_protection_helpers.h"
  21    :  #include "syzygy/agent/asan/runtime.h"
  22    :  #include "syzygy/agent/asan/unittest_util.h"
  23    :  
  24    :  namespace agent {
  25    :  namespace asan {
  26    :  
  27    :  namespace {
  28    :  
  29    :  typedef public testing::TestWithAsanRuntime HeapCheckerTest;
  30    :  
  31    :  using testing::FakeAsanBlock;
  32    :  
  33    :  }  // namespace
  34    :  
  35  E :  TEST_F(HeapCheckerTest, HeapCheckerHandlesPageProtections) {
  36    :    // Make a large allocation bigger than a couple pages. This will ensure
  37    :    // that its big enough to have page protections. The HeapChecker will have
  38    :    // to unset these in order to do its work successfully. Otherwise it will
  39    :    // cause an access violation.
  40    :    FakeAsanBlock fake_large_block(
  41  E :        runtime_->shadow(), kShadowRatioLog, runtime_->stack_cache());
  42  E :    fake_large_block.InitializeBlock(2 * GetPageSize());
  43  E :    base::RandBytes(fake_large_block.block_info.body, 2 * GetPageSize());
  44  E :    fake_large_block.MarkBlockAsQuarantined();
  45  E :    BlockProtectAll(fake_large_block.block_info, runtime_->shadow());
  46    :  
  47  E :    HeapChecker heap_checker(runtime_->shadow());
  48  E :    HeapChecker::CorruptRangesVector corrupt_ranges;
  49  E :    EXPECT_FALSE(heap_checker.IsHeapCorrupt(&corrupt_ranges));
  50    :  
  51  E :    BlockProtectNone(fake_large_block.block_info, runtime_->shadow());
  52  E :  }
  53    :  
  54  E :  TEST_F(HeapCheckerTest, IsHeapCorruptInvalidChecksum) {
  55  E :    const size_t kAllocSize = 100;
  56    :    FakeAsanBlock fake_block(
  57  E :        runtime_->shadow(), kShadowRatioLog, runtime_->stack_cache());
  58    :  
  59  E :    fake_block.InitializeBlock(kAllocSize);
  60  E :    base::RandBytes(fake_block.block_info.body, kAllocSize);
  61    :  
  62  E :    HeapChecker heap_checker(runtime_->shadow());
  63  E :    HeapChecker::CorruptRangesVector corrupt_ranges;
  64  E :    EXPECT_FALSE(heap_checker.IsHeapCorrupt(&corrupt_ranges));
  65    :  
  66    :    // Free the block and corrupt its data.
  67  E :    ASSERT_TRUE(fake_block.MarkBlockAsQuarantined());
  68  E :    size_t header_checksum = fake_block.block_info.header->checksum;
  69    :  
  70    :    // Corrupt the data in such a way that we can guarantee no hash collision.
  71  E :    const size_t kMaxIterations = 10;
  72  E :    size_t iteration = 0;
  73  E :    uint8 original_value = fake_block.block_info.RawBody(0);
  74    :    do {
  75  E :      fake_block.block_info.RawBody(0)++;
  76  E :      BlockSetChecksum(fake_block.block_info);
  77    :    } while (fake_block.block_info.header->checksum == header_checksum &&
  78  E :             iteration++ < kMaxIterations);
  79    :  
  80    :    // Restore the checksum to make sure that the corruption gets detected.
  81  E :    fake_block.block_info.header->checksum = header_checksum;
  82    :  
  83  E :    EXPECT_TRUE(heap_checker.IsHeapCorrupt(&corrupt_ranges));
  84  E :    ASSERT_EQ(1, corrupt_ranges.size());
  85  E :    AsanCorruptBlockRange range_info = *corrupt_ranges.begin();
  86    :  
  87  E :    EXPECT_EQ(1, range_info.block_count);
  88    :    ShadowWalker shadow_walker(
  89    :        runtime_->shadow(),
  90    :        false,
  91    :        reinterpret_cast<const uint8*>(range_info.address),
  92  E :        reinterpret_cast<const uint8*>(range_info.address) + range_info.length);
  93  E :    BlockInfo block_info = {};
  94  E :    EXPECT_TRUE(shadow_walker.Next(&block_info));
  95  E :    EXPECT_EQ(fake_block.block_info.header, block_info.header);
  96  E :    EXPECT_FALSE(shadow_walker.Next(&block_info));
  97    :  
  98  E :    fake_block.block_info.header->checksum = header_checksum;
  99  E :    fake_block.block_info.RawBody(0) = original_value;
 100  E :    EXPECT_FALSE(heap_checker.IsHeapCorrupt(&corrupt_ranges));
 101  E :  }
 102    :  
 103  E :  TEST_F(HeapCheckerTest, IsHeapCorruptInvalidMagicNumber) {
 104  E :    const size_t kAllocSize = 100;
 105    :    FakeAsanBlock fake_block(
 106  E :        runtime_->shadow(), kShadowRatioLog, runtime_->stack_cache());
 107    :  
 108  E :    fake_block.InitializeBlock(kAllocSize);
 109  E :    base::RandBytes(fake_block.block_info.body, kAllocSize);
 110    :  
 111  E :    HeapChecker heap_checker(runtime_->shadow());
 112  E :    HeapChecker::CorruptRangesVector corrupt_ranges;
 113  E :    EXPECT_FALSE(heap_checker.IsHeapCorrupt(&corrupt_ranges));
 114    :  
 115    :    // Corrupt the header of the block and ensure that the heap corruption gets
 116    :    // detected.
 117  E :    fake_block.block_info.header->magic = ~fake_block.block_info.header->magic;
 118  E :    EXPECT_TRUE(heap_checker.IsHeapCorrupt(&corrupt_ranges));
 119  E :    ASSERT_EQ(1, corrupt_ranges.size());
 120  E :    AsanCorruptBlockRange range_info = *corrupt_ranges.begin();
 121    :  
 122  E :    EXPECT_EQ(1, range_info.block_count);
 123    :    ShadowWalker shadow_walker(
 124    :        runtime_->shadow(),
 125    :        false,
 126    :        reinterpret_cast<const uint8*>(range_info.address),
 127  E :        reinterpret_cast<const uint8*>(range_info.address) + range_info.length);
 128  E :    BlockInfo block_info = {};
 129  E :    EXPECT_TRUE(shadow_walker.Next(&block_info));
 130  E :    EXPECT_EQ(fake_block.block_info.header, block_info.header);
 131  E :    EXPECT_FALSE(shadow_walker.Next(&block_info));
 132    :  
 133  E :    fake_block.block_info.header->magic = ~fake_block.block_info.header->magic;
 134  E :    EXPECT_FALSE(heap_checker.IsHeapCorrupt(&corrupt_ranges));
 135  E :  }
 136    :  
 137  E :  TEST_F(HeapCheckerTest, IsHeapCorrupt) {
 138  E :    const size_t kAllocSize = 100;
 139    :  
 140  E :    BlockLayout block_layout = {};
 141    :    EXPECT_TRUE(BlockPlanLayout(kShadowRatio, kShadowRatio, kAllocSize, 0, 0,
 142  E :                                &block_layout));
 143    :  
 144  E :    const size_t kNumberOfBlocks = 4;
 145  E :    size_t total_alloc_size = block_layout.block_size * kNumberOfBlocks;
 146  E :    uint8* global_alloc = reinterpret_cast<uint8*>(::malloc(total_alloc_size));
 147    :  
 148    :    uint8* blocks[kNumberOfBlocks];
 149    :    BlockHeader* block_headers[kNumberOfBlocks];
 150    :  
 151  E :    for (size_t i = 0; i < kNumberOfBlocks; ++i) {
 152  E :      blocks[i] = global_alloc + i * block_layout.block_size;
 153  E :      BlockInfo block_info = {};
 154  E :      BlockInitialize(block_layout, blocks[i], false, &block_info);
 155  E :      runtime_->shadow()->PoisonAllocatedBlock(block_info);
 156  E :      BlockSetChecksum(block_info);
 157  E :      block_headers[i] = block_info.header;
 158  E :      EXPECT_EQ(block_headers[i], reinterpret_cast<BlockHeader*>(blocks[i]));
 159  E :    }
 160    :  
 161  E :    HeapChecker heap_checker(runtime_->shadow());
 162  E :    HeapChecker::CorruptRangesVector corrupt_ranges;
 163  E :    EXPECT_FALSE(heap_checker.IsHeapCorrupt(&corrupt_ranges));
 164    :  
 165    :    // Corrupt the header of the first two blocks and of the last one.
 166  E :    block_headers[0]->magic++;
 167  E :    block_headers[1]->magic++;
 168  E :    block_headers[kNumberOfBlocks - 1]->magic++;
 169    :  
 170  E :    EXPECT_TRUE(heap_checker.IsHeapCorrupt(&corrupt_ranges));
 171    :  
 172    :    // We expect the heap to contain 2 ranges of corrupt blocks, the first one
 173    :    // containing the 2 first blocks and the second one containing the last block.
 174    :  
 175  E :    EXPECT_EQ(2, corrupt_ranges.size());
 176    :  
 177  E :    BlockInfo block_info = {};
 178    :    ShadowWalker shadow_walker_1(
 179    :        runtime_->shadow(),
 180    :        false,
 181    :        reinterpret_cast<const uint8*>(corrupt_ranges[0].address),
 182    :        reinterpret_cast<const uint8*>(corrupt_ranges[0].address) +
 183  E :            corrupt_ranges[0].length);
 184  E :    EXPECT_TRUE(shadow_walker_1.Next(&block_info));
 185    :    EXPECT_EQ(reinterpret_cast<const BlockHeader*>(block_info.header),
 186  E :              block_headers[0]);
 187  E :    EXPECT_TRUE(shadow_walker_1.Next(&block_info));
 188    :    EXPECT_EQ(reinterpret_cast<const BlockHeader*>(block_info.header),
 189  E :              block_headers[1]);
 190  E :    EXPECT_FALSE(shadow_walker_1.Next(&block_info));
 191    :  
 192    :    ShadowWalker shadow_walker_2(
 193    :        runtime_->shadow(),
 194    :        false,
 195    :        reinterpret_cast<const uint8*>(corrupt_ranges[1].address),
 196    :        reinterpret_cast<const uint8*>(corrupt_ranges[1].address) +
 197  E :            corrupt_ranges[1].length);
 198  E :    EXPECT_TRUE(shadow_walker_2.Next(&block_info));
 199    :    EXPECT_EQ(reinterpret_cast<const BlockHeader*>(block_info.header),
 200  E :              block_headers[kNumberOfBlocks - 1]);
 201  E :    EXPECT_FALSE(shadow_walker_2.Next(&block_info));
 202    :  
 203    :    // Restore the checksum of the blocks.
 204  E :    block_headers[0]->magic--;
 205  E :    block_headers[1]->magic--;
 206  E :    block_headers[kNumberOfBlocks - 1]->magic--;
 207    :  
 208  E :    runtime_->shadow()->Unpoison(global_alloc, total_alloc_size);
 209  E :    ::free(global_alloc);
 210  E :  }
 211    :  
 212    :  }  // namespace asan
 213    :  }  // namespace agent

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