security/sandbox/win/src/policy_target_test.cc

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial