security/sandbox/win/src/policy_target_test.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
michael@0 2 // Use of this source code is governed by a BSD-style license that can be
michael@0 3 // found in the LICENSE file.
michael@0 4
michael@0 5 #include "base/win/scoped_process_information.h"
michael@0 6 #include "base/win/windows_version.h"
michael@0 7 #include "sandbox/win/src/sandbox.h"
michael@0 8 #include "sandbox/win/src/sandbox_factory.h"
michael@0 9 #include "sandbox/win/src/sandbox_utils.h"
michael@0 10 #include "sandbox/win/src/target_services.h"
michael@0 11 #include "sandbox/win/tests/common/controller.h"
michael@0 12 #include "testing/gtest/include/gtest/gtest.h"
michael@0 13
michael@0 14 namespace sandbox {
michael@0 15
michael@0 16 #define BINDNTDLL(name) \
michael@0 17 name ## Function name = reinterpret_cast<name ## Function>( \
michael@0 18 ::GetProcAddress(::GetModuleHandle(L"ntdll.dll"), #name))
michael@0 19
michael@0 20 // Reverts to self and verify that SetInformationToken was faked. Returns
michael@0 21 // SBOX_TEST_SUCCEEDED if faked and SBOX_TEST_FAILED if not faked.
michael@0 22 SBOX_TESTS_COMMAND int PolicyTargetTest_token(int argc, wchar_t **argv) {
michael@0 23 HANDLE thread_token;
michael@0 24 // Get the thread token, using impersonation.
michael@0 25 if (!::OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE |
michael@0 26 TOKEN_DUPLICATE, FALSE, &thread_token))
michael@0 27 return ::GetLastError();
michael@0 28
michael@0 29 ::RevertToSelf();
michael@0 30 ::CloseHandle(thread_token);
michael@0 31
michael@0 32 int ret = SBOX_TEST_FAILED;
michael@0 33 if (::OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE | TOKEN_DUPLICATE,
michael@0 34 FALSE, &thread_token)) {
michael@0 35 ret = SBOX_TEST_SUCCEEDED;
michael@0 36 ::CloseHandle(thread_token);
michael@0 37 }
michael@0 38 return ret;
michael@0 39 }
michael@0 40
michael@0 41 // Stores the high privilege token on a static variable, change impersonation
michael@0 42 // again to that one and verify that we are not interfering anymore with
michael@0 43 // RevertToSelf.
michael@0 44 SBOX_TESTS_COMMAND int PolicyTargetTest_steal(int argc, wchar_t **argv) {
michael@0 45 static HANDLE thread_token;
michael@0 46 if (!SandboxFactory::GetTargetServices()->GetState()->RevertedToSelf()) {
michael@0 47 if (!::OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE |
michael@0 48 TOKEN_DUPLICATE, FALSE, &thread_token))
michael@0 49 return ::GetLastError();
michael@0 50 } else {
michael@0 51 if (!::SetThreadToken(NULL, thread_token))
michael@0 52 return ::GetLastError();
michael@0 53
michael@0 54 // See if we fake the call again.
michael@0 55 int ret = PolicyTargetTest_token(argc, argv);
michael@0 56 ::CloseHandle(thread_token);
michael@0 57 return ret;
michael@0 58 }
michael@0 59 return 0;
michael@0 60 }
michael@0 61
michael@0 62 // Opens the thread token with and without impersonation.
michael@0 63 SBOX_TESTS_COMMAND int PolicyTargetTest_token2(int argc, wchar_t **argv) {
michael@0 64 HANDLE thread_token;
michael@0 65 // Get the thread token, using impersonation.
michael@0 66 if (!::OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE |
michael@0 67 TOKEN_DUPLICATE, FALSE, &thread_token))
michael@0 68 return ::GetLastError();
michael@0 69 ::CloseHandle(thread_token);
michael@0 70
michael@0 71 // Get the thread token, without impersonation.
michael@0 72 if (!OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE | TOKEN_DUPLICATE,
michael@0 73 TRUE, &thread_token))
michael@0 74 return ::GetLastError();
michael@0 75 ::CloseHandle(thread_token);
michael@0 76 return SBOX_TEST_SUCCEEDED;
michael@0 77 }
michael@0 78
michael@0 79 // Opens the thread token with and without impersonation, using
michael@0 80 // NtOpenThreadTokenEX.
michael@0 81 SBOX_TESTS_COMMAND int PolicyTargetTest_token3(int argc, wchar_t **argv) {
michael@0 82 BINDNTDLL(NtOpenThreadTokenEx);
michael@0 83 if (!NtOpenThreadTokenEx)
michael@0 84 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
michael@0 85
michael@0 86 HANDLE thread_token;
michael@0 87 // Get the thread token, using impersonation.
michael@0 88 NTSTATUS status = NtOpenThreadTokenEx(GetCurrentThread(),
michael@0 89 TOKEN_IMPERSONATE | TOKEN_DUPLICATE,
michael@0 90 FALSE, 0, &thread_token);
michael@0 91 if (status == STATUS_NO_TOKEN)
michael@0 92 return ERROR_NO_TOKEN;
michael@0 93 if (!NT_SUCCESS(status))
michael@0 94 return SBOX_TEST_FAILED;
michael@0 95
michael@0 96 ::CloseHandle(thread_token);
michael@0 97
michael@0 98 // Get the thread token, without impersonation.
michael@0 99 status = NtOpenThreadTokenEx(GetCurrentThread(),
michael@0 100 TOKEN_IMPERSONATE | TOKEN_DUPLICATE, TRUE, 0,
michael@0 101 &thread_token);
michael@0 102 if (!NT_SUCCESS(status))
michael@0 103 return SBOX_TEST_FAILED;
michael@0 104
michael@0 105 ::CloseHandle(thread_token);
michael@0 106 return SBOX_TEST_SUCCEEDED;
michael@0 107 }
michael@0 108
michael@0 109 // Tests that we can open the current thread.
michael@0 110 SBOX_TESTS_COMMAND int PolicyTargetTest_thread(int argc, wchar_t **argv) {
michael@0 111 DWORD thread_id = ::GetCurrentThreadId();
michael@0 112 HANDLE thread = ::OpenThread(SYNCHRONIZE, FALSE, thread_id);
michael@0 113 if (!thread)
michael@0 114 return ::GetLastError();
michael@0 115 if (!::CloseHandle(thread))
michael@0 116 return ::GetLastError();
michael@0 117
michael@0 118 return SBOX_TEST_SUCCEEDED;
michael@0 119 }
michael@0 120
michael@0 121 // New thread entry point: do nothing.
michael@0 122 DWORD WINAPI PolicyTargetTest_thread_main(void* param) {
michael@0 123 ::Sleep(INFINITE);
michael@0 124 return 0;
michael@0 125 }
michael@0 126
michael@0 127 // Tests that we can create a new thread, and open it.
michael@0 128 SBOX_TESTS_COMMAND int PolicyTargetTest_thread2(int argc, wchar_t **argv) {
michael@0 129 // Use default values to create a new thread.
michael@0 130 DWORD thread_id;
michael@0 131 HANDLE thread = ::CreateThread(NULL, 0, &PolicyTargetTest_thread_main, 0, 0,
michael@0 132 &thread_id);
michael@0 133 if (!thread)
michael@0 134 return ::GetLastError();
michael@0 135 if (!::CloseHandle(thread))
michael@0 136 return ::GetLastError();
michael@0 137
michael@0 138 thread = ::OpenThread(SYNCHRONIZE, FALSE, thread_id);
michael@0 139 if (!thread)
michael@0 140 return ::GetLastError();
michael@0 141
michael@0 142 if (!::CloseHandle(thread))
michael@0 143 return ::GetLastError();
michael@0 144
michael@0 145 return SBOX_TEST_SUCCEEDED;
michael@0 146 }
michael@0 147
michael@0 148 // Tests that we can call CreateProcess.
michael@0 149 SBOX_TESTS_COMMAND int PolicyTargetTest_process(int argc, wchar_t **argv) {
michael@0 150 // Use default values to create a new process.
michael@0 151 STARTUPINFO startup_info = {0};
michael@0 152 startup_info.cb = sizeof(startup_info);
michael@0 153 base::win::ScopedProcessInformation process_info;
michael@0 154 if (!::CreateProcessW(L"foo.exe", L"foo.exe", NULL, NULL, FALSE, 0,
michael@0 155 NULL, NULL, &startup_info, process_info.Receive()))
michael@0 156 return SBOX_TEST_SUCCEEDED;
michael@0 157 return SBOX_TEST_FAILED;
michael@0 158 }
michael@0 159
michael@0 160 TEST(PolicyTargetTest, SetInformationThread) {
michael@0 161 TestRunner runner;
michael@0 162 if (base::win::GetVersion() >= base::win::VERSION_XP) {
michael@0 163 runner.SetTestState(BEFORE_REVERT);
michael@0 164 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"PolicyTargetTest_token"));
michael@0 165 }
michael@0 166
michael@0 167 runner.SetTestState(AFTER_REVERT);
michael@0 168 EXPECT_EQ(ERROR_NO_TOKEN, runner.RunTest(L"PolicyTargetTest_token"));
michael@0 169
michael@0 170 runner.SetTestState(EVERY_STATE);
michael@0 171 if (base::win::GetVersion() >= base::win::VERSION_XP)
michael@0 172 EXPECT_EQ(SBOX_TEST_FAILED, runner.RunTest(L"PolicyTargetTest_steal"));
michael@0 173 }
michael@0 174
michael@0 175 TEST(PolicyTargetTest, OpenThreadToken) {
michael@0 176 TestRunner runner;
michael@0 177 if (base::win::GetVersion() >= base::win::VERSION_XP) {
michael@0 178 runner.SetTestState(BEFORE_REVERT);
michael@0 179 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"PolicyTargetTest_token2"));
michael@0 180 }
michael@0 181
michael@0 182 runner.SetTestState(AFTER_REVERT);
michael@0 183 EXPECT_EQ(ERROR_NO_TOKEN, runner.RunTest(L"PolicyTargetTest_token2"));
michael@0 184 }
michael@0 185
michael@0 186 TEST(PolicyTargetTest, OpenThreadTokenEx) {
michael@0 187 TestRunner runner;
michael@0 188 if (base::win::GetVersion() < base::win::VERSION_XP)
michael@0 189 return;
michael@0 190
michael@0 191 runner.SetTestState(BEFORE_REVERT);
michael@0 192 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"PolicyTargetTest_token3"));
michael@0 193
michael@0 194 runner.SetTestState(AFTER_REVERT);
michael@0 195 EXPECT_EQ(ERROR_NO_TOKEN, runner.RunTest(L"PolicyTargetTest_token3"));
michael@0 196 }
michael@0 197
michael@0 198 TEST(PolicyTargetTest, OpenThread) {
michael@0 199 TestRunner runner;
michael@0 200 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"PolicyTargetTest_thread")) <<
michael@0 201 "Opens the current thread";
michael@0 202
michael@0 203 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"PolicyTargetTest_thread2")) <<
michael@0 204 "Creates a new thread and opens it";
michael@0 205 }
michael@0 206
michael@0 207 TEST(PolicyTargetTest, OpenProcess) {
michael@0 208 TestRunner runner;
michael@0 209 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"PolicyTargetTest_process")) <<
michael@0 210 "Opens a process";
michael@0 211 }
michael@0 212
michael@0 213 // Launches the app in the sandbox and ask it to wait in an
michael@0 214 // infinite loop. Waits for 2 seconds and then check if the
michael@0 215 // desktop associated with the app thread is not the same as the
michael@0 216 // current desktop.
michael@0 217 TEST(PolicyTargetTest, DesktopPolicy) {
michael@0 218 BrokerServices* broker = GetBroker();
michael@0 219
michael@0 220 // Precreate the desktop.
michael@0 221 TargetPolicy* temp_policy = broker->CreatePolicy();
michael@0 222 temp_policy->CreateAlternateDesktop(false);
michael@0 223 temp_policy->Release();
michael@0 224
michael@0 225 ASSERT_TRUE(broker != NULL);
michael@0 226
michael@0 227 // Get the path to the sandboxed app.
michael@0 228 wchar_t prog_name[MAX_PATH];
michael@0 229 GetModuleFileNameW(NULL, prog_name, MAX_PATH);
michael@0 230
michael@0 231 std::wstring arguments(L"\"");
michael@0 232 arguments += prog_name;
michael@0 233 arguments += L"\" -child 0 wait"; // Don't care about the "state" argument.
michael@0 234
michael@0 235 // Launch the app.
michael@0 236 ResultCode result = SBOX_ALL_OK;
michael@0 237 base::win::ScopedProcessInformation target;
michael@0 238
michael@0 239 TargetPolicy* policy = broker->CreatePolicy();
michael@0 240 policy->SetAlternateDesktop(false);
michael@0 241 policy->SetTokenLevel(USER_INTERACTIVE, USER_LOCKDOWN);
michael@0 242 result = broker->SpawnTarget(prog_name, arguments.c_str(), policy,
michael@0 243 target.Receive());
michael@0 244 policy->Release();
michael@0 245
michael@0 246 EXPECT_EQ(SBOX_ALL_OK, result);
michael@0 247
michael@0 248 EXPECT_EQ(1, ::ResumeThread(target.thread_handle()));
michael@0 249
michael@0 250 EXPECT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(target.process_handle(), 2000));
michael@0 251
michael@0 252 EXPECT_NE(::GetThreadDesktop(target.thread_id()),
michael@0 253 ::GetThreadDesktop(::GetCurrentThreadId()));
michael@0 254
michael@0 255 std::wstring desktop_name = policy->GetAlternateDesktop();
michael@0 256 HDESK desk = ::OpenDesktop(desktop_name.c_str(), 0, FALSE, DESKTOP_ENUMERATE);
michael@0 257 EXPECT_TRUE(NULL != desk);
michael@0 258 EXPECT_TRUE(::CloseDesktop(desk));
michael@0 259 EXPECT_TRUE(::TerminateProcess(target.process_handle(), 0));
michael@0 260
michael@0 261 ::WaitForSingleObject(target.process_handle(), INFINITE);
michael@0 262
michael@0 263 // Close the desktop handle.
michael@0 264 temp_policy = broker->CreatePolicy();
michael@0 265 temp_policy->DestroyAlternateDesktop();
michael@0 266 temp_policy->Release();
michael@0 267
michael@0 268 // Make sure the desktop does not exist anymore.
michael@0 269 desk = ::OpenDesktop(desktop_name.c_str(), 0, FALSE, DESKTOP_ENUMERATE);
michael@0 270 EXPECT_TRUE(NULL == desk);
michael@0 271 }
michael@0 272
michael@0 273 // Launches the app in the sandbox and ask it to wait in an
michael@0 274 // infinite loop. Waits for 2 seconds and then check if the
michael@0 275 // winstation associated with the app thread is not the same as the
michael@0 276 // current desktop.
michael@0 277 TEST(PolicyTargetTest, WinstaPolicy) {
michael@0 278 BrokerServices* broker = GetBroker();
michael@0 279
michael@0 280 // Precreate the desktop.
michael@0 281 TargetPolicy* temp_policy = broker->CreatePolicy();
michael@0 282 temp_policy->CreateAlternateDesktop(true);
michael@0 283 temp_policy->Release();
michael@0 284
michael@0 285 ASSERT_TRUE(broker != NULL);
michael@0 286
michael@0 287 // Get the path to the sandboxed app.
michael@0 288 wchar_t prog_name[MAX_PATH];
michael@0 289 GetModuleFileNameW(NULL, prog_name, MAX_PATH);
michael@0 290
michael@0 291 std::wstring arguments(L"\"");
michael@0 292 arguments += prog_name;
michael@0 293 arguments += L"\" -child 0 wait"; // Don't care about the "state" argument.
michael@0 294
michael@0 295 // Launch the app.
michael@0 296 ResultCode result = SBOX_ALL_OK;
michael@0 297 base::win::ScopedProcessInformation target;
michael@0 298
michael@0 299 TargetPolicy* policy = broker->CreatePolicy();
michael@0 300 policy->SetAlternateDesktop(true);
michael@0 301 policy->SetTokenLevel(USER_INTERACTIVE, USER_LOCKDOWN);
michael@0 302 result = broker->SpawnTarget(prog_name, arguments.c_str(), policy,
michael@0 303 target.Receive());
michael@0 304 policy->Release();
michael@0 305
michael@0 306 EXPECT_EQ(SBOX_ALL_OK, result);
michael@0 307
michael@0 308 EXPECT_EQ(1, ::ResumeThread(target.thread_handle()));
michael@0 309
michael@0 310 EXPECT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(target.process_handle(), 2000));
michael@0 311
michael@0 312 EXPECT_NE(::GetThreadDesktop(target.thread_id()),
michael@0 313 ::GetThreadDesktop(::GetCurrentThreadId()));
michael@0 314
michael@0 315 std::wstring desktop_name = policy->GetAlternateDesktop();
michael@0 316 ASSERT_FALSE(desktop_name.empty());
michael@0 317
michael@0 318 // Make sure there is a backslash, for the window station name.
michael@0 319 EXPECT_NE(desktop_name.find_first_of(L'\\'), std::wstring::npos);
michael@0 320
michael@0 321 // Isolate the desktop name.
michael@0 322 desktop_name = desktop_name.substr(desktop_name.find_first_of(L'\\') + 1);
michael@0 323
michael@0 324 HDESK desk = ::OpenDesktop(desktop_name.c_str(), 0, FALSE, DESKTOP_ENUMERATE);
michael@0 325 // This should fail if the desktop is really on another window station.
michael@0 326 EXPECT_FALSE(NULL != desk);
michael@0 327 EXPECT_TRUE(::TerminateProcess(target.process_handle(), 0));
michael@0 328
michael@0 329 ::WaitForSingleObject(target.process_handle(), INFINITE);
michael@0 330
michael@0 331 // Close the desktop handle.
michael@0 332 temp_policy = broker->CreatePolicy();
michael@0 333 temp_policy->DestroyAlternateDesktop();
michael@0 334 temp_policy->Release();
michael@0 335 }
michael@0 336
michael@0 337 } // namespace sandbox

mercurial