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 : struct AsanErrorInfo;
38 :
39 : // An helper function to send a command to Windbg. Windbg should first receive
40 : // the ".ocommand ASAN" command to treat those messages as commands.
41 : // TODO(sebmarchand): Move this function and the following one to the
42 : // AsanRuntime class once it's ready.
43 : void ASANDbgCmd(const wchar_t* fmt, ...);
44 :
45 : // An helper function to print a message to Windbg's console.
46 : void ASANDbgMessage(const wchar_t* fmt, ...);
47 :
48 : // Makes like a Win32 heap manager heap, but adds a redzone before and after
49 : // each allocation and maintains a quarantine list of freed blocks.
50 : class HeapProxy {
51 : public:
52 : // The different memory access modes that we can encounter.
53 : enum AccessMode {
54 : ASAN_READ_ACCESS,
55 : ASAN_WRITE_ACCESS,
56 : ASAN_UNKNOWN_ACCESS
57 : };
58 :
59 : // Enumeration of the different kinds of bad heap accesses that we can
60 : // encounter.
61 : enum BadAccessKind {
62 : UNKNOWN_BAD_ACCESS,
63 : WILD_ACCESS,
64 : USE_AFTER_FREE,
65 : HEAP_BUFFER_OVERFLOW,
66 : HEAP_BUFFER_UNDERFLOW,
67 : };
68 :
69 : // The different types of error we can encounter.
70 : static const char* kHeapUseAfterFree;
71 : static const char* kHeapBufferUnderFlow;
72 : static const char* kHeapBufferOverFlow;
73 : static const char* kAttemptingDoubleFree;
74 : static const char* kWildAccess;
75 : static const char* kHeapUnknownError;
76 :
77 : // The sleep time (in milliseconds) used to approximate the CPU frequency.
78 : // Exposed for testing.
79 : static const size_t kSleepTimeForApproximatingCPUFrequency = 100;
80 :
81 : HeapProxy(StackCaptureCache* cache, AsanLogger* logger);
82 : ~HeapProxy();
83 :
84 : // @name Cast to/from HANDLE.
85 : // @{
86 : static HANDLE ToHandle(HeapProxy* proxy);
87 : static HeapProxy* FromHandle(HANDLE heap);
88 : // @}
89 :
90 : // @name Heap interface.
91 : // @{
92 : bool Create(DWORD options,
93 : size_t initial_size,
94 : size_t maximum_size);
95 : bool Destroy();
96 : void* Alloc(DWORD flags, size_t bytes);
97 : void* ReAlloc(DWORD flags, void* mem, size_t bytes);
98 : bool Free(DWORD flags, void* mem);
99 : size_t Size(DWORD flags, const void* mem);
100 : bool Validate(DWORD flags, const void* mem);
101 : size_t Compact(DWORD flags);
102 : bool Lock();
103 : bool Unlock();
104 : bool Walk(PROCESS_HEAP_ENTRY* entry);
105 : bool SetInformation(HEAP_INFORMATION_CLASS info_class,
106 : void* info,
107 : size_t info_length);
108 : bool QueryInformation(HEAP_INFORMATION_CLASS info_class,
109 : void* info,
110 : size_t info_length,
111 : unsigned long* return_length);
112 : // @}
113 :
114 : // Report a bad access to the heap.
115 : // @param addr The red-zoned address causing a bad access.
116 : // @param context The context at which the access occurred.
117 : // @param stack The stack capture at the point of error.
118 : // @param access_mode The kind of the access (read or write).
119 : // @param access_size The size of the access (in bytes).
120 : // @param bad_access_info Will receive the information about this access.
121 : // @returns true if the address belongs to a memory block, false otherwise.
122 : bool OnBadAccess(const void* addr,
123 : const CONTEXT& context,
124 : const StackCapture& stack,
125 : AccessMode access_mode,
126 : size_t access_size,
127 : AsanErrorInfo* bad_access_info);
128 :
129 : // Report a wild access to the memory; this can either be an access to an
130 : // internal structure or an access to the upper memory (over the 2GB limit).
131 : // @param addr The address causing an error.
132 : // @param context The context at which the access occurred.
133 : // @param stack The stack capture at the point of error.
134 : // @param access_mode The kind of the access (read or write).
135 : // @param access_size The size of the access (in bytes).
136 : void ReportWildAccess(const void* addr,
137 : const CONTEXT& context,
138 : const StackCapture& stack,
139 : AccessMode access_mode,
140 : size_t access_size);
141 :
142 : // @name Cast to/from HANDLE.
143 : // @{
144 : static LIST_ENTRY* ToListEntry(HeapProxy* proxy);
145 : static HeapProxy* FromListEntry(LIST_ENTRY* list_entry);
146 : // @}
147 :
148 : // Set the default max size of the quarantine of a heap proxy.
149 : // @param quarantine_max_size The maximum size of the quarantine list, in
150 : // bytes.
151 E : static void set_default_quarantine_max_size(size_t quarantine_max_size) {
152 E : default_quarantine_max_size_ = quarantine_max_size;
153 E : }
154 :
155 : // Get the default max size of the quarantine of a heap proxy.
156 E : static size_t default_quarantine_max_size() {
157 E : return default_quarantine_max_size_;
158 E : }
159 :
160 : // Set the max size of the quarantine of a heap proxy. If the current size of
161 : // the quarantine is greater than this new max size then the extra blocks are
162 : // removed from the quarantine.
163 : // @param quarantine_max_size The maximum size of the quarantine list, in
164 : // bytes.
165 : void SetQuarantineMaxSize(size_t quarantine_max_size);
166 :
167 : // Get the max size of the quarantine of a heap proxy.
168 E : size_t quarantine_max_size() {
169 E : return quarantine_max_size_;
170 E : }
171 :
172 : // Static initialization of HeapProxy context.
173 : static void Init();
174 :
175 : // Returns a string describing a bad access kind.
176 : static const char* AccessTypeToStr(BadAccessKind bad_access_kind);
177 :
178 : protected:
179 : enum BlockState {
180 : ALLOCATED,
181 : FREED,
182 : QUARANTINED,
183 : };
184 :
185 : // Every allocated block starts with a BlockHeader...
186 : struct BlockHeader {
187 : size_t magic_number : 24;
188 : BlockState state : 8;
189 : size_t block_size;
190 : const StackCapture* alloc_stack;
191 : DWORD alloc_tid;
192 : };
193 : COMPILE_ASSERT((sizeof(BlockHeader) & 7) == 0,
194 : asan_block_header_not_multiple_of_8_bytes);
195 : COMPILE_ASSERT(sizeof(BlockHeader) == 16, asan_block_header_too_big);
196 :
197 : // ... and ends with a BlockTrailer.
198 : #pragma pack(push, 4)
199 : struct BlockTrailer {
200 : uint64 free_timestamp;
201 : const StackCapture* free_stack;
202 : DWORD free_tid;
203 : // Free blocks are linked together.
204 : BlockHeader* next_free_block;
205 : };
206 : #pragma pack(pop)
207 : COMPILE_ASSERT(sizeof(BlockTrailer) == 20, asan_block_trailer_too_big);
208 :
209 : // Magic number to identify the beginning of a block header.
210 : static const size_t kBlockHeaderSignature = 0xCA80E7;
211 :
212 : // Returns the block header for an alloc.
213 : BlockHeader* ToBlockHeader(const void* alloc);
214 :
215 : // Returns the block trailer for a block header.
216 : BlockTrailer* GetBlockTrailer(const BlockHeader* header);
217 :
218 : // Returns alloc for a block.
219 : uint8* ToAlloc(BlockHeader* block);
220 :
221 : // Find the memory block containing @p addr.
222 : // @returns a pointer to this memory block in case of success, NULL otherwise.
223 : BlockHeader* FindAddressBlock(const void* addr);
224 :
225 : // Give the type of a bad heap access corresponding to an address.
226 : // @param addr The address causing a bad heap access.
227 : // @param header The header of the block containing this address.
228 : BadAccessKind GetBadAccessKind(const void* addr, BlockHeader* header);
229 :
230 : // Calculates the underlying allocation size for a requested
231 : // allocation of @p bytes.
232 : static size_t GetAllocSize(size_t bytes);
233 :
234 : // Quarantines @p block and flushes quarantine overage.
235 : void QuarantineBlock(BlockHeader* block);
236 :
237 : // If the quarantine size is over quarantine_max_size_, trim it down until
238 : // it's below the limit.
239 : void TrimQuarantine();
240 :
241 : // Get the information about an address belonging to a memory block. This
242 : // function will output the relative position of this address inside a block
243 : // and the bounds of this block.
244 : // @param addr The address for which we want information.
245 : // @param header The block containing the address.
246 : // @param bad_access_kind The kind of bad access corresponding to this
247 : // address.
248 : // @param bad_access_info Will receive the information about this access.
249 : void ReportAddressInformation(const void* addr,
250 : BlockHeader* header,
251 : BadAccessKind bad_access_kind,
252 : AsanErrorInfo* bad_access_info);
253 :
254 : // Low-level ASAN reporting function. This function dumps the stack,
255 : // optionally including an extra (free-form) description of the address
256 : // being accessed when the error occurred.
257 : // @param bug_descr The description of the error.
258 : // @param addr The address causing an error.
259 : // @param context The context at which the access occurred.
260 : // @param stack The stack capture at the point of error.
261 : // @param bad_access_kind The kind of error.
262 : // @param access_mode The mode of the access (read or write).
263 : // @param access_size The size of the access (in bytes).
264 : void ReportAsanErrorBase(const char* bug_descr,
265 : const void* addr,
266 : const CONTEXT& context,
267 : const StackCapture& stack,
268 : BadAccessKind bad_access_kind,
269 : AccessMode access_mode,
270 : size_t access_size);
271 :
272 : // Report an ASAN error, automatically including information about the
273 : // address being accessed when the error occurred.
274 : // @param bug_descr The description of the error.
275 : // @param addr The address causing an error.
276 : // @param context The context at which the access occurred.
277 : // @param stack The stack capture at the point of error.
278 : // @param bad_access_kind The kind of error.
279 : // @param header The header of the block containing this address.
280 : // @param access_mode The kind of the access (read or write).
281 : // @param access_size The size of the access (in bytes).
282 : // @param bad_access_info Will receive the information about this access.
283 : void ReportAsanError(const char* bug_descr,
284 : const void* addr,
285 : const CONTEXT& context,
286 : const StackCapture& stack,
287 : BadAccessKind bad_access_kind,
288 : BlockHeader* header,
289 : AccessMode access_mode,
290 : size_t access_size,
291 : AsanErrorInfo* bad_access_info);
292 :
293 : // Returns the time since the block @p header was freed (in microseconds).
294 : uint64 GetTimeSinceFree(const BlockHeader* header);
295 :
296 : // Arbitrarily keep 16 megabytes of quarantine per heap by default.
297 : static const size_t kDefaultQuarantineMaxSize_ = 16 * 1024 * 1024;
298 :
299 : // Default max size of blocks in quarantine (in bytes).
300 : static size_t default_quarantine_max_size_;
301 :
302 : // The number of CPU cycles per microsecond on the current machine.
303 : static double cpu_cycles_per_us_;
304 :
305 : // The underlying heap we delegate to.
306 : HANDLE heap_;
307 :
308 : // A repository of unique stack captures recorded on alloc and free.
309 : StackCaptureCache* const stack_cache_;
310 :
311 : // The logger to use when an error occurs.
312 : AsanLogger* const logger_;
313 :
314 : // Protects concurrent access to HeapProxy internals.
315 : base::Lock lock_;
316 :
317 : // Points to the head of the quarantine queue.
318 : BlockHeader* head_; // Under lock_.
319 :
320 : // Points to the tail of the quarantine queue.
321 : BlockHeader* tail_; // Under lock_.
322 :
323 : // Total size of blocks in quarantine.
324 : size_t quarantine_size_; // Under lock_.
325 :
326 : // Max size of blocks in quarantine.
327 : size_t quarantine_max_size_; // Under lock_.
328 :
329 : // The entry linking to us.
330 : LIST_ENTRY list_entry_;
331 : };
332 :
333 : } // namespace asan
334 : } // namespace agent
335 :
336 : #endif // SYZYGY_AGENT_ASAN_ASAN_HEAP_H_
|