Revert "Fix broken channel icon in chrome://help on CrOS" and try again
[chromium-blink-merge.git] / sandbox / win / src / handle_closer_test.cc
blob1cb2bb5276abc22bdabe31e2ead109cf2a2c231d
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
3 // found in the LICENSE file.
5 #include "base/strings/stringprintf.h"
6 #include "base/win/scoped_handle.h"
7 #include "sandbox/win/src/handle_closer_agent.h"
8 #include "sandbox/win/src/nt_internals.h"
9 #include "sandbox/win/src/sandbox.h"
10 #include "sandbox/win/src/sandbox_factory.h"
11 #include "sandbox/win/src/target_services.h"
12 #include "sandbox/win/tests/common/controller.h"
13 #include "testing/gtest/include/gtest/gtest.h"
15 namespace {
17 const wchar_t *kFileExtensions[] = { L".1", L".2", L".3", L".4" };
19 // Returns a handle to a unique marker file that can be retrieved between runs.
20 HANDLE GetMarkerFile(const wchar_t *extension) {
21 wchar_t path_buffer[MAX_PATH + 1];
22 CHECK(::GetTempPath(MAX_PATH, path_buffer));
23 base::string16 marker_path = path_buffer;
24 marker_path += L"\\sbox_marker_";
26 // Generate a unique value from the exe's size and timestamp.
27 CHECK(::GetModuleFileName(NULL, path_buffer, MAX_PATH));
28 base::win::ScopedHandle module(::CreateFile(path_buffer,
29 FILE_READ_ATTRIBUTES, FILE_SHARE_READ, NULL,
30 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
31 CHECK(module.IsValid());
32 FILETIME timestamp;
33 CHECK(::GetFileTime(module.Get(), &timestamp, NULL, NULL));
34 marker_path += base::StringPrintf(L"%08x%08x%08x",
35 ::GetFileSize(module.Get(), NULL),
36 timestamp.dwLowDateTime,
37 timestamp.dwHighDateTime);
38 marker_path += extension;
40 // Make the file delete-on-close so cleanup is automatic.
41 return CreateFile(marker_path.c_str(), FILE_ALL_ACCESS,
42 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
43 NULL, OPEN_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL);
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);
54 NTSTATUS status = STATUS_UNSUCCESSFUL;
55 __try {
56 status = QueryObject(handle, ObjectTypeInformation, buffer, *size, size);
58 __except(GetExceptionCode() == STATUS_INVALID_HANDLE
59 ? EXCEPTION_EXECUTE_HANDLER
60 : EXCEPTION_CONTINUE_SEARCH) {
61 status = STATUS_INVALID_HANDLE;
63 return status;
66 // Used by the thread pool tests.
67 HANDLE finish_event;
68 const int kWaitCount = 20;
70 } // namespace
72 namespace sandbox {
74 // Checks for the presence of a list of files (in object path form).
75 // Format: CheckForFileHandle (Y|N) \path\to\file1 [\path\to\file2 ...]
76 // - Y or N depending if the file should exist or not.
77 SBOX_TESTS_COMMAND int CheckForFileHandles(int argc, wchar_t **argv) {
78 if (argc < 2)
79 return SBOX_TEST_FAILED_TO_RUN_TEST;
80 bool should_find = argv[0][0] == L'Y';
81 if (argv[0][1] != L'\0' || (!should_find && argv[0][0] != L'N'))
82 return SBOX_TEST_FAILED_TO_RUN_TEST;
84 static int state = BEFORE_INIT;
85 switch (state++) {
86 case BEFORE_INIT:
87 // Create a unique marker file that is open while the test is running.
88 // The handles leak, but it will be closed by the test or on exit.
89 for (int i = 0; i < arraysize(kFileExtensions); ++i)
90 CHECK_NE(GetMarkerFile(kFileExtensions[i]), INVALID_HANDLE_VALUE);
91 return SBOX_TEST_SUCCEEDED;
93 case AFTER_REVERT: {
94 // Brute force the handle table to find what we're looking for.
95 DWORD handle_count = UINT_MAX;
96 const int kInvalidHandleThreshold = 100;
97 const size_t kHandleOffset = 4; // Handles are always a multiple of 4.
98 HANDLE handle = NULL;
99 int invalid_count = 0;
100 base::string16 handle_name;
102 if (!::GetProcessHandleCount(::GetCurrentProcess(), &handle_count))
103 return SBOX_TEST_FAILED_TO_RUN_TEST;
105 while (handle_count && invalid_count < kInvalidHandleThreshold) {
106 reinterpret_cast<size_t&>(handle) += kHandleOffset;
107 if (GetHandleName(handle, &handle_name)) {
108 for (int i = 1; i < argc; ++i) {
109 if (handle_name == argv[i])
110 return should_find ? SBOX_TEST_SUCCEEDED : SBOX_TEST_FAILED;
112 --handle_count;
113 } else {
114 ++invalid_count;
118 return should_find ? SBOX_TEST_FAILED : SBOX_TEST_SUCCEEDED;
121 default: // Do nothing.
122 break;
125 return SBOX_TEST_SUCCEEDED;
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;
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);
142 return SBOX_TEST_SUCCEEDED;
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;
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;
167 CHECK(NT_SUCCESS(rc));
168 CHECK(type_info->Name.Buffer);
170 type_info->Name.Buffer[type_info->Name.Length / sizeof(wchar_t)] =
171 L'\0';
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);
177 // Should not be able to wait.
178 CHECK_EQ(WaitForSingleObject(handle, INFINITE), WAIT_FAILED);
180 // Should be able to close.
181 CHECK_EQ(TRUE, CloseHandle(handle));
183 return SBOX_TEST_SUCCEEDED;
185 default: // Do nothing.
186 break;
189 return SBOX_TEST_SUCCEEDED;
192 TEST(HandleCloserTest, CheckForMarkerFiles) {
193 TestRunner runner;
194 runner.SetTimeout(2000);
195 runner.SetTestState(EVERY_STATE);
197 base::string16 command = base::string16(L"CheckForFileHandles Y");
198 for (int i = 0; i < arraysize(kFileExtensions); ++i) {
199 base::string16 handle_name;
200 base::win::ScopedHandle marker(GetMarkerFile(kFileExtensions[i]));
201 CHECK(marker.IsValid());
202 CHECK(sandbox::GetHandleName(marker.Get(), &handle_name));
203 command += (L" ");
204 command += handle_name;
207 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command.c_str())) <<
208 "Failed: " << command;
211 TEST(HandleCloserTest, CloseMarkerFiles) {
212 TestRunner runner;
213 runner.SetTimeout(2000);
214 runner.SetTestState(EVERY_STATE);
215 sandbox::TargetPolicy* policy = runner.GetPolicy();
217 base::string16 command = base::string16(L"CheckForFileHandles N");
218 for (int i = 0; i < arraysize(kFileExtensions); ++i) {
219 base::string16 handle_name;
220 base::win::ScopedHandle marker(GetMarkerFile(kFileExtensions[i]));
221 CHECK(marker.IsValid());
222 CHECK(sandbox::GetHandleName(marker.Get(), &handle_name));
223 CHECK_EQ(policy->AddKernelObjectToClose(L"File", handle_name.c_str()),
224 SBOX_ALL_OK);
225 command += (L" ");
226 command += handle_name;
229 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command.c_str())) <<
230 "Failed: " << command;
233 TEST(HandleCloserTest, CheckStuffedHandle) {
234 TestRunner runner;
235 runner.SetTimeout(2000);
236 runner.SetTestState(EVERY_STATE);
237 sandbox::TargetPolicy* policy = runner.GetPolicy();
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);
248 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckForEventHandles"));
251 void WINAPI ThreadPoolTask(void* event, BOOLEAN timeout) {
252 static volatile LONG waiters_remaining = kWaitCount;
253 CHECK(!timeout);
254 CHECK(::CloseHandle(event));
255 if (::InterlockedDecrement(&waiters_remaining) == 0)
256 CHECK(::SetEvent(finish_event));
259 // Run a thread pool inside a sandbox without a CSRSS connection.
260 SBOX_TESTS_COMMAND int RunThreadPool(int argc, wchar_t **argv) {
261 HANDLE wait_list[20];
262 finish_event = ::CreateEvent(NULL, TRUE, FALSE, NULL);
263 CHECK(finish_event);
265 // Set up a bunch of waiters.
266 HANDLE pool = NULL;
267 for (int i = 0; i < kWaitCount; ++i) {
268 HANDLE event = ::CreateEvent(NULL, TRUE, FALSE, NULL);
269 CHECK(event);
270 CHECK(::RegisterWaitForSingleObject(&pool, event, ThreadPoolTask, event,
271 INFINITE, WT_EXECUTEONLYONCE));
272 wait_list[i] = event;
275 // Signal all the waiters.
276 for (int i = 0; i < kWaitCount; ++i)
277 CHECK(::SetEvent(wait_list[i]));
279 CHECK_EQ(::WaitForSingleObject(finish_event, INFINITE), WAIT_OBJECT_0);
280 CHECK(::CloseHandle(finish_event));
282 return SBOX_TEST_SUCCEEDED;
285 TEST(HandleCloserTest, RunThreadPool) {
286 TestRunner runner;
287 runner.SetTimeout(2000);
288 runner.SetTestState(AFTER_REVERT);
289 sandbox::TargetPolicy* policy = runner.GetPolicy();
291 // Sever the CSRSS connection by closing ALPC ports inside the sandbox.
292 CHECK_EQ(policy->AddKernelObjectToClose(L"ALPC Port", NULL), SBOX_ALL_OK);
294 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"RunThreadPool"));
297 } // namespace sandbox