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/crt_interceptors.h"
16 :
17 : #include <algorithm>
18 :
19 : #include "base/logging.h"
20 : #include "syzygy/agent/asan/error_info.h"
21 : #include "syzygy/agent/asan/rtl_utils.h"
22 : #include "syzygy/agent/asan/shadow.h"
23 :
24 : namespace {
25 :
26 : using agent::asan::Shadow;
27 : using agent::asan::TestMemoryRange;
28 :
29 : // The global shadow memory that is used by the CRT interceptors.
30 : Shadow* crt_interceptor_shadow_ = nullptr;
31 :
32 : } // namespace
33 :
34 : namespace agent {
35 : namespace asan {
36 :
37 E : Shadow* SetCrtInterceptorShadow(Shadow* shadow) {
38 E : Shadow* old_shadow = crt_interceptor_shadow_;
39 E : crt_interceptor_shadow_ = shadow;
40 E : return old_shadow;
41 E : }
42 :
43 : } // namespace asan
44 : } // namespace agent
45 :
46 : extern "C" {
47 :
48 : void* __cdecl asan_memcpy(void* destination,
49 : const void* source,
50 E : size_t num) {
51 E : TestMemoryRange(crt_interceptor_shadow_,
52 : reinterpret_cast<const uint8_t*>(source), num,
53 : agent::asan::ASAN_READ_ACCESS);
54 E : TestMemoryRange(crt_interceptor_shadow_,
55 : reinterpret_cast<uint8_t*>(destination), num,
56 : agent::asan::ASAN_WRITE_ACCESS);
57 E : return ::memcpy(destination, source, num);
58 E : }
59 :
60 : void* __cdecl asan_memmove(void* destination,
61 : const void* source,
62 E : size_t num) {
63 E : TestMemoryRange(crt_interceptor_shadow_,
64 : reinterpret_cast<const uint8_t*>(source), num,
65 : agent::asan::ASAN_READ_ACCESS);
66 E : TestMemoryRange(crt_interceptor_shadow_,
67 : reinterpret_cast<uint8_t*>(destination), num,
68 : agent::asan::ASAN_WRITE_ACCESS);
69 E : return ::memmove(destination, source, num);
70 E : }
71 :
72 E : void* __cdecl asan_memset(void* ptr, int value, size_t num) {
73 E : TestMemoryRange(crt_interceptor_shadow_,
74 : reinterpret_cast<uint8_t*>(ptr), num,
75 : agent::asan::ASAN_WRITE_ACCESS);
76 E : return ::memset(ptr, value, num);
77 E : }
78 :
79 : const void* __cdecl asan_memchr(const void* ptr,
80 : int value,
81 E : size_t num) {
82 E : TestMemoryRange(crt_interceptor_shadow_,
83 : reinterpret_cast<const uint8_t*>(ptr), num,
84 : agent::asan::ASAN_READ_ACCESS);
85 E : return ::memchr(ptr, value, num);
86 E : }
87 :
88 i : size_t __cdecl asan_strcspn(const char* str1, const char* str2) {
89 : // TODO(sebmarchand): Provide an implementation that guarantees the same
90 : // behavior as the original function.
91 i : NOTIMPLEMENTED();
92 i : return 0;
93 i : }
94 :
95 E : size_t __cdecl asan_strlen(const char* str) {
96 E : if (!crt_interceptor_shadow_)
97 i : return ::strlen(str);
98 :
99 E : size_t size = 0;
100 E : if (!crt_interceptor_shadow_->GetNullTerminatedArraySize<char>(str, 0U,
101 : &size)) {
102 E : ReportBadAccess(reinterpret_cast<const uint8_t*>(str) + size,
103 : agent::asan::ASAN_READ_ACCESS);
104 E : return ::strlen(str);
105 : }
106 E : return size - 1;
107 E : }
108 :
109 E : size_t __cdecl asan_strnlen(const char* str, size_t max_count) {
110 E : if (!crt_interceptor_shadow_)
111 i : return ::strnlen(str, max_count);
112 :
113 E : size_t size = 0;
114 E : if (!crt_interceptor_shadow_->GetNullTerminatedArraySize<char>(
115 : str, max_count, &size)) {
116 E : ReportBadAccess(reinterpret_cast<const uint8_t*>(str) + size,
117 : agent::asan::ASAN_READ_ACCESS);
118 E : return ::strnlen(str, max_count);
119 : }
120 E : return size - 1;
121 E : }
122 :
123 E : const char* __cdecl asan_strrchr(const char* str, int character) {
124 E : if (!crt_interceptor_shadow_)
125 i : return ::strrchr(str, character);
126 :
127 E : size_t size = 0;
128 E : if (!crt_interceptor_shadow_->GetNullTerminatedArraySize<char>(str, 0U,
129 : &size)) {
130 E : ReportBadAccess(reinterpret_cast<const uint8_t*>(str) + size,
131 : agent::asan::ASAN_READ_ACCESS);
132 : }
133 E : return ::strrchr(str, character);
134 E : }
135 :
136 E : size_t __cdecl asan_wcsnlen(const wchar_t* str, size_t max_count) {
137 E : if (!crt_interceptor_shadow_)
138 i : return ::wcsnlen(str, max_count);
139 :
140 : // GetNullTerminatedArraySize always speaks in bytes.
141 E : size_t size = 0;
142 E : if (crt_interceptor_shadow_->GetNullTerminatedArraySize<wchar_t>(
143 : str, sizeof(wchar_t) * max_count, &size)) {
144 E : return (size / sizeof(wchar_t)) - 1;
145 : }
146 :
147 E : ReportBadAccess(reinterpret_cast<const uint8_t*>(str) + size,
148 : agent::asan::ASAN_READ_ACCESS);
149 E : return ::wcsnlen(str, max_count);
150 E : }
151 :
152 E : const wchar_t* asan_wcsrchr(const wchar_t* str, wchar_t character) {
153 E : if (!crt_interceptor_shadow_)
154 i : return ::wcsrchr(str, character);
155 :
156 E : size_t size = 0;
157 E : if (!crt_interceptor_shadow_->GetNullTerminatedArraySize<wchar_t>(str, 0U,
158 : &size)) {
159 E : ReportBadAccess(reinterpret_cast<const uint8_t*>(str) + size,
160 : agent::asan::ASAN_READ_ACCESS);
161 : }
162 E : return ::wcsrchr(str, character);
163 E : }
164 :
165 E : const wchar_t* asan_wcsstr(const wchar_t* str, const wchar_t* keys) {
166 E : if (!crt_interceptor_shadow_)
167 i : return ::wcsstr(str, keys);
168 :
169 E : size_t size = 0;
170 E : if (!crt_interceptor_shadow_->GetNullTerminatedArraySize<wchar_t>(keys, 0U,
171 : &size)) {
172 E : ReportBadAccess(reinterpret_cast<const uint8_t*>(keys) + size,
173 : agent::asan::ASAN_READ_ACCESS);
174 : }
175 E : const wchar_t* ret = ::wcsstr(str, keys);
176 E : if (ret != NULL && !crt_interceptor_shadow_->IsAccessible(ret)) {
177 i : ReportBadAccess(reinterpret_cast<const uint8_t*>(ret),
178 : agent::asan::ASAN_READ_ACCESS);
179 : }
180 E : return ret;
181 E : }
182 :
183 E : const wchar_t* asan_wcschr(const wchar_t* str, wchar_t character) {
184 E : if (!crt_interceptor_shadow_)
185 i : return ::wcschr(str, character);
186 :
187 E : const wchar_t* s = str;
188 E : while (crt_interceptor_shadow_->IsAccessible(s) && *s != character &&
189 : *s != NULL) {
190 E : s++;
191 E : }
192 E : if (!crt_interceptor_shadow_->IsAccessible(s)) {
193 E : ReportBadAccess(reinterpret_cast<const uint8_t*>(s),
194 : agent::asan::ASAN_READ_ACCESS);
195 E : return ::wcschr(str, character);
196 : }
197 E : if (*s == NULL)
198 E : return NULL;
199 E : return s;
200 E : }
201 :
202 i : int __cdecl asan_strcmp(const char* str1, const char* str2) {
203 : // TODO(sebmarchand): Provide an implementation that guarantees the same
204 : // behavior as the original function.
205 i : NOTIMPLEMENTED();
206 i : return 0;
207 i : }
208 :
209 i : const char* __cdecl asan_strpbrk(const char* str1, const char* str2) {
210 : // TODO(sebmarchand): Provide an implementation that guarantees the same
211 : // behavior as the original function.
212 i : NOTIMPLEMENTED();
213 i : return NULL;
214 i : }
215 :
216 i : const char* __cdecl asan_strstr(const char* str1, const char* str2) {
217 : // TODO(sebmarchand): Provide an implementation that guarantees the same
218 : // behavior as the original function.
219 i : NOTIMPLEMENTED();
220 i : return NULL;
221 i : }
222 :
223 i : size_t __cdecl asan_strspn(const char* str1, const char* str2) {
224 : // TODO(sebmarchand): Provide an implementation that guarantees the same
225 : // behavior as the original function.
226 i : NOTIMPLEMENTED();
227 i : return 0;
228 i : }
229 :
230 E : char* __cdecl asan_strncpy(char* destination, const char* source, size_t num) {
231 E : if (!crt_interceptor_shadow_)
232 i : return ::strncpy(destination, source, num);
233 :
234 E : if (num != 0U) {
235 E : size_t src_size = 0;
236 : if (!crt_interceptor_shadow_->GetNullTerminatedArraySize<char>(source, num,
237 E : &src_size) &&
238 : src_size <= num) {
239 E : ReportBadAccess(reinterpret_cast<const uint8_t*>(source) + src_size,
240 : agent::asan::ASAN_READ_ACCESS);
241 : }
242 : // We can't use the GetNullTerminatedArraySize function here, as destination
243 : // might not be null terminated.
244 E : TestMemoryRange(crt_interceptor_shadow_,
245 : reinterpret_cast<const uint8_t*>(destination), num,
246 : agent::asan::ASAN_WRITE_ACCESS);
247 : }
248 E : return ::strncpy(destination, source, num);
249 E : }
250 :
251 E : char* __cdecl asan_strncat(char* destination, const char* source, size_t num) {
252 E : if (!crt_interceptor_shadow_)
253 i : return ::strncat(destination, source, num);
254 :
255 E : if (num != 0U) {
256 E : size_t src_size = 0;
257 : if (!crt_interceptor_shadow_->GetNullTerminatedArraySize<char>(source, num,
258 E : &src_size) &&
259 : src_size <= num) {
260 E : ReportBadAccess(reinterpret_cast<const uint8_t*>(source) + src_size,
261 : agent::asan::ASAN_READ_ACCESS);
262 : }
263 E : size_t dst_size = 0;
264 E : if (!crt_interceptor_shadow_->GetNullTerminatedArraySize<char>(
265 : destination, 0U, &dst_size)) {
266 E : ReportBadAccess(reinterpret_cast<const uint8_t*>(destination) + dst_size,
267 : agent::asan::ASAN_WRITE_ACCESS);
268 E : } else {
269 : // Test if we can append the source to the destination.
270 E : TestMemoryRange(crt_interceptor_shadow_,
271 : reinterpret_cast<const uint8_t*>(destination + dst_size),
272 : std::min(num, src_size), agent::asan::ASAN_WRITE_ACCESS);
273 : }
274 : }
275 E : return ::strncat(destination, source, num);
276 E : }
277 :
278 : } // extern "C"
|