OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
| 5 #include <memory> |
5 #include <windows.h> | 6 #include <windows.h> |
| 7 #include <vector> |
6 | 8 |
7 #include "base/win/scoped_handle.h" | 9 #include "base/win/scoped_handle.h" |
8 #include "base/win/scoped_process_information.h" | 10 #include "base/win/scoped_process_information.h" |
9 #include "sandbox/win/src/policy_broker.h" | 11 #include "sandbox/win/src/policy_broker.h" |
10 #include "sandbox/win/src/sandbox_nt_util.h" | 12 #include "sandbox/win/src/sandbox_nt_util.h" |
11 #include "testing/gtest/include/gtest/gtest.h" | 13 #include "testing/gtest/include/gtest/gtest.h" |
12 | 14 |
13 namespace sandbox { | 15 namespace sandbox { |
14 namespace { | 16 namespace { |
15 | 17 |
(...skipping 20 matching lines...) Expand all Loading... |
36 PROCESS_INFORMATION pi = {}; | 38 PROCESS_INFORMATION pi = {}; |
37 wchar_t notepad[] = L"notepad"; | 39 wchar_t notepad[] = L"notepad"; |
38 ASSERT_TRUE(CreateProcessW(nullptr, notepad, nullptr, nullptr, FALSE, 0, | 40 ASSERT_TRUE(CreateProcessW(nullptr, notepad, nullptr, nullptr, FALSE, 0, |
39 nullptr, nullptr, &si, &pi)); | 41 nullptr, nullptr, &si, &pi)); |
40 base::win::ScopedProcessInformation process_info(pi); | 42 base::win::ScopedProcessInformation process_info(pi); |
41 | 43 |
42 EXPECT_FALSE(IsSameProcess(process_info.process_handle())); | 44 EXPECT_FALSE(IsSameProcess(process_info.process_handle())); |
43 EXPECT_TRUE(TerminateProcess(process_info.process_handle(), 0)); | 45 EXPECT_TRUE(TerminateProcess(process_info.process_handle(), 0)); |
44 } | 46 } |
45 | 47 |
| 48 #if defined(_WIN64) |
| 49 struct VirtualMemDeleter { |
| 50 void operator()(char* p) { ::VirtualFree(p, 0, MEM_RELEASE); } |
| 51 }; |
| 52 |
| 53 typedef std::unique_ptr<char, VirtualMemDeleter> unique_ptr_vmem; |
| 54 |
| 55 void AllocateBlock(SIZE_T size, |
| 56 SIZE_T free_size, |
| 57 char** base_address, |
| 58 std::vector<unique_ptr_vmem>* mem_range) { |
| 59 unique_ptr_vmem ptr(static_cast<char*>(::VirtualAlloc( |
| 60 *base_address, size - free_size, MEM_RESERVE, PAGE_READWRITE))); |
| 61 ASSERT_NE(nullptr, ptr.get()); |
| 62 mem_range->push_back(std::move(ptr)); |
| 63 *base_address += size; |
| 64 } |
| 65 |
| 66 #define KIB(x) ((x)*1024ULL) |
| 67 #define MIB(x) (KIB(x) * 1024ULL) |
| 68 #define GIB(x) (MIB(x) * 1024ULL) |
| 69 // Construct a basic memory layout to do the test. We reserve first to get a |
| 70 // base address then reallocate with the following pattern. |
| 71 // |512MiB-64KiB Free|512MiB-128Kib Free|512MiB-256Kib Free|512MiB+512KiB Free| |
| 72 // The purpose of this is leave a couple of free memory regions within a 2GiB |
| 73 // block of reserved memory that we can test the searching allocator. |
| 74 void AllocateTestRange(std::vector<unique_ptr_vmem>* mem_range) { |
| 75 // Ensure we preallocate enough space in the vector to prevent unexpected |
| 76 // allocations. |
| 77 mem_range->reserve(5); |
| 78 SIZE_T total_size = |
| 79 MIB(512) + MIB(512) + MIB(512) + MIB(512) + KIB(512) + KIB(64); |
| 80 unique_ptr_vmem ptr(static_cast<char*>( |
| 81 ::VirtualAlloc(nullptr, total_size, MEM_RESERVE, PAGE_READWRITE))); |
| 82 ASSERT_NE(nullptr, ptr.get()); |
| 83 char* base_address = ptr.get(); |
| 84 char* orig_base = base_address; |
| 85 ptr.reset(); |
| 86 AllocateBlock(MIB(512), KIB(64), &base_address, mem_range); |
| 87 AllocateBlock(MIB(512), KIB(128), &base_address, mem_range); |
| 88 AllocateBlock(MIB(512), KIB(256), &base_address, mem_range); |
| 89 AllocateBlock(MIB(512) + KIB(512), KIB(512), &base_address, mem_range); |
| 90 // Allocate a memory block at end to act as an upper bound. |
| 91 AllocateBlock(KIB(64), 0, &base_address, mem_range); |
| 92 ASSERT_EQ(total_size, static_cast<SIZE_T>(base_address - orig_base)); |
| 93 } |
| 94 |
| 95 // Test we can allocate appropriate blocks. |
| 96 void TestAlignedRange(char* base_address) { |
| 97 unique_ptr_vmem ptr_256k(new (sandbox::NT_PAGE, base_address) char[KIB(256)]); |
| 98 EXPECT_EQ(base_address + GIB(1) + MIB(512) - KIB(256), ptr_256k.get()); |
| 99 unique_ptr_vmem ptr_64k(new (sandbox::NT_PAGE, base_address) char[KIB(64)]); |
| 100 EXPECT_EQ(base_address + MIB(512) - KIB(64), ptr_64k.get()); |
| 101 unique_ptr_vmem ptr_128k(new (sandbox::NT_PAGE, base_address) char[KIB(128)]); |
| 102 EXPECT_EQ(base_address + GIB(1) - KIB(128), ptr_128k.get()); |
| 103 // We will have run out of space here so should also fail. |
| 104 unique_ptr_vmem ptr_64k_noalloc( |
| 105 new (sandbox::NT_PAGE, base_address) char[KIB(64)]); |
| 106 EXPECT_EQ(nullptr, ptr_64k_noalloc.get()); |
| 107 } |
| 108 |
| 109 // Test the 512k block which exists at the end of the maximum allocation |
| 110 // boundary. |
| 111 void Test512kBlock(char* base_address) { |
| 112 // This should fail as it'll just be out of range. |
| 113 unique_ptr_vmem ptr_512k_noalloc( |
| 114 new (sandbox::NT_PAGE, base_address) char[KIB(512)]); |
| 115 EXPECT_EQ(nullptr, ptr_512k_noalloc.get()); |
| 116 // Check that moving base address we can allocate the 512k block. |
| 117 unique_ptr_vmem ptr_512k( |
| 118 new (sandbox::NT_PAGE, base_address + GIB(1)) char[KIB(512)]); |
| 119 EXPECT_EQ(base_address + GIB(2), ptr_512k.get()); |
| 120 // Free pointer first. |
| 121 ptr_512k.reset(); |
| 122 ptr_512k.reset(new (sandbox::NT_PAGE, base_address + GIB(2)) char[KIB(512)]); |
| 123 EXPECT_EQ(base_address + GIB(2), ptr_512k.get()); |
| 124 } |
| 125 |
| 126 // Test we can allocate appropriate blocks even when starting at an unaligned |
| 127 // address. |
| 128 void TestUnalignedRange(char* base_address) { |
| 129 char* unaligned_base = base_address + 123456; |
| 130 unique_ptr_vmem ptr_256k( |
| 131 new (sandbox::NT_PAGE, unaligned_base) char[KIB(256)]); |
| 132 EXPECT_EQ(base_address + GIB(1) + MIB(512) - KIB(256), ptr_256k.get()); |
| 133 unique_ptr_vmem ptr_64k(new (sandbox::NT_PAGE, unaligned_base) char[KIB(64)]); |
| 134 EXPECT_EQ(base_address + MIB(512) - KIB(64), ptr_64k.get()); |
| 135 unique_ptr_vmem ptr_128k( |
| 136 new (sandbox::NT_PAGE, unaligned_base) char[KIB(128)]); |
| 137 EXPECT_EQ(base_address + GIB(1) - KIB(128), ptr_128k.get()); |
| 138 } |
| 139 |
| 140 // Test maximum number of available allocations within the predefined pattern. |
| 141 void TestMaxAllocations(char* base_address) { |
| 142 // There's only 7 64k blocks in the first 2g which we can fill. |
| 143 unique_ptr_vmem ptr_1(new (sandbox::NT_PAGE, base_address) char[1]); |
| 144 EXPECT_NE(nullptr, ptr_1.get()); |
| 145 unique_ptr_vmem ptr_2(new (sandbox::NT_PAGE, base_address) char[1]); |
| 146 EXPECT_NE(nullptr, ptr_2.get()); |
| 147 unique_ptr_vmem ptr_3(new (sandbox::NT_PAGE, base_address) char[1]); |
| 148 EXPECT_NE(nullptr, ptr_3.get()); |
| 149 unique_ptr_vmem ptr_4(new (sandbox::NT_PAGE, base_address) char[1]); |
| 150 EXPECT_NE(nullptr, ptr_4.get()); |
| 151 unique_ptr_vmem ptr_5(new (sandbox::NT_PAGE, base_address) char[1]); |
| 152 EXPECT_NE(nullptr, ptr_5.get()); |
| 153 unique_ptr_vmem ptr_6(new (sandbox::NT_PAGE, base_address) char[1]); |
| 154 EXPECT_NE(nullptr, ptr_6.get()); |
| 155 unique_ptr_vmem ptr_7(new (sandbox::NT_PAGE, base_address) char[1]); |
| 156 EXPECT_NE(nullptr, ptr_7.get()); |
| 157 unique_ptr_vmem ptr_8(new (sandbox::NT_PAGE, base_address) char[1]); |
| 158 EXPECT_EQ(nullptr, ptr_8.get()); |
| 159 } |
| 160 |
| 161 // Test extreme allocations we know should fail. |
| 162 void TestExtremes() { |
| 163 unique_ptr_vmem ptr_null(new (sandbox::NT_PAGE, nullptr) char[1]); |
| 164 EXPECT_EQ(nullptr, ptr_null.get()); |
| 165 unique_ptr_vmem ptr_too_large( |
| 166 new (sandbox::NT_PAGE, reinterpret_cast<void*>(0x1000000)) char[GIB(4)]); |
| 167 EXPECT_EQ(nullptr, ptr_too_large.get()); |
| 168 unique_ptr_vmem ptr_overflow( |
| 169 new (sandbox::NT_PAGE, reinterpret_cast<void*>(SIZE_MAX)) char[1]); |
| 170 EXPECT_EQ(nullptr, ptr_overflow.get()); |
| 171 unique_ptr_vmem ptr_invalid(new ( |
| 172 sandbox::NT_PAGE, reinterpret_cast<void*>(SIZE_MAX - 0x1000000)) char[1]); |
| 173 EXPECT_EQ(nullptr, ptr_invalid.get()); |
| 174 } |
| 175 |
| 176 // Test nearest allocator, only do this for 64 bit. We test through the exposed |
| 177 // new operator as we can't call the AllocateNearTo function directly. |
| 178 TEST(SandboxNtUtil, NearestAllocator) { |
| 179 InitGlobalNt(); |
| 180 std::vector<unique_ptr_vmem> mem_range; |
| 181 AllocateTestRange(&mem_range); |
| 182 ASSERT_LT(0U, mem_range.size()); |
| 183 char* base_address = static_cast<char*>(mem_range[0].get()); |
| 184 |
| 185 TestAlignedRange(base_address); |
| 186 Test512kBlock(base_address); |
| 187 TestUnalignedRange(base_address); |
| 188 TestMaxAllocations(base_address); |
| 189 TestExtremes(); |
| 190 } |
| 191 |
| 192 #endif // defined(_WIN64) |
| 193 |
46 } // namespace | 194 } // namespace |
47 } // namespace sandbox | 195 } // namespace sandbox |
OLD | NEW |