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 : #include "syzygy/agent/asan/asan_rtl_impl.h"
16 :
17 : #include "base/bind.h"
18 : #include "base/callback.h"
19 : #include "base/logging.h"
20 : #include "base/debug/alias.h"
21 : #include "syzygy/agent/asan/asan_heap.h"
22 : #include "syzygy/agent/asan/asan_runtime.h"
23 : #include "syzygy/agent/asan/asan_shadow.h"
24 : #include "syzygy/agent/asan/stack_capture.h"
25 : #include "syzygy/agent/common/scoped_last_error_keeper.h"
26 :
27 : namespace {
28 :
29 : using agent::asan::AsanErrorInfo;
30 : using agent::asan::AsanRuntime;
31 : using agent::asan::HeapProxy;
32 :
33 : HANDLE process_heap = NULL;
34 :
35 : // The asan runtime manager.
36 : AsanRuntime* asan_runtime = NULL;
37 :
38 : // A callback that will be used in the functions interceptors once the call
39 : // to the intercepted function has been done. This is for testing purposes
40 : // only.
41 : InterceptorTailCallback interceptor_tail_callback = NULL;
42 :
43 : } // namespace
44 :
45 : namespace agent {
46 : namespace asan {
47 :
48 E : void SetUpRtl(AsanRuntime* runtime) {
49 E : DCHECK(runtime != NULL);
50 E : asan_runtime = runtime;
51 E : process_heap = GetProcessHeap();
52 E : }
53 :
54 E : void TearDownRtl() {
55 E : process_heap = NULL;
56 E : }
57 :
58 : // Contents of the registers before calling the ASAN memory check function.
59 : #pragma pack(push, 1)
60 : struct AsanContext {
61 : DWORD original_edi;
62 : DWORD original_esi;
63 : DWORD original_ebp;
64 : DWORD original_esp;
65 : DWORD original_ebx;
66 : DWORD original_edx;
67 : DWORD original_ecx;
68 : DWORD original_eax;
69 : DWORD original_eflags;
70 : DWORD original_eip;
71 : };
72 : #pragma pack(pop)
73 :
74 : // Report a bad access to the memory.
75 : // @param location The memory address of the access.
76 : // @param access_mode The mode of the access.
77 : // @param access_size The size of the access.
78 : // @param asan_context The context of the access.
79 : void ReportBadMemoryAccess(void* location,
80 : HeapProxy::AccessMode access_mode,
81 : size_t access_size,
82 E : struct AsanContext* asan_context) {
83 : // Capture the context and restore the value of the register as before calling
84 : // the asan hook.
85 :
86 : // Save the last error value so this function will be able to restore it.
87 E : agent::common::ScopedLastErrorKeeper scoped_last_error_keeper;
88 :
89 : // We keep a structure with all the useful information about this bad access
90 : // on the stack.
91 E : AsanErrorInfo bad_access_info = {};
92 :
93 : // We need to call ::RtlCaptureContext if we want SegSS and SegCS to be
94 : // properly set.
95 E : ::RtlCaptureContext(&bad_access_info.context);
96 E : bad_access_info.context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
97 :
98 : // Restore the original value of the registers.
99 E : bad_access_info.context.Eip = asan_context->original_eip;
100 E : bad_access_info.context.Eax = asan_context->original_eax;
101 E : bad_access_info.context.Ecx = asan_context->original_ecx;
102 E : bad_access_info.context.Edx = asan_context->original_edx;
103 E : bad_access_info.context.Ebx = asan_context->original_ebx;
104 E : bad_access_info.context.Ebp = asan_context->original_ebp;
105 E : bad_access_info.context.Esp = asan_context->original_esp;
106 E : bad_access_info.context.Esi = asan_context->original_esi;
107 E : bad_access_info.context.Edi = asan_context->original_edi;
108 E : bad_access_info.context.EFlags = asan_context->original_eflags;
109 :
110 E : StackCapture stack;
111 E : stack.InitFromStack();
112 : // We need to compute a relative stack id so that for the same stack trace
113 : // we'll get the same value every time even if the modules are loaded at a
114 : // different base address.
115 E : stack.set_stack_id(stack.ComputeRelativeStackId());
116 :
117 : // Check if we can ignore this error.
118 E : if (asan_runtime->ShouldIgnoreError(stack.stack_id()))
119 i : return;
120 :
121 E : bad_access_info.crash_stack_id = stack.stack_id();
122 E : bad_access_info.location = location;
123 E : bad_access_info.access_mode = access_mode;
124 E : bad_access_info.access_size = access_size;
125 E : bad_access_info.alloc_stack_size = 0U;
126 E : bad_access_info.alloc_tid = 0U;
127 E : bad_access_info.error_type = HeapProxy::UNKNOWN_BAD_ACCESS;
128 E : bad_access_info.free_stack_size = 0U;
129 E : bad_access_info.free_tid = 0U;
130 E : bad_access_info.microseconds_since_free = 0U;
131 :
132 : // Make sure this structure is not optimized out.
133 E : base::debug::Alias(&bad_access_info);
134 :
135 E : asan_runtime->GetBadAccessInformation(&bad_access_info);
136 :
137 : // Report this error.
138 E : asan_runtime->OnError(&bad_access_info);
139 E : }
140 :
141 : // Check if the memory location is accessible and report an error on bad memory
142 : // accesses.
143 : // @param location The memory address of the access.
144 : // @param access_mode The mode of the access.
145 : // @param access_size The size of the access.
146 : // @param context The registers context of the access.
147 : void CheckMemoryAccess(void* location,
148 : HeapProxy::AccessMode access_mode,
149 : size_t access_size,
150 E : AsanContext* context) {
151 E : if (!agent::asan::Shadow::IsAccessible(location))
152 E : ReportBadMemoryAccess(location, access_mode, access_size, context);
153 E : }
154 :
155 : // Check if the memory accesses done by a string instructions are valid.
156 : // @param dst The destination memory address of the access.
157 : // @param dst_access_mode The destination mode of the access.
158 : // @param src The source memory address of the access.
159 : // @param src_access_mode The source mode of the access.
160 : // @param length The number of memory accesses.
161 : // @param access_size The size of each the access in byte.
162 : // @param increment The increment to move dst/src after each access.
163 : // @param compare Flag to activate shortcut of the execution on difference.
164 : // @param context The registers context of the access.
165 : void CheckStringsMemoryAccesses(
166 : uint8* dst, HeapProxy::AccessMode dst_access_mode,
167 : uint8* src, HeapProxy::AccessMode src_access_mode,
168 : uint32 length, size_t access_size, int32 increment, bool compare,
169 E : AsanContext* context) {
170 E : int32 offset = 0;
171 :
172 E : for (uint32 i = 0; i < length; ++i) {
173 : // Check next memory location at src[offset].
174 E : if (src_access_mode != HeapProxy::ASAN_UNKNOWN_ACCESS)
175 E : CheckMemoryAccess(&src[offset], src_access_mode, access_size, context);
176 :
177 : // Check next memory location at dst[offset].
178 E : if (dst_access_mode != HeapProxy::ASAN_UNKNOWN_ACCESS)
179 E : CheckMemoryAccess(&dst[offset], dst_access_mode, access_size, context);
180 :
181 : // For CMPS instructions, we shortcut the execution of prefix REPZ when
182 : // memory contents differ.
183 E : if (compare) {
184 E : uint32 src_content = 0;
185 E : uint32 dst_content = 0;
186 E : switch (access_size) {
187 : case 4:
188 E : src_content = *reinterpret_cast<uint32*>(&src[offset]);
189 E : dst_content = *reinterpret_cast<uint32*>(&dst[offset]);
190 E : break;
191 : case 2:
192 E : src_content = *reinterpret_cast<uint16*>(&src[offset]);
193 E : dst_content = *reinterpret_cast<uint16*>(&dst[offset]);
194 E : break;
195 : case 1:
196 E : src_content = *reinterpret_cast<uint8*>(&src[offset]);
197 E : dst_content = *reinterpret_cast<uint8*>(&dst[offset]);
198 E : break;
199 : default:
200 i : NOTREACHED() << "Unexpected access_size.";
201 : break;
202 : }
203 :
204 E : if (src_content != dst_content)
205 E : return;
206 : }
207 :
208 : // Increments offset of dst/src to the next memory location.
209 E : offset += increment;
210 E : }
211 E : }
212 :
213 : } // namespace asan
214 : } // namespace agent
215 :
216 : // This is a trick for efficient saving/restoring part of the flags register.
217 : // see http://blog.freearrow.com/archives/396
218 : // Flags (bits 16-31) probably need a pipeline flush on update (POPFD). Thus,
219 : // using LAHF/SAHF instead gives better performance.
220 : // PUSHFD/POPFD: 23.314684 ticks
221 : // LAHF/SAHF: 8.838665 ticks
222 :
223 : // This macro starts by saving EAX onto the stack and then loads the value of
224 : // the flags into it.
225 : #define ASAN_SAVE_EFLAGS \
226 : __asm push eax \
227 : __asm lahf \
228 : __asm seto al
229 :
230 : // This macro restores the flags, their previous value is assumed to be in EAX
231 : // and we expect to have the previous value of EAX on the top of the stack.
232 : // AL is set to 1 if the overflow flag was set before the call to our hook, 0
233 : // otherwise. We add 0x7f to it so it'll restore the flag. Then we restore the
234 : // low bytes of the flags and EAX.
235 : #define ASAN_RESTORE_EFLAGS \
236 : __asm add al, 0x7f \
237 : __asm sahf \
238 : __asm pop eax
239 :
240 : // This is the common part of the fast path shared between the different
241 : // implementations of the hooks, this does the following:
242 : // - Saves the memory location in EDX for the slow path.
243 : // - Checks if the address we're trying to access is signed, if so this mean
244 : // that this is an access to the upper region of the memory (over the
245 : // 2GB limit) and we should report this as an invalid wild access.
246 : // - Checks for zero shadow for this memory location. We use the cmp
247 : // instruction so it'll set the sign flag if the upper bit of the shadow
248 : // value of this memory location is set to 1.
249 : // - If the shadow byte is not equal to zero then it jumps to the slow path.
250 : // - Otherwise it removes the memory location from the top of the stack.
251 : #define ASAN_FAST_PATH \
252 : __asm push edx \
253 : __asm sar edx, 3 \
254 : __asm js report_failure \
255 : __asm movzx edx, BYTE PTR[edx + agent::asan::Shadow::shadow_] \
256 : __asm cmp dl, 0 \
257 : __asm jnz check_access_slow \
258 : __asm add esp, 4
259 :
260 : // This is the common part of the slow path shared between the different
261 : // implementations of the hooks. The memory location is expected to be on top of
262 : // the stack and the shadow value for it is assumed to be in DL at this point.
263 : // This also relies on the fact that the shadow non accessible byte mask has its
264 : // upper bit set to 1 and that we jump to this macro after doing a
265 : // "cmp shadow_byte, 0", so the sign flag would be set to 1 if the value isn't
266 : // accessible.
267 : // We inline the Shadow::IsAccessible function for performance reasons.
268 : // This function does the following:
269 : // - Checks if this byte is accessible and jump to the error path if it's
270 : // not.
271 : // - Removes the memory location from the top of the stack.
272 : #define ASAN_SLOW_PATH \
273 : __asm js report_failure \
274 : __asm mov dh, BYTE PTR[esp] \
275 : __asm and dh, 7 \
276 : __asm cmp dh, dl \
277 : __asm jae report_failure \
278 : __asm add esp, 4
279 :
280 : // This is the error path. It expects to have the previous value of EDX at
281 : // [ESP + 4] and the address of the faulty instruction at [ESP].
282 : // This macro take cares of saving and restoring the flags.
283 : #define ASAN_ERROR_PATH(access_size, access_mode_value) \
284 : /* Restore original value of EDX, and put memory location on stack. */ \
285 : __asm xchg edx, DWORD PTR[esp + 4] \
286 : /* Create an ASAN registers context on the stack. */ \
287 : __asm pushfd \
288 : __asm pushad \
289 : /* Fix the original value of ESP in the ASAN registers context. */ \
290 : /* Removing 12 bytes (e.g. EFLAGS / EIP / Original EDX). */ \
291 : __asm add DWORD PTR[esp + 12], 12 \
292 : /* Push ARG4: the address of ASAN context on stack. */ \
293 : __asm push esp \
294 : /* Push ARG3: the access size. */ \
295 : __asm push access_size \
296 : /* Push ARG2: the access type. */ \
297 : __asm push access_mode_value \
298 : /* Push ARG1: the memory location. */ \
299 : __asm push DWORD PTR[esp + 52] \
300 : __asm call agent::asan::ReportBadMemoryAccess \
301 : /* Remove 4 x ARG on stack. */ \
302 : __asm add esp, 16 \
303 : /* Restore original registers. */ \
304 : __asm popad \
305 : __asm popfd \
306 : /* Return and remove memory location on stack. */ \
307 : __asm ret 4
308 :
309 : // Generates the asan check access functions. The name of the generated method
310 : // will be asan_check_(@p access_size)_byte_(@p access_mode_str)().
311 : // @param access_size The size of the access (in byte).
312 : // @param access_mode_str The string representing the access mode (read_access
313 : // or write_access).
314 : // @param access_mode_value The internal value representing this kind of access.
315 : // @note Calling this function doesn't alter any register.
316 : #define ASAN_CHECK_FUNCTION(access_size, access_mode_str, access_mode_value) \
317 : extern "C" __declspec(naked) \
318 : void asan_check_ ## access_size ## _byte_ ## access_mode_str ## () { \
319 : __asm { \
320 : /* Save the EFLAGS. */ \
321 : ASAN_SAVE_EFLAGS \
322 : ASAN_FAST_PATH \
323 : /* Restore original EDX. */ \
324 : __asm mov edx, DWORD PTR[esp + 8] \
325 : /* Restore the EFLAGS. */ \
326 : ASAN_RESTORE_EFLAGS \
327 : __asm ret 4 \
328 : __asm check_access_slow: \
329 : ASAN_SLOW_PATH \
330 : /* Restore original EDX. */ \
331 : __asm mov edx, DWORD PTR[esp + 8] \
332 : /* Restore the EFLAGS. */ \
333 : ASAN_RESTORE_EFLAGS \
334 : __asm ret 4 \
335 : __asm report_failure: \
336 : /* Restore memory location in EDX. */ \
337 : __asm pop edx \
338 : /* Restore the EFLAGS. */ \
339 : ASAN_RESTORE_EFLAGS \
340 : ASAN_ERROR_PATH(access_size, access_mode_value) \
341 : } \
342 : }
343 :
344 : // Generates a variant of the asan check access functions that don't save the
345 : // flags. The name of the generated method will be
346 : // asan_check_(@p access_size)_byte_(@p access_mode_str)_no_flags().
347 : // @param access_size The size of the access (in byte).
348 : // @param access_mode_str The string representing the access mode (read_access
349 : // or write_access).
350 : // @param access_mode_value The internal value representing this kind of access.
351 : // @note Calling this function may alter the EFLAGS register only.
352 : #define ASAN_CHECK_FUNCTION_NO_FLAGS(access_size, \
353 : access_mode_str, \
354 : access_mode_value) \
355 : extern "C" __declspec(naked) \
356 : void asan_check_ ## access_size ## _byte_ ## access_mode_str ## \
357 : _no_flags() { \
358 : __asm { \
359 : ASAN_FAST_PATH \
360 : /* Restore original EDX. */ \
361 : __asm mov edx, DWORD PTR[esp + 4] \
362 : __asm ret 4 \
363 : __asm check_access_slow: \
364 : ASAN_SLOW_PATH \
365 : /* Restore original EDX. */ \
366 : __asm mov edx, DWORD PTR[esp + 4] \
367 : __asm ret 4 \
368 : __asm report_failure: \
369 : /* Restore memory location in EDX. */ \
370 : __asm pop edx \
371 : ASAN_ERROR_PATH(access_size, access_mode_value) \
372 : } \
373 : }
374 :
375 : // Redefine some enums to make them accessible in the inlined assembly.
376 : // @{
377 : enum AccessMode {
378 : AsanReadAccess = HeapProxy::ASAN_READ_ACCESS,
379 : AsanWriteAccess = HeapProxy::ASAN_WRITE_ACCESS,
380 : AsanUnknownAccess = HeapProxy::ASAN_UNKNOWN_ACCESS,
381 : };
382 : // @}
383 :
384 : // The slow path rely on the fact that the shadow memory non accessible byte
385 : // mask have its upper bit set to 1..
386 : COMPILE_ASSERT(
387 : (agent::asan::Shadow::kHeapNonAccessibleByteMask & (1 << 7)) != 0,
388 : asan_shadow_mask_upper_bit_is_0);
389 :
390 i : ASAN_CHECK_FUNCTION(1, read_access, AsanReadAccess)
391 i : ASAN_CHECK_FUNCTION(2, read_access, AsanReadAccess)
392 i : ASAN_CHECK_FUNCTION(4, read_access, AsanReadAccess)
393 i : ASAN_CHECK_FUNCTION(8, read_access, AsanReadAccess)
394 i : ASAN_CHECK_FUNCTION(10, read_access, AsanReadAccess)
395 i : ASAN_CHECK_FUNCTION(16, read_access, AsanReadAccess)
396 i : ASAN_CHECK_FUNCTION(32, read_access, AsanReadAccess)
397 i : ASAN_CHECK_FUNCTION(1, write_access, AsanWriteAccess)
398 i : ASAN_CHECK_FUNCTION(2, write_access, AsanWriteAccess)
399 i : ASAN_CHECK_FUNCTION(4, write_access, AsanWriteAccess)
400 i : ASAN_CHECK_FUNCTION(8, write_access, AsanWriteAccess)
401 i : ASAN_CHECK_FUNCTION(10, write_access, AsanWriteAccess)
402 i : ASAN_CHECK_FUNCTION(16, write_access, AsanWriteAccess)
403 i : ASAN_CHECK_FUNCTION(32, write_access, AsanWriteAccess)
404 :
405 : #undef ASAN_CHECK_FUNCTION
406 :
407 i : ASAN_CHECK_FUNCTION_NO_FLAGS(1, read_access, AsanReadAccess)
408 i : ASAN_CHECK_FUNCTION_NO_FLAGS(2, read_access, AsanReadAccess)
409 i : ASAN_CHECK_FUNCTION_NO_FLAGS(4, read_access, AsanReadAccess)
410 i : ASAN_CHECK_FUNCTION_NO_FLAGS(8, read_access, AsanReadAccess)
411 i : ASAN_CHECK_FUNCTION_NO_FLAGS(10, read_access, AsanReadAccess)
412 i : ASAN_CHECK_FUNCTION_NO_FLAGS(16, read_access, AsanReadAccess)
413 i : ASAN_CHECK_FUNCTION_NO_FLAGS(32, read_access, AsanReadAccess)
414 i : ASAN_CHECK_FUNCTION_NO_FLAGS(1, write_access, AsanWriteAccess)
415 i : ASAN_CHECK_FUNCTION_NO_FLAGS(2, write_access, AsanWriteAccess)
416 i : ASAN_CHECK_FUNCTION_NO_FLAGS(4, write_access, AsanWriteAccess)
417 i : ASAN_CHECK_FUNCTION_NO_FLAGS(8, write_access, AsanWriteAccess)
418 i : ASAN_CHECK_FUNCTION_NO_FLAGS(10, write_access, AsanWriteAccess)
419 i : ASAN_CHECK_FUNCTION_NO_FLAGS(16, write_access, AsanWriteAccess)
420 i : ASAN_CHECK_FUNCTION_NO_FLAGS(32, write_access, AsanWriteAccess)
421 :
422 : #undef ASAN_CHECK_FUNCTION_NO_FLAGS
423 : #undef ASAN_SAVE_EFLAGS
424 : #undef ASAN_RESTORE_EFLAGS
425 : #undef ASAN_FAST_PATH
426 : #undef ASAN_SLOW_PATH
427 : #undef ASAN_ERROR_PATH
428 :
429 : // Generates the asan check access functions for a string instruction.
430 : // The name of the generated method will be
431 : // asan_check_(@p prefix)(@p access_size)_byte_(@p inst)_access().
432 : // @param inst The instruction mnemonic.
433 : // @param prefix The prefix of the instruction (repz or nothing).
434 : // @param counter The number of times the instruction must be executed (ECX). It
435 : // may be a register or a constant.
436 : // @param dst_mode The memory access mode for destination (EDI).
437 : // @param src_mode The memory access mode for destination (ESI).
438 : // @param access_size The size of the access (in byte).
439 : // @param compare A flag to enable shortcut execution by comparing memory
440 : // contents.
441 : #define ASAN_CHECK_STRINGS(func, prefix, counter, dst_mode, src_mode, \
442 : access_size, compare) \
443 : extern "C" __declspec(naked) \
444 : void asan_check ## prefix ## access_size ## _byte_ ## func ## _access() { \
445 : __asm { \
446 : /* Prologue, save context. */ \
447 : __asm pushfd \
448 : __asm pushad \
449 : /* Fix the original value of ESP in the ASAN registers context. */ \
450 : /* Removing 8 bytes (e.g.EFLAGS / EIP was on stack). */ \
451 : __asm add DWORD PTR[esp + 12], 8 \
452 : /* Setup increment in EBX (depends on direction flag in EFLAGS). */ \
453 : __asm mov ebx, access_size \
454 : __asm pushfd \
455 : __asm pop eax \
456 : __asm test eax, 0x400 \
457 : __asm jz skip_neg_direction \
458 : __asm neg ebx \
459 : __asm skip_neg_direction: \
460 : /* By standard calling convention, direction flag must be forward. */ \
461 : __asm cld \
462 : /* Push ARG(context), the ASAN registers context. */ \
463 : __asm push esp \
464 : /* Push ARG(compare), shortcut when memory contents differ. */ \
465 : __asm push compare \
466 : /* Push ARG(increment), increment for EDI/EDI. */ \
467 : __asm push ebx \
468 : /* Push ARG(access_size), the access size. */ \
469 : __asm push access_size \
470 : /* Push ARG(length), the number of memory accesses. */ \
471 : __asm push counter \
472 : /* Push ARG(src_access_mode), source access type. */ \
473 : __asm push src_mode \
474 : /* Push ARG(src), the source pointer. */ \
475 : __asm push esi \
476 : /* Push ARG(dst_access_mode), destination access type. */ \
477 : __asm push dst_mode \
478 : /* Push ARG(dst), the destination pointer. */ \
479 : __asm push edi \
480 : /* Call the generic check strings function. */ \
481 : __asm call agent::asan::CheckStringsMemoryAccesses \
482 : __asm add esp, 36 \
483 : /* Epilogue, restore context. */ \
484 : __asm popad \
485 : __asm popfd \
486 : __asm ret \
487 : } \
488 : }
489 :
490 i : ASAN_CHECK_STRINGS(cmps, _repz_, ecx, AsanReadAccess, AsanReadAccess, 4, 1)
491 i : ASAN_CHECK_STRINGS(cmps, _repz_, ecx, AsanReadAccess, AsanReadAccess, 2, 1)
492 i : ASAN_CHECK_STRINGS(cmps, _repz_, ecx, AsanReadAccess, AsanReadAccess, 1, 1)
493 i : ASAN_CHECK_STRINGS(cmps, _, 1, AsanReadAccess, AsanReadAccess, 4, 1)
494 i : ASAN_CHECK_STRINGS(cmps, _, 1, AsanReadAccess, AsanReadAccess, 2, 1)
495 i : ASAN_CHECK_STRINGS(cmps, _, 1, AsanReadAccess, AsanReadAccess, 1, 1)
496 :
497 i : ASAN_CHECK_STRINGS(movs, _repz_, ecx, AsanWriteAccess, AsanReadAccess, 4, 0)
498 i : ASAN_CHECK_STRINGS(movs, _repz_, ecx, AsanWriteAccess, AsanReadAccess, 2, 0)
499 i : ASAN_CHECK_STRINGS(movs, _repz_, ecx, AsanWriteAccess, AsanReadAccess, 1, 0)
500 i : ASAN_CHECK_STRINGS(movs, _, 1, AsanWriteAccess, AsanReadAccess, 4, 0)
501 i : ASAN_CHECK_STRINGS(movs, _, 1, AsanWriteAccess, AsanReadAccess, 2, 0)
502 i : ASAN_CHECK_STRINGS(movs, _, 1, AsanWriteAccess, AsanReadAccess, 1, 0)
503 :
504 i : ASAN_CHECK_STRINGS(stos, _repz_, ecx, AsanWriteAccess, AsanUnknownAccess, 4, 0)
505 i : ASAN_CHECK_STRINGS(stos, _repz_, ecx, AsanWriteAccess, AsanUnknownAccess, 2, 0)
506 i : ASAN_CHECK_STRINGS(stos, _repz_, ecx, AsanWriteAccess, AsanUnknownAccess, 1, 0)
507 i : ASAN_CHECK_STRINGS(stos, _, 1, AsanWriteAccess, AsanUnknownAccess, 4, 0)
508 i : ASAN_CHECK_STRINGS(stos, _, 1, AsanWriteAccess, AsanUnknownAccess, 2, 0)
509 i : ASAN_CHECK_STRINGS(stos, _, 1, AsanWriteAccess, AsanUnknownAccess, 1, 0)
510 :
511 : #undef ASAN_CHECK_STRINGS
512 :
513 : namespace {
514 :
515 : void ContextToAsanContext(const CONTEXT& context,
516 E : agent::asan::AsanContext* asan_context) {
517 E : DCHECK(asan_context != NULL);
518 E : asan_context->original_eax = context.Eax;
519 E : asan_context->original_ebp = context.Ebp;
520 E : asan_context->original_ebx = context.Ebx;
521 E : asan_context->original_ecx = context.Ecx;
522 E : asan_context->original_edi = context.Edi;
523 E : asan_context->original_edx = context.Edx;
524 E : asan_context->original_eflags = context.EFlags;
525 E : asan_context->original_eip = context.Eip;
526 E : asan_context->original_esi = context.Esi;
527 E : asan_context->original_esp = context.Esp;
528 E : }
529 :
530 : // Report an invalid access to @p location.
531 : // @param location The memory address of the access.
532 : // @param access_mode The mode of the access.
533 E : void ReportBadAccess(const uint8* location, HeapProxy::AccessMode access_mode) {
534 E : agent::asan::AsanContext asan_context = {};
535 E : CONTEXT context = {};
536 E : ::RtlCaptureContext(&context);
537 E : ContextToAsanContext(context, &asan_context);
538 : ReportBadMemoryAccess(const_cast<uint8*>(location),
539 : access_mode,
540 : 1U,
541 E : &asan_context);
542 E : }
543 :
544 : // Test that a memory range is accessible. Report an error if it's not.
545 : // @param memory The pointer to the beginning of the memory range that we want
546 : // to check.
547 : // @param size The size of the memory range that we want to check.
548 : // @param access_mode The access mode.
549 : void TestMemoryRange(const uint8* memory,
550 : size_t size,
551 E : HeapProxy::AccessMode access_mode) {
552 E : if (size == 0U)
553 E : return;
554 : // TODO(sebmarchand): This approach is pretty limited because it only check
555 : // if the first and the last elements are accessible. Once we have the
556 : // plumbing in place we should benchmark a check that looks at each
557 : // address to be touched (via the shadow memory, 8 bytes at a time).
558 : if (!agent::asan::Shadow::IsAccessible(memory) ||
559 E : !agent::asan::Shadow::IsAccessible(memory + size - 1)) {
560 E : const uint8* location = NULL;
561 E : if (!agent::asan::Shadow::IsAccessible(memory))
562 E : location = memory;
563 E : else
564 E : location = memory + size - 1;
565 E : ReportBadAccess(location, access_mode);
566 : }
567 E : }
568 :
569 : // Helper function to test if the memory range of a given structure is
570 : // accessible.
571 : // @tparam T the type of the structure to be tested.
572 : // @param structure A pointer to this structure.
573 : // @param access mode The access mode.
574 : template <typename T>
575 E : void TestStructure(const T* structure, HeapProxy::AccessMode access_mode) {
576 : TestMemoryRange(reinterpret_cast<const uint8*>(structure),
577 : sizeof(T),
578 E : access_mode);
579 E : }
580 :
581 : } // namespace
582 :
583 : extern "C" {
584 :
585 : HANDLE WINAPI asan_HeapCreate(DWORD options,
586 : SIZE_T initial_size,
587 E : SIZE_T maximum_size) {
588 E : DCHECK(asan_runtime != NULL);
589 E : scoped_ptr<HeapProxy> proxy(new HeapProxy());
590 E : if (!proxy->Create(options, initial_size, maximum_size))
591 E : return NULL;
592 :
593 E : asan_runtime->AddHeap(proxy.get());
594 :
595 E : return HeapProxy::ToHandle(proxy.release());
596 E : }
597 :
598 E : BOOL WINAPI asan_HeapDestroy(HANDLE heap) {
599 E : DCHECK(process_heap != NULL);
600 E : if (heap == process_heap)
601 i : return ::HeapDestroy(heap);
602 :
603 E : HeapProxy* proxy = HeapProxy::FromHandle(heap);
604 E : if (!proxy)
605 i : return FALSE;
606 :
607 E : asan_runtime->RemoveHeap(proxy);
608 :
609 E : if (proxy->Destroy()) {
610 E : delete proxy;
611 E : return TRUE;
612 : }
613 :
614 i : return FALSE;
615 E : }
616 :
617 : LPVOID WINAPI asan_HeapAlloc(HANDLE heap,
618 : DWORD flags,
619 E : SIZE_T bytes) {
620 E : DCHECK(process_heap != NULL);
621 E : if (heap == process_heap)
622 i : return ::HeapAlloc(heap, flags, bytes);
623 :
624 E : HeapProxy* proxy = HeapProxy::FromHandle(heap);
625 E : if (!proxy)
626 i : return NULL;
627 :
628 E : return proxy->Alloc(flags, bytes);
629 E : }
630 :
631 : LPVOID WINAPI asan_HeapReAlloc(HANDLE heap,
632 : DWORD flags,
633 : LPVOID mem,
634 E : SIZE_T bytes) {
635 E : DCHECK(process_heap != NULL);
636 E : if (heap == process_heap)
637 i : return ::HeapReAlloc(heap, flags, mem, bytes);
638 :
639 E : HeapProxy* proxy = HeapProxy::FromHandle(heap);
640 E : if (!proxy)
641 i : return NULL;
642 :
643 E : return proxy->ReAlloc(flags, mem, bytes);
644 E : }
645 :
646 : BOOL WINAPI asan_HeapFree(HANDLE heap,
647 : DWORD flags,
648 E : LPVOID mem) {
649 E : DCHECK(process_heap != NULL);
650 E : if (heap == process_heap)
651 i : return ::HeapFree(heap, flags, mem);
652 :
653 E : HeapProxy* proxy = HeapProxy::FromHandle(heap);
654 E : if (!proxy)
655 i : return FALSE;
656 :
657 E : if (!proxy->Free(flags, mem)) {
658 E : AsanErrorInfo error_info = {};
659 E : ::RtlCaptureContext(&error_info.context);
660 E : error_info.location = mem;
661 E : error_info.error_type = HeapProxy::DOUBLE_FREE;
662 E : proxy->GetBadAccessInformation(&error_info);
663 E : agent::asan::StackCapture stack;
664 E : stack.InitFromStack();
665 E : error_info.crash_stack_id = stack.ComputeRelativeStackId();
666 E : asan_runtime->OnError(&error_info);
667 E : return false;
668 : }
669 :
670 E : return true;
671 E : }
672 :
673 : SIZE_T WINAPI asan_HeapSize(HANDLE heap,
674 : DWORD flags,
675 E : LPCVOID mem) {
676 E : DCHECK(process_heap != NULL);
677 E : if (heap == process_heap)
678 i : return ::HeapSize(heap, flags, mem);
679 :
680 E : HeapProxy* proxy = HeapProxy::FromHandle(heap);
681 E : if (!proxy)
682 i : return static_cast<SIZE_T>(-1);
683 :
684 E : return proxy->Size(flags, mem);
685 E : }
686 :
687 : BOOL WINAPI asan_HeapValidate(HANDLE heap,
688 : DWORD flags,
689 E : LPCVOID mem) {
690 E : DCHECK(process_heap != NULL);
691 E : if (heap == process_heap)
692 i : return ::HeapValidate(heap, flags, mem);
693 :
694 E : HeapProxy* proxy = HeapProxy::FromHandle(heap);
695 E : if (!proxy)
696 i : return FALSE;
697 :
698 E : return proxy->Validate(flags, mem);
699 E : }
700 :
701 : SIZE_T WINAPI asan_HeapCompact(HANDLE heap,
702 E : DWORD flags) {
703 E : DCHECK(process_heap != NULL);
704 E : if (heap == process_heap)
705 i : return ::HeapCompact(heap, flags);
706 :
707 E : HeapProxy* proxy = HeapProxy::FromHandle(heap);
708 E : if (!proxy)
709 i : return 0;
710 :
711 E : return proxy->Compact(flags);
712 E : }
713 :
714 E : BOOL WINAPI asan_HeapLock(HANDLE heap) {
715 E : DCHECK(process_heap != NULL);
716 E : if (heap == process_heap)
717 i : return ::HeapLock(heap);
718 :
719 E : HeapProxy* proxy = HeapProxy::FromHandle(heap);
720 E : if (!proxy)
721 i : return FALSE;
722 :
723 E : return proxy->Lock();
724 E : }
725 :
726 E : BOOL WINAPI asan_HeapUnlock(HANDLE heap) {
727 E : DCHECK(process_heap != NULL);
728 E : if (heap == process_heap)
729 i : return ::HeapUnlock(heap);
730 :
731 E : HeapProxy* proxy = HeapProxy::FromHandle(heap);
732 E : if (!proxy)
733 i : return FALSE;
734 :
735 E : return proxy->Unlock();
736 E : }
737 :
738 : BOOL WINAPI asan_HeapWalk(HANDLE heap,
739 E : LPPROCESS_HEAP_ENTRY entry) {
740 E : DCHECK(process_heap != NULL);
741 E : if (heap == process_heap)
742 i : return ::HeapWalk(heap, entry);
743 :
744 E : HeapProxy* proxy = HeapProxy::FromHandle(heap);
745 E : if (!proxy)
746 i : return FALSE;
747 :
748 E : return proxy->Walk(entry);
749 E : }
750 :
751 : BOOL WINAPI asan_HeapSetInformation(
752 : HANDLE heap, HEAP_INFORMATION_CLASS info_class,
753 E : PVOID info, SIZE_T info_length) {
754 E : DCHECK(process_heap != NULL);
755 E : if (heap == NULL || heap == process_heap)
756 E : return ::HeapSetInformation(heap, info_class, info, info_length);
757 :
758 E : HeapProxy* proxy = HeapProxy::FromHandle(heap);
759 E : if (!proxy)
760 i : return FALSE;
761 :
762 E : return proxy->SetInformation(info_class, info, info_length);
763 E : }
764 :
765 : BOOL WINAPI asan_HeapQueryInformation(
766 : HANDLE heap, HEAP_INFORMATION_CLASS info_class,
767 E : PVOID info, SIZE_T info_length, PSIZE_T return_length) {
768 E : DCHECK(process_heap != NULL);
769 E : if (heap == NULL || heap == process_heap) {
770 : return ::HeapQueryInformation(heap,
771 : info_class,
772 : info,
773 : info_length,
774 i : return_length);
775 : }
776 :
777 E : HeapProxy* proxy = HeapProxy::FromHandle(heap);
778 E : if (!proxy)
779 i : return FALSE;
780 :
781 : bool ret = proxy->QueryInformation(info_class,
782 : info,
783 : info_length,
784 E : return_length);
785 E : return ret == true;
786 E : }
787 :
788 E : void WINAPI asan_SetCallBack(AsanErrorCallBack callback) {
789 E : DCHECK(asan_runtime != NULL);
790 E : asan_runtime->SetErrorCallBack(base::Bind(callback));
791 E : }
792 :
793 : void* __cdecl asan_memcpy(unsigned char* destination,
794 : const unsigned char* source,
795 E : size_t num) {
796 E : TestMemoryRange(source, num, HeapProxy::ASAN_READ_ACCESS);
797 E : TestMemoryRange(destination, num, HeapProxy::ASAN_WRITE_ACCESS);
798 E : return memcpy(destination, source, num);
799 E : }
800 :
801 : void* __cdecl asan_memmove(unsigned char* destination,
802 : const unsigned char* source,
803 E : size_t num) {
804 E : TestMemoryRange(source, num, HeapProxy::ASAN_READ_ACCESS);
805 E : TestMemoryRange(destination, num, HeapProxy::ASAN_WRITE_ACCESS);
806 E : return memmove(destination, source, num);
807 E : }
808 :
809 E : void* __cdecl asan_memset(unsigned char* ptr, int value, size_t num) {
810 E : TestMemoryRange(ptr, num, HeapProxy::ASAN_WRITE_ACCESS);
811 E : return memset(ptr, value, num);
812 E : }
813 :
814 : const void* __cdecl asan_memchr(const unsigned char* ptr,
815 : int value,
816 E : size_t num) {
817 E : TestMemoryRange(ptr, num, HeapProxy::ASAN_READ_ACCESS);
818 E : return memchr(ptr, value, num);
819 E : }
820 :
821 : size_t __cdecl asan_strcspn(const char* str1,
822 E : const char* str2) {
823 E : size_t size = 0;
824 E : if (!agent::asan::Shadow::GetNullTerminatedArraySize(str1, &size, 0U)) {
825 : ReportBadAccess(reinterpret_cast<const uint8*>(str1) + size,
826 E : HeapProxy::ASAN_READ_ACCESS);
827 : }
828 E : if (!agent::asan::Shadow::GetNullTerminatedArraySize(str2, &size, 0U)) {
829 : ReportBadAccess(reinterpret_cast<const uint8*>(str2) + size,
830 E : HeapProxy::ASAN_READ_ACCESS);
831 : }
832 E : return strcspn(str1, str2);
833 E : }
834 :
835 E : size_t __cdecl asan_strlen(const char* str) {
836 E : size_t size = 0;
837 E : if (!agent::asan::Shadow::GetNullTerminatedArraySize(str, &size, 0U)) {
838 : ReportBadAccess(reinterpret_cast<const uint8*>(str) + size,
839 E : HeapProxy::ASAN_READ_ACCESS);
840 E : return strlen(str);
841 : }
842 E : return size - 1;
843 E : }
844 :
845 E : const char* __cdecl asan_strrchr(const char* str, int character) {
846 E : size_t size = 0;
847 E : if (!agent::asan::Shadow::GetNullTerminatedArraySize(str, &size, 0U)) {
848 : ReportBadAccess(reinterpret_cast<const uint8*>(str) + size,
849 E : HeapProxy::ASAN_READ_ACCESS);
850 : }
851 E : return strrchr(str, character);
852 E : }
853 :
854 E : int __cdecl asan_strcmp(const char* str1, const char* str2) {
855 E : size_t size = 0;
856 E : if (!agent::asan::Shadow::GetNullTerminatedArraySize(str1, &size, 0U)) {
857 : ReportBadAccess(reinterpret_cast<const uint8*>(str1) + size,
858 E : HeapProxy::ASAN_READ_ACCESS);
859 : }
860 E : if (!agent::asan::Shadow::GetNullTerminatedArraySize(str2, &size, 0U)) {
861 : ReportBadAccess(reinterpret_cast<const uint8*>(str2) + size,
862 E : HeapProxy::ASAN_READ_ACCESS);
863 : }
864 E : return strcmp(str1, str2);
865 E : }
866 :
867 E : const char* __cdecl asan_strpbrk(const char* str1, const char* str2) {
868 E : size_t size = 0;
869 E : if (!agent::asan::Shadow::GetNullTerminatedArraySize(str1, &size, 0U)) {
870 : ReportBadAccess(reinterpret_cast<const uint8*>(str1) + size,
871 E : HeapProxy::ASAN_READ_ACCESS);
872 : }
873 E : if (!agent::asan::Shadow::GetNullTerminatedArraySize(str2, &size, 0U)) {
874 : ReportBadAccess(reinterpret_cast<const uint8*>(str2) + size,
875 E : HeapProxy::ASAN_READ_ACCESS);
876 : }
877 E : return strpbrk(str1, str2);
878 E : }
879 :
880 E : const char* __cdecl asan_strstr(const char* str1, const char* str2) {
881 E : size_t size = 0;
882 E : if (!agent::asan::Shadow::GetNullTerminatedArraySize(str1, &size, 0U)) {
883 : ReportBadAccess(reinterpret_cast<const uint8*>(str1) + size,
884 E : HeapProxy::ASAN_READ_ACCESS);
885 : }
886 E : if (!agent::asan::Shadow::GetNullTerminatedArraySize(str2, &size, 0U)) {
887 : ReportBadAccess(reinterpret_cast<const uint8*>(str2) + size,
888 E : HeapProxy::ASAN_READ_ACCESS);
889 : }
890 E : return strstr(str1, str2);
891 E : }
892 :
893 E : size_t __cdecl asan_strspn(const char* str1, const char* str2) {
894 E : size_t size = 0;
895 E : if (!agent::asan::Shadow::GetNullTerminatedArraySize(str1, &size, 0U)) {
896 : ReportBadAccess(reinterpret_cast<const uint8*>(str1) + size,
897 E : HeapProxy::ASAN_READ_ACCESS);
898 : }
899 E : if (!agent::asan::Shadow::GetNullTerminatedArraySize(str2, &size, 0U)) {
900 : ReportBadAccess(reinterpret_cast<const uint8*>(str2) + size,
901 E : HeapProxy::ASAN_READ_ACCESS);
902 : }
903 E : return strspn(str1, str2);
904 E : }
905 :
906 E : char* __cdecl asan_strncpy(char* destination, const char* source, size_t num) {
907 E : if (num != 0U) {
908 E : size_t src_size = 0;
909 : if (!agent::asan::Shadow::GetNullTerminatedArraySize(source,
910 : &src_size,
911 : num) &&
912 E : src_size <= num) {
913 : ReportBadAccess(reinterpret_cast<const uint8*>(source) + src_size,
914 E : HeapProxy::ASAN_READ_ACCESS);
915 : }
916 : // We can't use the GetNullTerminatedArraySize function here, as destination
917 : // might not be null terminated.
918 : TestMemoryRange(reinterpret_cast<const uint8*>(destination),
919 : num,
920 E : HeapProxy::ASAN_WRITE_ACCESS);
921 : }
922 E : return strncpy(destination, source, num);
923 E : }
924 :
925 E : char* __cdecl asan_strncat(char* destination, const char* source, size_t num) {
926 E : if (num != 0U) {
927 E : size_t src_size = 0;
928 : if (!agent::asan::Shadow::GetNullTerminatedArraySize(source,
929 : &src_size,
930 : num) &&
931 E : src_size <= num) {
932 : ReportBadAccess(reinterpret_cast<const uint8*>(source) + src_size,
933 E : HeapProxy::ASAN_READ_ACCESS);
934 : }
935 E : size_t dst_size = 0;
936 : if (!agent::asan::Shadow::GetNullTerminatedArraySize(destination,
937 : &dst_size,
938 E : 0U)) {
939 : ReportBadAccess(reinterpret_cast<const uint8*>(destination) + dst_size,
940 E : HeapProxy::ASAN_WRITE_ACCESS);
941 E : } else {
942 : // Test if we can append the source to the destination.
943 : TestMemoryRange(reinterpret_cast<const uint8*>(destination + dst_size),
944 : std::min(num, src_size),
945 E : HeapProxy::ASAN_WRITE_ACCESS);
946 : }
947 : }
948 E : return strncat(destination, source, num);
949 E : }
950 :
951 E : void asan_SetInterceptorCallback(InterceptorTailCallback callback) {
952 E : interceptor_tail_callback = callback;
953 E : }
954 :
955 : BOOL WINAPI asan_ReadFile(HANDLE file_handle,
956 : LPVOID buffer,
957 : DWORD bytes_to_read,
958 : LPDWORD bytes_read,
959 E : LPOVERLAPPED overlapped) {
960 : // TODO(sebmarchand): Add more checks for the asynchronous calls to this
961 : // function. More details about the asynchronous calls to ReadFile are
962 : // available here: http://support.microsoft.com/kb/156932.
963 :
964 : // Ensures that the input values are accessible.
965 :
966 : TestMemoryRange(reinterpret_cast<uint8*>(buffer),
967 : bytes_to_read,
968 E : HeapProxy::ASAN_WRITE_ACCESS);
969 :
970 E : if (bytes_read != NULL)
971 E : TestStructure<DWORD>(bytes_read, HeapProxy::ASAN_WRITE_ACCESS);
972 :
973 E : if (overlapped != NULL)
974 E : TestStructure<OVERLAPPED>(overlapped, HeapProxy::ASAN_READ_ACCESS);
975 :
976 : BOOL ret = ::ReadFile(file_handle,
977 : buffer,
978 : bytes_to_read,
979 : bytes_read,
980 E : overlapped);
981 :
982 : // Run the interceptor callback if it has been set.
983 E : if (interceptor_tail_callback != NULL)
984 E : (*interceptor_tail_callback)();
985 :
986 E : if (ret == FALSE)
987 i : return ret;
988 :
989 : // Even if the overlapped pointer wasn't NULL it might become invalid after
990 : // the call to ReadFile, and so we can't test that this structure is
991 : // accessible.
992 :
993 E : DCHECK_EQ(TRUE, ret);
994 E : CHECK(bytes_read == NULL || *bytes_read <= bytes_to_read);
995 : TestMemoryRange(reinterpret_cast<uint8*>(buffer),
996 : bytes_to_read,
997 E : HeapProxy::ASAN_WRITE_ACCESS);
998 :
999 E : if (bytes_read != NULL)
1000 E : TestStructure<DWORD>(bytes_read, HeapProxy::ASAN_WRITE_ACCESS);
1001 :
1002 E : return ret;
1003 E : }
1004 :
1005 : BOOL WINAPI asan_WriteFile(HANDLE file_handle,
1006 : LPCVOID buffer,
1007 : DWORD bytes_to_write,
1008 : LPDWORD bytes_written,
1009 E : LPOVERLAPPED overlapped) {
1010 : // Ensures that the input values are accessible.
1011 :
1012 : TestMemoryRange(reinterpret_cast<const uint8*>(buffer),
1013 : bytes_to_write,
1014 E : HeapProxy::ASAN_READ_ACCESS);
1015 :
1016 E : if (bytes_written != NULL)
1017 E : TestStructure<DWORD>(bytes_written, HeapProxy::ASAN_WRITE_ACCESS);
1018 :
1019 E : if (overlapped != NULL)
1020 E : TestStructure<OVERLAPPED>(overlapped, HeapProxy::ASAN_READ_ACCESS);
1021 :
1022 : BOOL ret = ::WriteFile(file_handle,
1023 : buffer,
1024 : bytes_to_write,
1025 : bytes_written,
1026 E : overlapped);
1027 :
1028 : // Run the interceptor callback if it has been set.
1029 E : if (interceptor_tail_callback != NULL)
1030 E : (*interceptor_tail_callback)();
1031 :
1032 E : if (ret == FALSE)
1033 i : return ret;
1034 :
1035 : // Even if the overlapped pointer wasn't NULL it might become invalid after
1036 : // the call to WriteFile, and so we can't test that this structure is
1037 : // accessible.
1038 :
1039 E : DCHECK_EQ(TRUE, ret);
1040 E : CHECK(bytes_written == NULL || *bytes_written <= bytes_to_write);
1041 : TestMemoryRange(reinterpret_cast<const uint8*>(buffer),
1042 : bytes_to_write,
1043 E : HeapProxy::ASAN_READ_ACCESS);
1044 :
1045 E : if (bytes_written != NULL)
1046 E : TestStructure<DWORD>(bytes_written, HeapProxy::ASAN_WRITE_ACCESS);
1047 :
1048 E : return ret;
1049 E : }
1050 :
1051 : } // extern "C"
|