1 : // Copyright 2012 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 : // Implements HeapProxy, a class that wraps Win32 heap allocations but adds
16 : // heap/tail redzones.
17 :
18 : #ifndef SYZYGY_AGENT_ASAN_ASAN_HEAP_H_
19 : #define SYZYGY_AGENT_ASAN_ASAN_HEAP_H_
20 :
21 : #include <windows.h> // NOLINT
22 :
23 : #include "base/logging.h"
24 : #include "base/string_piece.h"
25 : #include "base/debug/stack_trace.h"
26 : #include "base/synchronization/lock.h"
27 : #include "syzygy/agent/asan/stack_capture_cache.h"
28 : #include "syzygy/agent/common/dlist.h"
29 :
30 : namespace agent {
31 : namespace asan {
32 :
33 : // Forward declaration.
34 : class AsanLogger;
35 : class StackCapture;
36 : class StackCaptureCache;
37 :
38 : // An helper function to send a command to Windbg. Windbg should first receive
39 : // the ".ocommand ASAN" command to treat those messages as commands.
40 : // TODO(sebmarchand): Move this function and the following one to the
41 : // AsanRuntime class once it's ready.
42 : void ASANDbgCmd(const wchar_t* fmt, ...);
43 :
44 : // An helper function to print a message to Windbg's console.
45 : void ASANDbgMessage(const wchar_t* fmt, ...);
46 :
47 : // Makes like a Win32 heap manager heap, but adds a redzone before and after
48 : // each allocation and maintains a quarantine list of freed blocks.
49 : class HeapProxy {
50 : public:
51 : // The different memory access modes that we can encounter.
52 : enum AccessMode {
53 : ASAN_READ_ACCESS,
54 : ASAN_WRITE_ACCESS,
55 : ASAN_UNKNOWN_ACCESS
56 : };
57 :
58 : HeapProxy(StackCaptureCache* cache, AsanLogger* logger);
59 : ~HeapProxy();
60 :
61 : // @name Cast to/from HANDLE.
62 : // @{
63 : static HANDLE ToHandle(HeapProxy* proxy);
64 : static HeapProxy* FromHandle(HANDLE heap);
65 : // @}
66 :
67 : // @name Heap interface.
68 : // @{
69 : bool Create(DWORD options,
70 : size_t initial_size,
71 : size_t maximum_size);
72 : bool Destroy();
73 : void* Alloc(DWORD flags, size_t bytes);
74 : void* ReAlloc(DWORD flags, void* mem, size_t bytes);
75 : bool Free(DWORD flags, void* mem);
76 : size_t Size(DWORD flags, const void* mem);
77 : bool Validate(DWORD flags, const void* mem);
78 : size_t Compact(DWORD flags);
79 : bool Lock();
80 : bool Unlock();
81 : bool Walk(PROCESS_HEAP_ENTRY* entry);
82 : bool SetInformation(HEAP_INFORMATION_CLASS info_class,
83 : void* info,
84 : size_t info_length);
85 : bool QueryInformation(HEAP_INFORMATION_CLASS info_class,
86 : void* info,
87 : size_t info_length,
88 : unsigned long* return_length);
89 : // @}
90 :
91 : // Report a bad access to the heap.
92 : // @param addr The red-zoned address causing a bad access.
93 : // @param context The context at which the access occurred.
94 : // @param stack The stack capture at the point of error.
95 : // @param access_mode The kind of the access (read or write).
96 : // @param access_size The size of the access (in bytes).
97 : // @returns true if the address belongs to a memory block, false otherwise.
98 : bool OnBadAccess(const void* addr,
99 : const CONTEXT& context,
100 : const StackCapture& stack,
101 : AccessMode access_mode,
102 : size_t access_size);
103 :
104 : // Report an unknown error while attempting to access a red-zoned heap
105 : // address.
106 : // @param addr The address causing an error.
107 : // @param context The context at which the access occurred.
108 : // @param stack The stack capture at the point of error.
109 : // @param access_mode The kind of the access (read or write).
110 : // @param access_size The size of the access (in bytes).
111 : void ReportUnknownError(const void* addr,
112 : const CONTEXT& context,
113 : const StackCapture& stack,
114 : AccessMode access_mode,
115 : size_t access_size);
116 :
117 : // @name Cast to/from HANDLE.
118 : // @{
119 : static LIST_ENTRY* ToListEntry(HeapProxy* proxy);
120 : static HeapProxy* FromListEntry(LIST_ENTRY* list_entry);
121 : // @}
122 :
123 : // Set the default max size of the quarantine of a heap proxy.
124 : // @param quarantine_max_size The maximum size of the quarantine list, in
125 : // bytes.
126 E : static void set_default_quarantine_max_size(size_t quarantine_max_size) {
127 E : default_quarantine_max_size_ = quarantine_max_size;
128 E : }
129 :
130 : // Get the default max size of the quarantine of a heap proxy.
131 E : static size_t default_quarantine_max_size() {
132 E : return default_quarantine_max_size_;
133 E : }
134 :
135 : // Set the max size of the quarantine of a heap proxy. If the current size of
136 : // the quarantine is greater than this new max size then the extra blocks are
137 : // removed from the quarantine.
138 : // @param quarantine_max_size The maximum size of the quarantine list, in
139 : // bytes.
140 : void set_quarantine_max_size(size_t quarantine_max_size);
141 :
142 : // Get the max size of the quarantine of a heap proxy.
143 E : size_t quarantine_max_size() {
144 E : return quarantine_max_size_;
145 E : }
146 :
147 : protected:
148 : // Enumeration of the different kind of bad heap access that we can encounter.
149 : enum BadAccessKind {
150 : UNKNOWN_BAD_ACCESS,
151 : USE_AFTER_FREE,
152 : HEAP_BUFFER_OVERFLOW,
153 : HEAP_BUFFER_UNDERFLOW,
154 : };
155 :
156 : enum BlockState {
157 : ALLOCATED,
158 : FREED,
159 : QUARANTINED,
160 : };
161 :
162 : // Every allocated block starts with a BlockHeader.
163 : struct BlockHeader {
164 : size_t magic_number;
165 : size_t size;
166 : BlockState state;
167 : const StackCapture* alloc_stack;
168 : const StackCapture* free_stack;
169 : };
170 :
171 : // Free blocks are linked together.
172 : struct FreeBlockHeader : public BlockHeader {
173 : FreeBlockHeader* next;
174 : };
175 :
176 : // Magic number to identify the beginning of a block header.
177 : static const size_t kBlockHeaderSignature = 0x03CA80E7;
178 :
179 : // Returns a string describing a bad access kind.
180 : static const char* AccessTypeToStr(BadAccessKind bad_access_kind);
181 :
182 : // Returns the block header for an alloc.
183 : BlockHeader* ToBlock(const void* alloc);
184 :
185 : // Returns alloc for a block.
186 : uint8* ToAlloc(BlockHeader* block);
187 :
188 : // Find the memory block containing @p addr.
189 : // @returns a pointer to this memory block in case of success, NULL otherwise.
190 : BlockHeader* FindAddressBlock(const void* addr);
191 :
192 : // Give the type of a bad heap access corresponding to an address.
193 : // @param addr The address causing a bad heap access.
194 : // @param header The header of the block containing this address.
195 : BadAccessKind GetBadAccessKind(const void* addr, BlockHeader* header);
196 :
197 : // Calculates the underlying allocation size for a requested
198 : // allocation of @p bytes.
199 : static size_t GetAllocSize(size_t bytes);
200 :
201 : // Quarantines @p block and flushes quarantine overage.
202 : void QuarantineBlock(BlockHeader* block);
203 :
204 : // Free and remove the first block of the quarantine. lock_ must be held.
205 : void PopQuarantineUnlocked();
206 :
207 : // Get the information about an address belonging to a memory block. This
208 : // function will output the relative position of this address inside a block
209 : // and the bounds of this block.
210 : // @param addr The address for which we want information.
211 : // @param header The block containing the address.
212 : // @param bad_access_kind The kind of bad access corresponding to this
213 : // address.
214 : void ReportAddressInformation(const void* addr,
215 : BlockHeader* header,
216 : BadAccessKind bad_access_kind);
217 :
218 : // Low-level ASAN reporting function. This function dumps the stack,
219 : // optionally including an extra (free-form) description of the address
220 : // being accessed when the error occurred.
221 : // @param bug_descr The description of the error.
222 : // @param addr The address causing an error.
223 : // @param context The context at which the access occurred.
224 : // @param stack The stack capture at the point of error.
225 : // @param bad_access_kind The kind of error.
226 : // @param access_mode The mode of the access (read or write).
227 : // @param access_size The size of the access (in bytes).
228 : void ReportAsanErrorBase(const char* bug_descr,
229 : const void* addr,
230 : const CONTEXT& context,
231 : const StackCapture& stack,
232 : BadAccessKind bad_access_kind,
233 : AccessMode access_mode,
234 : size_t access_size);
235 :
236 : // Report an ASAN error, automatically including information about the
237 : // address being accessed when the error occurred.
238 : // @param bug_descr The description of the error.
239 : // @param addr The address causing an error.
240 : // @param context The context at which the access occurred.
241 : // @param stack The stack capture at the point of error.
242 : // @param bad_access_kind The kind of error.
243 : // @param header The header of the block containing this address.
244 : // @param access_mode The kind of the access (read or write).
245 : // @param access_size The size of the access (in bytes).
246 : void ReportAsanError(const char* bug_descr,
247 : const void* addr,
248 : const CONTEXT& context,
249 : const StackCapture& stack,
250 : BadAccessKind bad_access_kind,
251 : BlockHeader* header,
252 : AccessMode access_mode,
253 : size_t access_size);
254 :
255 : // Default max size of blocks in quarantine (in bytes).
256 : static size_t default_quarantine_max_size_;
257 :
258 : // The underlying heap we delegate to.
259 : HANDLE heap_;
260 :
261 : // A repository of unique stack captures recorded on alloc and free.
262 : StackCaptureCache* const stack_cache_;
263 :
264 : // The logger to use when an error occurs.
265 : AsanLogger* const logger_;
266 :
267 : // Protects concurrent access to HeapProxy internals.
268 : base::Lock lock_;
269 :
270 : // Points to the head of the quarantine queue.
271 : FreeBlockHeader* head_; // Under lock_.
272 :
273 : // Points to the tail of the quarantine queue.
274 : FreeBlockHeader* tail_; // Under lock_.
275 :
276 : // Total size of blocks in quarantine.
277 : size_t quarantine_size_; // Under lock_.
278 :
279 : // Max size of blocks in quarantine.
280 : size_t quarantine_max_size_; // Under lock_.
281 :
282 : // The entry linking to us.
283 : LIST_ENTRY list_entry_;
284 : };
285 :
286 : } // namespace asan
287 : } // namespace agent
288 :
289 : #endif // SYZYGY_AGENT_ASAN_ASAN_HEAP_H_
|