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(unsigned char* destination,
49 : const unsigned char* source,
50 E : size_t num) {
51 : TestMemoryRange(crt_interceptor_shadow_, source, num,
52 E : agent::asan::ASAN_READ_ACCESS);
53 : TestMemoryRange(crt_interceptor_shadow_, destination, num,
54 E : agent::asan::ASAN_WRITE_ACCESS);
55 E : return ::memcpy(destination, source, num);
56 E : }
57 :
58 : void* __cdecl asan_memmove(unsigned char* destination,
59 : const unsigned char* source,
60 E : size_t num) {
61 : TestMemoryRange(crt_interceptor_shadow_, source, num,
62 E : agent::asan::ASAN_READ_ACCESS);
63 : TestMemoryRange(crt_interceptor_shadow_, destination, num,
64 E : agent::asan::ASAN_WRITE_ACCESS);
65 E : return ::memmove(destination, source, num);
66 E : }
67 :
68 E : void* __cdecl asan_memset(unsigned char* ptr, int value, size_t num) {
69 : TestMemoryRange(crt_interceptor_shadow_, ptr, num,
70 E : agent::asan::ASAN_WRITE_ACCESS);
71 E : return ::memset(ptr, value, num);
72 E : }
73 :
74 : const void* __cdecl asan_memchr(const unsigned char* ptr,
75 : int value,
76 E : size_t num) {
77 : TestMemoryRange(crt_interceptor_shadow_, ptr, num,
78 E : agent::asan::ASAN_READ_ACCESS);
79 E : return ::memchr(ptr, value, num);
80 E : }
81 :
82 i : size_t __cdecl asan_strcspn(const char* str1, const char* str2) {
83 : // TODO(sebmarchand): Provide an implementation that guarantees the same
84 : // behavior as the original function.
85 i : NOTIMPLEMENTED();
86 i : return 0;
87 i : }
88 :
89 E : size_t __cdecl asan_strlen(const char* str) {
90 E : if (!crt_interceptor_shadow_)
91 i : return ::strlen(str);
92 :
93 E : size_t size = 0;
94 : if (!crt_interceptor_shadow_->GetNullTerminatedArraySize<char>(str, 0U,
95 E : &size)) {
96 : ReportBadAccess(reinterpret_cast<const uint8*>(str) + size,
97 E : agent::asan::ASAN_READ_ACCESS);
98 E : return ::strlen(str);
99 : }
100 E : return size - 1;
101 E : }
102 :
103 E : const char* __cdecl asan_strrchr(const char* str, int character) {
104 E : if (!crt_interceptor_shadow_)
105 i : return ::strrchr(str, character);
106 :
107 E : size_t size = 0;
108 : if (!crt_interceptor_shadow_->GetNullTerminatedArraySize<char>(str, 0U,
109 E : &size)) {
110 : ReportBadAccess(reinterpret_cast<const uint8*>(str) + size,
111 E : agent::asan::ASAN_READ_ACCESS);
112 : }
113 E : return ::strrchr(str, character);
114 E : }
115 :
116 E : const wchar_t* asan_wcsrchr(const wchar_t* str, wchar_t character) {
117 E : if (!crt_interceptor_shadow_)
118 i : return ::wcsrchr(str, character);
119 :
120 E : size_t size = 0;
121 : if (!crt_interceptor_shadow_->GetNullTerminatedArraySize<wchar_t>(str, 0U,
122 E : &size)) {
123 : ReportBadAccess(reinterpret_cast<const uint8*>(str) + size,
124 E : agent::asan::ASAN_READ_ACCESS);
125 : }
126 E : return ::wcsrchr(str, character);
127 E : }
128 :
129 E : const wchar_t* asan_wcsstr(const wchar_t* str, const wchar_t* keys) {
130 E : if (!crt_interceptor_shadow_)
131 i : return ::wcsstr(str, keys);
132 :
133 E : size_t size = 0;
134 : if (!crt_interceptor_shadow_->GetNullTerminatedArraySize<wchar_t>(keys, 0U,
135 E : &size)) {
136 : ReportBadAccess(reinterpret_cast<const uint8*>(keys) + size,
137 E : agent::asan::ASAN_READ_ACCESS);
138 : }
139 E : const wchar_t* ret = ::wcsstr(str, keys);
140 E : if (ret != NULL && !crt_interceptor_shadow_->IsAccessible(ret)) {
141 : ReportBadAccess(reinterpret_cast<const uint8*>(ret),
142 i : agent::asan::ASAN_READ_ACCESS);
143 : }
144 E : return ret;
145 E : }
146 :
147 E : const wchar_t* asan_wcschr(const wchar_t* str, wchar_t character) {
148 E : if (!crt_interceptor_shadow_)
149 i : return ::wcschr(str, character);
150 :
151 E : const wchar_t* s = str;
152 : while (crt_interceptor_shadow_->IsAccessible(s) && *s != character &&
153 E : *s != NULL) {
154 E : s++;
155 E : }
156 E : if (!crt_interceptor_shadow_->IsAccessible(s)) {
157 : ReportBadAccess(reinterpret_cast<const uint8*>(s),
158 E : agent::asan::ASAN_READ_ACCESS);
159 E : return ::wcschr(str, character);
160 : }
161 E : if (*s == NULL)
162 E : return NULL;
163 E : return s;
164 E : }
165 :
166 i : int __cdecl asan_strcmp(const char* str1, const char* str2) {
167 : // TODO(sebmarchand): Provide an implementation that guarantees the same
168 : // behavior as the original function.
169 i : NOTIMPLEMENTED();
170 i : return 0;
171 i : }
172 :
173 i : const char* __cdecl asan_strpbrk(const char* str1, const char* str2) {
174 : // TODO(sebmarchand): Provide an implementation that guarantees the same
175 : // behavior as the original function.
176 i : NOTIMPLEMENTED();
177 i : return NULL;
178 i : }
179 :
180 i : const char* __cdecl asan_strstr(const char* str1, const char* str2) {
181 : // TODO(sebmarchand): Provide an implementation that guarantees the same
182 : // behavior as the original function.
183 i : NOTIMPLEMENTED();
184 i : return NULL;
185 i : }
186 :
187 i : size_t __cdecl asan_strspn(const char* str1, const char* str2) {
188 : // TODO(sebmarchand): Provide an implementation that guarantees the same
189 : // behavior as the original function.
190 i : NOTIMPLEMENTED();
191 i : return 0;
192 i : }
193 :
194 E : char* __cdecl asan_strncpy(char* destination, const char* source, size_t num) {
195 E : if (!crt_interceptor_shadow_)
196 i : return ::strncpy(destination, source, num);
197 :
198 E : if (num != 0U) {
199 E : size_t src_size = 0;
200 : if (!crt_interceptor_shadow_->GetNullTerminatedArraySize<char>(source, num,
201 : &src_size) &&
202 E : src_size <= num) {
203 : ReportBadAccess(reinterpret_cast<const uint8*>(source) + src_size,
204 E : agent::asan::ASAN_READ_ACCESS);
205 : }
206 : // We can't use the GetNullTerminatedArraySize function here, as destination
207 : // might not be null terminated.
208 : TestMemoryRange(crt_interceptor_shadow_,
209 : reinterpret_cast<const uint8*>(destination), num,
210 E : agent::asan::ASAN_WRITE_ACCESS);
211 : }
212 E : return ::strncpy(destination, source, num);
213 E : }
214 :
215 E : char* __cdecl asan_strncat(char* destination, const char* source, size_t num) {
216 E : if (!crt_interceptor_shadow_)
217 i : return ::strncat(destination, source, num);
218 :
219 E : if (num != 0U) {
220 E : size_t src_size = 0;
221 : if (!crt_interceptor_shadow_->GetNullTerminatedArraySize<char>(source, num,
222 : &src_size) &&
223 E : src_size <= num) {
224 : ReportBadAccess(reinterpret_cast<const uint8*>(source) + src_size,
225 E : agent::asan::ASAN_READ_ACCESS);
226 : }
227 E : size_t dst_size = 0;
228 : if (!crt_interceptor_shadow_->GetNullTerminatedArraySize<char>(
229 E : destination, 0U, &dst_size)) {
230 : ReportBadAccess(reinterpret_cast<const uint8*>(destination) + dst_size,
231 E : agent::asan::ASAN_WRITE_ACCESS);
232 E : } else {
233 : // Test if we can append the source to the destination.
234 : TestMemoryRange(crt_interceptor_shadow_,
235 : reinterpret_cast<const uint8*>(destination + dst_size),
236 E : std::min(num, src_size), agent::asan::ASAN_WRITE_ACCESS);
237 : }
238 : }
239 E : return ::strncat(destination, source, num);
240 E : }
241 :
242 : } // extern "C"
|