1 : // Copyright 2012 Google Inc.
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 : #include "syzygy/agent/asan/asan_heap.h"
15 :
16 : #include "base/logging.h"
17 : #include "syzygy/agent/asan/asan_shadow.h"
18 :
19 : namespace agent {
20 : namespace asan {
21 :
22 : namespace {
23 :
24 : // Redzone size allocated at the start of every heap block.
25 : const size_t kRedZoneSize = 32;
26 :
27 : } // namespace
28 :
29 : HeapProxy::HeapProxy()
30 : : heap_(NULL),
31 : head_(NULL),
32 : tail_(NULL),
33 E : quarantine_size_(0) {
34 E : }
35 :
36 E : HeapProxy::~HeapProxy() {
37 E : if (heap_ != NULL)
38 i : Destroy();
39 :
40 E : DCHECK(heap_ == NULL);
41 E : }
42 :
43 E : HANDLE HeapProxy::ToHandle(HeapProxy* proxy) {
44 E : return proxy;
45 E : }
46 :
47 E : HeapProxy* HeapProxy::FromHandle(HANDLE heap) {
48 E : return reinterpret_cast<HeapProxy*>(heap);
49 E : }
50 :
51 : bool HeapProxy::Create(DWORD options,
52 : size_t initial_size,
53 E : size_t maximum_size) {
54 E : DCHECK(heap_ == NULL);
55 :
56 E : heap_ = ::HeapCreate(options, initial_size, maximum_size);
57 E : if (heap_ != NULL)
58 E : return true;
59 :
60 i : return false;
61 E : }
62 :
63 E : bool HeapProxy::Destroy(){
64 E : DCHECK(heap_ != NULL);
65 E : if (::HeapDestroy(heap_)) {
66 E : heap_ = NULL;
67 E : return true;
68 : }
69 :
70 i : return false;
71 E : }
72 :
73 E : void* HeapProxy::Alloc(DWORD flags, size_t bytes){
74 E : DCHECK(heap_ != NULL);
75 :
76 E : size_t alloc_size = GetAllocSize(bytes);
77 : BlockHeader* block =
78 E : reinterpret_cast<BlockHeader*>(::HeapAlloc(heap_, flags, alloc_size));
79 :
80 E : if (block == NULL)
81 i : return NULL;
82 :
83 : // Poison head and tail zones, and unpoison alloc.
84 E : size_t header_size = kRedZoneSize;
85 E : size_t trailer_size = alloc_size - kRedZoneSize - bytes;
86 E : memset(block, '0xCC', header_size);
87 E : Shadow::Poison(block, kRedZoneSize);
88 :
89 E : Shadow::Unpoison(ToAlloc(block), bytes);
90 :
91 E : memset(ToAlloc(block) + bytes, '0xCD', trailer_size);
92 E : Shadow::Poison(ToAlloc(block) + bytes, trailer_size);
93 :
94 E : block->size = bytes;
95 :
96 E : return ToAlloc(block);
97 E : }
98 :
99 E : void* HeapProxy::ReAlloc(DWORD flags, void* mem, size_t bytes){
100 E : DCHECK(heap_ != NULL);
101 :
102 E : void *new_mem = Alloc(flags, bytes);
103 E : if (new_mem != NULL && mem != NULL)
104 E : memcpy(new_mem, mem, std::min(bytes, Size(0, mem)));
105 :
106 E : if (mem)
107 E : Free(flags, mem);
108 :
109 E : return new_mem;
110 E : }
111 :
112 E : bool HeapProxy::Free(DWORD flags, void* mem){
113 E : DCHECK(heap_ != NULL);
114 E : BlockHeader* block = ToBlock(mem);
115 E : if (block == NULL)
116 i : return true;
117 :
118 E : QuarantineBlock(block);
119 :
120 E : return true;
121 E : }
122 :
123 E : size_t HeapProxy::Size(DWORD flags, const void* mem){
124 E : DCHECK(heap_ != NULL);
125 E : BlockHeader* block = ToBlock(mem);
126 E : if (block == NULL)
127 i : return -1;
128 :
129 E : return block->size;
130 E : }
131 :
132 E : bool HeapProxy::Validate(DWORD flags, const void* mem){
133 E : DCHECK(heap_ != NULL);
134 E : return ::HeapValidate(heap_, flags, ToBlock(mem)) == TRUE;
135 E : }
136 :
137 E : size_t HeapProxy::Compact(DWORD flags){
138 E : DCHECK(heap_ != NULL);
139 E : return ::HeapCompact(heap_, flags);
140 E : }
141 :
142 E : bool HeapProxy::Lock(){
143 E : DCHECK(heap_ != NULL);
144 E : return ::HeapLock(heap_) == TRUE;
145 E : }
146 :
147 E : bool HeapProxy::Unlock(){
148 E : DCHECK(heap_ != NULL);
149 E : return ::HeapUnlock(heap_) == TRUE;
150 E : }
151 :
152 E : bool HeapProxy::Walk(PROCESS_HEAP_ENTRY* entry){
153 E : DCHECK(heap_ != NULL);
154 E : return ::HeapWalk(heap_, entry) == TRUE;
155 E : }
156 :
157 : bool HeapProxy::SetInformation(HEAP_INFORMATION_CLASS info_class,
158 : void* info,
159 E : size_t info_length){
160 E : DCHECK(heap_ != NULL);
161 E : return ::HeapSetInformation(heap_, info_class, info, info_length) == TRUE;
162 E : }
163 :
164 : bool HeapProxy::QueryInformation(HEAP_INFORMATION_CLASS info_class,
165 : void* info,
166 : size_t info_length,
167 E : unsigned long* return_length){
168 E : DCHECK(heap_ != NULL);
169 : return ::HeapQueryInformation(heap_,
170 : info_class,
171 : info,
172 : info_length,
173 E : return_length) == TRUE;
174 E : }
175 :
176 E : void HeapProxy::QuarantineBlock(BlockHeader* block) {
177 E : base::AutoLock lock(lock_);
178 E : FreeBlockHeader* free_block = static_cast<FreeBlockHeader*>(block);
179 :
180 E : free_block->next = NULL;
181 E : if (tail_ != NULL) {
182 E : tail_->next = free_block;
183 E : } else {
184 E : DCHECK(head_ == NULL);
185 E : head_ = free_block;
186 : }
187 E : tail_ = free_block;
188 :
189 : // Poison the released alloc.
190 E : size_t alloc_size = GetAllocSize(free_block->size);
191 : // Trash the data in the block and poison it.
192 E : memset(ToAlloc(free_block), 0xCC, free_block->size);
193 E : Shadow::Poison(free_block, alloc_size);
194 E : quarantine_size_ += alloc_size;
195 :
196 : // Arbitrarily keep ten megabytes of quarantine per heap.
197 E : const size_t kMaxQuarantineSizeBytes = 10 * 1024 * 1024;
198 :
199 : // Flush quarantine overage.
200 E : while (quarantine_size_ > kMaxQuarantineSizeBytes) {
201 i : DCHECK(head_ != NULL && tail_ != NULL);
202 :
203 i : free_block = head_;
204 i : head_ = free_block->next;
205 i : if (head_ == NULL)
206 i : tail_ = NULL;
207 :
208 i : alloc_size = GetAllocSize(free_block->size);
209 i : Shadow::Unpoison(free_block, alloc_size);
210 i : ::HeapFree(heap_, 0, free_block);
211 :
212 i : DCHECK_GE(quarantine_size_, alloc_size);
213 i : quarantine_size_ -= alloc_size;
214 i : }
215 E : }
216 :
217 E : size_t HeapProxy::GetAllocSize(size_t bytes) {
218 E : bytes += kRedZoneSize;
219 E : return (bytes + kRedZoneSize + kRedZoneSize - 1) & ~(kRedZoneSize - 1);
220 E : }
221 :
222 E : HeapProxy::BlockHeader* HeapProxy::ToBlock(const void* alloc) {
223 E : if (alloc == NULL)
224 i : return NULL;
225 :
226 E : uint8* mem = reinterpret_cast<uint8*>(const_cast<void*>(alloc));
227 :
228 E : return reinterpret_cast<BlockHeader*>(mem - kRedZoneSize);
229 E : }
230 :
231 E : uint8* HeapProxy::ToAlloc(BlockHeader* block) {
232 E : uint8* mem = reinterpret_cast<uint8*>(block);
233 :
234 E : return mem + kRedZoneSize;
235 E : }
236 :
237 : } // namespace asan
238 : } // namespace agent
|