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 : // Declares structures and utility functions used to get information about an
16 : // Asan error.
17 :
18 : #ifndef SYZYGY_AGENT_ASAN_ERROR_INFO_H_
19 : #define SYZYGY_AGENT_ASAN_ERROR_INFO_H_
20 :
21 : #include <utility>
22 : #include <vector>
23 :
24 : #include "base/callback.h"
25 : #include "syzygy/agent/asan/block.h"
26 : #include "syzygy/agent/asan/heap.h"
27 : #include "syzygy/agent/common/stack_capture.h"
28 : #include "syzygy/common/asan_parameters.h"
29 :
30 : // Forward declaration.
31 : namespace crashdata {
32 : class Value;
33 : } // namespace crashdata
34 :
35 : namespace agent {
36 : namespace asan {
37 :
38 : // Forward declarations.
39 : class Shadow;
40 : class StackCaptureCache;
41 : struct BlockHeader;
42 :
43 : // The different memory access modes that we can encounter.
44 : enum AccessMode {
45 : ASAN_READ_ACCESS,
46 : ASAN_WRITE_ACCESS,
47 : ASAN_UNKNOWN_ACCESS,
48 :
49 : ASAN_ACCESS_MODE_MAX,
50 : };
51 :
52 : // Enumeration of the different kinds of bad heap accesses that we can
53 : // encounter.
54 : enum BadAccessKind {
55 : // This enum should start with bad access type that are not relative to a
56 : // heap block.
57 : // @note The ordering is important because those labels are used in
58 : // numeric inequalities.
59 : UNKNOWN_BAD_ACCESS,
60 : WILD_ACCESS,
61 : INVALID_ADDRESS,
62 : CORRUPT_BLOCK,
63 : CORRUPT_HEAP,
64 :
65 : // This enum should end with bad access types that are relative to heap
66 : // blocks.
67 : USE_AFTER_FREE,
68 : HEAP_BUFFER_OVERFLOW,
69 : HEAP_BUFFER_UNDERFLOW,
70 : DOUBLE_FREE,
71 :
72 : BAD_ACCESS_KIND_MAX,
73 : };
74 :
75 : // The different types of errors we can encounter.
76 : extern const char kHeapUseAfterFree[];
77 : extern const char kHeapBufferUnderFlow[];
78 : extern const char kHeapBufferOverFlow[];
79 : extern const char kAttemptingDoubleFree[];
80 : extern const char kInvalidAddress[];
81 : extern const char kWildAccess[];
82 : extern const char kHeapUnknownError[];
83 : extern const char kHeapCorruptBlock[];
84 : extern const char kCorruptHeap[];
85 :
86 : enum AsanFeature : uint32_t {
87 : ASAN_FEATURE_ENABLE_PAGE_PROTECTIONS = (1 << 0),
88 : // This feature flag is currently deprecated and ignored.
89 : DEPRECATED_ASAN_FEATURE_ENABLE_CTMALLOC = (1 << 1),
90 : ASAN_FEATURE_ENABLE_LARGE_BLOCK_HEAP = (1 << 2),
91 : // This feature flag is currently deprecated and ignored.
92 : DEPRECATED_ASAN_FEATURE_ENABLE_KASKO = (1 << 3),
93 : ASAN_FEATURE_ENABLE_CRASHPAD = (1 << 4),
94 : ASAN_FEATURE_MAX = (1 << 5),
95 : };
96 : using AsanFeatureSet = uint32_t;
97 :
98 : // Feature set for all valid features.
99 : const AsanFeatureSet kAsanValidFeatures =
100 : ASAN_FEATURE_ENABLE_PAGE_PROTECTIONS |
101 : ASAN_FEATURE_ENABLE_LARGE_BLOCK_HEAP | ASAN_FEATURE_ENABLE_CRASHPAD;
102 :
103 : // Feature set for all deprecated features.
104 : const AsanFeatureSet kAsanDeprecatedFeatures =
105 : DEPRECATED_ASAN_FEATURE_ENABLE_CTMALLOC |
106 : DEPRECATED_ASAN_FEATURE_ENABLE_KASKO;
107 :
108 : // Store the information that we want to report about a block.
109 : // TODO(sebmarchand): Rename this to avoid the confusion with the BlockInfo
110 : // structure?
111 : struct AsanBlockInfo {
112 : // The address of the header for this block.
113 : const void* header;
114 : // The user size of the block.
115 : size_t user_size : 30;
116 : // This is implicitly a BlockState value.
117 : size_t state : 2;
118 : // The ID of the allocation thread.
119 : DWORD alloc_tid;
120 : // The ID of the free thread.
121 : DWORD free_tid;
122 : // The result of a block analysis on this block.
123 : BlockAnalysisResult analysis;
124 : // The allocation stack trace.
125 : void* alloc_stack[agent::common::StackCapture::kMaxNumFrames];
126 : // The free stack trace.
127 : void* free_stack[agent::common::StackCapture::kMaxNumFrames];
128 : // The size of the allocation stack trace.
129 : uint8_t alloc_stack_size;
130 : // The size of the free stack trace.
131 : uint8_t free_stack_size;
132 : // The type of heap that made the allocation.
133 : HeapType heap_type;
134 : // The time since this block has been freed. This would be equal to zero if
135 : // the block is still allocated.
136 : // TODO(chrisha): We actually keep track of this in ticks. Rename this?
137 : uint32_t milliseconds_since_free;
138 : };
139 :
140 : struct AsanCorruptBlockRange {
141 : // The beginning address of the range.
142 : const void* address;
143 : // The length of the range.
144 : size_t length;
145 : // The number of blocks in this range.
146 : size_t block_count;
147 : // The number of blocks in the |block_info| array.
148 : size_t block_info_count;
149 : // The information about the blocks in this range. This may include one or
150 : // more of the corrupt blocks and/or the valid blocks surrounding them; at the
151 : // very least it will contain the first corrupt block in the range. The real
152 : // length of this array will be stored in |block_info_count|. The array itself
153 : // is allocated on the stack so that it gets shipped with minidumps.
154 : AsanBlockInfo* block_info;
155 : };
156 :
157 : // Store the information about a bad memory access.
158 : struct AsanErrorInfo {
159 : // The address where the bad access happened.
160 : const void* location;
161 : // The context prior to the crash.
162 : CONTEXT context;
163 : // The ID of the crash stack, this is needed to be able to blacklist some
164 : // known bugs.
165 : common::StackCapture::StackId crash_stack_id;
166 : // The information about the block that contains the invalid location.
167 : AsanBlockInfo block_info;
168 : // The error type.
169 : BadAccessKind error_type;
170 : // The access mode.
171 : AccessMode access_mode;
172 : // The access size.
173 : size_t access_size;
174 : // The information about the shadow memory for this address, this would be
175 : // something like: "0x12345678 is located 8 bytes inside of a 10-byte region
176 : // [0x12345670,0x1234567A)."
177 : char shadow_info[128];
178 : // A textual description of the shadow memory around |location|.
179 : char shadow_memory[512];
180 : // Indicates if the heap is corrupt.
181 : bool heap_is_corrupt;
182 : // The number of corrupt ranges encountered.
183 : size_t corrupt_range_count;
184 : // The number of corrupt blocks encountered.
185 : size_t corrupt_block_count;
186 : // The number of corrupt ranges reported in |corrupt_ranges|.
187 : size_t corrupt_ranges_reported;
188 : // The information about the corrupt ranges of memory. The real length of this
189 : // array will be stored in |corrupt_ranges_reported|. This will be NULL if
190 : // |corrupt_ranges_reported| is zero.
191 : AsanCorruptBlockRange* corrupt_ranges;
192 : // The current configuration of the runtime library.
193 : ::common::AsanParameters asan_parameters;
194 : // Temporarily report the list of features that have been randomly enabled for
195 : // this client. This is something that could be deduced by analyzing the
196 : // |asan_parameters| structure but having it directly available in the crash
197 : // report structure will make it easier to investigate on the heap corruption
198 : // bug that we're tracking.
199 : // TODO(sebmarchand): Remove this once we don't need it anymore.
200 : AsanFeatureSet feature_set;
201 : };
202 :
203 : // Helper struct that is used when calculating the range of the shadow memory
204 : // surrounding a point of invalid access.
205 : struct AsanErrorShadowMemory {
206 : uintptr_t index;
207 : uintptr_t address;
208 : uintptr_t length;
209 : };
210 :
211 : // This callback allows a heap manager to report heap consistency problems that
212 : // it encounters during its operation. This is usually plumbed into the Asan
213 : // runtime so that the errors may be appropriately reported.
214 : //
215 : // |asan_error_info| contains information about the primary heap error that
216 : // was encountered. It is guaranteed to be on the stack.
217 : typedef base::Callback<void(AsanErrorInfo* asan_error_info)>
218 : HeapErrorCallback;
219 :
220 : // Contains pairs of address/size of data to be reported to Kasko during a
221 : // crash.
222 : typedef std::vector<std::pair<const char*, size_t>> MemoryRanges;
223 :
224 : // Returns a string describing a bad access kind.
225 : // @param bad_access_kind The bad access kind for which we want a textual
226 : // representation.
227 : // @returns a string describing the bad access kind.
228 : const char* ErrorInfoAccessTypeToStr(BadAccessKind bad_access_kind);
229 :
230 : // Get information about a bad access.
231 : // @param shadow The shadow memory to query.
232 : // @param stack_cache The stack cache that owns the alloc and free stack traces
233 : // of the blocks.
234 : // @param bad_access_info Will receive the information about this access.
235 : // @returns true if the address belongs to a memory block, false otherwise.
236 : bool ErrorInfoGetBadAccessInformation(const Shadow* shadow,
237 : StackCaptureCache* stack_cache,
238 : AsanErrorInfo* bad_access_info);
239 :
240 : // Give the type of a bad heap access corresponding to an address.
241 : // @param shadow The shadow memory to query.
242 : // @param addr The address causing a bad heap access.
243 : // @param header The header of the block containing this address.
244 : // @returns The type of the bad heap access corresponding to this address.
245 : // @note Exposed for unittesting.
246 : BadAccessKind ErrorInfoGetBadAccessKind(const Shadow* shadow,
247 : const void* addr,
248 : const BlockHeader* header);
249 :
250 : // Retrieves a block's metadata.
251 : // @param shadow The shadow memory to query.
252 : // @param block_info The block whose info is to be gathered.
253 : // @param stack_cache The stack cache that owns the alloc and free stack traces
254 : // of this block.
255 : // @param asan_block_info Will receive the block's metadata.
256 : void ErrorInfoGetAsanBlockInfo(const Shadow* shadow,
257 : const BlockInfo& block_info,
258 : StackCaptureCache* stack_cache,
259 : AsanBlockInfo* asan_block_info);
260 :
261 : // Computes the range of the shadow memory surrounding the point of invalid
262 : // access.
263 : // @param shadow The shadow memory to query.
264 : // @param error_location The memory location where the error occured.
265 : // @param shadow_memory Will receive the shadow memory surrounding the error.
266 : void GetAsanErrorShadowMemory(const Shadow* shadow,
267 : const void* error_location,
268 : AsanErrorShadowMemory* shadow_memory);
269 :
270 : // Given a populated AsanBlockInfo struct, fills out a corresponding crashdata
271 : // protobuf.
272 : // @param shadow The shadow memory to query.
273 : // @param block_info The block info information.
274 : // @param include_block_contents If this is true the block contents will be
275 : // explicitly included in the protobuf.
276 : // @param value The uninitialized protobuf value to be populated.
277 : // @param memory_ranges If its value is not nullptr, the address/size of
278 : // relevant memory content will be appended to this variable.
279 : void PopulateBlockInfo(const Shadow* shadow,
280 : const AsanBlockInfo& block_info,
281 : bool include_block_contents,
282 : crashdata::Value* value,
283 : MemoryRanges* memory_ranges);
284 :
285 : // Given a populated AsanCorruptBlockRange struct, fills out a corresponding
286 : // crashdata protobuf.
287 : // @param shadow The shadow memory to query.
288 : // @param range The corrupt block range information.
289 : // @param value The uninitialized protobuf value to be populated.
290 : // @param memory_ranges If its value is not nullptr, the address/size of
291 : // relevant memory content will be appended to this variable.
292 : void PopulateCorruptBlockRange(const Shadow* shadow,
293 : const AsanCorruptBlockRange& range,
294 : crashdata::Value* value,
295 : MemoryRanges* memory_ranges);
296 :
297 : // Given a populated AsanErrorInfo struct, fills out a corresponding crashdata
298 : // protobuf.
299 : // @param shadow The shadow memory to query.
300 : // @param error_info The filled in error information.
301 : // @param value The uninitialized protobuf value to be populated.
302 : // @param memory_ranges If its value is not nullptr, the address/size of
303 : // relevant memory content will be appended to this variable.
304 : void PopulateErrorInfo(const Shadow* shadow,
305 : const AsanErrorInfo& error_info,
306 : crashdata::Value* value,
307 : MemoryRanges* memory_ranges);
308 :
309 : // Given a populated crashdata protobuf, fills out a corresponding AsanErrorInfo
310 : // struct.
311 : // @param protobuf The filled in error information protobuf.
312 : // @param value The uninitialized AsanErrorInfo struct to be populated.
313 : void CrashdataProtobufToErrorInfo(const crashdata::Value& protobuf,
314 : AsanErrorInfo* error_info);
315 :
316 : // Helper function to get the instruction pointer from a CONTEXT
317 : // on both ia32 and x64.
318 E : inline void* GetInstructionPointer(const CONTEXT& context) {
319 : #ifdef _WIN64
320 : return reinterpret_cast<void*>(context.Rip);
321 : #else
322 E : return reinterpret_cast<void*>(context.Eip);
323 : #endif
324 E : }
325 :
326 : } // namespace asan
327 : } // namespace agent
328 :
329 : #endif // SYZYGY_AGENT_ASAN_ERROR_INFO_H_
|