# HG changeset patch
# User Bob Owen <bobowencode@gmail.com>
# Date 1485985575 0
#      Wed Feb 01 21:46:15 2017 +0000
# Node ID 9328428e5f863472f3702057b01d472b46b7b6a2
# Parent  4c1880ac25a66dec6455dc88ba693096d65df704
Reinstate sandbox::TargetServices::BrokerDuplicateHandle. r=aklotz

This basically reverts chromium commit 569193665184525ca366e65d0735f5c851106e43.

diff --git a/security/sandbox/chromium/sandbox/win/src/handle_dispatcher.cc b/security/sandbox/chromium/sandbox/win/src/handle_dispatcher.cc
new file mode 100644
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/handle_dispatcher.cc
@@ -0,0 +1,92 @@
+// 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/src/handle_dispatcher.h"
+
+#include <stdint.h>
+
+#include "base/win/scoped_handle.h"
+#include "sandbox/win/src/handle_interception.h"
+#include "sandbox/win/src/handle_policy.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_broker.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+#include "sandbox/win/src/sandbox_types.h"
+#include "sandbox/win/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, UINT32_TYPE, UINT32_TYPE, UINT32_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,
+                                            uint32_t target_process_id,
+                                            uint32_t desired_access,
+                                            uint32_t options) {
+  static NtQueryObject QueryObject = NULL;
+  if (!QueryObject)
+    ResolveNTFunctionPtr("NtQueryObject", &QueryObject);
+
+  // Get a copy of the handle for use in the broker process.
+  HANDLE handle_temp;
+  if (!::DuplicateHandle(ipc->client_info->process, source_handle,
+                         ::GetCurrentProcess(), &handle_temp,
+                         0, FALSE, DUPLICATE_SAME_ACCESS | options)) {
+    ipc->return_info.win32_result = ::GetLastError();
+    return false;
+  }
+  options &= ~DUPLICATE_CLOSE_SOURCE;
+  base::win::ScopedHandle handle(handle_temp);
+
+  // 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);
+  NTSTATUS error =
+      QueryObject(handle.Get(), ObjectTypeInformation, type_info, size, &size);
+  if (!NT_SUCCESS(error)) {
+    ipc->return_info.nt_status = error;
+    return false;
+  }
+  type_info->Name.Buffer[type_info->Name.Length / sizeof(wchar_t)] = L'\0';
+
+  CountedParameterSet<HandleTarget> params;
+  params[HandleTarget::NAME] = ParamPickerMake(type_info->Name.Buffer);
+  params[HandleTarget::TARGET] = ParamPickerMake(target_process_id);
+
+  EvalResult eval = policy_base_->EvalPolicy(IPC_DUPLICATEHANDLEPROXY_TAG,
+                                             params.GetBase());
+  ipc->return_info.win32_result =
+      HandlePolicy::DuplicateHandleProxyAction(eval, handle.Get(),
+                                               target_process_id,
+                                               &ipc->return_info.handle,
+                                               desired_access, options);
+  return true;
+}
+
+}  // namespace sandbox
+
diff --git a/security/sandbox/chromium/sandbox/win/src/handle_dispatcher.h b/security/sandbox/chromium/sandbox/win/src/handle_dispatcher.h
new file mode 100644
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/handle_dispatcher.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_DISPATCHER_H_
+#define SANDBOX_SRC_HANDLE_DISPATCHER_H_
+
+#include <stdint.h>
+
+#include "base/macros.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/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() override {}
+
+  // Dispatcher interface.
+  bool SetupService(InterceptionManager* manager, int service) override;
+
+ private:
+  // Processes IPC requests coming from calls to
+  // TargetServices::DuplicateHandle() in the target.
+  bool DuplicateHandleProxy(IPCInfo* ipc,
+                            HANDLE source_handle,
+                            uint32_t target_process_id,
+                            uint32_t desired_access,
+                            uint32_t options);
+
+  PolicyBase* policy_base_;
+  DISALLOW_COPY_AND_ASSIGN(HandleDispatcher);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_HANDLE_DISPATCHER_H_
+
diff --git a/security/sandbox/chromium/sandbox/win/src/handle_interception.cc b/security/sandbox/chromium/sandbox/win/src/handle_interception.cc
new file mode 100644
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/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/win/src/handle_interception.h"
+
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+#include "sandbox/win/src/sharedmem_ipc_client.h"
+#include "sandbox/win/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.win32_result);
+    return SBOX_ERROR_GENERIC;
+  }
+
+  *target_handle = answer.handle;
+  return SBOX_ALL_OK;
+}
+
+}  // namespace sandbox
+
diff --git a/security/sandbox/chromium/sandbox/win/src/handle_interception.h b/security/sandbox/chromium/sandbox/win/src/handle_interception.h
new file mode 100644
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/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/win/src/nt_internals.h"
+#include "sandbox/win/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/security/sandbox/chromium/sandbox/win/src/handle_policy.cc b/security/sandbox/chromium/sandbox/win/src/handle_policy.cc
new file mode 100644
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/handle_policy.cc
@@ -0,0 +1,92 @@
+// 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/src/handle_policy.h"
+
+#include <string>
+
+#include "base/win/scoped_handle.h"
+#include "sandbox/win/src/broker_services.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_engine_opcodes.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/sandbox_types.h"
+#include "sandbox/win/src/sandbox_utils.h"
+
+namespace sandbox {
+
+bool HandlePolicy::GenerateRules(const wchar_t* type_name,
+                                 TargetPolicy::Semantics semantics,
+                                 LowLevelPolicy* policy) {
+  PolicyRule duplicate_rule(ASK_BROKER);
+
+  switch (semantics) {
+    case TargetPolicy::HANDLES_DUP_ANY: {
+      if (!duplicate_rule.AddNumberMatch(IF_NOT, HandleTarget::TARGET,
+                                         ::GetCurrentProcessId(), EQUAL)) {
+        return false;
+      }
+      break;
+    }
+
+    case TargetPolicy::HANDLES_DUP_BROKER: {
+      if (!duplicate_rule.AddNumberMatch(IF, HandleTarget::TARGET,
+                                         ::GetCurrentProcessId(), EQUAL)) {
+        return false;
+      }
+      break;
+    }
+
+    default:
+     return false;
+  }
+  if (!duplicate_rule.AddStringMatch(IF, HandleTarget::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,
+                                               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;
+  }
+
+  base::win::ScopedHandle remote_target_process;
+  if (target_process_id != ::GetCurrentProcessId()) {
+    // Sandboxed children are dynamic, so we check that manually.
+    if (!BrokerServicesBase::GetInstance()->IsActiveTarget(target_process_id)) {
+      return ERROR_ACCESS_DENIED;
+    }
+
+    remote_target_process.Set(::OpenProcess(PROCESS_DUP_HANDLE, FALSE,
+                                            target_process_id));
+    if (!remote_target_process.IsValid())
+      return ::GetLastError();
+  }
+
+  // If the policy didn't block us and we have no valid target, then the broker
+  // (this process) is the valid target.
+  HANDLE target_process = remote_target_process.IsValid() ?
+                          remote_target_process.Get() : ::GetCurrentProcess();
+  if (!::DuplicateHandle(::GetCurrentProcess(), source_handle, target_process,
+                         target_handle, desired_access, FALSE,
+                         options)) {
+    return ::GetLastError();
+  }
+
+  return ERROR_SUCCESS;
+}
+
+}  // namespace sandbox
+
diff --git a/security/sandbox/chromium/sandbox/win/src/handle_policy.h b/security/sandbox/chromium/sandbox/win/src/handle_policy.h
new file mode 100644
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/handle_policy.h
@@ -0,0 +1,39 @@
+// 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 "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/policy_low_level.h"
+#include "sandbox/win/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,
+                                          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/security/sandbox/chromium/sandbox/win/src/handle_policy_test.cc b/security/sandbox/chromium/sandbox/win/src/handle_policy_test.cc
new file mode 100644
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/handle_policy_test.cc
@@ -0,0 +1,114 @@
+// 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/strings/stringprintf.h"
+#include "sandbox/win/src/handle_policy.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/sandbox_policy.h"
+#include "sandbox/win/src/win_utils.h"
+#include "sandbox/win/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.Get(), 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.
+  base::string16 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()));
+}
+
+// Tests that duplicating an object works only when the policy allows it.
+TEST(HandlePolicyTest, DuplicatePeerHandle) {
+  TestRunner target;
+  TestRunner runner;
+
+  // Kick off an asynchronous target process for testing.
+  target.SetAsynchronous(true);
+  target.SetUnsandboxed(true);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, target.RunTest(L"Handle_WaitProcess 30000"));
+
+  // First test that we fail to open the event.
+  base::string16 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()));
+}
+
+// Tests that duplicating an object works only when the policy allows it.
+TEST(HandlePolicyTest, DuplicateBrokerHandle) {
+  TestRunner runner;
+
+  // First test that we fail to open the event.
+  base::string16 cmd_line = base::StringPrintf(L"Handle_DuplicateEvent %d",
+                                             ::GetCurrentProcessId());
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(cmd_line.c_str()));
+
+  // Add the peer rule and make sure we fail again.
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_HANDLES,
+                             TargetPolicy::HANDLES_DUP_ANY,
+                             L"Event"));
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(cmd_line.c_str()));
+
+
+  // Now successfully open the event after adding a broker handle rule.
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_HANDLES,
+                             TargetPolicy::HANDLES_DUP_BROKER,
+                             L"Event"));
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(cmd_line.c_str()));
+}
+
+}  // namespace sandbox
+
diff --git a/security/sandbox/chromium/sandbox/win/src/ipc_tags.h b/security/sandbox/chromium/sandbox/win/src/ipc_tags.h
--- a/security/sandbox/chromium/sandbox/win/src/ipc_tags.h
+++ b/security/sandbox/chromium/sandbox/win/src/ipc_tags.h
@@ -23,16 +23,17 @@ enum {
   IPC_NTOPENPROCESS_TAG,
   IPC_NTOPENPROCESSTOKEN_TAG,
   IPC_NTOPENPROCESSTOKENEX_TAG,
   IPC_CREATEPROCESSW_TAG,
   IPC_CREATEEVENT_TAG,
   IPC_OPENEVENT_TAG,
   IPC_NTCREATEKEY_TAG,
   IPC_NTOPENKEY_TAG,
+  IPC_DUPLICATEHANDLEPROXY_TAG,
   IPC_GDI_GDIDLLINITIALIZE_TAG,
   IPC_GDI_GETSTOCKOBJECT_TAG,
   IPC_USER_REGISTERCLASSW_TAG,
   IPC_CREATETHREAD_TAG,
   IPC_USER_ENUMDISPLAYMONITORS_TAG,
   IPC_USER_ENUMDISPLAYDEVICES_TAG,
   IPC_USER_GETMONITORINFO_TAG,
   IPC_GDI_CREATEOPMPROTECTEDOUTPUTS_TAG,
diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox.h b/security/sandbox/chromium/sandbox/win/src/sandbox.h
--- a/security/sandbox/chromium/sandbox/win/src/sandbox.h
+++ b/security/sandbox/chromium/sandbox/win/src/sandbox.h
@@ -136,14 +136,28 @@ class TargetServices {
   // processing any untrusted data or running third-party code. If this call
   // fails the current process could be terminated immediately.
   virtual void LowerToken() = 0;
 
   // Returns the ProcessState object. Through that object it's possible to have
   // 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
 
 
 #endif  // SANDBOX_WIN_SRC_SANDBOX_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox_policy.h b/security/sandbox/chromium/sandbox/win/src/sandbox_policy.h
--- a/security/sandbox/chromium/sandbox/win/src/sandbox_policy.h
+++ b/security/sandbox/chromium/sandbox/win/src/sandbox_policy.h
@@ -21,27 +21,31 @@ class TargetPolicy {
   // exactly like the CreateProcess API does. See the comment at the top of
   // process_thread_dispatcher.cc for more details.
   enum SubSystem {
     SUBSYS_FILES,             // Creation and opening of files and pipes.
     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_HANDLES,           // Duplication of handles to other processes.
     SUBSYS_WIN32K_LOCKDOWN    // Win32K Lockdown related policy.
   };
 
   // Allowable semantics when a rule is matched.
   enum Semantics {
     FILES_ALLOW_ANY,       // Allows open or create for any kind of access that
                            // the file system supports.
     FILES_ALLOW_READONLY,  // Allows open or create with read access only.
     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.
+    HANDLES_DUP_BROKER,    // Allows duplicating handles to the broker process.
     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.
                            // No other parameters besides the command line are
                            // passed to the child process.
     PROCESS_ALL_EXEC,      // Allows the creation of a process and return full
                            // access on the returned handles.
                            // This flag can be used only when the main token of
diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.cc b/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.cc
--- a/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.cc
+++ b/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.cc
@@ -10,16 +10,17 @@
 
 #include "base/callback.h"
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/win/windows_version.h"
 #include "sandbox/win/src/filesystem_policy.h"
+#include "sandbox/win/src/handle_policy.h"
 #include "sandbox/win/src/interception.h"
 #include "sandbox/win/src/job.h"
 #include "sandbox/win/src/named_pipe_policy.h"
 #include "sandbox/win/src/policy_broker.h"
 #include "sandbox/win/src/policy_engine_processor.h"
 #include "sandbox/win/src/policy_low_level.h"
 #include "sandbox/win/src/process_mitigations.h"
 #include "sandbox/win/src/process_mitigations_win32k_policy.h"
@@ -733,16 +734,24 @@ ResultCode PolicyBase::AddRuleInternal(S
     }
     case SUBSYS_REGISTRY: {
       if (!RegistryPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
         NOTREACHED();
         return SBOX_ERROR_BAD_PARAMS;
       }
       break;
     }
+    case SUBSYS_HANDLES: {
+      if (!HandlePolicy::GenerateRules(pattern, semantics, policy_maker_)) {
+        NOTREACHED();
+        return SBOX_ERROR_BAD_PARAMS;
+      }
+      break;
+    }
+
     case SUBSYS_WIN32K_LOCKDOWN: {
       if (!ProcessMitigationsWin32KLockdownPolicy::GenerateRules(
               pattern, semantics, policy_maker_)) {
         NOTREACHED();
         return SBOX_ERROR_BAD_PARAMS;
       }
       break;
     }
diff --git a/security/sandbox/chromium/sandbox/win/src/target_services.cc b/security/sandbox/chromium/sandbox/win/src/target_services.cc
--- a/security/sandbox/chromium/sandbox/win/src/target_services.cc
+++ b/security/sandbox/chromium/sandbox/win/src/target_services.cc
@@ -7,16 +7,17 @@
 #include <new>
 
 #include <process.h>
 #include <stdint.h>
 
 #include "base/win/windows_version.h"
 #include "sandbox/win/src/crosscall_client.h"
 #include "sandbox/win/src/handle_closer_agent.h"
+#include "sandbox/win/src/handle_interception.h"
 #include "sandbox/win/src/heap_helper.h"
 #include "sandbox/win/src/ipc_tags.h"
 #include "sandbox/win/src/process_mitigations.h"
 #include "sandbox/win/src/restricted_token_utils.h"
 #include "sandbox/win/src/sandbox.h"
 #include "sandbox/win/src/sandbox_nt_util.h"
 #include "sandbox/win/src/sandbox_types.h"
 #include "sandbox/win/src/sharedmem_ipc_client.h"
@@ -259,9 +260,19 @@ void ProcessState::SetRevertedToSelf() {
   if (process_state_ < 3)
     process_state_ = 3;
 }
 
 void ProcessState::SetCsrssConnected(bool csrss_connected) {
   csrss_connected_ = csrss_connected;
 }
 
+
+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/security/sandbox/chromium/sandbox/win/src/target_services.h b/security/sandbox/chromium/sandbox/win/src/target_services.h
--- a/security/sandbox/chromium/sandbox/win/src/target_services.h
+++ b/security/sandbox/chromium/sandbox/win/src/target_services.h
@@ -41,16 +41,21 @@ class ProcessState {
 class TargetServicesBase : public TargetServices {
  public:
   TargetServicesBase();
 
   // Public interface of TargetServices.
   ResultCode Init() override;
   void LowerToken() override;
   ProcessState* GetState() override;
+  ResultCode DuplicateHandle(HANDLE source_handle,
+                             DWORD target_process_id,
+                             HANDLE* target_handle,
+                             DWORD desired_access,
+                             DWORD options) override;
 
   // Factory method.
   static TargetServicesBase* GetInstance();
 
   // Sends a simple IPC Message that has a well-known answer. Returns true
   // if the IPC was successful and false otherwise. There are 2 versions of
   // this test: 1 and 2. The first one send a simple message while the
   // second one send a message with an in/out param.
diff --git a/security/sandbox/chromium/sandbox/win/src/top_level_dispatcher.cc b/security/sandbox/chromium/sandbox/win/src/top_level_dispatcher.cc
--- a/security/sandbox/chromium/sandbox/win/src/top_level_dispatcher.cc
+++ b/security/sandbox/chromium/sandbox/win/src/top_level_dispatcher.cc
@@ -5,16 +5,17 @@
 #include "sandbox/win/src/top_level_dispatcher.h"
 
 #include <stdint.h>
 #include <string.h>
 
 #include "base/logging.h"
 #include "sandbox/win/src/crosscall_server.h"
 #include "sandbox/win/src/filesystem_dispatcher.h"
+#include "sandbox/win/src/handle_dispatcher.h"
 #include "sandbox/win/src/interception.h"
 #include "sandbox/win/src/internal_types.h"
 #include "sandbox/win/src/ipc_tags.h"
 #include "sandbox/win/src/named_pipe_dispatcher.h"
 #include "sandbox/win/src/process_mitigations_win32k_dispatcher.h"
 #include "sandbox/win/src/process_thread_dispatcher.h"
 #include "sandbox/win/src/registry_dispatcher.h"
 #include "sandbox/win/src/sandbox_policy_base.h"
@@ -53,16 +54,20 @@ TopLevelDispatcher::TopLevelDispatcher(P
   ipc_targets_[IPC_OPENEVENT_TAG] = dispatcher;
   sync_dispatcher_.reset(dispatcher);
 
   dispatcher = new RegistryDispatcher(policy_);
   ipc_targets_[IPC_NTCREATEKEY_TAG] = dispatcher;
   ipc_targets_[IPC_NTOPENKEY_TAG] = dispatcher;
   registry_dispatcher_.reset(dispatcher);
 
+  dispatcher = new HandleDispatcher(policy_);
+  ipc_targets_[IPC_DUPLICATEHANDLEPROXY_TAG] = dispatcher;
+  handle_dispatcher_.reset(dispatcher);
+
   dispatcher = new ProcessMitigationsWin32KDispatcher(policy_);
   ipc_targets_[IPC_GDI_GDIDLLINITIALIZE_TAG] = dispatcher;
   ipc_targets_[IPC_GDI_GETSTOCKOBJECT_TAG] = dispatcher;
   ipc_targets_[IPC_USER_REGISTERCLASSW_TAG] = dispatcher;
   ipc_targets_[IPC_USER_ENUMDISPLAYMONITORS_TAG] = dispatcher;
   ipc_targets_[IPC_USER_ENUMDISPLAYDEVICES_TAG] = dispatcher;
   ipc_targets_[IPC_USER_GETMONITORINFO_TAG] = dispatcher;
   ipc_targets_[IPC_GDI_CREATEOPMPROTECTEDOUTPUTS_TAG] = dispatcher;
