diff options
author | jschuh@chromium.org <jschuh@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-29 15:29:56 +0000 |
---|---|---|
committer | jschuh@chromium.org <jschuh@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-29 15:29:56 +0000 |
commit | f6e06204466d7ce6d33a3f5a9cf3ae2128561df7 (patch) | |
tree | 13b24c2df28443793ee04ae4cf340bbf370bf8ed /sandbox | |
parent | b54b3fae08eee524456da5fdc598485e251cc8a0 (diff) | |
download | chromium_src-f6e06204466d7ce6d33a3f5a9cf3ae2128561df7.zip chromium_src-f6e06204466d7ce6d33a3f5a9cf3ae2128561df7.tar.gz chromium_src-f6e06204466d7ce6d33a3f5a9cf3ae2128561df7.tar.bz2 |
Add a sandbox API for broker handle duplication
BUG=119250
Review URL: https://chromiumcodereview.appspot.com/9838083
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@129627 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sandbox')
-rw-r--r-- | sandbox/sandbox.gyp | 9 | ||||
-rw-r--r-- | sandbox/src/broker_services.cc | 12 | ||||
-rw-r--r-- | sandbox/src/broker_services.h | 14 | ||||
-rw-r--r-- | sandbox/src/handle_dispatcher.cc | 88 | ||||
-rw-r--r-- | sandbox/src/handle_dispatcher.h | 37 | ||||
-rw-r--r-- | sandbox/src/handle_interception.cc | 45 | ||||
-rw-r--r-- | sandbox/src/handle_interception.h | 24 | ||||
-rw-r--r-- | sandbox/src/handle_policy.cc | 71 | ||||
-rw-r--r-- | sandbox/src/handle_policy.h | 41 | ||||
-rw-r--r-- | sandbox/src/handle_policy_test.cc | 69 | ||||
-rw-r--r-- | sandbox/src/ipc_tags.h | 3 | ||||
-rw-r--r-- | sandbox/src/sandbox.h | 16 | ||||
-rw-r--r-- | sandbox/src/sandbox_policy.h | 7 | ||||
-rw-r--r-- | sandbox/src/sandbox_policy_base.cc | 15 | ||||
-rw-r--r-- | sandbox/src/target_services.cc | 12 | ||||
-rw-r--r-- | sandbox/src/target_services.h | 7 | ||||
-rw-r--r-- | sandbox/tests/common/controller.cc | 36 | ||||
-rw-r--r-- | sandbox/tests/common/controller.h | 15 |
18 files changed, 506 insertions, 15 deletions
diff --git a/sandbox/sandbox.gyp b/sandbox/sandbox.gyp index 4224019..50a9bfe 100644 --- a/sandbox/sandbox.gyp +++ b/sandbox/sandbox.gyp @@ -1,4 +1,4 @@ -# Copyright (c) 2011 The Chromium Authors. All rights reserved. +# 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. @@ -37,6 +37,12 @@ 'src/handle_closer.h', 'src/handle_closer_agent.cc', 'src/handle_closer_agent.h', + 'src/handle_dispatcher.cc', + 'src/handle_dispatcher.h', + 'src/handle_interception.cc', + 'src/handle_interception.h', + 'src/handle_policy.cc', + 'src/handle_policy.h', 'src/handle_table.cc', 'src/handle_table.h', 'src/interception.cc', @@ -276,6 +282,7 @@ 'tests/integration_tests/integration_tests.cc', 'src/dep_test.cc', 'src/file_policy_test.cc', + 'src/handle_policy_test.cc', 'tests/integration_tests/integration_tests_test.cc', 'src/handle_closer_test.cc', 'src/integrity_level_test.cc', diff --git a/sandbox/src/broker_services.cc b/sandbox/src/broker_services.cc index f6a0577..ff5be3a 100644 --- a/sandbox/src/broker_services.cc +++ b/sandbox/src/broker_services.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. +// 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. @@ -184,6 +184,10 @@ DWORD WINAPI BrokerServicesBase::TargetEventsThread(PVOID param) { case JOB_OBJECT_MSG_EXIT_PROCESS: case JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS: { + { + AutoLock lock(&broker->lock_); + broker->child_process_ids_.erase(reinterpret_cast<DWORD>(ovl)); + } --target_counter; if (0 == target_counter) ::SetEvent(no_targets); @@ -292,6 +296,7 @@ ResultCode BrokerServicesBase::SpawnTarget(const wchar_t* exe_path, // Save the tracker because in cleanup we might need to force closing // the Jobs. tracker_list_.push_back(tracker); + child_process_ids_.insert(process_info.dwProcessId); // We return the caller a duplicate of the process handle so they // can close it at will. @@ -312,4 +317,9 @@ ResultCode BrokerServicesBase::WaitForAllTargets() { return SBOX_ALL_OK; } +bool BrokerServicesBase::IsActiveTarget(DWORD process_id) { + AutoLock lock(&lock_); + return child_process_ids_.find(process_id) != child_process_ids_.end(); +} + } // namespace sandbox diff --git a/sandbox/src/broker_services.h b/sandbox/src/broker_services.h index 3e57dd2..8e4cb54 100644 --- a/sandbox/src/broker_services.h +++ b/sandbox/src/broker_services.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// 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. @@ -6,6 +6,7 @@ #define SANDBOX_SRC_BROKER_SERVICES_H__ #include <list> +#include <set> #include "base/basictypes.h" #include "sandbox/src/crosscall_server.h" #include "sandbox/src/job.h" @@ -32,7 +33,7 @@ class BrokerServicesBase : public BrokerServices, ~BrokerServicesBase(); - // The next four methods are the BrokerServices interface + // The next five methods are the BrokerServices interface virtual ResultCode Init(); virtual TargetPolicy* CreatePolicy(); @@ -44,6 +45,12 @@ class BrokerServicesBase : public BrokerServices, virtual ResultCode WaitForAllTargets(); + // Checks if the supplied process ID matches one of the broker's active + // target processes + // Returns: + // true if there is an active target process for this ID, otherwise false. + bool IsActiveTarget(DWORD process_id); + private: // Helper structure that allows the Broker to associate a job notification // with a job object and with a policy. @@ -85,6 +92,9 @@ class BrokerServicesBase : public BrokerServices, typedef std::list<JobTracker*> JobTrackerList; JobTrackerList tracker_list_; + // Provides a fast lookup to identify sandboxed processes. + std::set<DWORD> child_process_ids_; + DISALLOW_COPY_AND_ASSIGN(BrokerServicesBase); }; diff --git a/sandbox/src/handle_dispatcher.cc b/sandbox/src/handle_dispatcher.cc new file mode 100644 index 0000000..921a42f --- /dev/null +++ b/sandbox/src/handle_dispatcher.cc @@ -0,0 +1,88 @@ +// 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/src/handle_dispatcher.h" + +#include "base/win/scoped_handle.h" +#include "sandbox/src/handle_interception.h" +#include "sandbox/src/handle_policy.h" +#include "sandbox/src/ipc_tags.h" +#include "sandbox/src/policy_broker.h" +#include "sandbox/src/policy_params.h" +#include "sandbox/src/sandbox.h" +#include "sandbox/src/sandbox_nt_util.h" +#include "sandbox/src/sandbox_types.h" +#include "sandbox/src/sandbox_utils.h" + +namespace sandbox { + +HandleDispatcher::HandleDispatcher(PolicyBase* policy_base) + : policy_base_(policy_base) { + static const IPCCall duplicate_handle_proxy = { + {IPC_DUPLICATEHANDLEPROXY_TAG, VOIDPTR_TYPE, ULONG_TYPE, ULONG_TYPE, + ULONG_TYPE}, + reinterpret_cast<CallbackGeneric>(&HandleDispatcher::DuplicateHandleProxy) + }; + + ipc_calls_.push_back(duplicate_handle_proxy); +} + +bool HandleDispatcher::SetupService(InterceptionManager* manager, + int service) { + // We perform no interceptions for handles right now. + switch (service) { + case IPC_DUPLICATEHANDLEPROXY_TAG: + return true; + } + + return false; +} + +bool HandleDispatcher::DuplicateHandleProxy(IPCInfo* ipc, + HANDLE source_handle, + DWORD target_process_id, + DWORD desired_access, + DWORD options) { + NTSTATUS error; + static NtQueryObject QueryObject = NULL; + if (!QueryObject) + ResolveNTFunctionPtr("NtQueryObject", &QueryObject); + + // Get a copy of the handle for use in the broker process. + base::win::ScopedHandle handle; + if (!::DuplicateHandle(ipc->client_info->process, source_handle, + ::GetCurrentProcess(), handle.Receive(), + 0, FALSE, 0)) { + ipc->return_info.win32_result = ::GetLastError(); + return false; + } + + // Get the object type (32 characters is safe; current max is 14). + BYTE buffer[sizeof(OBJECT_TYPE_INFORMATION) + 32 * sizeof(wchar_t)]; + OBJECT_TYPE_INFORMATION* type_info = + reinterpret_cast<OBJECT_TYPE_INFORMATION*>(buffer); + ULONG size = sizeof(buffer) - sizeof(wchar_t); + error = QueryObject(handle, ObjectTypeInformation, type_info, size, &size); + if (!NT_SUCCESS(error)) { + ipc->return_info.win32_result = error; + return false; + } + type_info->Name.Buffer[type_info->Name.Length / sizeof(wchar_t)] = L'\0'; + + CountedParameterSet<NameBased> params; + params[NameBased::NAME] = ParamPickerMake(type_info->Name.Buffer); + + EvalResult eval = policy_base_->EvalPolicy(IPC_DUPLICATEHANDLEPROXY_TAG, + params.GetBase()); + ipc->return_info.win32_result = + HandlePolicy::DuplicateHandleProxyAction(eval, *ipc->client_info, + source_handle, + target_process_id, + &ipc->return_info.handle, + desired_access, options); + return true; +} + +} // namespace sandbox + diff --git a/sandbox/src/handle_dispatcher.h b/sandbox/src/handle_dispatcher.h new file mode 100644 index 0000000..c1abc28 --- /dev/null +++ b/sandbox/src/handle_dispatcher.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_SRC_HANDLE_DISPATCHER_H_ +#define SANDBOX_SRC_HANDLE_DISPATCHER_H_ + +#include "base/basictypes.h" +#include "sandbox/src/crosscall_server.h" +#include "sandbox/src/sandbox_policy_base.h" + +namespace sandbox { + +// This class handles handle-related IPC calls. +class HandleDispatcher : public Dispatcher { + public: + explicit HandleDispatcher(PolicyBase* policy_base); + ~HandleDispatcher() {} + + // Dispatcher interface. + virtual bool SetupService(InterceptionManager* manager, int service); + + private: + // Processes IPC requests coming from calls to + // TargetServices::DuplicateHandle() in the target. + bool DuplicateHandleProxy(IPCInfo* ipc, HANDLE source_handle, + DWORD target_process_id, DWORD desired_access, + DWORD options); + + PolicyBase* policy_base_; + DISALLOW_COPY_AND_ASSIGN(HandleDispatcher); +}; + +} // namespace sandbox + +#endif // SANDBOX_SRC_HANDLE_DISPATCHER_H_ + diff --git a/sandbox/src/handle_interception.cc b/sandbox/src/handle_interception.cc new file mode 100644 index 0000000..0f7b9f8 --- /dev/null +++ b/sandbox/src/handle_interception.cc @@ -0,0 +1,45 @@ +// 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/src/handle_interception.h" + +#include "sandbox/src/crosscall_client.h" +#include "sandbox/src/ipc_tags.h" +#include "sandbox/src/sandbox_factory.h" +#include "sandbox/src/sandbox_nt_util.h" +#include "sandbox/src/sharedmem_ipc_client.h" +#include "sandbox/src/target_services.h" + +namespace sandbox { + +ResultCode DuplicateHandleProxy(HANDLE source_handle, + DWORD target_process_id, + HANDLE* target_handle, + DWORD desired_access, + DWORD options) { + *target_handle = NULL; + + void* memory = GetGlobalIPCMemory(); + if (NULL == memory) + return SBOX_ERROR_NO_SPACE; + + SharedMemIPCClient ipc(memory); + CrossCallReturn answer = {0}; + ResultCode code = CrossCall(ipc, IPC_DUPLICATEHANDLEPROXY_TAG, + source_handle, target_process_id, + desired_access, options, &answer); + if (SBOX_ALL_OK != code) + return code; + + if (answer.win32_result) { + ::SetLastError(answer.nt_status); + return SBOX_ERROR_GENERIC; + } + + *target_handle = answer.handle; + return SBOX_ALL_OK; +} + +} // namespace sandbox + diff --git a/sandbox/src/handle_interception.h b/sandbox/src/handle_interception.h new file mode 100644 index 0000000..543c7ba --- /dev/null +++ b/sandbox/src/handle_interception.h @@ -0,0 +1,24 @@ +// 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/src/nt_internals.h" +#include "sandbox/src/sandbox_types.h" + +#ifndef SANDBOX_SRC_HANDLE_INTERCEPTION_H_ +#define SANDBOX_SRC_HANDLE_INTERCEPTION_H_ + +namespace sandbox { + +// TODO(jschuh) Add an interception to catch dangerous DuplicateHandle calls. + +ResultCode DuplicateHandleProxy(HANDLE source_handle, + DWORD target_process_id, + HANDLE* target_handle, + DWORD desired_access, + DWORD options); + +} // namespace sandbox + +#endif // SANDBOX_SRC_HANDLE_INTERCEPTION_H_ + diff --git a/sandbox/src/handle_policy.cc b/sandbox/src/handle_policy.cc new file mode 100644 index 0000000..ef06e32 --- /dev/null +++ b/sandbox/src/handle_policy.cc @@ -0,0 +1,71 @@ +// 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/src/handle_policy.h" + +#include <string> + +#include "base/win/scoped_handle.h" +#include "sandbox/src/broker_services.h" +#include "sandbox/src/ipc_tags.h" +#include "sandbox/src/policy_engine_opcodes.h" +#include "sandbox/src/policy_params.h" +#include "sandbox/src/sandbox_types.h" +#include "sandbox/src/sandbox_utils.h" + +namespace sandbox { + +bool HandlePolicy::GenerateRules(const wchar_t* type_name, + TargetPolicy::Semantics semantics, + LowLevelPolicy* policy) { + // We don't support any other semantics for handles yet. + if (TargetPolicy::HANDLES_DUP_ANY != semantics) { + return false; + } + PolicyRule duplicate_rule(ASK_BROKER); + if (!duplicate_rule.AddStringMatch(IF, NameBased::NAME, type_name, + CASE_INSENSITIVE)) { + return false; + } + if (!policy->AddRule(IPC_DUPLICATEHANDLEPROXY_TAG, &duplicate_rule)) { + return false; + } + return true; +} + +DWORD HandlePolicy::DuplicateHandleProxyAction(EvalResult eval_result, + const ClientInfo& client_info, + HANDLE source_handle, + DWORD target_process_id, + HANDLE* target_handle, + DWORD desired_access, + DWORD options) { + // The only action supported is ASK_BROKER which means duplicate the handle. + if (ASK_BROKER != eval_result) { + return ERROR_ACCESS_DENIED; + } + + // Make sure the target is one of our sandboxed children. + if (!BrokerServicesBase::GetInstance()->IsActiveTarget(target_process_id)) { + return ERROR_ACCESS_DENIED; + } + + base::win::ScopedHandle target_process(::OpenProcess(PROCESS_DUP_HANDLE, + FALSE, + target_process_id)); + if (NULL == target_process) + return ::GetLastError(); + + DWORD result = ERROR_SUCCESS; + if (!::DuplicateHandle(client_info.process, source_handle, target_process, + target_handle, desired_access, FALSE, + options)) { + return ::GetLastError(); + } + + return ERROR_SUCCESS; +} + +} // namespace sandbox + diff --git a/sandbox/src/handle_policy.h b/sandbox/src/handle_policy.h new file mode 100644 index 0000000..c3b7156 --- /dev/null +++ b/sandbox/src/handle_policy.h @@ -0,0 +1,41 @@ +// 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_SRC_HANDLE_POLICY_H_ +#define SANDBOX_SRC_HANDLE_POLICY_H_ + +#include <string> + +#include "base/basictypes.h" +#include "sandbox/src/crosscall_server.h" +#include "sandbox/src/policy_low_level.h" +#include "sandbox/src/sandbox_policy.h" + +namespace sandbox { + +enum EvalResult; + +// This class centralizes most of the knowledge related to handle policy. +class HandlePolicy { + public: + // Creates the required low-level policy rules to evaluate a high-level + // policy rule for handles, in particular duplicate action. + static bool GenerateRules(const wchar_t* type_name, + TargetPolicy::Semantics semantics, + LowLevelPolicy* policy); + + // Processes a 'TargetPolicy::DuplicateHandle()' request from the target. + static DWORD DuplicateHandleProxyAction(EvalResult eval_result, + const ClientInfo& client_info, + HANDLE source_handle, + DWORD target_process_id, + HANDLE* target_handle, + DWORD desired_access, + DWORD options); +}; + +} // namespace sandbox + +#endif // SANDBOX_SRC_HANDLE_POLICY_H_ + diff --git a/sandbox/src/handle_policy_test.cc b/sandbox/src/handle_policy_test.cc new file mode 100644 index 0000000..bccca67 --- /dev/null +++ b/sandbox/src/handle_policy_test.cc @@ -0,0 +1,69 @@ +// 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 "base/stringprintf.h" +#include "sandbox/src/handle_policy.h" +#include "sandbox/src/nt_internals.h" +#include "sandbox/src/sandbox.h" +#include "sandbox/src/sandbox_factory.h" +#include "sandbox/src/sandbox_policy.h" +#include "sandbox/src/win_utils.h" +#include "sandbox/tests/common/controller.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace sandbox { + +// Just waits for the supplied number of milliseconds. +SBOX_TESTS_COMMAND int Handle_WaitProcess(int argc, wchar_t **argv) { + if (argc != 1) + return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; + + ::Sleep(::wcstoul(argv[0], NULL, 10)); + return SBOX_TEST_TIMED_OUT; +} + +// Attempts to duplicate an event handle into the target process. +SBOX_TESTS_COMMAND int Handle_DuplicateEvent(int argc, wchar_t **argv) { + if (argc != 1) + return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; + + // Create a test event to use as a handle. + base::win::ScopedHandle test_event; + test_event.Set(::CreateEvent(NULL, TRUE, TRUE, NULL)); + if (!test_event.IsValid()) + return SBOX_TEST_FIRST_ERROR; + + // Get the target process ID. + DWORD target_process_id = ::wcstoul(argv[0], NULL, 10); + + HANDLE handle = NULL; + ResultCode result = SandboxFactory::GetTargetServices()->DuplicateHandle( + test_event, target_process_id, &handle, 0, DUPLICATE_SAME_ACCESS); + + return (result == SBOX_ALL_OK) ? SBOX_TEST_SUCCEEDED : SBOX_TEST_DENIED; +} + +// Tests that duplicating an object works only when the policy allows it. +TEST(HandlePolicyTest, DuplicateHandle) { + TestRunner target; + TestRunner runner; + + // Kick off an asynchronous target process for testing. + target.SetAsynchronous(true); + EXPECT_EQ(SBOX_TEST_SUCCEEDED, target.RunTest(L"Handle_WaitProcess 30000")); + + // First test that we fail to open the event. + std::wstring cmd_line = base::StringPrintf(L"Handle_DuplicateEvent %d", + target.process_id()); + EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(cmd_line.c_str())); + + // Now successfully open the event after adding a duplicate handle rule. + EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_HANDLES, + TargetPolicy::HANDLES_DUP_ANY, + L"Event")); + EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(cmd_line.c_str())); +} + +} // namespace sandbox + diff --git a/sandbox/src/ipc_tags.h b/sandbox/src/ipc_tags.h index 397a529f..4e3a806 100644 --- a/sandbox/src/ipc_tags.h +++ b/sandbox/src/ipc_tags.h @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// 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. @@ -28,6 +28,7 @@ enum { IPC_OPENEVENT_TAG, IPC_NTCREATEKEY_TAG, IPC_NTOPENKEY_TAG, + IPC_DUPLICATEHANDLEPROXY_TAG, IPC_LAST_TAG }; diff --git a/sandbox/src/sandbox.h b/sandbox/src/sandbox.h index bbc4f77..683bda7 100644 --- a/sandbox/src/sandbox.h +++ b/sandbox/src/sandbox.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// 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. @@ -126,6 +126,20 @@ class TargetServices { // information about the current state of the process, such as whether // LowerToken has been called or not. virtual ProcessState* GetState() = 0; + + // Requests the broker to duplicate the supplied handle into the target + // process. The target process must be an active sandbox child process + // and the source process must have a corresponding policy allowing + // handle duplication for this object type. + // Returns: + // ALL_OK if successful. All other return values imply failure. + // If the return is ERROR_GENERIC, you can call ::GetLastError() to get + // more information. + virtual ResultCode DuplicateHandle(HANDLE source_handle, + DWORD target_process_id, + HANDLE* target_handle, + DWORD desired_access, + DWORD options) = 0; }; } // namespace sandbox diff --git a/sandbox/src/sandbox_policy.h b/sandbox/src/sandbox_policy.h index 4f21158..1f561f5 100644 --- a/sandbox/src/sandbox_policy.h +++ b/sandbox/src/sandbox_policy.h @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2011 The Chromium Authors. All rights reserved. +// 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. @@ -128,7 +128,8 @@ class TargetPolicy { SUBSYS_NAMED_PIPES, // Creation of named pipes. SUBSYS_PROCESS, // Creation of child processes. SUBSYS_REGISTRY, // Creation and opening of registry keys. - SUBSYS_SYNC // Creation of named sync objects. + SUBSYS_SYNC, // Creation of named sync objects. + SUBSYS_HANDLES // Duplication of handles to other processes. }; // Allowable semantics when a rule is matched. @@ -139,6 +140,8 @@ class TargetPolicy { FILES_ALLOW_QUERY, // Allows access to query the attributes of a file. FILES_ALLOW_DIR_ANY, // Allows open or create with directory semantics // only. + HANDLES_DUP_ANY, // Allows duplicating handles opened with any + // access permissions. NAMEDPIPES_ALLOW_ANY, // Allows creation of a named pipe. PROCESS_MIN_EXEC, // Allows to create a process with minimal rights // over the resulting process and thread handles. diff --git a/sandbox/src/sandbox_policy_base.cc b/sandbox/src/sandbox_policy_base.cc index e65f648..587d59d 100644 --- a/sandbox/src/sandbox_policy_base.cc +++ b/sandbox/src/sandbox_policy_base.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2011 The Chromium Authors. All rights reserved. +// 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. @@ -9,6 +9,8 @@ #include "base/logging.h" #include "sandbox/src/filesystem_dispatcher.h" #include "sandbox/src/filesystem_policy.h" +#include "sandbox/src/handle_dispatcher.h" +#include "sandbox/src/handle_policy.h" #include "sandbox/src/job.h" #include "sandbox/src/interception.h" #include "sandbox/src/named_pipe_dispatcher.h" @@ -96,6 +98,9 @@ PolicyBase::PolicyBase() dispatcher = new RegistryDispatcher(this); ipc_targets_[IPC_NTCREATEKEY_TAG] = dispatcher; ipc_targets_[IPC_NTOPENKEY_TAG] = dispatcher; + + dispatcher = new HandleDispatcher(this); + ipc_targets_[IPC_DUPLICATEHANDLEPROXY_TAG] = dispatcher; } PolicyBase::~PolicyBase() { @@ -109,6 +114,7 @@ PolicyBase::~PolicyBase() { delete ipc_targets_[IPC_NTOPENTHREAD_TAG]; delete ipc_targets_[IPC_CREATEEVENT_TAG]; delete ipc_targets_[IPC_NTCREATEKEY_TAG]; + delete ipc_targets_[IPC_DUPLICATEHANDLEPROXY_TAG]; delete policy_maker_; delete policy_; ::DeleteCriticalSection(&lock_); @@ -320,6 +326,13 @@ ResultCode PolicyBase::AddRule(SubSystem subsystem, Semantics semantics, } break; } + case SUBSYS_HANDLES: { + if (!HandlePolicy::GenerateRules(pattern, semantics, policy_maker_)) { + NOTREACHED(); + return SBOX_ERROR_BAD_PARAMS; + } + break; + } default: { return SBOX_ERROR_UNSUPPORTED; } diff --git a/sandbox/src/target_services.cc b/sandbox/src/target_services.cc index 9b91a1c..e13a3d6 100644 --- a/sandbox/src/target_services.cc +++ b/sandbox/src/target_services.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// 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. @@ -9,6 +9,7 @@ #include "base/basictypes.h" #include "sandbox/src/crosscall_client.h" #include "sandbox/src/handle_closer_agent.h" +#include "sandbox/src/handle_interception.h" #include "sandbox/src/ipc_tags.h" #include "sandbox/src/restricted_token_utils.h" #include "sandbox/src/sandbox.h" @@ -175,4 +176,13 @@ void ProcessState::SetRevertedToSelf() { process_state_ = 3; } +ResultCode TargetServicesBase::DuplicateHandle(HANDLE source_handle, + DWORD target_process_id, + HANDLE* target_handle, + DWORD desired_access, + DWORD options) { + return sandbox::DuplicateHandleProxy(source_handle, target_process_id, + target_handle, desired_access, options); +} + } // namespace sandbox diff --git a/sandbox/src/target_services.h b/sandbox/src/target_services.h index 7099098..c4bf4f6 100644 --- a/sandbox/src/target_services.h +++ b/sandbox/src/target_services.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// 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. @@ -46,6 +46,11 @@ class TargetServicesBase : public TargetServices { virtual ResultCode Init(); virtual void LowerToken(); virtual ProcessState* GetState(); + virtual ResultCode DuplicateHandle(HANDLE source_handle, + DWORD target_process_id, + HANDLE* target_handle, + DWORD desired_access, + DWORD options); // Factory method. static TargetServicesBase* GetInstance(); diff --git a/sandbox/tests/common/controller.cc b/sandbox/tests/common/controller.cc index a221ee1..3de3221 100644 --- a/sandbox/tests/common/controller.cc +++ b/sandbox/tests/common/controller.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// 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. @@ -51,6 +51,13 @@ std::wstring MakePathToSysWow64(const wchar_t* name, bool is_obj_man_path) { 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 { @@ -81,11 +88,13 @@ BrokerServices* GetBroker() { } TestRunner::TestRunner(JobLevel job_level, TokenLevel startup_token, - TokenLevel main_token) : is_init_(false) { + TokenLevel main_token) + : is_init_(false), is_async_(false), target_process_id_(0) { Init(job_level, startup_token, main_token); } -TestRunner::TestRunner() : is_init_(false) { +TestRunner::TestRunner() + : is_init_(false), is_async_(false), target_process_id_(0) { Init(JOB_LOCKDOWN, USER_RESTRICTED_SAME_ACCESS, USER_LOCKDOWN); } @@ -95,6 +104,8 @@ void TestRunner::Init(JobLevel job_level, TokenLevel startup_token, policy_ = NULL; timeout_ = kDefaultTimeout; state_ = AFTER_REVERT; + is_async_= false; + target_process_id_ = 0; broker_ = GetBroker(); if (!broker_) @@ -115,6 +126,9 @@ TargetPolicy* TestRunner::GetPolicy() { } TestRunner::~TestRunner() { + if (target_process_) + ::TerminateProcess(target_process_, 0); + if (policy_) policy_->Release(); } @@ -177,6 +191,14 @@ 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); @@ -198,6 +220,14 @@ int TestRunner::InternalRunTest(const wchar_t* command) { ::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; diff --git a/sandbox/tests/common/controller.h b/sandbox/tests/common/controller.h index 3f1d0c2..0a78a0e 100644 --- a/sandbox/tests/common/controller.h +++ b/sandbox/tests/common/controller.h @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved. +// 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. @@ -8,6 +8,7 @@ #include <windows.h> #include <string> +#include "base/win/scoped_handle.h" #include "sandbox/src/sandbox.h" namespace sandbox { @@ -91,6 +92,9 @@ class TestRunner { // 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 the desired state for the test to run. void SetTestState(SboxTestsState desired_state); @@ -98,6 +102,12 @@ class TestRunner { // 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. @@ -112,6 +122,9 @@ class TestRunner { DWORD timeout_; SboxTestsState state_; bool is_init_; + bool is_async_; + base::win::ScopedHandle target_process_; + DWORD target_process_id_; }; // Returns the broker services. |