summaryrefslogtreecommitdiffstats
path: root/sandbox
diff options
context:
space:
mode:
authorjschuh@chromium.org <jschuh@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-29 15:29:56 +0000
committerjschuh@chromium.org <jschuh@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-29 15:29:56 +0000
commitf6e06204466d7ce6d33a3f5a9cf3ae2128561df7 (patch)
tree13b24c2df28443793ee04ae4cf340bbf370bf8ed /sandbox
parentb54b3fae08eee524456da5fdc598485e251cc8a0 (diff)
downloadchromium_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.gyp9
-rw-r--r--sandbox/src/broker_services.cc12
-rw-r--r--sandbox/src/broker_services.h14
-rw-r--r--sandbox/src/handle_dispatcher.cc88
-rw-r--r--sandbox/src/handle_dispatcher.h37
-rw-r--r--sandbox/src/handle_interception.cc45
-rw-r--r--sandbox/src/handle_interception.h24
-rw-r--r--sandbox/src/handle_policy.cc71
-rw-r--r--sandbox/src/handle_policy.h41
-rw-r--r--sandbox/src/handle_policy_test.cc69
-rw-r--r--sandbox/src/ipc_tags.h3
-rw-r--r--sandbox/src/sandbox.h16
-rw-r--r--sandbox/src/sandbox_policy.h7
-rw-r--r--sandbox/src/sandbox_policy_base.cc15
-rw-r--r--sandbox/src/target_services.cc12
-rw-r--r--sandbox/src/target_services.h7
-rw-r--r--sandbox/tests/common/controller.cc36
-rw-r--r--sandbox/tests/common/controller.h15
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.