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

Coverage information generated Thu Mar 26 16:15:41 2015.