diff options
author | jln@chromium.org <jln@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-07-13 20:05:09 +0000 |
---|---|---|
committer | jln@chromium.org <jln@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-07-13 20:05:09 +0000 |
commit | 4bcf1c120956613b5f899fb1d6f677961ea8806d (patch) | |
tree | 90bcbbab2dcfdb98a676ce7c689f2b6c0f79e383 /sandbox/win/tests | |
parent | a5e451505f3e2a4120473b451d49d7ea3b289f78 (diff) | |
download | chromium_src-4bcf1c120956613b5f899fb1d6f677961ea8806d.zip chromium_src-4bcf1c120956613b5f899fb1d6f677961ea8806d.tar.gz chromium_src-4bcf1c120956613b5f899fb1d6f677961ea8806d.tar.bz2 |
Move Windows sandbox
- Move Windows sandbox to sandbox/win
- Update sandbox_win.gypi
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@146625 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sandbox/win/tests')
-rw-r--r-- | sandbox/win/tests/common/controller.cc | 338 | ||||
-rw-r--r-- | sandbox/win/tests/common/controller.h | 145 | ||||
-rw-r--r-- | sandbox/win/tests/common/test_utils.cc | 72 | ||||
-rw-r--r-- | sandbox/win/tests/common/test_utils.h | 19 | ||||
-rw-r--r-- | sandbox/win/tests/integration_tests/integration_tests.cc | 18 | ||||
-rw-r--r-- | sandbox/win/tests/integration_tests/integration_tests_test.cc | 94 | ||||
-rw-r--r-- | sandbox/win/tests/integration_tests/sbox_integration_tests.vcproj | 242 | ||||
-rw-r--r-- | sandbox/win/tests/unit_tests/sbox_unittests.vcproj | 258 | ||||
-rw-r--r-- | sandbox/win/tests/unit_tests/unit_tests.cc | 16 | ||||
-rw-r--r-- | sandbox/win/tests/validation_tests/commands.cc | 262 | ||||
-rw-r--r-- | sandbox/win/tests/validation_tests/commands.h | 37 | ||||
-rw-r--r-- | sandbox/win/tests/validation_tests/sbox_validation_tests.vcproj | 216 | ||||
-rw-r--r-- | sandbox/win/tests/validation_tests/suite.cc | 200 | ||||
-rw-r--r-- | sandbox/win/tests/validation_tests/unit_tests.cc | 16 |
14 files changed, 1933 insertions, 0 deletions
diff --git a/sandbox/win/tests/common/controller.cc b/sandbox/win/tests/common/controller.cc new file mode 100644 index 0000000..6c73c2d --- /dev/null +++ b/sandbox/win/tests/common/controller.cc @@ -0,0 +1,338 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "sandbox/tests/common/controller.h" + +#include <string> + +#include "base/process.h" +#include "base/process_util.h" +#include "base/sys_string_conversions.h" +#include "base/win/windows_version.h" +#include "sandbox/src/sandbox_factory.h" +#include "sandbox/src/sandbox_utils.h" + +namespace { + +static const int kDefaultTimeout = 3000; + +// Constructs a full path to a file inside the system32 folder. +std::wstring MakePathToSys32(const wchar_t* name, bool is_obj_man_path) { + wchar_t windows_path[MAX_PATH] = {0}; + if (0 == ::GetSystemWindowsDirectoryW(windows_path, MAX_PATH)) + return std::wstring(); + + std::wstring full_path(windows_path); + if (full_path.empty()) + return full_path; + + if (is_obj_man_path) + full_path.insert(0, L"\\??\\"); + + full_path += L"\\system32\\"; + full_path += name; + return full_path; +} + +// Constructs a full path to a file inside the syswow64 folder. +std::wstring MakePathToSysWow64(const wchar_t* name, bool is_obj_man_path) { + wchar_t windows_path[MAX_PATH] = {0}; + if (0 == ::GetSystemWindowsDirectoryW(windows_path, MAX_PATH)) + return std::wstring(); + + std::wstring full_path(windows_path); + if (full_path.empty()) + return full_path; + + if (is_obj_man_path) + full_path.insert(0, L"\\??\\"); + + full_path += L"\\SysWOW64\\"; + full_path += name; + return full_path; +} + +bool IsProcessRunning(HANDLE process) { + DWORD exit_code = 0; + if (::GetExitCodeProcess(process, &exit_code)) + return exit_code == STILL_ACTIVE; + return false; +} + +} // namespace + +namespace sandbox { + +std::wstring MakePathToSys(const wchar_t* name, bool is_obj_man_path) { + return (base::win::OSInfo::GetInstance()->wow64_status() == + base::win::OSInfo::WOW64_ENABLED) ? + MakePathToSysWow64(name, is_obj_man_path) : + MakePathToSys32(name, is_obj_man_path); +} + +BrokerServices* GetBroker() { + static BrokerServices* broker = SandboxFactory::GetBrokerServices(); + static bool is_initialized = false; + + if (!broker) { + return NULL; + } + + if (!is_initialized) { + if (SBOX_ALL_OK != broker->Init()) + return NULL; + + is_initialized = true; + } + + return broker; +} + +TestRunner::TestRunner(JobLevel job_level, TokenLevel startup_token, + TokenLevel main_token) + : is_init_(false), is_async_(false), no_sandbox_(false), + target_process_id_(0) { + Init(job_level, startup_token, main_token); +} + +TestRunner::TestRunner() + : is_init_(false), is_async_(false), no_sandbox_(false), + target_process_id_(0) { + Init(JOB_LOCKDOWN, USER_RESTRICTED_SAME_ACCESS, USER_LOCKDOWN); +} + +void TestRunner::Init(JobLevel job_level, TokenLevel startup_token, + TokenLevel main_token) { + broker_ = NULL; + policy_ = NULL; + timeout_ = kDefaultTimeout; + state_ = AFTER_REVERT; + is_async_= false; + target_process_id_ = 0; + + broker_ = GetBroker(); + if (!broker_) + return; + + policy_ = broker_->CreatePolicy(); + if (!policy_) + return; + + policy_->SetJobLevel(job_level, 0); + policy_->SetTokenLevel(startup_token, main_token); + + is_init_ = true; +} + +TargetPolicy* TestRunner::GetPolicy() { + return policy_; +} + +TestRunner::~TestRunner() { + if (target_process_) + ::TerminateProcess(target_process_, 0); + + if (policy_) + policy_->Release(); +} + +bool TestRunner::AddRule(TargetPolicy::SubSystem subsystem, + TargetPolicy::Semantics semantics, + const wchar_t* pattern) { + if (!is_init_) + return false; + + return (SBOX_ALL_OK == policy_->AddRule(subsystem, semantics, pattern)); +} + +bool TestRunner::AddRuleSys32(TargetPolicy::Semantics semantics, + const wchar_t* pattern) { + if (!is_init_) + return false; + + std::wstring win32_path = MakePathToSys32(pattern, false); + if (win32_path.empty()) + return false; + + if (!AddRule(TargetPolicy::SUBSYS_FILES, semantics, win32_path.c_str())) + return false; + + if (base::win::OSInfo::GetInstance()->wow64_status() != + base::win::OSInfo::WOW64_ENABLED) + return true; + + win32_path = MakePathToSysWow64(pattern, false); + if (win32_path.empty()) + return false; + + return AddRule(TargetPolicy::SUBSYS_FILES, semantics, win32_path.c_str()); +} + +bool TestRunner::AddFsRule(TargetPolicy::Semantics semantics, + const wchar_t* pattern) { + if (!is_init_) + return false; + + return AddRule(TargetPolicy::SUBSYS_FILES, semantics, pattern); +} + +int TestRunner::RunTest(const wchar_t* command) { + if (MAX_STATE > 10) + return SBOX_TEST_INVALID_PARAMETER; + + wchar_t state_number[2]; + state_number[0] = L'0' + state_; + state_number[1] = L'\0'; + std::wstring full_command(state_number); + full_command += L" "; + full_command += command; + + return InternalRunTest(full_command.c_str()); +} + +int TestRunner::InternalRunTest(const wchar_t* command) { + if (!is_init_) + return SBOX_TEST_FAILED_TO_RUN_TEST; + + // For simplicity TestRunner supports only one process per instance. + if (target_process_) { + if (IsProcessRunning(target_process_)) + return SBOX_TEST_FAILED_TO_RUN_TEST; + target_process_.Close(); + target_process_id_ = 0; + } + + // Get the path to the sandboxed process. + wchar_t prog_name[MAX_PATH]; + GetModuleFileNameW(NULL, prog_name, MAX_PATH); + + // Launch the sandboxed process. + ResultCode result = SBOX_ALL_OK; + PROCESS_INFORMATION target = {0}; + + std::wstring arguments(L"\""); + arguments += prog_name; + arguments += L"\" -child"; + arguments += no_sandbox_ ? L"-no-sandbox " : L" "; + arguments += command; + + if (no_sandbox_) { + STARTUPINFO startup_info = {sizeof(STARTUPINFO)}; + if (!::CreateProcessW(prog_name, &arguments[0], NULL, NULL, FALSE, 0, + NULL, NULL, &startup_info, &target)) { + return SBOX_ERROR_GENERIC; + } + broker_->AddTargetPeer(target.hProcess); + } else { + result = broker_->SpawnTarget(prog_name, arguments.c_str(), policy_, + &target); + } + + if (SBOX_ALL_OK != result) + return SBOX_TEST_FAILED_TO_RUN_TEST; + + ::ResumeThread(target.hThread); + + // For an asynchronous run we don't bother waiting. + if (is_async_) { + target_process_.Set(target.hProcess); + target_process_id_ = target.dwProcessId; + ::CloseHandle(target.hThread); + return SBOX_TEST_SUCCEEDED; + } + + if (::IsDebuggerPresent()) { + // Don't kill the target process on a time-out while we are debugging. + timeout_ = INFINITE; + } + + if (WAIT_TIMEOUT == ::WaitForSingleObject(target.hProcess, timeout_)) { + ::TerminateProcess(target.hProcess, SBOX_TEST_TIMED_OUT); + ::CloseHandle(target.hProcess); + ::CloseHandle(target.hThread); + return SBOX_TEST_TIMED_OUT; + } + + DWORD exit_code = SBOX_TEST_LAST_RESULT; + if (!::GetExitCodeProcess(target.hProcess, &exit_code)) { + ::CloseHandle(target.hProcess); + ::CloseHandle(target.hThread); + return SBOX_TEST_FAILED_TO_RUN_TEST; + } + + ::CloseHandle(target.hProcess); + ::CloseHandle(target.hThread); + + return exit_code; +} + +void TestRunner::SetTimeout(DWORD timeout_ms) { + timeout_ = timeout_ms; +} + +void TestRunner::SetTestState(SboxTestsState desired_state) { + state_ = desired_state; +} + +// This is the main procedure for the target (child) application. We'll find out +// the target test and call it. +// We expect the arguments to be: +// argv[1] = "-child" +// argv[2] = SboxTestsState when to run the command +// argv[3] = command to run +// argv[4...] = command arguments. +int DispatchCall(int argc, wchar_t **argv) { + if (argc < 4) + return SBOX_TEST_INVALID_PARAMETER; + + // We hard code two tests to avoid dispatch failures. + if (0 == _wcsicmp(argv[3], L"wait")) { + Sleep(INFINITE); + return SBOX_TEST_TIMED_OUT; + } + + if (0 == _wcsicmp(argv[3], L"ping")) + return SBOX_TEST_PING_OK; + + SboxTestsState state = static_cast<SboxTestsState>(_wtoi(argv[2])); + if ((state <= MIN_STATE) || (state >= MAX_STATE)) + return SBOX_TEST_INVALID_PARAMETER; + + HMODULE module; + if (!GetModuleHandleHelper(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | + GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + reinterpret_cast<wchar_t*>(&DispatchCall), + &module)) + return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; + + std::string command_name = base::SysWideToMultiByte(argv[3], CP_UTF8); + CommandFunction command = reinterpret_cast<CommandFunction>( + ::GetProcAddress(module, command_name.c_str())); + if (!command) + return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; + + if (BEFORE_INIT == state) + return command(argc - 4, argv + 4); + else if (EVERY_STATE == state) + command(argc - 4, argv + 4); + + TargetServices* target = SandboxFactory::GetTargetServices(); + if (target) { + if (SBOX_ALL_OK != target->Init()) + return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; + + if (BEFORE_REVERT == state) + return command(argc - 4, argv + 4); + else if (EVERY_STATE == state) + command(argc - 4, argv + 4); + + target->LowerToken(); + } else if (0 != _wcsicmp(argv[1], L"-child-no-sandbox")) { + return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; + } + + return command(argc - 4, argv + 4); +} + +} // namespace sandbox diff --git a/sandbox/win/tests/common/controller.h b/sandbox/win/tests/common/controller.h new file mode 100644 index 0000000..5c2a471 --- /dev/null +++ b/sandbox/win/tests/common/controller.h @@ -0,0 +1,145 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SANDBOX_TESTS_COMMON_CONTROLLER_H_ +#define SANDBOX_TESTS_COMMON_CONTROLLER_H__ + +#include <windows.h> +#include <string> + +#include "base/win/scoped_handle.h" +#include "sandbox/src/sandbox.h" + +namespace sandbox { + +// See winerror.h for details. +#define SEVERITY_INFO_FLAGS 0x40000000 +#define SEVERITY_ERROR_FLAGS 0xC0000000 +#define CUSTOMER_CODE 0x20000000 +#define SBOX_TESTS_FACILITY 0x05B10000 + +// All the possible error codes returned by the child process in +// the sandbox. +enum SboxTestResult { + SBOX_TEST_FIRST_RESULT = CUSTOMER_CODE | SBOX_TESTS_FACILITY, + SBOX_TEST_SUCCEEDED, + SBOX_TEST_PING_OK, + SBOX_TEST_FIRST_INFO = SBOX_TEST_FIRST_RESULT | SEVERITY_INFO_FLAGS, + SBOX_TEST_DENIED, // Access was denied. + SBOX_TEST_NOT_FOUND, // The resource was not found. + SBOX_TEST_FIRST_ERROR = SBOX_TEST_FIRST_RESULT | SEVERITY_ERROR_FLAGS, + SBOX_TEST_INVALID_PARAMETER, + SBOX_TEST_FAILED_TO_RUN_TEST, + SBOX_TEST_FAILED_TO_EXECUTE_COMMAND, + SBOX_TEST_TIMED_OUT, + SBOX_TEST_FAILED, + SBOX_TEST_LAST_RESULT +}; + +inline bool IsSboxTestsResult(SboxTestResult result) { + unsigned int code = static_cast<unsigned int>(result); + unsigned int first = static_cast<unsigned int>(SBOX_TEST_FIRST_RESULT); + unsigned int last = static_cast<unsigned int>(SBOX_TEST_LAST_RESULT); + return (code > first) && (code < last); +} + +enum SboxTestsState { + MIN_STATE = 1, + BEFORE_INIT, + BEFORE_REVERT, + AFTER_REVERT, + EVERY_STATE, + MAX_STATE +}; + +#define SBOX_TESTS_API __declspec(dllexport) +#define SBOX_TESTS_COMMAND extern "C" SBOX_TESTS_API + +extern "C" { +typedef int (*CommandFunction)(int argc, wchar_t **argv); +} + +// Class to facilitate the launch of a test inside the sandbox. +class TestRunner { + public: + TestRunner(JobLevel job_level, TokenLevel startup_token, + TokenLevel main_token); + + TestRunner(); + + ~TestRunner(); + + // Adds a rule to the policy. The parameters are the same as the AddRule + // function in the sandbox. + bool AddRule(TargetPolicy::SubSystem subsystem, + TargetPolicy::Semantics semantics, + const wchar_t* pattern); + + // Adds a filesystem rules with the path of a file in system32. The function + // appends "pattern" to "system32" and then call AddRule. Return true if the + // function succeeds. + bool AddRuleSys32(TargetPolicy::Semantics semantics, const wchar_t* pattern); + + // Adds a filesystem rules to the policy. Returns true if the functions + // succeeds. + bool AddFsRule(TargetPolicy::Semantics semantics, const wchar_t* pattern); + + // Starts a child process in the sandbox and ask it to run |command|. Returns + // a SboxTestResult. By default, the test runs AFTER_REVERT. + int RunTest(const wchar_t* command); + + // Sets the timeout value for the child to run the command and return. + void SetTimeout(DWORD timeout_ms); + + // Sets TestRunner to return without waiting for the process to exit. + void SetAsynchronous(bool is_async) { is_async_ = is_async; } + + // Sets TestRunner to return without waiting for the process to exit. + void SetUnsandboxed(bool is_no_sandbox) { no_sandbox_ = is_no_sandbox; } + + // Sets the desired state for the test to run. + void SetTestState(SboxTestsState desired_state); + + // Returns the pointers to the policy object. It can be used to modify + // the policy manually. + TargetPolicy* GetPolicy(); + + // Return the process handle for an asynchronous test. + HANDLE process() { return target_process_; } + + // Return the process ID for an asynchronous test. + DWORD process_id() { return target_process_id_; } + + private: + // Initializes the data in the object. Sets is_init_ to tree if the + // function succeeds. This is meant to be called from the constructor. + void Init(JobLevel job_level, TokenLevel startup_token, + TokenLevel main_token); + + // The actual runner. + int InternalRunTest(const wchar_t* command); + + BrokerServices* broker_; + TargetPolicy* policy_; + DWORD timeout_; + SboxTestsState state_; + bool is_init_; + bool is_async_; + bool no_sandbox_; + base::win::ScopedHandle target_process_; + DWORD target_process_id_; +}; + +// Returns the broker services. +BrokerServices* GetBroker(); + +// Constructs a full path to a file inside the system32 (or syswow64) folder. +std::wstring MakePathToSys(const wchar_t* name, bool is_obj_man_path); + +// Runs the given test on the target process. +int DispatchCall(int argc, wchar_t **argv); + +} // namespace sandbox + +#endif // SANDBOX_TESTS_COMMON_CONTROLLER_H_ diff --git a/sandbox/win/tests/common/test_utils.cc b/sandbox/win/tests/common/test_utils.cc new file mode 100644 index 0000000..929c322 --- /dev/null +++ b/sandbox/win/tests/common/test_utils.cc @@ -0,0 +1,72 @@ +// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "sandbox/tests/common/test_utils.h" + +#include <winioctl.h> + +typedef struct _REPARSE_DATA_BUFFER { + ULONG ReparseTag; + USHORT ReparseDataLength; + USHORT Reserved; + union { + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + ULONG Flags; + WCHAR PathBuffer[1]; + } SymbolicLinkReparseBuffer; + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + WCHAR PathBuffer[1]; + } MountPointReparseBuffer; + struct { + UCHAR DataBuffer[1]; + } GenericReparseBuffer; + }; +} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; + +// Sets a reparse point. |source| will now point to |target|. Returns true if +// the call succeeds, false otherwise. +bool SetReparsePoint(HANDLE source, const wchar_t* target) { + USHORT size_target = static_cast<USHORT>(wcslen(target)) * sizeof(target[0]); + + char buffer[2000] = {0}; + DWORD returned; + + REPARSE_DATA_BUFFER* data = reinterpret_cast<REPARSE_DATA_BUFFER*>(buffer); + + data->ReparseTag = 0xa0000003; + memcpy(data->MountPointReparseBuffer.PathBuffer, target, size_target + 2); + data->MountPointReparseBuffer.SubstituteNameLength = size_target; + data->MountPointReparseBuffer.PrintNameOffset = size_target + 2; + data->ReparseDataLength = size_target + 4 + 8; + + int data_size = data->ReparseDataLength + 8; + + if (!DeviceIoControl(source, FSCTL_SET_REPARSE_POINT, &buffer, data_size, + NULL, 0, &returned, NULL)) { + return false; + } + return true; +} + +// Delete the reparse point referenced by |source|. Returns true if the call +// succeeds, false otherwise. +bool DeleteReparsePoint(HANDLE source) { + DWORD returned; + REPARSE_DATA_BUFFER data = {0}; + data.ReparseTag = 0xa0000003; + if (!DeviceIoControl(source, FSCTL_DELETE_REPARSE_POINT, &data, 8, NULL, 0, + &returned, NULL)) { + return false; + } + + return true; +} diff --git a/sandbox/win/tests/common/test_utils.h b/sandbox/win/tests/common/test_utils.h new file mode 100644 index 0000000..9e17660 --- /dev/null +++ b/sandbox/win/tests/common/test_utils.h @@ -0,0 +1,19 @@ +// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SANDBOX_TESTS_COMMON_TEST_UTILS_H_ +#define SANDBOX_TESTS_COMMON_TEST_UTILS_H_ + +#include <windows.h> + +// Sets a reparse point. |source| will now point to |target|. Returns true if +// the call succeeds, false otherwise. +bool SetReparsePoint(HANDLE source, const wchar_t* target); + +// Delete the reparse point referenced by |source|. Returns true if the call +// succeeds, false otherwise. +bool DeleteReparsePoint(HANDLE source); + +#endif // SANDBOX_TESTS_COMMON_TEST_UTILS_H_ + diff --git a/sandbox/win/tests/integration_tests/integration_tests.cc b/sandbox/win/tests/integration_tests/integration_tests.cc new file mode 100644 index 0000000..5096abb --- /dev/null +++ b/sandbox/win/tests/integration_tests/integration_tests.cc @@ -0,0 +1,18 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "testing/gtest/include/gtest/gtest.h" +#include "sandbox/tests/common/controller.h" + +int wmain(int argc, wchar_t **argv) { + if (argc >= 2) { + if (0 == _wcsicmp(argv[1], L"-child") || + 0 == _wcsicmp(argv[1], L"-child-no-sandbox")) + // This instance is a child, not the test. + return sandbox::DispatchCall(argc, argv); + } + + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/sandbox/win/tests/integration_tests/integration_tests_test.cc b/sandbox/win/tests/integration_tests/integration_tests_test.cc new file mode 100644 index 0000000..b610681 --- /dev/null +++ b/sandbox/win/tests/integration_tests/integration_tests_test.cc @@ -0,0 +1,94 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Some tests for the framework itself. + +#include "testing/gtest/include/gtest/gtest.h" +#include "sandbox/src/sandbox.h" +#include "sandbox/src/target_services.h" +#include "sandbox/src/sandbox_factory.h" +#include "sandbox/tests/common/controller.h" + +namespace sandbox { + +// Returns the current process state. +SBOX_TESTS_COMMAND int IntegrationTestsTest_state(int argc, wchar_t **argv) { + if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled()) + return BEFORE_INIT; + + if (!SandboxFactory::GetTargetServices()->GetState()->RevertedToSelf()) + return BEFORE_REVERT; + + return AFTER_REVERT; +} + +// Returns the current process state, keeping track of it. +SBOX_TESTS_COMMAND int IntegrationTestsTest_state2(int argc, wchar_t **argv) { + static SboxTestsState state = MIN_STATE; + if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled()) { + if (MIN_STATE == state) + state = BEFORE_INIT; + return state; + } + + if (!SandboxFactory::GetTargetServices()->GetState()->RevertedToSelf()) { + if (BEFORE_INIT == state) + state = BEFORE_REVERT; + return state; + } + + if (BEFORE_REVERT == state) + state = AFTER_REVERT; + return state; +} + +// Returns the number of arguments +SBOX_TESTS_COMMAND int IntegrationTestsTest_args(int argc, wchar_t **argv) { + for (int i = 0; i < argc; i++) { + wchar_t argument[20]; + size_t argument_bytes = wcslen(argv[i]) * sizeof(wchar_t); + memcpy(argument, argv[i], __min(sizeof(argument), argument_bytes)); + } + + return argc; +} + +TEST(IntegrationTestsTest, CallsBeforeInit) { + TestRunner runner; + runner.SetTimeout(2000); + runner.SetTestState(BEFORE_INIT); + ASSERT_EQ(BEFORE_INIT, runner.RunTest(L"IntegrationTestsTest_state")); +} + +TEST(IntegrationTestsTest, CallsBeforeRevert) { + TestRunner runner; + runner.SetTimeout(2000); + runner.SetTestState(BEFORE_REVERT); + ASSERT_EQ(BEFORE_REVERT, runner.RunTest(L"IntegrationTestsTest_state")); +} + +TEST(IntegrationTestsTest, CallsAfterRevert) { + TestRunner runner; + runner.SetTimeout(2000); + runner.SetTestState(AFTER_REVERT); + ASSERT_EQ(AFTER_REVERT, runner.RunTest(L"IntegrationTestsTest_state")); +} + +TEST(IntegrationTestsTest, CallsEveryState) { + TestRunner runner; + runner.SetTimeout(2000); + runner.SetTestState(EVERY_STATE); + ASSERT_EQ(AFTER_REVERT, runner.RunTest(L"IntegrationTestsTest_state2")); +} + +TEST(IntegrationTestsTest, ForwardsArguments) { + TestRunner runner; + runner.SetTimeout(2000); + runner.SetTestState(BEFORE_INIT); + ASSERT_EQ(1, runner.RunTest(L"IntegrationTestsTest_args first")); + ASSERT_EQ(4, runner.RunTest(L"IntegrationTestsTest_args first second third " + L"fourth")); +} + +} // namespace sandbox diff --git a/sandbox/win/tests/integration_tests/sbox_integration_tests.vcproj b/sandbox/win/tests/integration_tests/sbox_integration_tests.vcproj new file mode 100644 index 0000000..53816e7 --- /dev/null +++ b/sandbox/win/tests/integration_tests/sbox_integration_tests.vcproj @@ -0,0 +1,242 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="8.00" + Name="sbox_integration_tests" + ProjectGUID="{542D4B3B-98D4-4233-B68D-0103891508C6}" + RootNamespace="unit_tests" + Keyword="Win32Proj" + > + <Platforms> + <Platform + Name="Win32" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|Win32" + ConfigurationType="1" + InheritedPropertySheets="$(SolutionDir)..\build\debug.vsprops;$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\testing\using_gtest.vsprops" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + PreprocessorDefinitions="_CONSOLE" + UsePrecompiledHeader="2" + ForcedIncludeFiles="stdafx.h" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalOptions="/safeseh /dynamicbase /ignore:4199 $(NoInherit)" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|Win32" + ConfigurationType="1" + InheritedPropertySheets="$(SolutionDir)..\build\release.vsprops;$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\testing\using_gtest.vsprops" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + PreprocessorDefinitions="_CONSOLE" + UsePrecompiledHeader="0" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalOptions="/safeseh /dynamicbase /ignore:4199 $(NoInherit)" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Common" + Filter="h;hpp;hxx;hm;inl;inc;xsd" + UniqueIdentifier="{49F2D231-E141-4455-B241-7D37C09B6EEB}" + > + <File + RelativePath="..\common\controller.cc" + > + </File> + <File + RelativePath="..\common\controller.h" + > + </File> + <File + RelativePath="..\..\..\testing\gtest\src\gtest.cc" + > + </File> + <File + RelativePath=".\integration_tests.cc" + > + </File> + <File + RelativePath=".\stdafx.cc" + > + <FileConfiguration + Name="Debug|Win32" + > + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="1" + /> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + > + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0" + /> + </FileConfiguration> + </File> + <File + RelativePath=".\stdafx.h" + > + </File> + </Filter> + <File + RelativePath="..\..\src\dep_test.cc" + > + </File> + <File + RelativePath="..\..\src\file_policy_test.cc" + > + </File> + <File + RelativePath=".\integration_tests_test.cc" + > + </File> + <File + RelativePath="..\..\src\integrity_level_test.cc" + > + </File> + <File + RelativePath="..\..\src\ipc_ping_test.cc" + > + </File> + <File + RelativePath="..\..\src\named_pipe_policy_test.cc" + > + </File> + <File + RelativePath="..\..\src\policy_target_test.cc" + > + </File> + <File + RelativePath="..\..\src\process_policy_test.cc" + > + </File> + <File + RelativePath="..\..\src\registry_policy_test.cc" + > + </File> + <File + RelativePath="..\..\src\sync_policy_test.cc" + > + </File> + <File + RelativePath="..\..\src\unload_dll_test.cc" + > + </File> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/sandbox/win/tests/unit_tests/sbox_unittests.vcproj b/sandbox/win/tests/unit_tests/sbox_unittests.vcproj new file mode 100644 index 0000000..a2df792 --- /dev/null +++ b/sandbox/win/tests/unit_tests/sbox_unittests.vcproj @@ -0,0 +1,258 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="8.00" + Name="sbox_unittests" + ProjectGUID="{883553BE-2A9D-418C-A121-61FE1DFBC562}" + RootNamespace="unit_tests" + Keyword="Win32Proj" + > + <Platforms> + <Platform + Name="Win32" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|Win32" + ConfigurationType="1" + InheritedPropertySheets="$(SolutionDir)..\build\debug.vsprops;$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\testing\using_gtest.vsprops" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + PreprocessorDefinitions="_CONSOLE" + UsePrecompiledHeader="2" + WarningLevel="3" + ForcedIncludeFiles="stdafx.h" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|Win32" + ConfigurationType="1" + InheritedPropertySheets="$(SolutionDir)..\build\release.vsprops;$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\testing\using_gtest.vsprops" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + PreprocessorDefinitions="_CONSOLE" + UsePrecompiledHeader="0" + WarningLevel="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Common" + Filter="h;hpp;hxx;hm;inl;inc;xsd" + UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" + > + <File + RelativePath="..\..\..\testing\gtest\src\gtest.cc" + > + </File> + <File + RelativePath=".\stdafx.cc" + > + <FileConfiguration + Name="Debug|Win32" + > + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="1" + /> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + > + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0" + /> + </FileConfiguration> + </File> + <File + RelativePath=".\stdafx.h" + > + </File> + <File + RelativePath=".\unit_tests.cc" + > + </File> + </Filter> + <Filter + Name="TestInterception" + > + <File + RelativePath="..\..\src\interception_unittest.cc" + > + </File> + <File + RelativePath="..\..\src\pe_image_unittest.cc" + > + </File> + <File + RelativePath="..\..\src\service_resolver_unittest.cc" + > + </File> + </Filter> + <Filter + Name="TestRestrictedToken" + > + <File + RelativePath="..\..\src\restricted_token_unittest.cc" + > + </File> + </Filter> + <Filter + Name="TestJob" + > + <File + RelativePath="..\..\src\job_unittest.cc" + > + </File> + </Filter> + <Filter + Name="Sid" + > + <File + RelativePath="..\..\src\sid_unittest.cc" + > + </File> + </Filter> + <Filter + Name="Policy" + > + <File + RelativePath="..\..\src\policy_engine_unittest.cc" + > + </File> + <File + RelativePath="..\..\src\policy_low_level_unittest.cc" + > + </File> + <File + RelativePath="..\..\src\policy_opcodes_unittest.cc" + > + </File> + </Filter> + <Filter + Name="IPC" + > + <File + RelativePath="..\..\src\ipc_unittest.cc" + > + </File> + <File + RelativePath="..\..\src\threadpool_unittest.cc" + > + </File> + </Filter> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/sandbox/win/tests/unit_tests/unit_tests.cc b/sandbox/win/tests/unit_tests/unit_tests.cc new file mode 100644 index 0000000..a9623db --- /dev/null +++ b/sandbox/win/tests/unit_tests/unit_tests.cc @@ -0,0 +1,16 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "testing/gtest/include/gtest/gtest.h" + +int wmain(int argc, wchar_t **argv) { + if (argc >= 2) { + if (0 == _wcsicmp(argv[1], L"-child")) + // This instance is a child, not the test. + return 0; + } + + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/sandbox/win/tests/validation_tests/commands.cc b/sandbox/win/tests/validation_tests/commands.cc new file mode 100644 index 0000000..d99451f --- /dev/null +++ b/sandbox/win/tests/validation_tests/commands.cc @@ -0,0 +1,262 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <windows.h> +#include <string> + +#include "sandbox/tests/validation_tests/commands.h" + +#include "sandbox/tests/common/controller.h" + +namespace { + +// Returns the HKEY corresponding to name. If there is no HKEY corresponding +// to the name it returns NULL. +HKEY GetHKEYFromString(const std::wstring &name) { + if (L"HKLM" == name) + return HKEY_LOCAL_MACHINE; + else if (L"HKCR" == name) + return HKEY_CLASSES_ROOT; + else if (L"HKCC" == name) + return HKEY_CURRENT_CONFIG; + else if (L"HKCU" == name) + return HKEY_CURRENT_USER; + else if (L"HKU" == name) + return HKEY_USERS; + + return NULL; +} + +// Modifies string to remove the leading and trailing quotes. +void trim_quote(std::wstring* string) { + std::wstring::size_type pos1 = string->find_first_not_of(L'"'); + std::wstring::size_type pos2 = string->find_last_not_of(L'"'); + + if (std::wstring::npos == pos1 || std::wstring::npos == pos2) + (*string) = L""; + else + (*string) = string->substr(pos1, pos2 + 1); +} + +int TestOpenFile(std::wstring path, bool for_write) { + wchar_t path_expanded[MAX_PATH + 1] = {0}; + DWORD size = ::ExpandEnvironmentStrings(path.c_str(), path_expanded, + MAX_PATH); + if (!size) + return sandbox::SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; + + HANDLE file; + file = ::CreateFile(path_expanded, + for_write ? GENERIC_READ | GENERIC_WRITE : GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, // No security attributes. + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL); // No template. + + if (INVALID_HANDLE_VALUE != file) { + ::CloseHandle(file); + return sandbox::SBOX_TEST_SUCCEEDED; + } else { + if (ERROR_ACCESS_DENIED == ::GetLastError()) { + return sandbox::SBOX_TEST_DENIED; + } else { + return sandbox::SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; + } + } +} + +} // namespace + +namespace sandbox { + +SBOX_TESTS_COMMAND int ValidWindow(int argc, wchar_t **argv) { + if (1 != argc) + return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; + + HWND window = reinterpret_cast<HWND>(static_cast<ULONG_PTR>(_wtoi(argv[0]))); + + return TestValidWindow(window); +} + +int TestValidWindow(HWND window) { + if (::IsWindow(window)) + return SBOX_TEST_SUCCEEDED; + + return SBOX_TEST_DENIED; +} + +SBOX_TESTS_COMMAND int OpenProcessCmd(int argc, wchar_t **argv) { + if (2 != argc) + return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; + + DWORD process_id = _wtol(argv[0]); + DWORD access_mask = _wtol(argv[1]); + return TestOpenProcess(process_id, access_mask); +} + +int TestOpenProcess(DWORD process_id, DWORD access_mask) { + HANDLE process = ::OpenProcess(access_mask, + FALSE, // Do not inherit handle. + process_id); + if (NULL == process) { + if (ERROR_ACCESS_DENIED == ::GetLastError()) { + return SBOX_TEST_DENIED; + } else { + return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; + } + } else { + ::CloseHandle(process); + return SBOX_TEST_SUCCEEDED; + } +} + +SBOX_TESTS_COMMAND int OpenThreadCmd(int argc, wchar_t **argv) { + if (1 != argc) + return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; + + DWORD thread_id = _wtoi(argv[0]); + return TestOpenThread(thread_id); +} + +int TestOpenThread(DWORD thread_id) { + + HANDLE thread = ::OpenThread(THREAD_QUERY_INFORMATION, + FALSE, // Do not inherit handles. + thread_id); + + if (NULL == thread) { + if (ERROR_ACCESS_DENIED == ::GetLastError()) { + return SBOX_TEST_DENIED; + } else { + return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; + } + } else { + ::CloseHandle(thread); + return SBOX_TEST_SUCCEEDED; + } +} + +SBOX_TESTS_COMMAND int OpenFile(int argc, wchar_t **argv) { + if (1 != argc) + return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; + + std::wstring path = argv[0]; + trim_quote(&path); + + return TestOpenReadFile(path); +} + +int TestOpenReadFile(const std::wstring& path) { + return TestOpenFile(path, false); +} + +int TestOpenWriteFile(int argc, wchar_t **argv) { + if (1 != argc) + return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; + + std::wstring path = argv[0]; + trim_quote(&path); + + return TestOpenWriteFile(path); + } + +int TestOpenWriteFile(const std::wstring& path) { + return TestOpenFile(path, true); +} + +SBOX_TESTS_COMMAND int OpenKey(int argc, wchar_t **argv) { + if (0 == argc || argc > 2) + return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; + + // Get the hive. + HKEY base_key = GetHKEYFromString(argv[0]); + + // Get the subkey. + std::wstring subkey; + if (2 == argc) { + subkey = argv[1]; + trim_quote(&subkey); + } + + return TestOpenKey(base_key, subkey); +} + +int TestOpenKey(HKEY base_key, std::wstring subkey) { + HKEY key; + LONG err_code = ::RegOpenKeyEx(base_key, + subkey.c_str(), + 0, // Reserved, must be 0. + MAXIMUM_ALLOWED, + &key); + if (ERROR_SUCCESS == err_code) { + ::RegCloseKey(key); + return SBOX_TEST_SUCCEEDED; + } else if (ERROR_INVALID_HANDLE == err_code || + ERROR_ACCESS_DENIED == err_code) { + return SBOX_TEST_DENIED; + } else { + return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; + } +} + +// Returns true if the current's thread desktop is the interactive desktop. +// In Vista there is a more direct test but for XP and w2k we need to check +// the object name. +bool IsInteractiveDesktop(bool* is_interactive) { + HDESK current_desk = ::GetThreadDesktop(::GetCurrentThreadId()); + if (NULL == current_desk) { + return false; + } + wchar_t current_desk_name[256] = {0}; + if (!::GetUserObjectInformationW(current_desk, UOI_NAME, current_desk_name, + sizeof(current_desk_name), NULL)) { + return false; + } + *is_interactive = (0 == _wcsicmp(L"default", current_desk_name)); + return true; +} + +SBOX_TESTS_COMMAND int OpenInteractiveDesktop(int, wchar_t **) { + return TestOpenInputDesktop(); +} + +int TestOpenInputDesktop() { + bool is_interactive = false; + if (IsInteractiveDesktop(&is_interactive) && is_interactive) { + return SBOX_TEST_SUCCEEDED; + } + HDESK desk = ::OpenInputDesktop(0, FALSE, DESKTOP_CREATEWINDOW); + if (desk) { + ::CloseDesktop(desk); + return SBOX_TEST_SUCCEEDED; + } + return SBOX_TEST_DENIED; +} + +SBOX_TESTS_COMMAND int SwitchToSboxDesktop(int, wchar_t **) { + return TestSwitchDesktop(); +} + +int TestSwitchDesktop() { + HDESK sbox_desk = ::GetThreadDesktop(::GetCurrentThreadId()); + if (NULL == sbox_desk) { + return SBOX_TEST_FAILED; + } + if (::SwitchDesktop(sbox_desk)) { + return SBOX_TEST_SUCCEEDED; + } + return SBOX_TEST_DENIED; +} + +SBOX_TESTS_COMMAND int SleepCmd(int argc, wchar_t **argv) { + if (1 != argc) + return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; + + ::Sleep(_wtoi(argv[0])); + return SBOX_TEST_SUCCEEDED; +} + + +} // namespace sandbox diff --git a/sandbox/win/tests/validation_tests/commands.h b/sandbox/win/tests/validation_tests/commands.h new file mode 100644 index 0000000..9b797a5 --- /dev/null +++ b/sandbox/win/tests/validation_tests/commands.h @@ -0,0 +1,37 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SANDBOX_TESTS_VALIDATION_TESTS_COMMANDS_H__ +#define SANDBOX_TESTS_VALIDATION_TESTS_COMMANDS_H__ + +namespace sandbox { + +// Checks if window is a real window. Returns a SboxTestResult. +int TestValidWindow(HWND window); + +// Tries to open the process_id. Returns a SboxTestResult. +int TestOpenProcess(DWORD process_id, DWORD access_mask); + +// Tries to open thread_id. Returns a SboxTestResult. +int TestOpenThread(DWORD thread_id); + +// Tries to open path for read access. Returns a SboxTestResult. +int TestOpenReadFile(const std::wstring& path); + +// Tries to open path for write access. Returns a SboxTestResult. +int TestOpenWriteFile(const std::wstring& path); + +// Tries to open a registry key. +int TestOpenKey(HKEY base_key, std::wstring subkey); + +// Tries to open the workstation's input desktop as long as the +// current desktop is not the interactive one. Returns a SboxTestResult. +int TestOpenInputDesktop(); + +// Tries to switch the interactive desktop. Returns a SboxTestResult. +int TestSwitchDesktop(); + +} // namespace sandbox + +#endif // SANDBOX_TESTS_VALIDATION_TESTS_COMMANDS_H__ diff --git a/sandbox/win/tests/validation_tests/sbox_validation_tests.vcproj b/sandbox/win/tests/validation_tests/sbox_validation_tests.vcproj new file mode 100644 index 0000000..9b7b599 --- /dev/null +++ b/sandbox/win/tests/validation_tests/sbox_validation_tests.vcproj @@ -0,0 +1,216 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="8.00" + Name="sbox_validation_tests" + ProjectGUID="{B9CC7B0D-145A-49C2-B887-84E43CFA0F27}" + RootNamespace="unit_tests" + Keyword="Win32Proj" + > + <Platforms> + <Platform + Name="Win32" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|Win32" + ConfigurationType="1" + InheritedPropertySheets="$(SolutionDir)..\build\debug.vsprops;$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\testing\using_gtest.vsprops" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + PreprocessorDefinitions="_CONSOLE" + UsePrecompiledHeader="2" + WarningLevel="3" + ForcedIncludeFiles="stdafx.h" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="shlwapi.lib" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|Win32" + ConfigurationType="1" + InheritedPropertySheets="$(SolutionDir)..\build\release.vsprops;$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\testing\using_gtest.vsprops" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + PreprocessorDefinitions="_CONSOLE" + UsePrecompiledHeader="0" + WarningLevel="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="shlwapi.lib" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Common" + Filter="h;hpp;hxx;hm;inl;inc;xsd" + UniqueIdentifier="{2E6C7E35-7538-4883-B80C-C89961A80D66}" + > + <File + RelativePath="..\common\controller.cc" + > + </File> + <File + RelativePath="..\common\controller.h" + > + </File> + <File + RelativePath="..\..\..\testing\gtest\src\gtest.cc" + > + </File> + <File + RelativePath=".\stdafx.cc" + > + <FileConfiguration + Name="Debug|Win32" + > + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="1" + /> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="true" + > + <Tool + Name="VCCLCompilerTool" + /> + </FileConfiguration> + </File> + <File + RelativePath=".\stdafx.h" + > + </File> + <File + RelativePath=".\unit_tests.cc" + > + </File> + </Filter> + <Filter + Name="Suite" + > + <File + RelativePath=".\commands.cc" + > + </File> + <File + RelativePath=".\commands.h" + > + </File> + <File + RelativePath=".\suite.cc" + > + </File> + </Filter> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/sandbox/win/tests/validation_tests/suite.cc b/sandbox/win/tests/validation_tests/suite.cc new file mode 100644 index 0000000..3147f70 --- /dev/null +++ b/sandbox/win/tests/validation_tests/suite.cc @@ -0,0 +1,200 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file contains the validation tests for the sandbox. +// It includes the tests that need to be performed inside the +// sandbox. + +#include <shlwapi.h> + +#include "base/win/windows_version.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "sandbox/tests/common/controller.h" + +#pragma comment(lib, "shlwapi.lib") + +namespace { + +void TestProcessAccess(sandbox::TestRunner* runner, DWORD target) { + const wchar_t *kCommandTemplate = L"OpenProcessCmd %d %d"; + wchar_t command[1024] = {0}; + + // Test all the scary process permissions. + wsprintf(command, kCommandTemplate, target, PROCESS_CREATE_THREAD); + EXPECT_EQ(sandbox::SBOX_TEST_DENIED, runner->RunTest(command)); + wsprintf(command, kCommandTemplate, target, PROCESS_DUP_HANDLE); + EXPECT_EQ(sandbox::SBOX_TEST_DENIED, runner->RunTest(command)); + wsprintf(command, kCommandTemplate, target, PROCESS_SET_INFORMATION); + EXPECT_EQ(sandbox::SBOX_TEST_DENIED, runner->RunTest(command)); + wsprintf(command, kCommandTemplate, target, PROCESS_VM_OPERATION); + EXPECT_EQ(sandbox::SBOX_TEST_DENIED, runner->RunTest(command)); + wsprintf(command, kCommandTemplate, target, PROCESS_VM_READ); + EXPECT_EQ(sandbox::SBOX_TEST_DENIED, runner->RunTest(command)); + wsprintf(command, kCommandTemplate, target, PROCESS_VM_WRITE); + EXPECT_EQ(sandbox::SBOX_TEST_DENIED, runner->RunTest(command)); + wsprintf(command, kCommandTemplate, target, PROCESS_QUERY_INFORMATION); + EXPECT_EQ(sandbox::SBOX_TEST_DENIED, runner->RunTest(command)); + wsprintf(command, kCommandTemplate, target, WRITE_DAC); + EXPECT_EQ(sandbox::SBOX_TEST_DENIED, runner->RunTest(command)); + wsprintf(command, kCommandTemplate, target, WRITE_OWNER); + EXPECT_EQ(sandbox::SBOX_TEST_DENIED, runner->RunTest(command)); + wsprintf(command, kCommandTemplate, target, READ_CONTROL); + EXPECT_EQ(sandbox::SBOX_TEST_DENIED, runner->RunTest(command)); +} + +} // namespace + +namespace sandbox { + +// Returns true if the volume that contains any_path supports ACL security. The +// input path can contain unexpanded environment strings. Returns false on any +// failure or if the file system does not support file security (such as FAT). +bool VolumeSupportsACLs(const wchar_t* any_path) { + wchar_t expand[MAX_PATH +1]; + DWORD len =::ExpandEnvironmentStringsW(any_path, expand, _countof(expand)); + if (0 == len) return false; + if (len > _countof(expand)) return false; + if (!::PathStripToRootW(expand)) return false; + DWORD fs_flags = 0; + if (!::GetVolumeInformationW(expand, NULL, 0, 0, NULL, &fs_flags, NULL, 0)) + return false; + if (fs_flags & FILE_PERSISTENT_ACLS) return true; + return false; +} + +// Tests if the suite is working properly. +TEST(ValidationSuite, TestSuite) { + TestRunner runner; + ASSERT_EQ(SBOX_TEST_PING_OK, runner.RunTest(L"ping")); +} + +// Tests if the file system is correctly protected by the sandbox. +TEST(ValidationSuite, TestFileSystem) { + // Do not perform the test if the system is using FAT or any other + // file system that does not have file security. + ASSERT_TRUE(VolumeSupportsACLs(L"%SystemDrive%\\")); + ASSERT_TRUE(VolumeSupportsACLs(L"%SystemRoot%\\")); + ASSERT_TRUE(VolumeSupportsACLs(L"%ProgramFiles%\\")); + ASSERT_TRUE(VolumeSupportsACLs(L"%Temp%\\")); + ASSERT_TRUE(VolumeSupportsACLs(L"%AppData%\\")); + + TestRunner runner; + EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"OpenFile %SystemDrive%")); + EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"OpenFile %SystemRoot%")); + EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"OpenFile %ProgramFiles%")); + EXPECT_EQ(SBOX_TEST_DENIED, + runner.RunTest(L"OpenFile %SystemRoot%\\System32")); + EXPECT_EQ(SBOX_TEST_DENIED, + runner.RunTest(L"OpenFile %SystemRoot%\\explorer.exe")); + EXPECT_EQ(SBOX_TEST_DENIED, + runner.RunTest(L"OpenFile %SystemRoot%\\Cursors\\arrow_i.cur")); + EXPECT_EQ(SBOX_TEST_DENIED, + runner.RunTest(L"OpenFile %AllUsersProfile%")); + EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"OpenFile %Temp%")); + EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"OpenFile %AppData%")); +} + +// Tests if the registry is correctly protected by the sandbox. +TEST(ValidationSuite, TestRegistry) { + TestRunner runner; + EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"OpenKey HKLM")); + EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"OpenKey HKCU")); + EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"OpenKey HKU")); + EXPECT_EQ(SBOX_TEST_DENIED, + runner.RunTest( + L"OpenKey HKLM " + L"\"Software\\Microsoft\\Windows NT\\CurrentVersion\\WinLogon\"")); +} + +// Tests that the permissions on the Windowstation does not allow the sandbox +// to get to the interactive desktop or to make the sbox desktop interactive. +TEST(ValidationSuite, TestDesktop) { + TestRunner runner; + runner.GetPolicy()->SetAlternateDesktop(false); + EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"OpenInteractiveDesktop NULL")); + EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"SwitchToSboxDesktop NULL")); +} + +// Tests if the windows are correctly protected by the sandbox. +TEST(ValidationSuite, TestWindows) { + TestRunner runner; + wchar_t command[1024] = {0}; + + wsprintf(command, L"ValidWindow %d", ::GetDesktopWindow()); + EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command)); + + wsprintf(command, L"ValidWindow %d", ::FindWindow(NULL, NULL)); + EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command)); +} + +// Tests that a locked-down process cannot open another locked-down process. +TEST(ValidationSuite, TestProcessDenyLockdown) { + TestRunner runner; + TestRunner target; + wchar_t command[1024] = {0}; + + target.SetAsynchronous(true); + + EXPECT_EQ(SBOX_TEST_SUCCEEDED, target.RunTest(L"SleepCmd 30000")); + + TestProcessAccess(&runner, target.process_id()); +} + +// Tests that a low-integrity process cannot open a locked-down process (due +// to the integrity label changing after startup via SetDelayedIntegrityLevel). +TEST(ValidationSuite, TestProcessDenyLowIntegrity) { + // This test applies only to Vista and above. + if (base::win::Version() < base::win::VERSION_VISTA) + return; + + TestRunner runner; + TestRunner target; + wchar_t command[1024] = {0}; + + target.SetAsynchronous(true); + target.GetPolicy()->SetDelayedIntegrityLevel(INTEGRITY_LEVEL_LOW); + + runner.GetPolicy()->SetIntegrityLevel(INTEGRITY_LEVEL_LOW); + runner.GetPolicy()->SetTokenLevel(USER_RESTRICTED_SAME_ACCESS, + USER_INTERACTIVE); + + EXPECT_EQ(SBOX_TEST_SUCCEEDED, target.RunTest(L"SleepCmd 30000")); + + TestProcessAccess(&runner, target.process_id()); +} + +// Tests that a locked-down process cannot open a low-integrity process. +TEST(ValidationSuite, TestProcessDenyBelowLowIntegrity) { + // This test applies only to Vista and above. + if (base::win::Version() < base::win::VERSION_VISTA) + return; + + TestRunner runner; + TestRunner target; + wchar_t command[1024] = {0}; + + target.SetAsynchronous(true); + target.GetPolicy()->SetIntegrityLevel(INTEGRITY_LEVEL_LOW); + target.GetPolicy()->SetTokenLevel(USER_RESTRICTED_SAME_ACCESS, + USER_INTERACTIVE); + + runner.GetPolicy()->SetDelayedIntegrityLevel(INTEGRITY_LEVEL_UNTRUSTED); + runner.GetPolicy()->SetTokenLevel(USER_RESTRICTED_SAME_ACCESS, + USER_INTERACTIVE); + + EXPECT_EQ(SBOX_TEST_SUCCEEDED, target.RunTest(L"SleepCmd 30000")); + + TestProcessAccess(&runner, target.process_id()); +} + +// Tests if the threads are correctly protected by the sandbox. +TEST(ValidationSuite, TestThread) { + TestRunner runner; + wchar_t command[1024] = {0}; + + wsprintf(command, L"OpenThreadCmd %d", ::GetCurrentThreadId()); + EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command)); +} + +} // namespace sandbox diff --git a/sandbox/win/tests/validation_tests/unit_tests.cc b/sandbox/win/tests/validation_tests/unit_tests.cc new file mode 100644 index 0000000..490f7ec --- /dev/null +++ b/sandbox/win/tests/validation_tests/unit_tests.cc @@ -0,0 +1,16 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "testing/gtest/include/gtest/gtest.h" +#include "sandbox/tests/common/controller.h" + +int wmain(int argc, wchar_t **argv) { + if (argc >= 2) { + if (0 == _wcsicmp(argv[1], L"-child")) + return sandbox::DispatchCall(argc, argv); + } + + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} |