1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/sandbox/win/src/policy_target_test.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,337 @@ 1.4 +// Copyright (c) 2012 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +#include "base/win/scoped_process_information.h" 1.9 +#include "base/win/windows_version.h" 1.10 +#include "sandbox/win/src/sandbox.h" 1.11 +#include "sandbox/win/src/sandbox_factory.h" 1.12 +#include "sandbox/win/src/sandbox_utils.h" 1.13 +#include "sandbox/win/src/target_services.h" 1.14 +#include "sandbox/win/tests/common/controller.h" 1.15 +#include "testing/gtest/include/gtest/gtest.h" 1.16 + 1.17 +namespace sandbox { 1.18 + 1.19 +#define BINDNTDLL(name) \ 1.20 + name ## Function name = reinterpret_cast<name ## Function>( \ 1.21 + ::GetProcAddress(::GetModuleHandle(L"ntdll.dll"), #name)) 1.22 + 1.23 +// Reverts to self and verify that SetInformationToken was faked. Returns 1.24 +// SBOX_TEST_SUCCEEDED if faked and SBOX_TEST_FAILED if not faked. 1.25 +SBOX_TESTS_COMMAND int PolicyTargetTest_token(int argc, wchar_t **argv) { 1.26 + HANDLE thread_token; 1.27 + // Get the thread token, using impersonation. 1.28 + if (!::OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE | 1.29 + TOKEN_DUPLICATE, FALSE, &thread_token)) 1.30 + return ::GetLastError(); 1.31 + 1.32 + ::RevertToSelf(); 1.33 + ::CloseHandle(thread_token); 1.34 + 1.35 + int ret = SBOX_TEST_FAILED; 1.36 + if (::OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE | TOKEN_DUPLICATE, 1.37 + FALSE, &thread_token)) { 1.38 + ret = SBOX_TEST_SUCCEEDED; 1.39 + ::CloseHandle(thread_token); 1.40 + } 1.41 + return ret; 1.42 +} 1.43 + 1.44 +// Stores the high privilege token on a static variable, change impersonation 1.45 +// again to that one and verify that we are not interfering anymore with 1.46 +// RevertToSelf. 1.47 +SBOX_TESTS_COMMAND int PolicyTargetTest_steal(int argc, wchar_t **argv) { 1.48 + static HANDLE thread_token; 1.49 + if (!SandboxFactory::GetTargetServices()->GetState()->RevertedToSelf()) { 1.50 + if (!::OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE | 1.51 + TOKEN_DUPLICATE, FALSE, &thread_token)) 1.52 + return ::GetLastError(); 1.53 + } else { 1.54 + if (!::SetThreadToken(NULL, thread_token)) 1.55 + return ::GetLastError(); 1.56 + 1.57 + // See if we fake the call again. 1.58 + int ret = PolicyTargetTest_token(argc, argv); 1.59 + ::CloseHandle(thread_token); 1.60 + return ret; 1.61 + } 1.62 + return 0; 1.63 +} 1.64 + 1.65 +// Opens the thread token with and without impersonation. 1.66 +SBOX_TESTS_COMMAND int PolicyTargetTest_token2(int argc, wchar_t **argv) { 1.67 + HANDLE thread_token; 1.68 + // Get the thread token, using impersonation. 1.69 + if (!::OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE | 1.70 + TOKEN_DUPLICATE, FALSE, &thread_token)) 1.71 + return ::GetLastError(); 1.72 + ::CloseHandle(thread_token); 1.73 + 1.74 + // Get the thread token, without impersonation. 1.75 + if (!OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE | TOKEN_DUPLICATE, 1.76 + TRUE, &thread_token)) 1.77 + return ::GetLastError(); 1.78 + ::CloseHandle(thread_token); 1.79 + return SBOX_TEST_SUCCEEDED; 1.80 +} 1.81 + 1.82 +// Opens the thread token with and without impersonation, using 1.83 +// NtOpenThreadTokenEX. 1.84 +SBOX_TESTS_COMMAND int PolicyTargetTest_token3(int argc, wchar_t **argv) { 1.85 + BINDNTDLL(NtOpenThreadTokenEx); 1.86 + if (!NtOpenThreadTokenEx) 1.87 + return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; 1.88 + 1.89 + HANDLE thread_token; 1.90 + // Get the thread token, using impersonation. 1.91 + NTSTATUS status = NtOpenThreadTokenEx(GetCurrentThread(), 1.92 + TOKEN_IMPERSONATE | TOKEN_DUPLICATE, 1.93 + FALSE, 0, &thread_token); 1.94 + if (status == STATUS_NO_TOKEN) 1.95 + return ERROR_NO_TOKEN; 1.96 + if (!NT_SUCCESS(status)) 1.97 + return SBOX_TEST_FAILED; 1.98 + 1.99 + ::CloseHandle(thread_token); 1.100 + 1.101 + // Get the thread token, without impersonation. 1.102 + status = NtOpenThreadTokenEx(GetCurrentThread(), 1.103 + TOKEN_IMPERSONATE | TOKEN_DUPLICATE, TRUE, 0, 1.104 + &thread_token); 1.105 + if (!NT_SUCCESS(status)) 1.106 + return SBOX_TEST_FAILED; 1.107 + 1.108 + ::CloseHandle(thread_token); 1.109 + return SBOX_TEST_SUCCEEDED; 1.110 +} 1.111 + 1.112 +// Tests that we can open the current thread. 1.113 +SBOX_TESTS_COMMAND int PolicyTargetTest_thread(int argc, wchar_t **argv) { 1.114 + DWORD thread_id = ::GetCurrentThreadId(); 1.115 + HANDLE thread = ::OpenThread(SYNCHRONIZE, FALSE, thread_id); 1.116 + if (!thread) 1.117 + return ::GetLastError(); 1.118 + if (!::CloseHandle(thread)) 1.119 + return ::GetLastError(); 1.120 + 1.121 + return SBOX_TEST_SUCCEEDED; 1.122 +} 1.123 + 1.124 +// New thread entry point: do nothing. 1.125 +DWORD WINAPI PolicyTargetTest_thread_main(void* param) { 1.126 + ::Sleep(INFINITE); 1.127 + return 0; 1.128 +} 1.129 + 1.130 +// Tests that we can create a new thread, and open it. 1.131 +SBOX_TESTS_COMMAND int PolicyTargetTest_thread2(int argc, wchar_t **argv) { 1.132 + // Use default values to create a new thread. 1.133 + DWORD thread_id; 1.134 + HANDLE thread = ::CreateThread(NULL, 0, &PolicyTargetTest_thread_main, 0, 0, 1.135 + &thread_id); 1.136 + if (!thread) 1.137 + return ::GetLastError(); 1.138 + if (!::CloseHandle(thread)) 1.139 + return ::GetLastError(); 1.140 + 1.141 + thread = ::OpenThread(SYNCHRONIZE, FALSE, thread_id); 1.142 + if (!thread) 1.143 + return ::GetLastError(); 1.144 + 1.145 + if (!::CloseHandle(thread)) 1.146 + return ::GetLastError(); 1.147 + 1.148 + return SBOX_TEST_SUCCEEDED; 1.149 +} 1.150 + 1.151 +// Tests that we can call CreateProcess. 1.152 +SBOX_TESTS_COMMAND int PolicyTargetTest_process(int argc, wchar_t **argv) { 1.153 + // Use default values to create a new process. 1.154 + STARTUPINFO startup_info = {0}; 1.155 + startup_info.cb = sizeof(startup_info); 1.156 + base::win::ScopedProcessInformation process_info; 1.157 + if (!::CreateProcessW(L"foo.exe", L"foo.exe", NULL, NULL, FALSE, 0, 1.158 + NULL, NULL, &startup_info, process_info.Receive())) 1.159 + return SBOX_TEST_SUCCEEDED; 1.160 + return SBOX_TEST_FAILED; 1.161 +} 1.162 + 1.163 +TEST(PolicyTargetTest, SetInformationThread) { 1.164 + TestRunner runner; 1.165 + if (base::win::GetVersion() >= base::win::VERSION_XP) { 1.166 + runner.SetTestState(BEFORE_REVERT); 1.167 + EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"PolicyTargetTest_token")); 1.168 + } 1.169 + 1.170 + runner.SetTestState(AFTER_REVERT); 1.171 + EXPECT_EQ(ERROR_NO_TOKEN, runner.RunTest(L"PolicyTargetTest_token")); 1.172 + 1.173 + runner.SetTestState(EVERY_STATE); 1.174 + if (base::win::GetVersion() >= base::win::VERSION_XP) 1.175 + EXPECT_EQ(SBOX_TEST_FAILED, runner.RunTest(L"PolicyTargetTest_steal")); 1.176 +} 1.177 + 1.178 +TEST(PolicyTargetTest, OpenThreadToken) { 1.179 + TestRunner runner; 1.180 + if (base::win::GetVersion() >= base::win::VERSION_XP) { 1.181 + runner.SetTestState(BEFORE_REVERT); 1.182 + EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"PolicyTargetTest_token2")); 1.183 + } 1.184 + 1.185 + runner.SetTestState(AFTER_REVERT); 1.186 + EXPECT_EQ(ERROR_NO_TOKEN, runner.RunTest(L"PolicyTargetTest_token2")); 1.187 +} 1.188 + 1.189 +TEST(PolicyTargetTest, OpenThreadTokenEx) { 1.190 + TestRunner runner; 1.191 + if (base::win::GetVersion() < base::win::VERSION_XP) 1.192 + return; 1.193 + 1.194 + runner.SetTestState(BEFORE_REVERT); 1.195 + EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"PolicyTargetTest_token3")); 1.196 + 1.197 + runner.SetTestState(AFTER_REVERT); 1.198 + EXPECT_EQ(ERROR_NO_TOKEN, runner.RunTest(L"PolicyTargetTest_token3")); 1.199 +} 1.200 + 1.201 +TEST(PolicyTargetTest, OpenThread) { 1.202 + TestRunner runner; 1.203 + EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"PolicyTargetTest_thread")) << 1.204 + "Opens the current thread"; 1.205 + 1.206 + EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"PolicyTargetTest_thread2")) << 1.207 + "Creates a new thread and opens it"; 1.208 +} 1.209 + 1.210 +TEST(PolicyTargetTest, OpenProcess) { 1.211 + TestRunner runner; 1.212 + EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"PolicyTargetTest_process")) << 1.213 + "Opens a process"; 1.214 +} 1.215 + 1.216 +// Launches the app in the sandbox and ask it to wait in an 1.217 +// infinite loop. Waits for 2 seconds and then check if the 1.218 +// desktop associated with the app thread is not the same as the 1.219 +// current desktop. 1.220 +TEST(PolicyTargetTest, DesktopPolicy) { 1.221 + BrokerServices* broker = GetBroker(); 1.222 + 1.223 + // Precreate the desktop. 1.224 + TargetPolicy* temp_policy = broker->CreatePolicy(); 1.225 + temp_policy->CreateAlternateDesktop(false); 1.226 + temp_policy->Release(); 1.227 + 1.228 + ASSERT_TRUE(broker != NULL); 1.229 + 1.230 + // Get the path to the sandboxed app. 1.231 + wchar_t prog_name[MAX_PATH]; 1.232 + GetModuleFileNameW(NULL, prog_name, MAX_PATH); 1.233 + 1.234 + std::wstring arguments(L"\""); 1.235 + arguments += prog_name; 1.236 + arguments += L"\" -child 0 wait"; // Don't care about the "state" argument. 1.237 + 1.238 + // Launch the app. 1.239 + ResultCode result = SBOX_ALL_OK; 1.240 + base::win::ScopedProcessInformation target; 1.241 + 1.242 + TargetPolicy* policy = broker->CreatePolicy(); 1.243 + policy->SetAlternateDesktop(false); 1.244 + policy->SetTokenLevel(USER_INTERACTIVE, USER_LOCKDOWN); 1.245 + result = broker->SpawnTarget(prog_name, arguments.c_str(), policy, 1.246 + target.Receive()); 1.247 + policy->Release(); 1.248 + 1.249 + EXPECT_EQ(SBOX_ALL_OK, result); 1.250 + 1.251 + EXPECT_EQ(1, ::ResumeThread(target.thread_handle())); 1.252 + 1.253 + EXPECT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(target.process_handle(), 2000)); 1.254 + 1.255 + EXPECT_NE(::GetThreadDesktop(target.thread_id()), 1.256 + ::GetThreadDesktop(::GetCurrentThreadId())); 1.257 + 1.258 + std::wstring desktop_name = policy->GetAlternateDesktop(); 1.259 + HDESK desk = ::OpenDesktop(desktop_name.c_str(), 0, FALSE, DESKTOP_ENUMERATE); 1.260 + EXPECT_TRUE(NULL != desk); 1.261 + EXPECT_TRUE(::CloseDesktop(desk)); 1.262 + EXPECT_TRUE(::TerminateProcess(target.process_handle(), 0)); 1.263 + 1.264 + ::WaitForSingleObject(target.process_handle(), INFINITE); 1.265 + 1.266 + // Close the desktop handle. 1.267 + temp_policy = broker->CreatePolicy(); 1.268 + temp_policy->DestroyAlternateDesktop(); 1.269 + temp_policy->Release(); 1.270 + 1.271 + // Make sure the desktop does not exist anymore. 1.272 + desk = ::OpenDesktop(desktop_name.c_str(), 0, FALSE, DESKTOP_ENUMERATE); 1.273 + EXPECT_TRUE(NULL == desk); 1.274 +} 1.275 + 1.276 +// Launches the app in the sandbox and ask it to wait in an 1.277 +// infinite loop. Waits for 2 seconds and then check if the 1.278 +// winstation associated with the app thread is not the same as the 1.279 +// current desktop. 1.280 +TEST(PolicyTargetTest, WinstaPolicy) { 1.281 + BrokerServices* broker = GetBroker(); 1.282 + 1.283 + // Precreate the desktop. 1.284 + TargetPolicy* temp_policy = broker->CreatePolicy(); 1.285 + temp_policy->CreateAlternateDesktop(true); 1.286 + temp_policy->Release(); 1.287 + 1.288 + ASSERT_TRUE(broker != NULL); 1.289 + 1.290 + // Get the path to the sandboxed app. 1.291 + wchar_t prog_name[MAX_PATH]; 1.292 + GetModuleFileNameW(NULL, prog_name, MAX_PATH); 1.293 + 1.294 + std::wstring arguments(L"\""); 1.295 + arguments += prog_name; 1.296 + arguments += L"\" -child 0 wait"; // Don't care about the "state" argument. 1.297 + 1.298 + // Launch the app. 1.299 + ResultCode result = SBOX_ALL_OK; 1.300 + base::win::ScopedProcessInformation target; 1.301 + 1.302 + TargetPolicy* policy = broker->CreatePolicy(); 1.303 + policy->SetAlternateDesktop(true); 1.304 + policy->SetTokenLevel(USER_INTERACTIVE, USER_LOCKDOWN); 1.305 + result = broker->SpawnTarget(prog_name, arguments.c_str(), policy, 1.306 + target.Receive()); 1.307 + policy->Release(); 1.308 + 1.309 + EXPECT_EQ(SBOX_ALL_OK, result); 1.310 + 1.311 + EXPECT_EQ(1, ::ResumeThread(target.thread_handle())); 1.312 + 1.313 + EXPECT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(target.process_handle(), 2000)); 1.314 + 1.315 + EXPECT_NE(::GetThreadDesktop(target.thread_id()), 1.316 + ::GetThreadDesktop(::GetCurrentThreadId())); 1.317 + 1.318 + std::wstring desktop_name = policy->GetAlternateDesktop(); 1.319 + ASSERT_FALSE(desktop_name.empty()); 1.320 + 1.321 + // Make sure there is a backslash, for the window station name. 1.322 + EXPECT_NE(desktop_name.find_first_of(L'\\'), std::wstring::npos); 1.323 + 1.324 + // Isolate the desktop name. 1.325 + desktop_name = desktop_name.substr(desktop_name.find_first_of(L'\\') + 1); 1.326 + 1.327 + HDESK desk = ::OpenDesktop(desktop_name.c_str(), 0, FALSE, DESKTOP_ENUMERATE); 1.328 + // This should fail if the desktop is really on another window station. 1.329 + EXPECT_FALSE(NULL != desk); 1.330 + EXPECT_TRUE(::TerminateProcess(target.process_handle(), 0)); 1.331 + 1.332 + ::WaitForSingleObject(target.process_handle(), INFINITE); 1.333 + 1.334 + // Close the desktop handle. 1.335 + temp_policy = broker->CreatePolicy(); 1.336 + temp_policy->DestroyAlternateDesktop(); 1.337 + temp_policy->Release(); 1.338 +} 1.339 + 1.340 +} // namespace sandbox