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