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 "syzygy/agent/asan/asan_runtime.h"
18 : #include "syzygy/agent/asan/page_protection_helpers.h"
19 : #include "syzygy/agent/asan/shadow.h"
20 :
21 : namespace agent {
22 : namespace asan {
23 :
24 E : bool HeapChecker::IsHeapCorrupt(CorruptRangesVector* corrupt_ranges) {
25 E : DCHECK_NE(reinterpret_cast<CorruptRangesVector*>(NULL), corrupt_ranges);
26 :
27 E : corrupt_ranges->clear();
28 :
29 : // Grab the page protection lock. This prevents multiple heap checkers from
30 : // running simultaneously, and also prevents page protections from being
31 : // modified from underneath us.
32 E : ::common::AutoRecursiveLock scoped_lock(block_protect_lock);
33 :
34 : // Walk over all of the addressable memory to find the corrupt blocks.
35 : // TODO(sebmarchand): Iterates over the heap slabs once we have switched to
36 : // a new memory allocator.
37 : GetCorruptRangesInSlab(
38 : reinterpret_cast<const uint8*>(Shadow::kAddressLowerBound),
39 : Shadow::kAddressUpperBound - Shadow::kAddressLowerBound - 1,
40 E : corrupt_ranges);
41 :
42 E : return !corrupt_ranges->empty();
43 E : }
44 :
45 : void HeapChecker::GetCorruptRangesInSlab(const uint8* lower_bound,
46 : size_t length,
47 E : CorruptRangesVector* corrupt_ranges) {
48 E : DCHECK_NE(reinterpret_cast<const uint8*>(NULL), lower_bound);
49 E : DCHECK_NE(0U, length);
50 E : DCHECK_NE(reinterpret_cast<CorruptRangesVector*>(NULL), corrupt_ranges);
51 :
52 E : ShadowWalker shadow_walker(false, lower_bound, lower_bound + length);
53 :
54 E : AsanCorruptBlockRange* current_corrupt_range = NULL;
55 :
56 : // Iterates over the blocks.
57 E : BlockInfo block_info = {};
58 E : while (shadow_walker.Next(&block_info)) {
59 : // Remove the protections on this block so its checksum can be safely
60 : // validated. We leave the protections permanently removed so that the
61 : // minidump generation has free access to block contents.
62 E : BlockProtectNone(block_info);
63 :
64 E : bool current_block_is_corrupt = IsBlockCorrupt(block_info.block, NULL);
65 : // If the current block is corrupt and |current_corrupt_range| is NULL
66 : // then this means that the current block is at the beginning of a corrupt
67 : // range.
68 E : if (current_block_is_corrupt && current_corrupt_range == NULL) {
69 : AsanCorruptBlockRange corrupt_range;
70 E : corrupt_range.address = block_info.block;
71 E : corrupt_range.length = 0;
72 E : corrupt_range.block_count = 0;
73 E : corrupt_range.block_info = NULL;
74 E : corrupt_range.block_info_count = 0;
75 E : corrupt_ranges->push_back(corrupt_range);
76 E : current_corrupt_range = &corrupt_ranges->back();
77 E : } else if (!current_block_is_corrupt && current_corrupt_range != NULL) {
78 E : current_corrupt_range = NULL;
79 : }
80 :
81 E : if (current_block_is_corrupt) {
82 : // If the current block is corrupt then we need to update the size of the
83 : // current range.
84 : DCHECK_NE(reinterpret_cast<AsanCorruptBlockRange*>(NULL),
85 E : current_corrupt_range);
86 E : current_corrupt_range->block_count++;
87 E : const uint8* current_block_end = block_info.block + block_info.block_size;
88 : current_corrupt_range->length = current_block_end -
89 E : reinterpret_cast<const uint8*>(current_corrupt_range->address);
90 : }
91 E : }
92 E : }
93 :
94 : } // namespace asan
95 : } // namespace agent
|