OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 "base/strings/stringprintf.h" | 5 #include "base/strings/stringprintf.h" |
6 #include "base/win/scoped_handle.h" | 6 #include "base/win/scoped_handle.h" |
7 #include "sandbox/win/src/handle_closer_agent.h" | 7 #include "sandbox/win/src/handle_closer_agent.h" |
| 8 #include "sandbox/win/src/nt_internals.h" |
8 #include "sandbox/win/src/sandbox.h" | 9 #include "sandbox/win/src/sandbox.h" |
9 #include "sandbox/win/src/sandbox_factory.h" | 10 #include "sandbox/win/src/sandbox_factory.h" |
10 #include "sandbox/win/src/target_services.h" | 11 #include "sandbox/win/src/target_services.h" |
11 #include "sandbox/win/tests/common/controller.h" | 12 #include "sandbox/win/tests/common/controller.h" |
12 #include "testing/gtest/include/gtest/gtest.h" | 13 #include "testing/gtest/include/gtest/gtest.h" |
13 | 14 |
14 namespace { | 15 namespace { |
15 | 16 |
16 const wchar_t *kFileExtensions[] = { L".1", L".2", L".3", L".4" }; | 17 const wchar_t *kFileExtensions[] = { L".1", L".2", L".3", L".4" }; |
17 | 18 |
(...skipping 17 matching lines...) Expand all Loading... |
35 timestamp.dwLowDateTime, | 36 timestamp.dwLowDateTime, |
36 timestamp.dwHighDateTime); | 37 timestamp.dwHighDateTime); |
37 marker_path += extension; | 38 marker_path += extension; |
38 | 39 |
39 // Make the file delete-on-close so cleanup is automatic. | 40 // Make the file delete-on-close so cleanup is automatic. |
40 return CreateFile(marker_path.c_str(), FILE_ALL_ACCESS, | 41 return CreateFile(marker_path.c_str(), FILE_ALL_ACCESS, |
41 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, | 42 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, |
42 NULL, OPEN_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL); | 43 NULL, OPEN_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL); |
43 } | 44 } |
44 | 45 |
| 46 // Returns type infomation for an NT object. This routine is expected to be |
| 47 // called for invalid handles so it catches STATUS_INVALID_HANDLE exceptions |
| 48 // that can be generated when handle tracing is enabled. |
| 49 NTSTATUS QueryObjectTypeInformation(HANDLE handle, void* buffer, ULONG* size) { |
| 50 static NtQueryObject QueryObject = NULL; |
| 51 if (!QueryObject) |
| 52 ResolveNTFunctionPtr("NtQueryObject", &QueryObject); |
| 53 |
| 54 NTSTATUS status = STATUS_UNSUCCESSFUL; |
| 55 __try { |
| 56 status = QueryObject(handle, ObjectTypeInformation, buffer, *size, size); |
| 57 } |
| 58 __except(GetExceptionCode() == STATUS_INVALID_HANDLE |
| 59 ? EXCEPTION_EXECUTE_HANDLER |
| 60 : EXCEPTION_CONTINUE_SEARCH) { |
| 61 status = STATUS_INVALID_HANDLE; |
| 62 } |
| 63 return status; |
| 64 } |
| 65 |
45 // Used by the thread pool tests. | 66 // Used by the thread pool tests. |
46 HANDLE finish_event; | 67 HANDLE finish_event; |
47 const int kWaitCount = 20; | 68 const int kWaitCount = 20; |
48 | 69 |
49 } // namespace | 70 } // namespace |
50 | 71 |
51 namespace sandbox { | 72 namespace sandbox { |
52 | 73 |
53 // Checks for the presence of a list of files (in object path form). | 74 // Checks for the presence of a list of files (in object path form). |
54 // Format: CheckForFileHandle (Y|N) \path\to\file1 [\path\to\file2 ...] | 75 // Format: CheckForFileHandle (Y|N) \path\to\file1 [\path\to\file2 ...] |
55 // - Y or N depending if the file should exist or not. | 76 // - Y or N depending if the file should exist or not. |
56 SBOX_TESTS_COMMAND int CheckForFileHandles(int argc, wchar_t **argv) { | 77 SBOX_TESTS_COMMAND int CheckForFileHandles(int argc, wchar_t **argv) { |
57 if (argc < 2) | 78 if (argc < 2) |
58 return SBOX_TEST_FAILED_TO_RUN_TEST; | 79 return SBOX_TEST_FAILED_TO_RUN_TEST; |
59 bool should_find = argv[0][0] == L'Y'; | 80 bool should_find = argv[0][0] == L'Y'; |
60 if (argv[0][1] != L'\0' || !should_find && argv[0][0] != L'N') | 81 if (argv[0][1] != L'\0' || !should_find && argv[0][0] != L'N') |
61 return SBOX_TEST_FAILED_TO_RUN_TEST; | 82 return SBOX_TEST_FAILED_TO_RUN_TEST; |
62 | 83 |
63 static int state = BEFORE_INIT; | 84 static int state = BEFORE_INIT; |
64 switch (state++) { | 85 switch (state++) { |
65 case BEFORE_INIT: | 86 case BEFORE_INIT: |
66 // Create a unique marker file that is open while the test is running. | 87 // Create a unique marker file that is open while the test is running. |
67 // The handles leak, but it will be closed by the test or on exit. | 88 // The handles leak, but it will be closed by the test or on exit. |
68 for (int i = 0; i < arraysize(kFileExtensions); ++i) | 89 for (int i = 0; i < arraysize(kFileExtensions); ++i) |
69 EXPECT_NE(GetMarkerFile(kFileExtensions[i]), INVALID_HANDLE_VALUE); | 90 CHECK_NE(GetMarkerFile(kFileExtensions[i]), INVALID_HANDLE_VALUE); |
70 return SBOX_TEST_SUCCEEDED; | 91 return SBOX_TEST_SUCCEEDED; |
71 | 92 |
72 case AFTER_REVERT: { | 93 case AFTER_REVERT: { |
73 // Brute force the handle table to find what we're looking for. | 94 // Brute force the handle table to find what we're looking for. |
74 DWORD handle_count = UINT_MAX; | 95 DWORD handle_count = UINT_MAX; |
75 const int kInvalidHandleThreshold = 100; | 96 const int kInvalidHandleThreshold = 100; |
76 const size_t kHandleOffset = 4; // Handles are always a multiple of 4. | 97 const size_t kHandleOffset = 4; // Handles are always a multiple of 4. |
77 HANDLE handle = NULL; | 98 HANDLE handle = NULL; |
78 int invalid_count = 0; | 99 int invalid_count = 0; |
79 base::string16 handle_name; | 100 base::string16 handle_name; |
(...skipping 17 matching lines...) Expand all Loading... |
97 return should_find ? SBOX_TEST_FAILED : SBOX_TEST_SUCCEEDED; | 118 return should_find ? SBOX_TEST_FAILED : SBOX_TEST_SUCCEEDED; |
98 } | 119 } |
99 | 120 |
100 default: // Do nothing. | 121 default: // Do nothing. |
101 break; | 122 break; |
102 } | 123 } |
103 | 124 |
104 return SBOX_TEST_SUCCEEDED; | 125 return SBOX_TEST_SUCCEEDED; |
105 } | 126 } |
106 | 127 |
| 128 // Checks that supplied handle is an Event and it's not waitable. |
| 129 // Format: CheckForEventHandles |
| 130 SBOX_TESTS_COMMAND int CheckForEventHandles(int argc, wchar_t** argv) { |
| 131 static int state = BEFORE_INIT; |
| 132 static std::vector<HANDLE> to_check; |
| 133 |
| 134 switch (state++) { |
| 135 case BEFORE_INIT: |
| 136 // Create a unique marker file that is open while the test is running. |
| 137 for (int i = 0; i < arraysize(kFileExtensions); ++i) { |
| 138 HANDLE handle = GetMarkerFile(kFileExtensions[i]); |
| 139 CHECK_NE(handle, INVALID_HANDLE_VALUE); |
| 140 to_check.push_back(handle); |
| 141 } |
| 142 return SBOX_TEST_SUCCEEDED; |
| 143 |
| 144 case AFTER_REVERT: |
| 145 for (auto handle : to_check) { |
| 146 // Set up buffers for the type info and the name. |
| 147 std::vector<BYTE> type_info_buffer(sizeof(OBJECT_TYPE_INFORMATION) + |
| 148 32 * sizeof(wchar_t)); |
| 149 OBJECT_TYPE_INFORMATION* type_info = |
| 150 reinterpret_cast<OBJECT_TYPE_INFORMATION*>(&(type_info_buffer[0])); |
| 151 NTSTATUS rc; |
| 152 |
| 153 // Get the type name, reusing the buffer. |
| 154 ULONG size = static_cast<ULONG>(type_info_buffer.size()); |
| 155 rc = QueryObjectTypeInformation(handle, type_info, &size); |
| 156 while (rc == STATUS_INFO_LENGTH_MISMATCH || |
| 157 rc == STATUS_BUFFER_OVERFLOW) { |
| 158 type_info_buffer.resize(size + sizeof(wchar_t)); |
| 159 type_info = reinterpret_cast<OBJECT_TYPE_INFORMATION*>( |
| 160 &(type_info_buffer[0])); |
| 161 rc = QueryObjectTypeInformation(handle, type_info, &size); |
| 162 // Leave padding for the nul terminator. |
| 163 if (NT_SUCCESS(rc) && size == type_info_buffer.size()) |
| 164 rc = STATUS_INFO_LENGTH_MISMATCH; |
| 165 } |
| 166 |
| 167 CHECK(NT_SUCCESS(rc)); |
| 168 CHECK(type_info->Name.Buffer); |
| 169 |
| 170 type_info->Name.Buffer[type_info->Name.Length / sizeof(wchar_t)] = |
| 171 L'\0'; |
| 172 |
| 173 // Should be an Event now. |
| 174 CHECK_EQ(wcslen(type_info->Name.Buffer), 5U); |
| 175 CHECK_EQ(wcscmp(L"Event", type_info->Name.Buffer), 0); |
| 176 |
| 177 // Should not be able to wait. |
| 178 CHECK_EQ(WaitForSingleObject(handle, INFINITE), WAIT_FAILED); |
| 179 |
| 180 // Should be able to close. |
| 181 CHECK_EQ(TRUE, CloseHandle(handle)); |
| 182 } |
| 183 return SBOX_TEST_SUCCEEDED; |
| 184 |
| 185 default: // Do nothing. |
| 186 break; |
| 187 } |
| 188 |
| 189 return SBOX_TEST_SUCCEEDED; |
| 190 } |
| 191 |
107 TEST(HandleCloserTest, CheckForMarkerFiles) { | 192 TEST(HandleCloserTest, CheckForMarkerFiles) { |
108 TestRunner runner; | 193 TestRunner runner; |
109 runner.SetTimeout(2000); | 194 runner.SetTimeout(2000); |
110 runner.SetTestState(EVERY_STATE); | 195 runner.SetTestState(EVERY_STATE); |
111 | 196 |
112 base::string16 command = base::string16(L"CheckForFileHandles Y"); | 197 base::string16 command = base::string16(L"CheckForFileHandles Y"); |
113 for (int i = 0; i < arraysize(kFileExtensions); ++i) { | 198 for (int i = 0; i < arraysize(kFileExtensions); ++i) { |
114 base::string16 handle_name; | 199 base::string16 handle_name; |
115 base::win::ScopedHandle marker(GetMarkerFile(kFileExtensions[i])); | 200 base::win::ScopedHandle marker(GetMarkerFile(kFileExtensions[i])); |
116 CHECK(marker.IsValid()); | 201 CHECK(marker.IsValid()); |
(...skipping 21 matching lines...) Expand all Loading... |
138 CHECK_EQ(policy->AddKernelObjectToClose(L"File", handle_name.c_str()), | 223 CHECK_EQ(policy->AddKernelObjectToClose(L"File", handle_name.c_str()), |
139 SBOX_ALL_OK); | 224 SBOX_ALL_OK); |
140 command += (L" "); | 225 command += (L" "); |
141 command += handle_name; | 226 command += handle_name; |
142 } | 227 } |
143 | 228 |
144 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command.c_str())) << | 229 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command.c_str())) << |
145 "Failed: " << command; | 230 "Failed: " << command; |
146 } | 231 } |
147 | 232 |
| 233 TEST(HandleCloserTest, CheckStuffedHandle) { |
| 234 TestRunner runner; |
| 235 runner.SetTimeout(2000); |
| 236 runner.SetTestState(EVERY_STATE); |
| 237 sandbox::TargetPolicy* policy = runner.GetPolicy(); |
| 238 |
| 239 for (int i = 0; i < arraysize(kFileExtensions); ++i) { |
| 240 base::string16 handle_name; |
| 241 base::win::ScopedHandle marker(GetMarkerFile(kFileExtensions[i])); |
| 242 CHECK(marker.IsValid()); |
| 243 CHECK(sandbox::GetHandleName(marker.Get(), &handle_name)); |
| 244 CHECK_EQ(policy->AddKernelObjectToClose(L"File", handle_name.c_str()), |
| 245 SBOX_ALL_OK); |
| 246 } |
| 247 |
| 248 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckForEventHandles")); |
| 249 } |
| 250 |
148 void WINAPI ThreadPoolTask(void* event, BOOLEAN timeout) { | 251 void WINAPI ThreadPoolTask(void* event, BOOLEAN timeout) { |
149 static volatile LONG waiters_remaining = kWaitCount; | 252 static volatile LONG waiters_remaining = kWaitCount; |
150 CHECK(!timeout); | 253 CHECK(!timeout); |
151 CHECK(::CloseHandle(event)); | 254 CHECK(::CloseHandle(event)); |
152 if (::InterlockedDecrement(&waiters_remaining) == 0) | 255 if (::InterlockedDecrement(&waiters_remaining) == 0) |
153 CHECK(::SetEvent(finish_event)); | 256 CHECK(::SetEvent(finish_event)); |
154 } | 257 } |
155 | 258 |
156 // Run a thread pool inside a sandbox without a CSRSS connection. | 259 // Run a thread pool inside a sandbox without a CSRSS connection. |
157 SBOX_TESTS_COMMAND int RunThreadPool(int argc, wchar_t **argv) { | 260 SBOX_TESTS_COMMAND int RunThreadPool(int argc, wchar_t **argv) { |
(...skipping 27 matching lines...) Expand all Loading... |
185 runner.SetTestState(AFTER_REVERT); | 288 runner.SetTestState(AFTER_REVERT); |
186 sandbox::TargetPolicy* policy = runner.GetPolicy(); | 289 sandbox::TargetPolicy* policy = runner.GetPolicy(); |
187 | 290 |
188 // Sever the CSRSS connection by closing ALPC ports inside the sandbox. | 291 // Sever the CSRSS connection by closing ALPC ports inside the sandbox. |
189 CHECK_EQ(policy->AddKernelObjectToClose(L"ALPC Port", NULL), SBOX_ALL_OK); | 292 CHECK_EQ(policy->AddKernelObjectToClose(L"ALPC Port", NULL), SBOX_ALL_OK); |
190 | 293 |
191 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"RunThreadPool")); | 294 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"RunThreadPool")); |
192 } | 295 } |
193 | 296 |
194 } // namespace sandbox | 297 } // namespace sandbox |
OLD | NEW |