1 : // Copyright 2012 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/shadow.h"
16 :
17 : #include "base/rand_util.h"
18 : #include "base/memory/scoped_ptr.h"
19 : #include "gtest/gtest.h"
20 : #include "syzygy/common/align.h"
21 : #include "syzygy/testing/metrics.h"
22 :
23 : namespace agent {
24 : namespace asan {
25 :
26 : namespace {
27 :
28 : // A derived class to expose protected members for unit-testing.
29 : class TestShadow : public Shadow {
30 : public:
31 E : TestShadow() : Shadow(kTestShadowSize) {
32 E : }
33 :
34 : // We'll simulate memory as being 1GB in size.
35 : static const size_t kTestShadowSize =
36 : (1 * 1024 * 1024 * 1024) >> kShadowRatioLog;
37 :
38 : // Protected functions that we want to unittest directly.
39 : using Shadow::Reset;
40 : using Shadow::ScanLeftForBracketingBlockStart;
41 : using Shadow::ScanRightForBracketingBlockEnd;
42 : using Shadow::shadow_;
43 : };
44 :
45 : // A fixture for shadow memory tests.
46 : class ShadowTest : public testing::Test {
47 : public:
48 : TestShadow test_shadow;
49 : };
50 :
51 : } // namespace
52 :
53 E : TEST_F(ShadowTest, PoisonUnpoisonAccess) {
54 E : for (size_t count = 0; count < 100; ++count) {
55 : // Use a random 8-byte aligned end address.
56 E : const size_t size = base::RandInt(1, 16384);
57 : const uint8* end_addr =
58 E : reinterpret_cast<const uint8*>(base::RandInt(65536, 10*1024*1024) * 8);
59 E : const uint8* start_addr = end_addr - size;
60 :
61 E : for (size_t i = 0; i < size; ++i)
62 E : EXPECT_TRUE(test_shadow.IsAccessible(start_addr + i));
63 :
64 E : test_shadow.Poison(start_addr, size, kAsanReservedMarker);
65 E : for (size_t i = 0; i < size; ++i)
66 E : EXPECT_FALSE(test_shadow.IsAccessible(start_addr + i));
67 E : EXPECT_TRUE(test_shadow.IsAccessible(start_addr - 1));
68 E : EXPECT_TRUE(test_shadow.IsAccessible(start_addr + size));
69 :
70 : const size_t aligned_size = ::common::AlignUp(size,
71 E : kShadowRatio);
72 E : const uint8* aligned_start_addr = end_addr - aligned_size;
73 E : test_shadow.Unpoison(aligned_start_addr, aligned_size);
74 E : for (size_t i = 0; i < size; ++i)
75 E : EXPECT_TRUE(test_shadow.IsAccessible(start_addr + i));
76 E : }
77 E : }
78 :
79 E : TEST_F(ShadowTest, SetUpAndTearDown) {
80 : // Don't check all the shadow bytes otherwise this test will take too much
81 : // time.
82 E : const size_t kLookupInterval = 25;
83 :
84 E : intptr_t shadow_array_start = reinterpret_cast<intptr_t>(test_shadow.shadow_);
85 E : size_t shadow_start = shadow_array_start >> 3;
86 E : size_t shadow_end = shadow_start + (test_shadow.length() >> 3);
87 :
88 E : const size_t non_addressable_memory_end = (0x10000 >> 3);
89 :
90 E : test_shadow.SetUp();
91 E : for (size_t i = shadow_start; i < shadow_end; i += kLookupInterval)
92 E : ASSERT_EQ(kAsanMemoryMarker, test_shadow.shadow_[i]);
93 :
94 E : for (size_t i = 0; i < non_addressable_memory_end; i += kLookupInterval)
95 E : ASSERT_EQ(kInvalidAddressMarker, test_shadow.shadow_[i]);
96 :
97 E : test_shadow.TearDown();
98 E : for (size_t i = shadow_start; i < shadow_end; i += kLookupInterval)
99 E : ASSERT_EQ(kHeapAddressableMarker, test_shadow.shadow_[i]);
100 :
101 E : for (size_t i = 0; i < non_addressable_memory_end; i += kLookupInterval)
102 E : ASSERT_EQ(kHeapAddressableMarker, test_shadow.shadow_[i]);
103 E : }
104 :
105 E : TEST_F(ShadowTest, GetNullTerminatedArraySize) {
106 E : const size_t kArrayLength = 100;
107 E : const uint8 kMarkerValue = 0xAA;
108 :
109 : uint8 test_array[kArrayLength];
110 : uint8* aligned_test_array = reinterpret_cast<uint8*>(
111 : ::common::AlignUp(reinterpret_cast<size_t>(test_array),
112 E : kShadowRatio));
113 : size_t aligned_array_length = ::common::AlignDown(kArrayLength -
114 E : (aligned_test_array - test_array), kShadowRatio);
115 :
116 E : ::memset(aligned_test_array, kMarkerValue, aligned_array_length);
117 : test_shadow.Poison(
118 E : aligned_test_array, aligned_array_length, kAsanReservedMarker);
119 :
120 E : size_t sizes_to_test[] = { 4, 7, 12, 15, 21, 87, 88 };
121 :
122 E : for (size_t i = 0; i < arraysize(sizes_to_test); ++i) {
123 E : test_shadow.Unpoison(aligned_test_array, sizes_to_test[i]);
124 E : size_t size = 0;
125 :
126 : // Put a null byte at the end of the array and call the
127 : // GetNullTerminatedArraySize function with a 1-byte template argument. This
128 : // simulates the use of this function for a null terminated string.
129 E : aligned_test_array[sizes_to_test[i] - 1] = 0;
130 : EXPECT_TRUE(test_shadow.GetNullTerminatedArraySize<uint8>(
131 E : aligned_test_array, 0U, &size));
132 E : EXPECT_EQ(sizes_to_test[i], size);
133 :
134 E : if (sizes_to_test[i] % sizeof(uint16) == 0) {
135 : // Call the GetNullTerminatedArraySize with a 2-byte template argument.
136 : // As there is only one null byte at the end of the array we expect the
137 : // function to return false.
138 : EXPECT_FALSE(test_shadow.GetNullTerminatedArraySize<uint16>(
139 E : aligned_test_array, 0U, &size));
140 E : EXPECT_EQ(sizes_to_test[i], size);
141 : // Put a second null byte at the end of the array and call the function
142 : // again, this time we expect the function to succeed.
143 E : aligned_test_array[sizes_to_test[i] - sizeof(uint16)] = 0;
144 : EXPECT_TRUE(test_shadow.GetNullTerminatedArraySize<uint16>(
145 E : aligned_test_array, 0U, &size));
146 E : EXPECT_EQ(sizes_to_test[i], size);
147 E : aligned_test_array[sizes_to_test[i] - sizeof(uint16)] = kMarkerValue;
148 : }
149 E : aligned_test_array[sizes_to_test[i] - 1] = kMarkerValue;
150 :
151 E : aligned_test_array[sizes_to_test[i]] = kMarkerValue;
152 : EXPECT_FALSE(test_shadow.GetNullTerminatedArraySize<uint8>(
153 E : aligned_test_array, 0U, &size));
154 E : EXPECT_EQ(sizes_to_test[i], size);
155 : EXPECT_TRUE(test_shadow.GetNullTerminatedArraySize<uint8>(
156 E : aligned_test_array, sizes_to_test[i], &size));
157 :
158 : test_shadow.Poison(
159 : aligned_test_array,
160 : ::common::AlignUp(sizes_to_test[i], kShadowRatio),
161 E : kAsanReservedMarker);
162 E : }
163 E : test_shadow.Unpoison(aligned_test_array, aligned_array_length);
164 E : }
165 :
166 E : TEST_F(ShadowTest, MarkAsFreed) {
167 E : BlockLayout l0 = {}, l1 = {};
168 E : EXPECT_TRUE(BlockPlanLayout(kShadowRatio, kShadowRatio, 16, 30, 30, &l1));
169 : EXPECT_TRUE(BlockPlanLayout(kShadowRatio, kShadowRatio,
170 E : l1.block_size + 2 * kShadowRatio, 30, 30, &l0));
171 :
172 E : uint8* data = new uint8[l0.block_size];
173 :
174 E : uint8* d0 = data;
175 E : BlockInfo i0 = {};
176 E : BlockInitialize(l0, d0, false, &i0);
177 E : test_shadow.PoisonAllocatedBlock(i0);
178 :
179 E : uint8* d1 = i0.RawBody() + kShadowRatio;
180 E : BlockInfo i1 = {};
181 E : BlockInitialize(l1, d1, true, &i1);
182 E : test_shadow.PoisonAllocatedBlock(i1);
183 :
184 E : test_shadow.MarkAsFreed(i0.body, i0.body_size);
185 E : for (uint8* p = i0.RawBlock(); p < i0.RawBlock() + i0.block_size; ++p) {
186 E : if (p >= i0.RawBlock() && p < i0.RawBody()) {
187 E : EXPECT_TRUE(test_shadow.IsLeftRedzone(p));
188 E : } else if (p >= i0.RawBody() &&
189 E : p < i0.RawTrailerPadding()) {
190 E : if (p >= i1.RawBlock() && p < i1.RawBody()) {
191 E : EXPECT_TRUE(test_shadow.IsLeftRedzone(p));
192 E : } else if (p >= i1.RawBody() && p < i1.RawTrailerPadding()) {
193 : EXPECT_EQ(kHeapFreedMarker,
194 E : test_shadow.GetShadowMarkerForAddress(p));
195 E : } else if (p >= i1.RawTrailerPadding() &&
196 E : p < i1.RawBlock() + i1.block_size) {
197 E : EXPECT_TRUE(test_shadow.IsRightRedzone(p));
198 E : } else {
199 : EXPECT_EQ(kHeapFreedMarker,
200 E : test_shadow.GetShadowMarkerForAddress(p));
201 : }
202 E : } else if (p >= i0.RawTrailerPadding() &&
203 E : p < i0.RawBlock() + i0.block_size) {
204 E : EXPECT_TRUE(test_shadow.IsRightRedzone(p));
205 : }
206 E : }
207 :
208 E : test_shadow.Unpoison(data, l0.block_size);
209 E : delete [] data;
210 E : }
211 :
212 E : TEST_F(ShadowTest, PoisonAllocatedBlock) {
213 E : BlockLayout layout = {};
214 E : EXPECT_TRUE(BlockPlanLayout(kShadowRatio, kShadowRatio, 15, 22, 0, &layout));
215 :
216 E : uint8* data = new uint8[layout.block_size];
217 E : BlockInfo info = {};
218 E : BlockInitialize(layout, data, false, &info);
219 :
220 E : test_shadow.PoisonAllocatedBlock(info);
221 : EXPECT_EQ(test_shadow.GetShadowMarkerForAddress(data + 0 * 8),
222 E : kHeapBlockStartMarker0 | 7);
223 : EXPECT_EQ(test_shadow.GetShadowMarkerForAddress(data + 1 * 8),
224 E : kHeapLeftPaddingMarker);
225 : EXPECT_EQ(test_shadow.GetShadowMarkerForAddress(data + 2 * 8),
226 E : kHeapLeftPaddingMarker);
227 : EXPECT_EQ(test_shadow.GetShadowMarkerForAddress(data + 3 * 8),
228 E : 0);
229 : EXPECT_EQ(test_shadow.GetShadowMarkerForAddress(data + 4 * 8),
230 E : 7);
231 : EXPECT_EQ(test_shadow.GetShadowMarkerForAddress(data + 5 * 8),
232 E : kHeapRightPaddingMarker);
233 : EXPECT_EQ(test_shadow.GetShadowMarkerForAddress(data + 6 * 8),
234 E : kHeapRightPaddingMarker);
235 : EXPECT_EQ(test_shadow.GetShadowMarkerForAddress(data + 7 * 8),
236 E : kHeapBlockEndMarker);
237 :
238 E : uint8* cursor = info.RawHeader();
239 E : for (; cursor < info.RawBody(); ++cursor)
240 E : EXPECT_FALSE(test_shadow.IsAccessible(cursor));
241 E : for (; cursor < info.RawBody() + info.body_size; ++cursor)
242 E : EXPECT_TRUE(test_shadow.IsAccessible(cursor));
243 E : for (; cursor < info.RawHeader() + info.block_size; ++cursor)
244 E : EXPECT_FALSE(test_shadow.IsAccessible(cursor));
245 E : test_shadow.Unpoison(info.RawBlock(), info.block_size);
246 :
247 E : delete [] data;
248 E : }
249 :
250 E : TEST_F(ShadowTest, ScanLeftAndRight) {
251 E : size_t offset = test_shadow.length() / 2;
252 E : size_t l = 0;
253 E : test_shadow.shadow_[offset + 0] = kHeapBlockStartMarker0;
254 E : test_shadow.shadow_[offset + 1] = kHeapNestedBlockStartMarker0;
255 E : test_shadow.shadow_[offset + 2] = kHeapAddressableMarker;
256 E : test_shadow.shadow_[offset + 3] = kHeapNestedBlockEndMarker;
257 E : test_shadow.shadow_[offset + 4] = kHeapBlockEndMarker;
258 :
259 E : EXPECT_TRUE(test_shadow.ScanLeftForBracketingBlockStart(0, offset + 0, &l));
260 E : EXPECT_EQ(offset, l);
261 E : EXPECT_TRUE(test_shadow.ScanLeftForBracketingBlockStart(0, offset + 1, &l));
262 E : EXPECT_EQ(offset + 1, l);
263 E : EXPECT_TRUE(test_shadow.ScanLeftForBracketingBlockStart(0, offset + 2, &l));
264 E : EXPECT_EQ(offset + 1, l);
265 E : EXPECT_TRUE(test_shadow.ScanLeftForBracketingBlockStart(0, offset + 3, &l));
266 E : EXPECT_EQ(offset + 1, l);
267 E : EXPECT_TRUE(test_shadow.ScanLeftForBracketingBlockStart(0, offset + 4, &l));
268 E : EXPECT_EQ(offset, l);
269 :
270 E : EXPECT_FALSE(test_shadow.ScanLeftForBracketingBlockStart(1, offset + 0, &l));
271 E : EXPECT_TRUE(test_shadow.ScanLeftForBracketingBlockStart(1, offset + 1, &l));
272 E : EXPECT_EQ(offset, l);
273 E : EXPECT_TRUE(test_shadow.ScanLeftForBracketingBlockStart(1, offset + 2, &l));
274 E : EXPECT_EQ(offset, l);
275 E : EXPECT_TRUE(test_shadow.ScanLeftForBracketingBlockStart(1, offset + 3, &l));
276 E : EXPECT_EQ(offset, l);
277 E : EXPECT_FALSE(test_shadow.ScanLeftForBracketingBlockStart(1, offset + 4, &l));
278 :
279 E : EXPECT_FALSE(test_shadow.ScanLeftForBracketingBlockStart(2, offset + 0, &l));
280 E : EXPECT_FALSE(test_shadow.ScanLeftForBracketingBlockStart(2, offset + 1, &l));
281 E : EXPECT_FALSE(test_shadow.ScanLeftForBracketingBlockStart(2, offset + 2, &l));
282 E : EXPECT_FALSE(test_shadow.ScanLeftForBracketingBlockStart(2, offset + 3, &l));
283 E : EXPECT_FALSE(test_shadow.ScanLeftForBracketingBlockStart(2, offset + 4, &l));
284 :
285 E : EXPECT_TRUE(test_shadow.ScanRightForBracketingBlockEnd(0, offset + 0, &l));
286 E : EXPECT_EQ(offset + 4, l);
287 E : EXPECT_TRUE(test_shadow.ScanRightForBracketingBlockEnd(0, offset + 1, &l));
288 E : EXPECT_EQ(offset + 3, l);
289 E : EXPECT_TRUE(test_shadow.ScanRightForBracketingBlockEnd(0, offset + 2, &l));
290 E : EXPECT_EQ(offset + 3, l);
291 E : EXPECT_TRUE(test_shadow.ScanRightForBracketingBlockEnd(0, offset + 3, &l));
292 E : EXPECT_EQ(offset + 3, l);
293 E : EXPECT_TRUE(test_shadow.ScanRightForBracketingBlockEnd(0, offset + 4, &l));
294 E : EXPECT_EQ(offset + 4, l);
295 :
296 E : EXPECT_FALSE(test_shadow.ScanRightForBracketingBlockEnd(1, offset + 0, &l));
297 E : EXPECT_TRUE(test_shadow.ScanRightForBracketingBlockEnd(1, offset + 1, &l));
298 E : EXPECT_EQ(offset + 4, l);
299 E : EXPECT_TRUE(test_shadow.ScanRightForBracketingBlockEnd(1, offset + 2, &l));
300 E : EXPECT_EQ(offset + 4, l);
301 E : EXPECT_TRUE(test_shadow.ScanRightForBracketingBlockEnd(1, offset + 3, &l));
302 E : EXPECT_EQ(offset + 4, l);
303 E : EXPECT_FALSE(test_shadow.ScanRightForBracketingBlockEnd(1, offset + 4, &l));
304 :
305 E : EXPECT_FALSE(test_shadow.ScanRightForBracketingBlockEnd(2, offset + 0, &l));
306 E : EXPECT_FALSE(test_shadow.ScanRightForBracketingBlockEnd(2, offset + 1, &l));
307 E : EXPECT_FALSE(test_shadow.ScanRightForBracketingBlockEnd(2, offset + 2, &l));
308 E : EXPECT_FALSE(test_shadow.ScanRightForBracketingBlockEnd(2, offset + 3, &l));
309 E : EXPECT_FALSE(test_shadow.ScanRightForBracketingBlockEnd(2, offset + 4, &l));
310 :
311 E : ::memset(test_shadow.shadow_ + offset, 0, 5);
312 E : }
313 :
314 E : TEST_F(ShadowTest, ScanRightPerfTest) {
315 E : size_t offset = test_shadow.length() / 2;
316 E : size_t length = 1 * 1024 * 1024;
317 :
318 E : ::memset(test_shadow.shadow_ + offset, 0, length);
319 :
320 E : test_shadow.shadow_[offset + 0] = kHeapBlockStartMarker0;
321 : // A nested block with freed contents.
322 E : test_shadow.shadow_[offset + 50] = kHeapNestedBlockStartMarker0;
323 E : ::memset(test_shadow.shadow_ + offset + 51, kHeapFreedMarker, 8);
324 E : test_shadow.shadow_[offset + 60] = kHeapNestedBlockEndMarker;
325 : // A nested block with a nested block.
326 E : test_shadow.shadow_[offset + 100000] = kHeapNestedBlockStartMarker0;
327 E : test_shadow.shadow_[offset + 100100] = kHeapNestedBlockStartMarker0;
328 E : test_shadow.shadow_[offset + 100400] = kHeapNestedBlockEndMarker;
329 E : test_shadow.shadow_[offset + 200000] = kHeapNestedBlockEndMarker;
330 : // The end of the outer block.
331 E : test_shadow.shadow_[offset + length - 1] = kHeapBlockEndMarker;
332 :
333 E : uint64 tnet = 0;
334 E : for (size_t i = 0; i < 100; ++i) {
335 E : size_t l = 0;
336 E : uint64 t0 = ::__rdtsc();
337 E : test_shadow.ScanRightForBracketingBlockEnd(0, offset + 1, &l);
338 E : uint64 t1 = ::__rdtsc();
339 E : tnet += t1 - t0;
340 E : }
341 : testing::EmitMetric("Syzygy.Asan.Shadow.ScanRightForBracketingBlockEnd",
342 E : tnet);
343 :
344 : // Reset the shadow memory.
345 E : ::memset(test_shadow.shadow_ + offset, 0, length);
346 E : }
347 :
348 E : TEST_F(ShadowTest, IsLeftOrRightRedzone) {
349 E : BlockLayout layout = {};
350 E : const size_t kAllocSize = 15;
351 E : ASSERT_NE(0U, kAllocSize % kShadowRatio);
352 : EXPECT_TRUE(BlockPlanLayout(kShadowRatio, kShadowRatio, kAllocSize, 0, 0,
353 E : &layout));
354 :
355 E : scoped_ptr<uint8> data(new uint8[layout.block_size]);
356 E : BlockInfo info = {};
357 E : BlockInitialize(layout, data.get(), false, &info);
358 :
359 E : test_shadow.PoisonAllocatedBlock(info);
360 E : uint8* block = reinterpret_cast<uint8*>(info.header);
361 E : uint8* cursor = block;
362 :
363 E : for (; cursor < info.RawBody(); ++cursor) {
364 E : EXPECT_TRUE(test_shadow.IsLeftRedzone(cursor));
365 E : EXPECT_FALSE(test_shadow.IsRightRedzone(cursor));
366 E : }
367 E : for (; cursor < info.RawBody() + info.body_size; ++cursor) {
368 E : EXPECT_FALSE(test_shadow.IsLeftRedzone(cursor));
369 E : EXPECT_FALSE(test_shadow.IsRightRedzone(cursor));
370 E : }
371 E : for (; cursor < block + info.block_size; ++cursor) {
372 E : EXPECT_FALSE(test_shadow.IsLeftRedzone(cursor));
373 E : EXPECT_TRUE(test_shadow.IsRightRedzone(cursor));
374 E : }
375 :
376 E : test_shadow.Unpoison(block, info.block_size);
377 E : }
378 :
379 : namespace {
380 :
381 : void TestBlockInfoFromShadow(Shadow* shadow,
382 : const BlockLayout& outer,
383 E : const BlockLayout& nested) {
384 E : ASSERT_TRUE(shadow != nullptr);
385 E : ASSERT_LE(nested.block_size, outer.body_size);
386 :
387 E : uint8* data = new uint8[outer.block_size];
388 :
389 : // Try recovering the block from every position within it when no nested
390 : // block exists. Expect finding a nested block to fail.
391 E : BlockInfo info = {};
392 E : BlockInitialize(outer, data, false, &info);
393 E : shadow->PoisonAllocatedBlock(info);
394 E : BlockInfo info_recovered = {};
395 E : for (size_t i = 0; i < info.block_size; ++i) {
396 : EXPECT_TRUE(shadow->BlockInfoFromShadow(
397 E : info.RawBlock() + i, &info_recovered));
398 E : EXPECT_EQ(0, ::memcmp(&info, &info_recovered, sizeof(info)));
399 :
400 : // This block should have no parent block as its not nested.
401 : EXPECT_FALSE(shadow->ParentBlockInfoFromShadow(
402 E : info, &info_recovered));
403 E : }
404 :
405 : // Place a nested block and try the recovery from every position again.
406 : size_t padding = ::common::AlignDown(info.body_size - nested.block_size,
407 E : kShadowRatio * 2);
408 E : uint8* nested_begin = info.RawBody() + padding / 2;
409 E : uint8* nested_end = nested_begin + nested.block_size;
410 E : BlockInfo nested_info = {};
411 E : BlockInitialize(nested, nested_begin, true, &nested_info);
412 E : nested_info.header->is_nested = true;
413 E : shadow->PoisonAllocatedBlock(nested_info);
414 E : for (size_t i = 0; i < info.block_size; ++i) {
415 E : uint8* pos = info.RawBlock() + i;
416 E : EXPECT_TRUE(shadow->BlockInfoFromShadow(pos, &info_recovered));
417 :
418 E : BlockInfo parent_info = {};
419 : bool found_parent = shadow->ParentBlockInfoFromShadow(
420 E : info_recovered, &parent_info);
421 :
422 E : if (pos >= nested_begin && pos < nested_end) {
423 : EXPECT_EQ(0, ::memcmp(&nested_info, &info_recovered,
424 E : sizeof(nested_info)));
425 E : EXPECT_TRUE(found_parent);
426 E : EXPECT_EQ(0, ::memcmp(&info, &parent_info, sizeof(info)));
427 E : } else {
428 E : EXPECT_EQ(0, ::memcmp(&info, &info_recovered, sizeof(info)));
429 E : EXPECT_FALSE(found_parent);
430 : }
431 E : }
432 E : shadow->Unpoison(info.header, info.block_size);
433 :
434 E : delete [] data;
435 E : }
436 :
437 : } // namespace
438 :
439 E : TEST_F(ShadowTest, BlockInfoFromShadow) {
440 : // This is a simple layout that will be nested inside of another block.
441 E : BlockLayout layout0 = {};
442 E : EXPECT_TRUE(BlockPlanLayout(kShadowRatio, kShadowRatio, 6, 0, 0, &layout0));
443 :
444 : // Plan two layouts, one with padding and another with none. The first has
445 : // exactly enough space for the nested block, while the second has room to
446 : // spare.
447 E : BlockLayout layout1 = {};
448 E : BlockLayout layout2 = {};
449 : EXPECT_TRUE(BlockPlanLayout(kShadowRatio, kShadowRatio,
450 : ::common::AlignUp(layout0.block_size, kShadowRatio) + 4, 0, 0,
451 E : &layout1));
452 E : ASSERT_EQ(0u, layout1.header_padding_size);
453 E : ASSERT_EQ(0u, layout1.trailer_padding_size);
454 : EXPECT_TRUE(BlockPlanLayout(kShadowRatio, kShadowRatio,
455 E : layout0.block_size + 2 * kShadowRatio, 32, 13, &layout2));
456 E : ASSERT_LT(0u, layout2.header_padding_size);
457 E : ASSERT_LT(0u, layout2.trailer_padding_size);
458 :
459 : EXPECT_NO_FATAL_FAILURE(TestBlockInfoFromShadow(
460 E : &test_shadow, layout1, layout0));
461 : EXPECT_NO_FATAL_FAILURE(TestBlockInfoFromShadow(
462 E : &test_shadow, layout2, layout0));
463 E : }
464 :
465 E : TEST_F(ShadowTest, IsBeginningOfBlockBody) {
466 E : BlockLayout l = {};
467 E : EXPECT_TRUE(BlockPlanLayout(kShadowRatio, kShadowRatio, 7, 0, 0, &l));
468 :
469 E : size_t data_size = l.block_size;
470 E : scoped_ptr<uint8> data(new uint8[data_size]);
471 :
472 E : BlockInfo block_info = {};
473 E : BlockInitialize(l, data.get(), false, &block_info);
474 :
475 E : test_shadow.PoisonAllocatedBlock(block_info);
476 :
477 E : EXPECT_TRUE(test_shadow.IsBeginningOfBlockBody(block_info.body));
478 E : EXPECT_FALSE(test_shadow.IsBeginningOfBlockBody(data.get()));
479 :
480 E : block_info.header->state = QUARANTINED_BLOCK;
481 E : test_shadow.MarkAsFreed(block_info.body, block_info.body_size);
482 :
483 E : EXPECT_TRUE(test_shadow.IsBeginningOfBlockBody(block_info.body));
484 E : EXPECT_FALSE(test_shadow.IsBeginningOfBlockBody(data.get()));
485 :
486 E : test_shadow.Unpoison(data.get(), data_size);
487 E : }
488 :
489 E : TEST_F(ShadowTest, IsBeginningOfBlockBodyForBlockOfSizeZero) {
490 E : BlockLayout l = {};
491 E : EXPECT_TRUE(BlockPlanLayout(kShadowRatio, kShadowRatio, 0, 0, 0, &l));
492 :
493 E : size_t data_size = l.block_size;
494 E : scoped_ptr<uint8> data(new uint8[data_size]);
495 :
496 E : BlockInfo block_info = {};
497 E : BlockInitialize(l, data.get(), false, &block_info);
498 :
499 E : test_shadow.PoisonAllocatedBlock(block_info);
500 :
501 E : EXPECT_TRUE(test_shadow.IsBeginningOfBlockBody(block_info.body));
502 E : EXPECT_FALSE(test_shadow.IsBeginningOfBlockBody(data.get()));
503 :
504 E : block_info.header->state = QUARANTINED_FLOODED_BLOCK;
505 E : test_shadow.MarkAsFreed(block_info.body, block_info.body_size);
506 :
507 E : EXPECT_TRUE(test_shadow.IsBeginningOfBlockBody(block_info.body));
508 E : EXPECT_FALSE(test_shadow.IsBeginningOfBlockBody(data.get()));
509 :
510 E : test_shadow.Unpoison(data.get(), data_size);
511 E : }
512 :
513 E : TEST_F(ShadowTest, MarkAsFreedPerfTest) {
514 E : std::vector<uint8> buf;
515 E : buf.resize(10 * 1024 * 1024, 0);
516 :
517 E : uint64 tnet = 0;
518 E : for (size_t i = 0; i < 1000; ++i) {
519 E : test_shadow.Unpoison(buf.data(), buf.size());
520 E : uint64 t0 = ::__rdtsc();
521 E : test_shadow.MarkAsFreed(buf.data(), buf.size());
522 E : uint64 t1 = ::__rdtsc();
523 E : tnet += t1 - t0;
524 E : test_shadow.Unpoison(buf.data(), buf.size());
525 E : }
526 E : testing::EmitMetric("Syzygy.Asan.Shadow.MarkAsFreed", tnet);
527 E : }
528 :
529 E : TEST_F(ShadowTest, PageBits) {
530 : // Set an individual page.
531 E : const uint8* addr = reinterpret_cast<const uint8*>(16 * 4096);
532 E : EXPECT_FALSE(test_shadow.PageIsProtected(addr));
533 E : test_shadow.MarkPageProtected(addr);
534 E : EXPECT_TRUE(test_shadow.PageIsProtected(addr));
535 E : test_shadow.MarkPageProtected(addr);
536 E : EXPECT_TRUE(test_shadow.PageIsProtected(addr));
537 E : test_shadow.MarkPageUnprotected(addr);
538 E : EXPECT_FALSE(test_shadow.PageIsProtected(addr));
539 E : test_shadow.MarkPageUnprotected(addr);
540 E : EXPECT_FALSE(test_shadow.PageIsProtected(addr));
541 :
542 : // Set a range of pages at once.
543 E : const uint8* addr2 = addr + 4096;
544 E : EXPECT_FALSE(test_shadow.PageIsProtected(addr - 4096));
545 E : EXPECT_FALSE(test_shadow.PageIsProtected(addr));
546 E : EXPECT_FALSE(test_shadow.PageIsProtected(addr2));
547 E : EXPECT_FALSE(test_shadow.PageIsProtected(addr2 + 4096));
548 E : test_shadow.MarkPagesProtected(addr, 2 * 4096);
549 E : EXPECT_FALSE(test_shadow.PageIsProtected(addr - 4096));
550 E : EXPECT_TRUE(test_shadow.PageIsProtected(addr));
551 E : EXPECT_TRUE(test_shadow.PageIsProtected(addr2));
552 E : EXPECT_FALSE(test_shadow.PageIsProtected(addr2 + 4096));
553 E : test_shadow.MarkPagesProtected(addr, 2 * 4096);
554 E : EXPECT_FALSE(test_shadow.PageIsProtected(addr - 4096));
555 E : EXPECT_TRUE(test_shadow.PageIsProtected(addr));
556 E : EXPECT_TRUE(test_shadow.PageIsProtected(addr2));
557 E : EXPECT_FALSE(test_shadow.PageIsProtected(addr2 + 4096));
558 E : test_shadow.MarkPagesUnprotected(addr, 2 * 4096);
559 E : EXPECT_FALSE(test_shadow.PageIsProtected(addr - 4096));
560 E : EXPECT_FALSE(test_shadow.PageIsProtected(addr));
561 E : EXPECT_FALSE(test_shadow.PageIsProtected(addr2));
562 E : EXPECT_FALSE(test_shadow.PageIsProtected(addr2 + 4096));
563 E : test_shadow.MarkPagesUnprotected(addr, 2 * 4096);
564 E : EXPECT_FALSE(test_shadow.PageIsProtected(addr - 4096));
565 E : EXPECT_FALSE(test_shadow.PageIsProtected(addr));
566 E : EXPECT_FALSE(test_shadow.PageIsProtected(addr2));
567 E : EXPECT_FALSE(test_shadow.PageIsProtected(addr2 + 4096));
568 E : }
569 :
570 : namespace {
571 :
572 : // A fixture for shadow walker tests.
573 : class ShadowWalkerTest : public testing::Test {
574 : public:
575 : TestShadow test_shadow;
576 : };
577 :
578 : } // namespace
579 :
580 E : TEST_F(ShadowWalkerTest, WalksNonNestedBlocks) {
581 E : BlockLayout l = {};
582 E : EXPECT_TRUE(BlockPlanLayout(kShadowRatio, kShadowRatio, 7, 0, 0, &l));
583 :
584 E : size_t data_size = l.block_size * 3 + kShadowRatio;
585 E : uint8* data = new uint8[data_size];
586 E : uint8* data0 = data;
587 E : uint8* data1 = data0 + l.block_size + kShadowRatio;
588 E : uint8* data2 = data1 + l.block_size;
589 :
590 E : BlockInfo i0 = {}, i1 = {}, i2 = {};
591 E : BlockInitialize(l, data0, false, &i0);
592 E : BlockInitialize(l, data1, false, &i1);
593 E : BlockInitialize(l, data2, false, &i2);
594 :
595 E : test_shadow.PoisonAllocatedBlock(i0);
596 E : test_shadow.PoisonAllocatedBlock(i1);
597 E : test_shadow.PoisonAllocatedBlock(i2);
598 :
599 E : i2.header->state = QUARANTINED_BLOCK;
600 E : test_shadow.MarkAsFreed(i2.body, i2.body_size);
601 :
602 : // Do a non-recursive walk through the shadow.
603 E : BlockInfo i = {};
604 E : ShadowWalker w0(&test_shadow, false, data, data + data_size);
605 E : EXPECT_EQ(-1, w0.nesting_depth());
606 E : EXPECT_TRUE(w0.Next(&i));
607 E : EXPECT_EQ(0, w0.nesting_depth());
608 E : EXPECT_TRUE(w0.Next(&i));
609 E : EXPECT_EQ(0, w0.nesting_depth());
610 E : EXPECT_TRUE(w0.Next(&i));
611 E : EXPECT_EQ(0, w0.nesting_depth());
612 E : EXPECT_FALSE(w0.Next(&i));
613 E : EXPECT_EQ(-1, w0.nesting_depth());
614 :
615 : // Walk recursively through the shadow and expect the same results.
616 E : ShadowWalker w1(&test_shadow, true, data, data + data_size);
617 E : EXPECT_EQ(-1, w1.nesting_depth());
618 E : EXPECT_TRUE(w1.Next(&i));
619 E : EXPECT_EQ(0, w1.nesting_depth());
620 E : EXPECT_EQ(0, ::memcmp(&i, &i0, sizeof(i)));
621 E : EXPECT_TRUE(w1.Next(&i));
622 E : EXPECT_EQ(0, w1.nesting_depth());
623 E : EXPECT_EQ(0, ::memcmp(&i, &i1, sizeof(i)));
624 E : EXPECT_TRUE(w1.Next(&i));
625 E : EXPECT_EQ(0, w1.nesting_depth());
626 E : EXPECT_EQ(0, ::memcmp(&i, &i2, sizeof(i)));
627 E : EXPECT_FALSE(w1.Next(&i));
628 E : EXPECT_EQ(-1, w1.nesting_depth());
629 :
630 E : test_shadow.Unpoison(data, data_size);
631 E : delete [] data;
632 E : }
633 :
634 E : TEST_F(ShadowWalkerTest, WalksNestedBlocks) {
635 E : BlockLayout b0 = {}, b1 = {}, b2 = {}, b00 = {}, b01 = {}, b10 = {},
636 E : b100 = {};
637 E : EXPECT_TRUE(BlockPlanLayout(kShadowRatio, kShadowRatio, 15, 30, 30, &b00));
638 E : EXPECT_TRUE(BlockPlanLayout(kShadowRatio, kShadowRatio, 7, 0, 0, &b01));
639 : EXPECT_TRUE(BlockPlanLayout(kShadowRatio, kShadowRatio,
640 E : b00.block_size + b01.block_size + kShadowRatio, 0, 0, &b0));
641 E : EXPECT_TRUE(BlockPlanLayout(kShadowRatio, kShadowRatio, 7, 0, 0, &b100));
642 : EXPECT_TRUE(BlockPlanLayout(kShadowRatio, kShadowRatio, b100.block_size, 0, 0,
643 E : &b10));
644 : EXPECT_TRUE(BlockPlanLayout(kShadowRatio, kShadowRatio, b10.block_size, 0, 0,
645 E : &b1));
646 E : EXPECT_TRUE(BlockPlanLayout(kShadowRatio, kShadowRatio, 100, 0, 0, &b2));
647 :
648 : size_t data_size = b0.block_size + b1.block_size + kShadowRatio +
649 E : b2.block_size;
650 E : uint8* data = new uint8[data_size];
651 :
652 : // Initialize the depth 0 blocks.
653 E : uint8* d0 = data;
654 E : uint8* d1 = d0 + b0.block_size;
655 E : uint8* d2 = d1 + b1.block_size + kShadowRatio;
656 E : BlockInfo i0 = {}, i1 = {}, i2 = {};
657 E : BlockInitialize(b0, d0, false, &i0);
658 E : BlockInitialize(b1, d1, false, &i1);
659 E : BlockInitialize(b2, d2, false, &i2);
660 E : test_shadow.PoisonAllocatedBlock(i0);
661 E : test_shadow.PoisonAllocatedBlock(i1);
662 E : test_shadow.PoisonAllocatedBlock(i2);
663 :
664 : // Initialize depth 1 blocks.
665 E : uint8* d00 = i0.RawBody();
666 E : uint8* d01 = d00 + b00.block_size + kShadowRatio;
667 E : uint8* d10 = i1.RawBody();
668 E : BlockInfo i00 = {}, i01 = {}, i10 = {};
669 E : BlockInitialize(b00, d00, true, &i00);
670 E : BlockInitialize(b01, d01, true, &i01);
671 E : BlockInitialize(b10, d10, true, &i10);
672 E : test_shadow.PoisonAllocatedBlock(i00);
673 E : test_shadow.PoisonAllocatedBlock(i01);
674 E : test_shadow.PoisonAllocatedBlock(i10);
675 :
676 : // Initialize depth 2 blocks.
677 E : uint8* d100 = i10.RawBody();
678 E : BlockInfo i100 = {};
679 E : BlockInitialize(b100, d100, true, &i100);
680 E : test_shadow.PoisonAllocatedBlock(i100);
681 E : i100.header->state = QUARANTINED_FLOODED_BLOCK;
682 E : test_shadow.MarkAsFreed(i100.body, i100.body_size);
683 :
684 : // Do a non-recursive walk through the shadow.
685 E : BlockInfo i = {};
686 E : ShadowWalker w0(&test_shadow, false, data, data + data_size);
687 E : EXPECT_EQ(-1, w0.nesting_depth());
688 E : EXPECT_TRUE(w0.Next(&i));
689 E : EXPECT_EQ(0, w0.nesting_depth());
690 E : EXPECT_EQ(0, ::memcmp(&i, &i0, sizeof(i)));
691 E : EXPECT_TRUE(w0.Next(&i));
692 E : EXPECT_EQ(0, w0.nesting_depth());
693 E : EXPECT_EQ(0, ::memcmp(&i, &i1, sizeof(i)));
694 E : EXPECT_TRUE(w0.Next(&i));
695 E : EXPECT_EQ(0, w0.nesting_depth());
696 E : EXPECT_EQ(0, ::memcmp(&i, &i2, sizeof(i)));
697 E : EXPECT_FALSE(w0.Next(&i));
698 E : EXPECT_EQ(-1, w0.nesting_depth());
699 :
700 : // Walk recursively through the shadow.
701 E : ShadowWalker w1(&test_shadow, true, data, data + data_size);
702 E : EXPECT_EQ(-1, w1.nesting_depth());
703 E : EXPECT_TRUE(w1.Next(&i));
704 E : EXPECT_EQ(0, w1.nesting_depth());
705 E : EXPECT_EQ(0, ::memcmp(&i, &i0, sizeof(i)));
706 E : EXPECT_TRUE(w1.Next(&i));
707 E : EXPECT_EQ(1, w1.nesting_depth());
708 E : EXPECT_EQ(0, ::memcmp(&i, &i00, sizeof(i)));
709 E : EXPECT_TRUE(w1.Next(&i));
710 E : EXPECT_EQ(1, w1.nesting_depth());
711 E : EXPECT_EQ(0, ::memcmp(&i, &i01, sizeof(i)));
712 E : EXPECT_TRUE(w1.Next(&i));
713 E : EXPECT_EQ(0, w1.nesting_depth());
714 E : EXPECT_EQ(0, ::memcmp(&i, &i1, sizeof(i)));
715 E : EXPECT_TRUE(w1.Next(&i));
716 E : EXPECT_EQ(1, w1.nesting_depth());
717 E : EXPECT_EQ(0, ::memcmp(&i, &i10, sizeof(i)));
718 E : EXPECT_TRUE(w1.Next(&i));
719 E : EXPECT_EQ(2, w1.nesting_depth());
720 E : EXPECT_EQ(0, ::memcmp(&i, &i100, sizeof(i)));
721 E : EXPECT_TRUE(w1.Next(&i));
722 E : EXPECT_EQ(0, w1.nesting_depth());
723 E : EXPECT_EQ(0, ::memcmp(&i, &i2, sizeof(i)));
724 E : EXPECT_FALSE(w1.Next(&i));
725 E : EXPECT_EQ(-1, w1.nesting_depth());
726 :
727 E : test_shadow.Unpoison(data, data_size);
728 E : delete [] data;
729 E : }
730 :
731 : } // namespace asan
732 : } // namespace agent
|