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