Don't preload rarely seen large images
[chromium-blink-merge.git] / sandbox / win / src / policy_target_test.cc
blob4395a4f0d22a6803ec4c2b1d004b7fdbd2c778b2
1 // Copyright (c) 2012 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/memory/shared_memory.h"
6 #include "base/strings/string_number_conversions.h"
7 #include "base/strings/string_piece.h"
8 #include "base/win/scoped_process_information.h"
9 #include "base/win/windows_version.h"
10 #include "sandbox/win/src/sandbox.h"
11 #include "sandbox/win/src/sandbox_factory.h"
12 #include "sandbox/win/src/sandbox_utils.h"
13 #include "sandbox/win/src/target_services.h"
14 #include "sandbox/win/tests/common/controller.h"
15 #include "testing/gtest/include/gtest/gtest.h"
17 namespace sandbox {
19 #define BINDNTDLL(name) \
20 name ## Function name = reinterpret_cast<name ## Function>( \
21 ::GetProcAddress(::GetModuleHandle(L"ntdll.dll"), #name))
23 // Reverts to self and verify that SetInformationToken was faked. Returns
24 // SBOX_TEST_SUCCEEDED if faked and SBOX_TEST_FAILED if not faked.
25 SBOX_TESTS_COMMAND int PolicyTargetTest_token(int argc, wchar_t **argv) {
26 HANDLE thread_token;
27 // Get the thread token, using impersonation.
28 if (!::OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE |
29 TOKEN_DUPLICATE, FALSE, &thread_token))
30 return ::GetLastError();
32 ::RevertToSelf();
33 ::CloseHandle(thread_token);
35 int ret = SBOX_TEST_FAILED;
36 if (::OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE | TOKEN_DUPLICATE,
37 FALSE, &thread_token)) {
38 ret = SBOX_TEST_SUCCEEDED;
39 ::CloseHandle(thread_token);
41 return ret;
44 // Stores the high privilege token on a static variable, change impersonation
45 // again to that one and verify that we are not interfering anymore with
46 // RevertToSelf.
47 SBOX_TESTS_COMMAND int PolicyTargetTest_steal(int argc, wchar_t **argv) {
48 static HANDLE thread_token;
49 if (!SandboxFactory::GetTargetServices()->GetState()->RevertedToSelf()) {
50 if (!::OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE |
51 TOKEN_DUPLICATE, FALSE, &thread_token))
52 return ::GetLastError();
53 } else {
54 if (!::SetThreadToken(NULL, thread_token))
55 return ::GetLastError();
57 // See if we fake the call again.
58 int ret = PolicyTargetTest_token(argc, argv);
59 ::CloseHandle(thread_token);
60 return ret;
62 return 0;
65 // Opens the thread token with and without impersonation.
66 SBOX_TESTS_COMMAND int PolicyTargetTest_token2(int argc, wchar_t **argv) {
67 HANDLE thread_token;
68 // Get the thread token, using impersonation.
69 if (!::OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE |
70 TOKEN_DUPLICATE, FALSE, &thread_token))
71 return ::GetLastError();
72 ::CloseHandle(thread_token);
74 // Get the thread token, without impersonation.
75 if (!OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE | TOKEN_DUPLICATE,
76 TRUE, &thread_token))
77 return ::GetLastError();
78 ::CloseHandle(thread_token);
79 return SBOX_TEST_SUCCEEDED;
82 // Opens the thread token with and without impersonation, using
83 // NtOpenThreadTokenEX.
84 SBOX_TESTS_COMMAND int PolicyTargetTest_token3(int argc, wchar_t **argv) {
85 BINDNTDLL(NtOpenThreadTokenEx);
86 if (!NtOpenThreadTokenEx)
87 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
89 HANDLE thread_token;
90 // Get the thread token, using impersonation.
91 NTSTATUS status = NtOpenThreadTokenEx(GetCurrentThread(),
92 TOKEN_IMPERSONATE | TOKEN_DUPLICATE,
93 FALSE, 0, &thread_token);
94 if (status == STATUS_NO_TOKEN)
95 return ERROR_NO_TOKEN;
96 if (!NT_SUCCESS(status))
97 return SBOX_TEST_FAILED;
99 ::CloseHandle(thread_token);
101 // Get the thread token, without impersonation.
102 status = NtOpenThreadTokenEx(GetCurrentThread(),
103 TOKEN_IMPERSONATE | TOKEN_DUPLICATE, TRUE, 0,
104 &thread_token);
105 if (!NT_SUCCESS(status))
106 return SBOX_TEST_FAILED;
108 ::CloseHandle(thread_token);
109 return SBOX_TEST_SUCCEEDED;
112 // Tests that we can open the current thread.
113 SBOX_TESTS_COMMAND int PolicyTargetTest_thread(int argc, wchar_t **argv) {
114 DWORD thread_id = ::GetCurrentThreadId();
115 HANDLE thread = ::OpenThread(SYNCHRONIZE, FALSE, thread_id);
116 if (!thread)
117 return ::GetLastError();
118 if (!::CloseHandle(thread))
119 return ::GetLastError();
121 return SBOX_TEST_SUCCEEDED;
124 // New thread entry point: do nothing.
125 DWORD WINAPI PolicyTargetTest_thread_main(void* param) {
126 ::Sleep(INFINITE);
127 return 0;
130 // Tests that we can create a new thread, and open it.
131 SBOX_TESTS_COMMAND int PolicyTargetTest_thread2(int argc, wchar_t **argv) {
132 // Use default values to create a new thread.
133 DWORD thread_id;
134 HANDLE thread = ::CreateThread(NULL, 0, &PolicyTargetTest_thread_main, 0, 0,
135 &thread_id);
136 if (!thread)
137 return ::GetLastError();
138 if (!::CloseHandle(thread))
139 return ::GetLastError();
141 thread = ::OpenThread(SYNCHRONIZE, FALSE, thread_id);
142 if (!thread)
143 return ::GetLastError();
145 if (!::CloseHandle(thread))
146 return ::GetLastError();
148 return SBOX_TEST_SUCCEEDED;
151 // Tests that we can call CreateProcess.
152 SBOX_TESTS_COMMAND int PolicyTargetTest_process(int argc, wchar_t **argv) {
153 // Use default values to create a new process.
154 STARTUPINFO startup_info = {0};
155 startup_info.cb = sizeof(startup_info);
156 PROCESS_INFORMATION temp_process_info = {};
157 // Note: CreateProcessW() can write to its lpCommandLine, don't pass a
158 // raw string literal.
159 base::string16 writable_cmdline_str(L"foo.exe");
160 if (!::CreateProcessW(L"foo.exe", &writable_cmdline_str[0], NULL, NULL, FALSE,
161 0, NULL, NULL, &startup_info, &temp_process_info))
162 return SBOX_TEST_SUCCEEDED;
163 base::win::ScopedProcessInformation process_info(temp_process_info);
164 return SBOX_TEST_FAILED;
167 TEST(PolicyTargetTest, SetInformationThread) {
168 TestRunner runner;
169 if (base::win::GetVersion() >= base::win::VERSION_XP) {
170 runner.SetTestState(BEFORE_REVERT);
171 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"PolicyTargetTest_token"));
174 runner.SetTestState(AFTER_REVERT);
175 EXPECT_EQ(ERROR_NO_TOKEN, runner.RunTest(L"PolicyTargetTest_token"));
177 runner.SetTestState(EVERY_STATE);
178 if (base::win::GetVersion() >= base::win::VERSION_XP)
179 EXPECT_EQ(SBOX_TEST_FAILED, runner.RunTest(L"PolicyTargetTest_steal"));
182 TEST(PolicyTargetTest, OpenThreadToken) {
183 TestRunner runner;
184 if (base::win::GetVersion() >= base::win::VERSION_XP) {
185 runner.SetTestState(BEFORE_REVERT);
186 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"PolicyTargetTest_token2"));
189 runner.SetTestState(AFTER_REVERT);
190 EXPECT_EQ(ERROR_NO_TOKEN, runner.RunTest(L"PolicyTargetTest_token2"));
193 TEST(PolicyTargetTest, OpenThreadTokenEx) {
194 TestRunner runner;
195 if (base::win::GetVersion() < base::win::VERSION_XP)
196 return;
198 runner.SetTestState(BEFORE_REVERT);
199 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"PolicyTargetTest_token3"));
201 runner.SetTestState(AFTER_REVERT);
202 EXPECT_EQ(ERROR_NO_TOKEN, runner.RunTest(L"PolicyTargetTest_token3"));
205 TEST(PolicyTargetTest, OpenThread) {
206 TestRunner runner;
207 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"PolicyTargetTest_thread")) <<
208 "Opens the current thread";
210 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"PolicyTargetTest_thread2")) <<
211 "Creates a new thread and opens it";
214 TEST(PolicyTargetTest, OpenProcess) {
215 TestRunner runner;
216 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"PolicyTargetTest_process")) <<
217 "Opens a process";
220 // Launches the app in the sandbox and ask it to wait in an
221 // infinite loop. Waits for 2 seconds and then check if the
222 // desktop associated with the app thread is not the same as the
223 // current desktop.
224 TEST(PolicyTargetTest, DesktopPolicy) {
225 BrokerServices* broker = GetBroker();
227 // Precreate the desktop.
228 TargetPolicy* temp_policy = broker->CreatePolicy();
229 temp_policy->CreateAlternateDesktop(false);
230 temp_policy->Release();
232 ASSERT_TRUE(broker != NULL);
234 // Get the path to the sandboxed app.
235 wchar_t prog_name[MAX_PATH];
236 GetModuleFileNameW(NULL, prog_name, MAX_PATH);
238 base::string16 arguments(L"\"");
239 arguments += prog_name;
240 arguments += L"\" -child 0 wait"; // Don't care about the "state" argument.
242 // Launch the app.
243 ResultCode result = SBOX_ALL_OK;
244 base::win::ScopedProcessInformation target;
246 TargetPolicy* policy = broker->CreatePolicy();
247 policy->SetAlternateDesktop(false);
248 policy->SetTokenLevel(USER_INTERACTIVE, USER_LOCKDOWN);
249 PROCESS_INFORMATION temp_process_info = {};
250 result = broker->SpawnTarget(prog_name, arguments.c_str(), policy,
251 &temp_process_info);
252 base::string16 desktop_name = policy->GetAlternateDesktop();
253 policy->Release();
255 EXPECT_EQ(SBOX_ALL_OK, result);
256 if (result == SBOX_ALL_OK)
257 target.Set(temp_process_info);
259 EXPECT_EQ(1, ::ResumeThread(target.thread_handle()));
261 EXPECT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(target.process_handle(), 2000));
263 EXPECT_NE(::GetThreadDesktop(target.thread_id()),
264 ::GetThreadDesktop(::GetCurrentThreadId()));
266 HDESK desk = ::OpenDesktop(desktop_name.c_str(), 0, FALSE, DESKTOP_ENUMERATE);
267 EXPECT_TRUE(NULL != desk);
268 EXPECT_TRUE(::CloseDesktop(desk));
269 EXPECT_TRUE(::TerminateProcess(target.process_handle(), 0));
271 ::WaitForSingleObject(target.process_handle(), INFINITE);
273 // Close the desktop handle.
274 temp_policy = broker->CreatePolicy();
275 temp_policy->DestroyAlternateDesktop();
276 temp_policy->Release();
278 // Make sure the desktop does not exist anymore.
279 desk = ::OpenDesktop(desktop_name.c_str(), 0, FALSE, DESKTOP_ENUMERATE);
280 EXPECT_TRUE(NULL == desk);
283 // Launches the app in the sandbox and ask it to wait in an
284 // infinite loop. Waits for 2 seconds and then check if the
285 // winstation associated with the app thread is not the same as the
286 // current desktop.
287 TEST(PolicyTargetTest, WinstaPolicy) {
288 BrokerServices* broker = GetBroker();
290 // Precreate the desktop.
291 TargetPolicy* temp_policy = broker->CreatePolicy();
292 temp_policy->CreateAlternateDesktop(true);
293 temp_policy->Release();
295 ASSERT_TRUE(broker != NULL);
297 // Get the path to the sandboxed app.
298 wchar_t prog_name[MAX_PATH];
299 GetModuleFileNameW(NULL, prog_name, MAX_PATH);
301 base::string16 arguments(L"\"");
302 arguments += prog_name;
303 arguments += L"\" -child 0 wait"; // Don't care about the "state" argument.
305 // Launch the app.
306 ResultCode result = SBOX_ALL_OK;
307 base::win::ScopedProcessInformation target;
309 TargetPolicy* policy = broker->CreatePolicy();
310 policy->SetAlternateDesktop(true);
311 policy->SetTokenLevel(USER_INTERACTIVE, USER_LOCKDOWN);
312 PROCESS_INFORMATION temp_process_info = {};
313 result = broker->SpawnTarget(prog_name, arguments.c_str(), policy,
314 &temp_process_info);
315 base::string16 desktop_name = policy->GetAlternateDesktop();
316 policy->Release();
318 EXPECT_EQ(SBOX_ALL_OK, result);
319 if (result == SBOX_ALL_OK)
320 target.Set(temp_process_info);
322 EXPECT_EQ(1, ::ResumeThread(target.thread_handle()));
324 EXPECT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(target.process_handle(), 2000));
326 EXPECT_NE(::GetThreadDesktop(target.thread_id()),
327 ::GetThreadDesktop(::GetCurrentThreadId()));
329 ASSERT_FALSE(desktop_name.empty());
331 // Make sure there is a backslash, for the window station name.
332 EXPECT_NE(desktop_name.find_first_of(L'\\'), base::string16::npos);
334 // Isolate the desktop name.
335 desktop_name = desktop_name.substr(desktop_name.find_first_of(L'\\') + 1);
337 HDESK desk = ::OpenDesktop(desktop_name.c_str(), 0, FALSE, DESKTOP_ENUMERATE);
338 // This should fail if the desktop is really on another window station.
339 EXPECT_FALSE(NULL != desk);
340 EXPECT_TRUE(::TerminateProcess(target.process_handle(), 0));
342 ::WaitForSingleObject(target.process_handle(), INFINITE);
344 // Close the desktop handle.
345 temp_policy = broker->CreatePolicy();
346 temp_policy->DestroyAlternateDesktop();
347 temp_policy->Release();
350 // Launches the app in the sandbox and share a handle with it. The app should
351 // be able to use the handle.
352 TEST(PolicyTargetTest, ShareHandleTest) {
353 // The way we share handles via STARTUPINFOEX does not work on XP.
354 if (base::win::GetVersion() < base::win::VERSION_VISTA)
355 return;
357 BrokerServices* broker = GetBroker();
358 ASSERT_TRUE(broker != NULL);
360 base::StringPiece contents = "Hello World";
361 std::string name = "TestSharedMemory";
362 base::SharedMemoryCreateOptions options;
363 options.size = contents.size();
364 options.share_read_only = true;
365 options.name_deprecated = &name;
366 base::SharedMemory writable_shmem;
367 ASSERT_TRUE(writable_shmem.Create(options));
368 ASSERT_TRUE(writable_shmem.Map(options.size));
369 memcpy(writable_shmem.memory(), contents.data(), contents.size());
371 base::SharedMemory read_only_view;
372 ASSERT_TRUE(read_only_view.Open(name, true));
374 // Get the path to the sandboxed app.
375 wchar_t prog_name[MAX_PATH];
376 GetModuleFileNameW(NULL, prog_name, MAX_PATH);
378 TargetPolicy* policy = broker->CreatePolicy();
379 void* shared_handle = policy->AddHandleToShare(
380 read_only_view.handle());
382 base::string16 arguments(L"\"");
383 arguments += prog_name;
384 arguments += L"\" -child 0 shared_memory_handle ";
385 arguments += base::UintToString16(
386 reinterpret_cast<unsigned int>(shared_handle));
388 // Launch the app.
389 ResultCode result = SBOX_ALL_OK;
390 base::win::ScopedProcessInformation target;
392 policy->SetTokenLevel(USER_INTERACTIVE, USER_LOCKDOWN);
393 PROCESS_INFORMATION temp_process_info = {};
394 result = broker->SpawnTarget(prog_name, arguments.c_str(), policy,
395 &temp_process_info);
396 policy->Release();
398 EXPECT_EQ(SBOX_ALL_OK, result);
399 if (result == SBOX_ALL_OK)
400 target.Set(temp_process_info);
402 EXPECT_EQ(1, ::ResumeThread(target.thread_handle()));
404 EXPECT_EQ(WAIT_TIMEOUT,
405 ::WaitForSingleObject(target.process_handle(), 2000));
407 EXPECT_TRUE(::TerminateProcess(target.process_handle(), 0));
409 ::WaitForSingleObject(target.process_handle(), INFINITE);
412 } // namespace sandbox