summaryrefslogtreecommitdiffstats
path: root/sandbox/src/policy_target_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sandbox/src/policy_target_test.cc')
-rw-r--r--sandbox/src/policy_target_test.cc239
1 files changed, 239 insertions, 0 deletions
diff --git a/sandbox/src/policy_target_test.cc b/sandbox/src/policy_target_test.cc
new file mode 100644
index 0000000..73e07e8
--- /dev/null
+++ b/sandbox/src/policy_target_test.cc
@@ -0,0 +1,239 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "base/win_util.h"
+#include "sandbox/src/sandbox.h"
+#include "sandbox/src/sandbox_factory.h"
+#include "sandbox/src/sandbox_utils.h"
+#include "sandbox/src/target_services.h"
+#include "sandbox/tests/common/controller.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+// Reverts to self and verify that SetInformationToken was faked. Returns
+// SBOX_TEST_SUCCEEDED if faked and SBOX_TEST_FAILED if not faked.
+SBOX_TESTS_COMMAND int PolicyTargetTest_token(int argc, wchar_t **argv) {
+ HANDLE thread_token;
+ // Get the thread token, using impersonation.
+ if (!::OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE |
+ TOKEN_DUPLICATE, FALSE, &thread_token))
+ return ::GetLastError();
+
+ ::RevertToSelf();
+ ::CloseHandle(thread_token);
+
+ int ret = SBOX_TEST_FAILED;
+ if (::OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE | TOKEN_DUPLICATE,
+ FALSE, &thread_token)) {
+ ret = SBOX_TEST_SUCCEEDED;
+ ::CloseHandle(thread_token);
+ }
+ return ret;
+}
+
+// Stores the high privilege token on a static variable, change impersonation
+// again to that one and verify that we are not interfering anymore with
+// RevertToSelf.
+SBOX_TESTS_COMMAND int PolicyTargetTest_steal(int argc, wchar_t **argv) {
+ static HANDLE thread_token;
+ if (!SandboxFactory::GetTargetServices()->GetState()->RevertedToSelf()) {
+ if (!::OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE |
+ TOKEN_DUPLICATE, FALSE, &thread_token))
+ return ::GetLastError();
+ } else {
+ if (!::SetThreadToken(NULL, thread_token))
+ return ::GetLastError();
+
+ // See if we fake the call again.
+ int ret = PolicyTargetTest_token(argc, argv);
+ ::CloseHandle(thread_token);
+ return ret;
+ }
+ return 0;
+}
+
+// Opens the thread token with and without impersonation.
+SBOX_TESTS_COMMAND int PolicyTargetTest_token2(int argc, wchar_t **argv) {
+ HANDLE thread_token;
+ // Get the thread token, using impersonation.
+ if (!::OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE |
+ TOKEN_DUPLICATE, FALSE, &thread_token))
+ return ::GetLastError();
+ ::CloseHandle(thread_token);
+
+ // Get the thread token, without impersonation.
+ if (!OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE | TOKEN_DUPLICATE,
+ TRUE, &thread_token))
+ return ::GetLastError();
+ ::CloseHandle(thread_token);
+ return SBOX_TEST_SUCCEEDED;
+}
+
+// Tests that we can open the current thread.
+SBOX_TESTS_COMMAND int PolicyTargetTest_thread(int argc, wchar_t **argv) {
+ DWORD thread_id = ::GetCurrentThreadId();
+ HANDLE thread = ::OpenThread(SYNCHRONIZE, FALSE, thread_id);
+ if (!thread)
+ return ::GetLastError();
+
+ ::CloseHandle(thread);
+ return SBOX_TEST_SUCCEEDED;
+}
+
+// New thread entry point: do nothing.
+DWORD WINAPI PolicyTargetTest_thread_main(void* param) {
+ ::Sleep(INFINITE);
+ return 0;
+}
+
+// Tests that we can create a new thread, and open it.
+SBOX_TESTS_COMMAND int PolicyTargetTest_thread2(int argc, wchar_t **argv) {
+ // Use default values to create a new thread.
+ DWORD thread_id;
+ HANDLE thread = ::CreateThread(NULL, 0, &PolicyTargetTest_thread_main, 0, 0,
+ &thread_id);
+ if (!thread)
+ return ::GetLastError();
+ ::CloseHandle(thread);
+
+ thread = ::OpenThread(SYNCHRONIZE, FALSE, thread_id);
+ if (!thread)
+ return ::GetLastError();
+ ::CloseHandle(thread);
+
+ return SBOX_TEST_SUCCEEDED;
+}
+
+// Tests that we can call CreateProcess.
+SBOX_TESTS_COMMAND int PolicyTargetTest_process(int argc, wchar_t **argv) {
+ // Use default values to create a new process.
+ STARTUPINFO startup_info = {0};
+ startup_info.cb = sizeof(startup_info);
+ PROCESS_INFORMATION process_info;
+ ::CreateProcess(L"foo.exe", L"foo.exe", NULL, NULL, FALSE, 0, NULL, NULL,
+ &startup_info, &process_info);
+
+ return SBOX_TEST_SUCCEEDED;
+}
+
+TEST(PolicyTargetTest, SetInformationThread) {
+ TestRunner runner;
+ if (win_util::GetWinVersion() >= win_util::WINVERSION_XP) {
+ runner.SetTestState(BEFORE_REVERT);
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"PolicyTargetTest_token"));
+ }
+
+ runner.SetTestState(AFTER_REVERT);
+ EXPECT_EQ(ERROR_NO_TOKEN, runner.RunTest(L"PolicyTargetTest_token"));
+
+ runner.SetTestState(EVERY_STATE);
+ if (win_util::GetWinVersion() >= win_util::WINVERSION_XP)
+ EXPECT_EQ(SBOX_TEST_FAILED, runner.RunTest(L"PolicyTargetTest_steal"));
+}
+
+TEST(PolicyTargetTest, OpenThreadToken) {
+ TestRunner runner;
+ if (win_util::GetWinVersion() >= win_util::WINVERSION_XP) {
+ runner.SetTestState(BEFORE_REVERT);
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"PolicyTargetTest_token2"));
+ }
+
+ runner.SetTestState(AFTER_REVERT);
+ EXPECT_EQ(ERROR_NO_TOKEN, runner.RunTest(L"PolicyTargetTest_token2"));
+}
+
+TEST(PolicyTargetTest, OpenThread) {
+ TestRunner runner;
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"PolicyTargetTest_thread")) <<
+ "Opens the current thread";
+
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"PolicyTargetTest_thread2")) <<
+ "Creates a new thread and opens it";
+}
+
+TEST(PolicyTargetTest, OpenProcess) {
+ TestRunner runner;
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"PolicyTargetTest_process")) <<
+ "Opens a process";
+}
+
+// Launches the app in the sandbox and ask it to wait in an
+// infinite loop. Waits for 2 seconds and then check if the
+// desktop associated with the app thread is not the same as the
+// current desktop.
+TEST(PolicyTargetTest, DesktopPolicy) {
+ BrokerServices* broker = GetBroker();
+ ASSERT_TRUE(broker != NULL);
+
+ // Get the path to the sandboxed app.
+ wchar_t prog_name[MAX_PATH];
+ GetModuleFileNameW(NULL, prog_name, MAX_PATH);
+
+ std::wstring arguments(L"\"");
+ arguments += prog_name;
+ arguments += L"\" -child 0 wait"; // Don't care about the "state" argument.
+
+ // Launch the app.
+ ResultCode result = SBOX_ALL_OK;
+ PROCESS_INFORMATION target = {0};
+
+ TargetPolicy* policy = broker->CreatePolicy();
+ policy->SetDesktop(L"desktop_for_sbox");
+ policy->SetTokenLevel(USER_INTERACTIVE, USER_LOCKDOWN);
+ result = broker->SpawnTarget(prog_name, arguments.c_str(), policy, &target);
+ policy->Release();
+
+ EXPECT_EQ(SBOX_ALL_OK, result);
+
+ EXPECT_EQ(1, ::ResumeThread(target.hThread));
+
+ EXPECT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(target.hProcess, 2000));
+
+ EXPECT_NE(::GetThreadDesktop(target.dwThreadId),
+ ::GetThreadDesktop(::GetCurrentThreadId()));
+
+ HDESK desk = ::OpenDesktop(L"desktop_for_sbox", 0, FALSE, DESKTOP_ENUMERATE);
+ EXPECT_TRUE(NULL != desk);
+ EXPECT_TRUE(::CloseDesktop(desk));
+ EXPECT_TRUE(::TerminateProcess(target.hProcess, 0));
+
+ ::WaitForSingleObject(target.hProcess, INFINITE);
+
+ EXPECT_TRUE(::CloseHandle(target.hProcess));
+ EXPECT_TRUE(::CloseHandle(target.hThread));
+
+ // Wait for the desktop to be deleted by the destructor of TargetProcess
+ Sleep(2000);
+
+ desk = ::OpenDesktop(L"desktop_for_sbox", 0, FALSE, DESKTOP_ENUMERATE);
+ EXPECT_TRUE(NULL == desk);
+}
+
+} // namespace sandbox