Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(154)

Side by Side Diff: sandbox/win/src/handle_closer_test.cc

Issue 1851213002: Remove sandbox on Windows. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix nacl compile issues Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « sandbox/win/src/handle_closer_agent.cc ('k') | sandbox/win/src/handle_dispatcher.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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.
4
5 #include <limits.h>
6 #include <stddef.h>
7
8 #include "base/strings/stringprintf.h"
9 #include "base/win/scoped_handle.h"
10 #include "sandbox/win/src/handle_closer_agent.h"
11 #include "sandbox/win/src/nt_internals.h"
12 #include "sandbox/win/src/sandbox.h"
13 #include "sandbox/win/src/sandbox_factory.h"
14 #include "sandbox/win/src/target_services.h"
15 #include "sandbox/win/tests/common/controller.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17
18 namespace {
19
20 const wchar_t *kFileExtensions[] = { L".1", L".2", L".3", L".4" };
21
22 // Returns a handle to a unique marker file that can be retrieved between runs.
23 HANDLE GetMarkerFile(const wchar_t *extension) {
24 wchar_t path_buffer[MAX_PATH + 1];
25 CHECK(::GetTempPath(MAX_PATH, path_buffer));
26 base::string16 marker_path = path_buffer;
27 marker_path += L"\\sbox_marker_";
28
29 // Generate a unique value from the exe's size and timestamp.
30 CHECK(::GetModuleFileName(NULL, path_buffer, MAX_PATH));
31 base::win::ScopedHandle module(::CreateFile(path_buffer,
32 FILE_READ_ATTRIBUTES, FILE_SHARE_READ, NULL,
33 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
34 CHECK(module.IsValid());
35 FILETIME timestamp;
36 CHECK(::GetFileTime(module.Get(), &timestamp, NULL, NULL));
37 marker_path += base::StringPrintf(L"%08x%08x%08x",
38 ::GetFileSize(module.Get(), NULL),
39 timestamp.dwLowDateTime,
40 timestamp.dwHighDateTime);
41 marker_path += extension;
42
43 // Make the file delete-on-close so cleanup is automatic.
44 return CreateFile(marker_path.c_str(), FILE_ALL_ACCESS,
45 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
46 NULL, OPEN_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL);
47 }
48
49 // Returns type infomation for an NT object. This routine is expected to be
50 // called for invalid handles so it catches STATUS_INVALID_HANDLE exceptions
51 // that can be generated when handle tracing is enabled.
52 NTSTATUS QueryObjectTypeInformation(HANDLE handle, void* buffer, ULONG* size) {
53 static NtQueryObject QueryObject = NULL;
54 if (!QueryObject)
55 ResolveNTFunctionPtr("NtQueryObject", &QueryObject);
56
57 NTSTATUS status = STATUS_UNSUCCESSFUL;
58 __try {
59 status = QueryObject(handle, ObjectTypeInformation, buffer, *size, size);
60 }
61 __except(GetExceptionCode() == STATUS_INVALID_HANDLE
62 ? EXCEPTION_EXECUTE_HANDLER
63 : EXCEPTION_CONTINUE_SEARCH) {
64 status = STATUS_INVALID_HANDLE;
65 }
66 return status;
67 }
68
69 // Used by the thread pool tests.
70 HANDLE finish_event;
71 const int kWaitCount = 20;
72
73 } // namespace
74
75 namespace sandbox {
76
77 // Checks for the presence of a list of files (in object path form).
78 // Format: CheckForFileHandle (Y|N) \path\to\file1 [\path\to\file2 ...]
79 // - Y or N depending if the file should exist or not.
80 SBOX_TESTS_COMMAND int CheckForFileHandles(int argc, wchar_t **argv) {
81 if (argc < 2)
82 return SBOX_TEST_FAILED_TO_RUN_TEST;
83 bool should_find = argv[0][0] == L'Y';
84 if (argv[0][1] != L'\0' || (!should_find && argv[0][0] != L'N'))
85 return SBOX_TEST_FAILED_TO_RUN_TEST;
86
87 static int state = BEFORE_INIT;
88 switch (state++) {
89 case BEFORE_INIT:
90 // Create a unique marker file that is open while the test is running.
91 // The handles leak, but it will be closed by the test or on exit.
92 for (const wchar_t* kExtension : kFileExtensions)
93 CHECK_NE(GetMarkerFile(kExtension), INVALID_HANDLE_VALUE);
94 return SBOX_TEST_SUCCEEDED;
95
96 case AFTER_REVERT: {
97 // Brute force the handle table to find what we're looking for.
98 DWORD handle_count = UINT_MAX;
99 const int kInvalidHandleThreshold = 100;
100 const size_t kHandleOffset = 4; // Handles are always a multiple of 4.
101 HANDLE handle = NULL;
102 int invalid_count = 0;
103 base::string16 handle_name;
104
105 if (!::GetProcessHandleCount(::GetCurrentProcess(), &handle_count))
106 return SBOX_TEST_FAILED_TO_RUN_TEST;
107
108 while (handle_count && invalid_count < kInvalidHandleThreshold) {
109 reinterpret_cast<size_t&>(handle) += kHandleOffset;
110 if (GetHandleName(handle, &handle_name)) {
111 for (int i = 1; i < argc; ++i) {
112 if (handle_name == argv[i])
113 return should_find ? SBOX_TEST_SUCCEEDED : SBOX_TEST_FAILED;
114 }
115 --handle_count;
116 } else {
117 ++invalid_count;
118 }
119 }
120
121 return should_find ? SBOX_TEST_FAILED : SBOX_TEST_SUCCEEDED;
122 }
123
124 default: // Do nothing.
125 break;
126 }
127
128 return SBOX_TEST_SUCCEEDED;
129 }
130
131 // Checks that supplied handle is an Event and it's not waitable.
132 // Format: CheckForEventHandles
133 SBOX_TESTS_COMMAND int CheckForEventHandles(int argc, wchar_t** argv) {
134 static int state = BEFORE_INIT;
135 static std::vector<HANDLE> to_check;
136
137 switch (state++) {
138 case BEFORE_INIT:
139 // Create a unique marker file that is open while the test is running.
140 for (const wchar_t* kExtension : kFileExtensions) {
141 HANDLE handle = GetMarkerFile(kExtension);
142 CHECK_NE(handle, INVALID_HANDLE_VALUE);
143 to_check.push_back(handle);
144 }
145 return SBOX_TEST_SUCCEEDED;
146
147 case AFTER_REVERT:
148 for (auto handle : to_check) {
149 // Set up buffers for the type info and the name.
150 std::vector<BYTE> type_info_buffer(sizeof(OBJECT_TYPE_INFORMATION) +
151 32 * sizeof(wchar_t));
152 OBJECT_TYPE_INFORMATION* type_info =
153 reinterpret_cast<OBJECT_TYPE_INFORMATION*>(&(type_info_buffer[0]));
154 NTSTATUS rc;
155
156 // Get the type name, reusing the buffer.
157 ULONG size = static_cast<ULONG>(type_info_buffer.size());
158 rc = QueryObjectTypeInformation(handle, type_info, &size);
159 while (rc == STATUS_INFO_LENGTH_MISMATCH ||
160 rc == STATUS_BUFFER_OVERFLOW) {
161 type_info_buffer.resize(size + sizeof(wchar_t));
162 type_info = reinterpret_cast<OBJECT_TYPE_INFORMATION*>(
163 &(type_info_buffer[0]));
164 rc = QueryObjectTypeInformation(handle, type_info, &size);
165 // Leave padding for the nul terminator.
166 if (NT_SUCCESS(rc) && size == type_info_buffer.size())
167 rc = STATUS_INFO_LENGTH_MISMATCH;
168 }
169
170 CHECK(NT_SUCCESS(rc));
171 CHECK(type_info->Name.Buffer);
172
173 type_info->Name.Buffer[type_info->Name.Length / sizeof(wchar_t)] =
174 L'\0';
175
176 // Should be an Event now.
177 CHECK_EQ(wcslen(type_info->Name.Buffer), 5U);
178 CHECK_EQ(wcscmp(L"Event", type_info->Name.Buffer), 0);
179
180 // Should not be able to wait.
181 CHECK_EQ(WaitForSingleObject(handle, INFINITE), WAIT_FAILED);
182
183 // Should be able to close.
184 CHECK_EQ(TRUE, CloseHandle(handle));
185 }
186 return SBOX_TEST_SUCCEEDED;
187
188 default: // Do nothing.
189 break;
190 }
191
192 return SBOX_TEST_SUCCEEDED;
193 }
194
195 TEST(HandleCloserTest, CheckForMarkerFiles) {
196 TestRunner runner;
197 runner.SetTimeout(2000);
198 runner.SetTestState(EVERY_STATE);
199
200 base::string16 command = base::string16(L"CheckForFileHandles Y");
201 for (const wchar_t* kExtension : kFileExtensions) {
202 base::string16 handle_name;
203 base::win::ScopedHandle marker(GetMarkerFile(kExtension));
204 CHECK(marker.IsValid());
205 CHECK(sandbox::GetHandleName(marker.Get(), &handle_name));
206 command += (L" ");
207 command += handle_name;
208 }
209
210 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command.c_str())) <<
211 "Failed: " << command;
212 }
213
214 TEST(HandleCloserTest, CloseMarkerFiles) {
215 TestRunner runner;
216 runner.SetTimeout(2000);
217 runner.SetTestState(EVERY_STATE);
218 sandbox::TargetPolicy* policy = runner.GetPolicy();
219
220 base::string16 command = base::string16(L"CheckForFileHandles N");
221 for (const wchar_t* kExtension : kFileExtensions) {
222 base::string16 handle_name;
223 base::win::ScopedHandle marker(GetMarkerFile(kExtension));
224 CHECK(marker.IsValid());
225 CHECK(sandbox::GetHandleName(marker.Get(), &handle_name));
226 CHECK_EQ(policy->AddKernelObjectToClose(L"File", handle_name.c_str()),
227 SBOX_ALL_OK);
228 command += (L" ");
229 command += handle_name;
230 }
231
232 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command.c_str())) <<
233 "Failed: " << command;
234 }
235
236 TEST(HandleCloserTest, CheckStuffedHandle) {
237 TestRunner runner;
238 runner.SetTimeout(2000);
239 runner.SetTestState(EVERY_STATE);
240 sandbox::TargetPolicy* policy = runner.GetPolicy();
241
242 for (const wchar_t* kExtension : kFileExtensions) {
243 base::string16 handle_name;
244 base::win::ScopedHandle marker(GetMarkerFile(kExtension));
245 CHECK(marker.IsValid());
246 CHECK(sandbox::GetHandleName(marker.Get(), &handle_name));
247 CHECK_EQ(policy->AddKernelObjectToClose(L"File", handle_name.c_str()),
248 SBOX_ALL_OK);
249 }
250
251 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckForEventHandles"));
252 }
253
254 void WINAPI ThreadPoolTask(void* event, BOOLEAN timeout) {
255 static volatile LONG waiters_remaining = kWaitCount;
256 CHECK(!timeout);
257 CHECK(::CloseHandle(event));
258 if (::InterlockedDecrement(&waiters_remaining) == 0)
259 CHECK(::SetEvent(finish_event));
260 }
261
262 // Run a thread pool inside a sandbox without a CSRSS connection.
263 SBOX_TESTS_COMMAND int RunThreadPool(int argc, wchar_t **argv) {
264 HANDLE wait_list[20];
265 finish_event = ::CreateEvent(NULL, TRUE, FALSE, NULL);
266 CHECK(finish_event);
267
268 // Set up a bunch of waiters.
269 HANDLE pool = NULL;
270 for (int i = 0; i < kWaitCount; ++i) {
271 HANDLE event = ::CreateEvent(NULL, TRUE, FALSE, NULL);
272 CHECK(event);
273 CHECK(::RegisterWaitForSingleObject(&pool, event, ThreadPoolTask, event,
274 INFINITE, WT_EXECUTEONLYONCE));
275 wait_list[i] = event;
276 }
277
278 // Signal all the waiters.
279 for (int i = 0; i < kWaitCount; ++i)
280 CHECK(::SetEvent(wait_list[i]));
281
282 CHECK_EQ(::WaitForSingleObject(finish_event, INFINITE), WAIT_OBJECT_0);
283 CHECK(::CloseHandle(finish_event));
284
285 return SBOX_TEST_SUCCEEDED;
286 }
287
288 TEST(HandleCloserTest, RunThreadPool) {
289 TestRunner runner;
290 runner.SetTimeout(2000);
291 runner.SetTestState(AFTER_REVERT);
292 sandbox::TargetPolicy* policy = runner.GetPolicy();
293
294 // Sever the CSRSS connection by closing ALPC ports inside the sandbox.
295 CHECK_EQ(policy->AddKernelObjectToClose(L"ALPC Port", NULL), SBOX_ALL_OK);
296
297 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"RunThreadPool"));
298 }
299
300 } // namespace sandbox
OLDNEW
« no previous file with comments | « sandbox/win/src/handle_closer_agent.cc ('k') | sandbox/win/src/handle_dispatcher.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698