summaryrefslogtreecommitdiffstats
path: root/sandbox/win/tests/common/controller.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sandbox/win/tests/common/controller.cc')
-rw-r--r--sandbox/win/tests/common/controller.cc338
1 files changed, 338 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..33dd776
--- /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/win/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/win/src/sandbox_factory.h"
+#include "sandbox/win/src/sandbox_utils.h"
+
+namespace {
+
+static const int kDefaultTimeout = 10000;
+
+// 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