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/memory_interceptors.h"
16 :
17 : #include "base/bind.h"
18 : #include "gmock/gmock.h"
19 : #include "gtest/gtest.h"
20 : #include "syzygy/agent/asan/unittest_util.h"
21 :
22 : namespace agent {
23 : namespace asan {
24 :
25 : namespace {
26 :
27 : using testing::_;
28 : using testing::MemoryAccessorTester;
29 : using testing::Return;
30 : using testing::TestMemoryInterceptors;
31 :
32 : static const TestMemoryInterceptors::InterceptFunction intercept_functions[] = {
33 : #define DEFINE_INTERCEPT_FUNCTION_TABLE(access_size, access_mode_str, \
34 : access_mode) \
35 : { asan_check_##access_size##_byte_##access_mode_str##_2gb, access_size } \
36 : , {asan_check_##access_size##_byte_##access_mode_str##_4gb, access_size},
37 :
38 : ASAN_MEM_INTERCEPT_FUNCTIONS(DEFINE_INTERCEPT_FUNCTION_TABLE)
39 :
40 : #undef DEFINE_INTERCEPT_FUNCTION_TABLE
41 : };
42 :
43 : static const TestMemoryInterceptors::InterceptFunction
44 : intercept_functions_no_flags[] = {
45 : #define DEFINE_INTERCEPT_FUNCTION_TABLE_NO_FLAGS(access_size, access_mode_str, \
46 : access_mode) \
47 : { \
48 : asan_check_##access_size##_byte_##access_mode_str##_no_flags_2gb, \
49 : access_size \
50 : } \
51 : , {asan_check_##access_size##_byte_##access_mode_str##_no_flags_4gb, \
52 : access_size},
53 :
54 : ASAN_MEM_INTERCEPT_FUNCTIONS(DEFINE_INTERCEPT_FUNCTION_TABLE_NO_FLAGS)
55 :
56 : #undef DEFINE_INTERCEPT_FUNCTION_TABLE_NO_FLAGS
57 : };
58 :
59 : static const TestMemoryInterceptors::InterceptFunction
60 : redirect_functions[] = {
61 : #define DEFINE_REDIRECT_FUNCTION_TABLE(access_size, access_mode_str, \
62 : access_mode) \
63 : { asan_redirect_ ## access_size ## _byte_ ## access_mode_str, \
64 : access_size }, \
65 :
66 : ASAN_MEM_INTERCEPT_FUNCTIONS(DEFINE_REDIRECT_FUNCTION_TABLE)
67 :
68 : #undef DEFINE_REDIRECT_FUNCTION_TABLE
69 : };
70 :
71 : static const TestMemoryInterceptors::InterceptFunction
72 : redirect_functions_no_flags[] = {
73 : #define DEFINE_REDIRECT_FUNCTION_TABLE_NO_FLAGS(access_size, access_mode_str, \
74 : access_mode) \
75 : { asan_redirect_ ## access_size ## _byte_ ## access_mode_str ## _no_flags, \
76 : access_size },
77 :
78 : ASAN_MEM_INTERCEPT_FUNCTIONS(DEFINE_REDIRECT_FUNCTION_TABLE_NO_FLAGS)
79 :
80 : #undef DEFINE_REDIRECT_FUNCTION_TABLE_NO_FLAGS
81 : };
82 :
83 : static const TestMemoryInterceptors::StringInterceptFunction
84 : string_intercept_functions[] = {
85 : #define DEFINE_STRING_INTERCEPT_FUNCTION_TABLE(func, prefix, counter, \
86 : dst_mode, src_mode, access_size, compare) \
87 : { asan_check ## prefix ## access_size ## _byte_ ## func ## _access, \
88 : access_size, TestMemoryInterceptors::dst_mode, \
89 : TestMemoryInterceptors::src_mode, \
90 : TestMemoryInterceptors::kCounterInit_##counter },
91 :
92 : ASAN_STRING_INTERCEPT_FUNCTIONS(DEFINE_STRING_INTERCEPT_FUNCTION_TABLE)
93 :
94 : #undef DEFINE_STRING_INTERCEPT_FUNCTION_TABLE
95 : };
96 :
97 : static const TestMemoryInterceptors::StringInterceptFunction
98 : string_redirect_functions[] = {
99 : #define DEFINE_STRING_REDIRECT_FUNCTION_TABLE(func, prefix, counter, \
100 : dst_mode, src_mode, access_size, compare) \
101 : { asan_redirect ## prefix ## access_size ## _byte_ ## func ## _access, \
102 : access_size, TestMemoryInterceptors::dst_mode, \
103 : TestMemoryInterceptors::src_mode, \
104 : TestMemoryInterceptors::kCounterInit_##counter },
105 :
106 : ASAN_STRING_INTERCEPT_FUNCTIONS(DEFINE_STRING_REDIRECT_FUNCTION_TABLE)
107 :
108 : #undef DEFINE_STRING_REDIRECT_FUNCTION_TABLE
109 : };
110 :
111 : class MemoryInterceptorsTest : public TestMemoryInterceptors {
112 : public:
113 : MOCK_METHOD1(OnRedirectorInvocation,
114 E : MemoryAccessorMode(const void* caller_address));
115 :
116 E : void SetUp() override {
117 E : ASSERT_NO_FATAL_FAILURE(TestMemoryInterceptors::SetUp());
118 :
119 : SetRedirectEntryCallback(
120 : base::Bind(&MemoryInterceptorsTest::OnRedirectorInvocation,
121 E : base::Unretained(this)));
122 E : }
123 :
124 E : void TearDown() override {
125 : // Clear the redirect callback, if any.
126 E : SetRedirectEntryCallback(RedirectEntryCallback());
127 :
128 E : TestMemoryInterceptors::TearDown();
129 E : }
130 : };
131 :
132 : } // namespace
133 :
134 E : TEST_F(MemoryInterceptorsTest, TestValidAccess) {
135 E : TestValidAccess(intercept_functions);
136 E : TestValidAccessIgnoreFlags(intercept_functions_no_flags);
137 E : }
138 :
139 E : TEST_F(MemoryInterceptorsTest, TestOverrunAccess) {
140 E : TestOverrunAccess(intercept_functions);
141 E : TestOverrunAccessIgnoreFlags(intercept_functions_no_flags);
142 E : }
143 :
144 E : TEST_F(MemoryInterceptorsTest, TestUnderrunAccess) {
145 E : TestUnderrunAccess(intercept_functions);
146 E : TestUnderrunAccessIgnoreFlags(intercept_functions_no_flags);
147 E : }
148 :
149 E : TEST_F(MemoryInterceptorsTest, TestRedirectorsNoop) {
150 : // Test that the redirect functions pass through to the noop tester.
151 : EXPECT_CALL(*this, OnRedirectorInvocation(_))
152 : .Times(arraysize(redirect_functions))
153 E : .WillRepeatedly(Return(MEMORY_ACCESSOR_MODE_NOOP));
154 E : TestValidAccess(redirect_functions);
155 :
156 : EXPECT_CALL(*this, OnRedirectorInvocation(_))
157 : .Times(arraysize(redirect_functions_no_flags))
158 E : .WillRepeatedly(Return(MEMORY_ACCESSOR_MODE_NOOP));
159 E : TestValidAccessIgnoreFlags(redirect_functions_no_flags);
160 E : }
161 :
162 E : TEST_F(MemoryInterceptorsTest, TestRedirectors2G) {
163 : EXPECT_CALL(*this, OnRedirectorInvocation(_))
164 : .Times(3 * arraysize(redirect_functions))
165 E : .WillRepeatedly(Return(MEMORY_ACCESSOR_MODE_2G));
166 :
167 : // Test valid, underrun and overrun.
168 E : TestValidAccess(redirect_functions);
169 E : TestUnderrunAccess(redirect_functions);
170 E : TestOverrunAccess(redirect_functions);
171 :
172 : EXPECT_CALL(*this, OnRedirectorInvocation(_))
173 : .Times(3 * arraysize(redirect_functions_no_flags))
174 E : .WillRepeatedly(Return(MEMORY_ACCESSOR_MODE_2G));
175 :
176 : // Test valid, underrun and overrun.
177 E : TestValidAccessIgnoreFlags(redirect_functions_no_flags);
178 E : TestUnderrunAccessIgnoreFlags(redirect_functions_no_flags);
179 E : TestOverrunAccessIgnoreFlags(redirect_functions_no_flags);
180 E : }
181 :
182 E : TEST_F(MemoryInterceptorsTest, TestStringValidAccess) {
183 E : TestStringValidAccess(string_intercept_functions);
184 E : }
185 :
186 E : TEST_F(MemoryInterceptorsTest, TestStringOverrunAccess) {
187 E : TestStringOverrunAccess(string_intercept_functions);
188 E : }
189 :
190 E : TEST_F(MemoryInterceptorsTest, TestStringRedirectorsNoop) {
191 : EXPECT_CALL(*this, OnRedirectorInvocation(_))
192 : // Each function is tested twice, forwards and backwards.
193 : .Times(2 * arraysize(string_redirect_functions))
194 E : .WillRepeatedly(Return(MEMORY_ACCESSOR_MODE_NOOP));
195 :
196 E : TestStringValidAccess(string_redirect_functions);
197 E : }
198 :
199 E : TEST_F(MemoryInterceptorsTest, TestStringRedirectors2G) {
200 : EXPECT_CALL(*this, OnRedirectorInvocation(_))
201 : // Each string function is tested forwards and backwards.
202 : .Times(2 * arraysize(string_redirect_functions))
203 E : .WillRepeatedly(Return(MEMORY_ACCESSOR_MODE_2G));
204 :
205 : // Test valid access.
206 E : TestStringValidAccess(string_redirect_functions);
207 :
208 : EXPECT_CALL(*this, OnRedirectorInvocation(_))
209 : // For overrun each string function is tested forwards and backwards
210 : // on src and dst, for a grand total of four tests. This is with the
211 : // exception of the stos instruction, which is tested only in two modes
212 : // and six variants.
213 : .Times(4 * arraysize(string_redirect_functions) - 2 * 6)
214 E : .WillRepeatedly(Return(MEMORY_ACCESSOR_MODE_2G));
215 E : TestStringOverrunAccess(string_redirect_functions);
216 E : }
217 :
218 : } // namespace asan
219 : } // namespace agent
|