1 // Copyright 2015 The Chromium Authors
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 "ipc/ipc_message_attachment.h"
6
7 #include "base/files/scoped_file.h"
8 #include "base/logging.h"
9 #include "base/notreached.h"
10 #include "build/build_config.h"
11 #include "ipc/ipc_mojo_handle_attachment.h"
12 #include "mojo/public/cpp/system/platform_handle.h"
13
14 #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
15 #include <unistd.h>
16
17 #include "base/posix/eintr_wrapper.h"
18 #include "ipc/ipc_platform_file_attachment_posix.h"
19 #endif
20
21 #if BUILDFLAG(IS_MAC)
22 #include "ipc/mach_port_attachment_mac.h"
23 #endif
24
25 #if BUILDFLAG(IS_WIN)
26 #include "ipc/handle_attachment_win.h"
27 #endif
28
29 #if BUILDFLAG(IS_FUCHSIA)
30 #include "ipc/handle_attachment_fuchsia.h"
31 #endif
32
33 namespace IPC {
34
35 namespace {
36
37 #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
TakeOrDupFile(internal::PlatformFileAttachment * attachment)38 base::ScopedFD TakeOrDupFile(internal::PlatformFileAttachment* attachment) {
39 return attachment->Owns()
40 ? base::ScopedFD(attachment->TakePlatformFile())
41 : base::ScopedFD(HANDLE_EINTR(dup(attachment->file())));
42 }
43 #endif // BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
44
45 } // namespace
46
47 MessageAttachment::MessageAttachment() = default;
48
49 MessageAttachment::~MessageAttachment() = default;
50
TakeMojoHandle()51 mojo::ScopedHandle MessageAttachment::TakeMojoHandle() {
52 switch (GetType()) {
53 case Type::MOJO_HANDLE:
54 return static_cast<internal::MojoHandleAttachment*>(this)->TakeHandle();
55
56 #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
57 case Type::PLATFORM_FILE: {
58 // We dup() the handles in IPC::Message to transmit.
59 // IPC::MessageAttachmentSet has intricate lifetime semantics for FDs, so
60 // just to dup()-and-own them is the safest option.
61 base::ScopedFD file =
62 TakeOrDupFile(static_cast<internal::PlatformFileAttachment*>(this));
63 if (!file.is_valid()) {
64 DPLOG(WARNING) << "Failed to dup FD to transmit.";
65 return mojo::ScopedHandle();
66 }
67 return mojo::WrapPlatformFile(std::move(file));
68 }
69 #endif // BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
70
71 #if BUILDFLAG(IS_MAC)
72 case Type::MACH_PORT: {
73 auto* attachment = static_cast<internal::MachPortAttachmentMac*>(this);
74 MojoPlatformHandle platform_handle = {
75 sizeof(platform_handle), MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT,
76 static_cast<uint64_t>(attachment->get_mach_port())};
77 MojoHandle wrapped_handle;
78 if (MojoWrapPlatformHandle(&platform_handle, nullptr, &wrapped_handle) !=
79 MOJO_RESULT_OK) {
80 return mojo::ScopedHandle();
81 }
82 attachment->reset_mach_port_ownership();
83 return mojo::MakeScopedHandle(mojo::Handle(wrapped_handle));
84 }
85 #elif BUILDFLAG(IS_FUCHSIA)
86 case Type::FUCHSIA_HANDLE: {
87 auto* attachment = static_cast<internal::HandleAttachmentFuchsia*>(this);
88 MojoPlatformHandle platform_handle = {
89 sizeof(platform_handle), MOJO_PLATFORM_HANDLE_TYPE_FUCHSIA_HANDLE,
90 static_cast<uint64_t>(attachment->Take())};
91 MojoHandle wrapped_handle;
92 if (MojoWrapPlatformHandle(&platform_handle, nullptr, &wrapped_handle) !=
93 MOJO_RESULT_OK) {
94 return mojo::ScopedHandle();
95 }
96 return mojo::MakeScopedHandle(mojo::Handle(wrapped_handle));
97 }
98 #elif BUILDFLAG(IS_WIN)
99 case Type::WIN_HANDLE:
100 return mojo::WrapPlatformFile(base::win::ScopedHandle(
101 static_cast<internal::HandleAttachmentWin*>(this)->Take()));
102 #endif
103 default:
104 break;
105 }
106 NOTREACHED();
107 return mojo::ScopedHandle();
108 }
109
110 // static
CreateFromMojoHandle(mojo::ScopedHandle handle,Type type)111 scoped_refptr<MessageAttachment> MessageAttachment::CreateFromMojoHandle(
112 mojo::ScopedHandle handle,
113 Type type) {
114 if (type == Type::MOJO_HANDLE)
115 return new internal::MojoHandleAttachment(std::move(handle));
116
117 MojoPlatformHandle platform_handle = {sizeof(platform_handle), 0, 0};
118 MojoResult unwrap_result = MojoUnwrapPlatformHandle(
119 handle.release().value(), nullptr, &platform_handle);
120 if (unwrap_result != MOJO_RESULT_OK)
121 return nullptr;
122
123 #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
124 if (type == Type::PLATFORM_FILE) {
125 base::PlatformFile file = base::kInvalidPlatformFile;
126 if (platform_handle.type == MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR)
127 file = static_cast<base::PlatformFile>(platform_handle.value);
128 return new internal::PlatformFileAttachment(file);
129 }
130 #endif // BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
131
132 #if BUILDFLAG(IS_MAC)
133 if (type == Type::MACH_PORT) {
134 mach_port_t mach_port = MACH_PORT_NULL;
135 if (platform_handle.type == MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT)
136 mach_port = static_cast<mach_port_t>(platform_handle.value);
137 return new internal::MachPortAttachmentMac(
138 mach_port, internal::MachPortAttachmentMac::FROM_WIRE);
139 }
140 #elif BUILDFLAG(IS_FUCHSIA)
141 if (type == Type::FUCHSIA_HANDLE) {
142 zx::handle zx_handle;
143 if (platform_handle.type == MOJO_PLATFORM_HANDLE_TYPE_FUCHSIA_HANDLE)
144 zx_handle.reset(static_cast<zx_handle_t>(platform_handle.value));
145 return new internal::HandleAttachmentFuchsia(std::move(zx_handle));
146 }
147 #elif BUILDFLAG(IS_WIN)
148 if (type == Type::WIN_HANDLE) {
149 base::PlatformFile platform_file = base::kInvalidPlatformFile;
150 if (platform_handle.type == MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE) {
151 platform_file =
152 reinterpret_cast<base::PlatformFile>(platform_handle.value);
153 }
154 return new internal::HandleAttachmentWin(
155 platform_file, internal::HandleAttachmentWin::FROM_WIRE);
156 }
157 #endif
158 NOTREACHED();
159 return nullptr;
160 }
161
162 } // namespace IPC
163