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 : #include "syzygy/agent/asan/rtl_utils.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 "base/memory/scoped_ptr.h"
22 : #include "syzygy/agent/asan/heap_checker.h"
23 : #include "syzygy/agent/asan/runtime.h"
24 : #include "syzygy/agent/asan/shadow.h"
25 : #include "syzygy/agent/common/scoped_last_error_keeper.h"
26 : #include "syzygy/agent/common/stack_capture.h"
27 :
28 : namespace {
29 :
30 : // The asan runtime manager.
31 : agent::asan::AsanRuntime* asan_runtime = NULL;
32 :
33 : } // namespace
34 :
35 : namespace agent {
36 : namespace asan {
37 :
38 E : void SetAsanRuntimeInstance(AsanRuntime* runtime) {
39 E : asan_runtime = runtime;
40 E : }
41 :
42 : void ReportBadMemoryAccess(void* location,
43 : AccessMode access_mode,
44 : size_t access_size,
45 E : const AsanContext& asan_context) {
46 : // Capture the context and restore the value of the register as before calling
47 : // the asan hook.
48 :
49 : // Save the last error value so this function will be able to restore it.
50 E : agent::common::ScopedLastErrorKeeper scoped_last_error_keeper;
51 :
52 : // We keep a structure with all the useful information about this bad access
53 : // on the stack.
54 E : AsanErrorInfo bad_access_info = {};
55 :
56 : // We need to call ::RtlCaptureContext if we want SegSS and SegCS to be
57 : // properly set.
58 E : ::RtlCaptureContext(&bad_access_info.context);
59 E : bad_access_info.context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
60 :
61 : // Restore the original value of the registers.
62 E : bad_access_info.context.Eip = asan_context.original_eip;
63 E : bad_access_info.context.Eax = asan_context.original_eax;
64 E : bad_access_info.context.Ecx = asan_context.original_ecx;
65 E : bad_access_info.context.Edx = asan_context.original_edx;
66 E : bad_access_info.context.Ebx = asan_context.original_ebx;
67 E : bad_access_info.context.Ebp = asan_context.original_ebp;
68 E : bad_access_info.context.Esp = asan_context.original_esp;
69 E : bad_access_info.context.Esi = asan_context.original_esi;
70 E : bad_access_info.context.Edi = asan_context.original_edi;
71 E : bad_access_info.context.EFlags = asan_context.original_eflags;
72 :
73 E : common::StackCapture stack;
74 E : stack.InitFromStack();
75 : // We need to use the relative stack id so that for the same stack trace we
76 : // get the same value every time even if the modules are loaded at a different
77 : // base address.
78 : //
79 : // Check if we can ignore this error.
80 E : if (asan_runtime->ShouldIgnoreError(stack.relative_stack_id()))
81 i : return;
82 :
83 E : bad_access_info.crash_stack_id = stack.relative_stack_id();
84 E : bad_access_info.location = location;
85 E : bad_access_info.access_mode = access_mode;
86 E : bad_access_info.access_size = access_size;
87 E : bad_access_info.error_type = UNKNOWN_BAD_ACCESS;
88 E : bad_access_info.block_info.alloc_stack_size = 0U;
89 E : bad_access_info.block_info.alloc_tid = 0U;
90 E : bad_access_info.block_info.free_stack_size = 0U;
91 E : bad_access_info.block_info.free_tid = 0U;
92 E : bad_access_info.block_info.milliseconds_since_free = 0U;
93 E : bad_access_info.corrupt_ranges = NULL;
94 E : bad_access_info.corrupt_range_count = 0;
95 :
96 : // Make sure this structure is not optimized out.
97 E : base::debug::Alias(&bad_access_info);
98 :
99 : // TODO(sebmarchand): Check if the heap is corrupt and store the information
100 : // about the corrupt blocks if it's the case.
101 E : bad_access_info.heap_is_corrupt = false;
102 :
103 E : asan_runtime->GetBadAccessInformation(&bad_access_info);
104 :
105 : // Accesses to the first 64k of the memory (invalid address) should not be
106 : // reported by SyzyASAN unless we detect a heap corruption or if it has been
107 : // requested by the user. By returning early, we let the unhandled exception
108 : // filter do the heap corruption check. The check is not done here because we
109 : // don't want to duplicate the work.
110 : if (!asan_runtime->params().report_invalid_accesses &&
111 : bad_access_info.location <
112 E : reinterpret_cast<void*>(Shadow::kAddressLowerBound)) {
113 E : return;
114 : }
115 :
116 : // Report this error.
117 E : asan_runtime->OnError(&bad_access_info);
118 E : }
119 :
120 E : void ContextToAsanContext(const CONTEXT& context, AsanContext* asan_context) {
121 E : DCHECK(asan_context != NULL);
122 E : asan_context->original_eax = context.Eax;
123 E : asan_context->original_ebp = context.Ebp;
124 E : asan_context->original_ebx = context.Ebx;
125 E : asan_context->original_ecx = context.Ecx;
126 E : asan_context->original_edi = context.Edi;
127 E : asan_context->original_edx = context.Edx;
128 E : asan_context->original_eflags = context.EFlags;
129 E : asan_context->original_eip = context.Eip;
130 E : asan_context->original_esi = context.Esi;
131 E : asan_context->original_esp = context.Esp;
132 E : }
133 :
134 E : void ReportBadAccess(const uint8* location, AccessMode access_mode) {
135 E : AsanContext asan_context = {};
136 E : CONTEXT context = {};
137 E : ::RtlCaptureContext(&context);
138 E : ContextToAsanContext(context, &asan_context);
139 : ReportBadMemoryAccess(const_cast<uint8*>(location), access_mode, 1U,
140 E : asan_context);
141 E : }
142 :
143 : void TestMemoryRange(Shadow* shadow,
144 : const uint8* memory,
145 : size_t size,
146 E : AccessMode access_mode) {
147 E : if (!shadow || size == 0U)
148 i : return;
149 :
150 : // TODO(sebmarchand): This approach is pretty limited because it only checks
151 : // if the first and the last elements are accessible. Once we have the
152 : // plumbing in place we should benchmark a check that looks at each
153 : // address to be touched (via the shadow memory, 8 bytes at a time).
154 : if (!shadow->IsAccessible(memory) ||
155 E : !shadow->IsAccessible(memory + size - 1)) {
156 E : const uint8* location = NULL;
157 E : if (!shadow->IsAccessible(memory)) {
158 E : location = memory;
159 E : } else {
160 E : location = memory + size - 1;
161 : }
162 E : ReportBadAccess(location, access_mode);
163 : }
164 E : }
165 :
166 : } // namespace asan
167 : } // namespace agent
|