• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "mojo/core/platform_handle_in_transit.h"
6 
7 #include <utility>
8 
9 #include "base/logging.h"
10 #include "base/process/process_handle.h"
11 #include "build/build_config.h"
12 
13 #if defined(OS_WIN)
14 #include <windows.h>
15 
16 #include "base/win/scoped_handle.h"
17 #endif
18 
19 namespace mojo {
20 namespace core {
21 
22 namespace {
23 
24 #if defined(OS_WIN)
TransferHandle(HANDLE handle,base::ProcessHandle from_process,base::ProcessHandle to_process)25 HANDLE TransferHandle(HANDLE handle,
26                       base::ProcessHandle from_process,
27                       base::ProcessHandle to_process) {
28   BOOL result =
29       ::DuplicateHandle(from_process, handle, to_process, &handle, 0, FALSE,
30                         DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
31   if (result) {
32     return handle;
33   } else {
34     DPLOG(ERROR) << "DuplicateHandle failed";
35     return INVALID_HANDLE_VALUE;
36   }
37 }
38 
CloseHandleInProcess(HANDLE handle,const ScopedProcessHandle & process)39 void CloseHandleInProcess(HANDLE handle, const ScopedProcessHandle& process) {
40   DCHECK_NE(handle, INVALID_HANDLE_VALUE);
41   DCHECK(process.is_valid());
42 
43   // The handle lives in |process|, so we close it there using a special
44   // incantation of |DuplicateHandle()|.
45   //
46   // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms724251 for
47   // this usage of |DuplicateHandle()|, particularly where it says "to close a
48   // handle from the source process...". Note that although the documentation
49   // says that the target *handle* address must be NULL, it seems that the
50   // target process handle being NULL is what really matters here.
51   BOOL result = ::DuplicateHandle(process.get(), handle, NULL, &handle, 0,
52                                   FALSE, DUPLICATE_CLOSE_SOURCE);
53   if (!result) {
54     DPLOG(ERROR) << "DuplicateHandle failed";
55   }
56 }
57 #endif
58 
59 }  // namespace
60 
61 PlatformHandleInTransit::PlatformHandleInTransit() = default;
62 
PlatformHandleInTransit(PlatformHandle handle)63 PlatformHandleInTransit::PlatformHandleInTransit(PlatformHandle handle)
64     : handle_(std::move(handle)) {}
65 
PlatformHandleInTransit(PlatformHandleInTransit && other)66 PlatformHandleInTransit::PlatformHandleInTransit(
67     PlatformHandleInTransit&& other) {
68   *this = std::move(other);
69 }
70 
~PlatformHandleInTransit()71 PlatformHandleInTransit::~PlatformHandleInTransit() {
72 #if defined(OS_WIN)
73   if (!owning_process_.is_valid()) {
74     DCHECK_EQ(remote_handle_, INVALID_HANDLE_VALUE);
75     return;
76   }
77 
78   CloseHandleInProcess(remote_handle_, owning_process_);
79 #endif
80 }
81 
operator =(PlatformHandleInTransit && other)82 PlatformHandleInTransit& PlatformHandleInTransit::operator=(
83     PlatformHandleInTransit&& other) {
84 #if defined(OS_WIN)
85   if (owning_process_.is_valid()) {
86     DCHECK_NE(remote_handle_, INVALID_HANDLE_VALUE);
87     CloseHandleInProcess(remote_handle_, owning_process_);
88   }
89 
90   remote_handle_ = INVALID_HANDLE_VALUE;
91   std::swap(remote_handle_, other.remote_handle_);
92 #elif defined(OS_MACOSX) && !defined(OS_IOS)
93   mach_port_name_ = MACH_PORT_NULL;
94   std::swap(mach_port_name_, other.mach_port_name_);
95 #endif
96   handle_ = std::move(other.handle_);
97   owning_process_ = std::move(other.owning_process_);
98   return *this;
99 }
100 
TakeHandle()101 PlatformHandle PlatformHandleInTransit::TakeHandle() {
102   DCHECK(!owning_process_.is_valid());
103   return std::move(handle_);
104 }
105 
CompleteTransit()106 void PlatformHandleInTransit::CompleteTransit() {
107 #if defined(OS_WIN)
108   remote_handle_ = INVALID_HANDLE_VALUE;
109 #endif
110   handle_.release();
111   owning_process_ = ScopedProcessHandle();
112 }
113 
TransferToProcess(ScopedProcessHandle target_process)114 bool PlatformHandleInTransit::TransferToProcess(
115     ScopedProcessHandle target_process) {
116   DCHECK(target_process.is_valid());
117   DCHECK(!owning_process_.is_valid());
118   DCHECK(handle_.is_valid());
119 #if defined(OS_WIN)
120   remote_handle_ =
121       TransferHandle(handle_.ReleaseHandle(), base::GetCurrentProcessHandle(),
122                      target_process.get());
123   if (remote_handle_ == INVALID_HANDLE_VALUE)
124     return false;
125 #endif
126   owning_process_ = std::move(target_process);
127   return true;
128 }
129 
130 #if defined(OS_WIN)
131 // static
TakeIncomingRemoteHandle(HANDLE handle,base::ProcessHandle owning_process)132 PlatformHandle PlatformHandleInTransit::TakeIncomingRemoteHandle(
133     HANDLE handle,
134     base::ProcessHandle owning_process) {
135   return PlatformHandle(base::win::ScopedHandle(
136       TransferHandle(handle, owning_process, base::GetCurrentProcessHandle())));
137 }
138 #endif
139 
140 #if defined(OS_MACOSX) && !defined(OS_IOS)
141 // static
CreateForMachPortName(mach_port_t name)142 PlatformHandleInTransit PlatformHandleInTransit::CreateForMachPortName(
143     mach_port_t name) {
144   if (name == MACH_PORT_NULL) {
145     return PlatformHandleInTransit(
146         PlatformHandle(base::mac::ScopedMachSendRight()));
147   }
148 
149   PlatformHandleInTransit handle;
150   handle.mach_port_name_ = name;
151   return handle;
152 }
153 #endif
154 
155 }  // namespace core
156 }  // namespace mojo
157