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