| OLD | NEW |
| (Empty) |
| 1 // Copyright 2015 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 "ipc/attachment_broker_privileged_mac.h" | |
| 6 | |
| 7 #include <stdint.h> | |
| 8 | |
| 9 #include <tuple> | |
| 10 | |
| 11 #include "base/mac/mach_port_util.h" | |
| 12 #include "base/mac/scoped_mach_port.h" | |
| 13 #include "base/memory/shared_memory.h" | |
| 14 #include "base/process/port_provider_mac.h" | |
| 15 #include "base/process/process.h" | |
| 16 #include "base/synchronization/lock.h" | |
| 17 #include "ipc/attachment_broker_messages.h" | |
| 18 #include "ipc/brokerable_attachment.h" | |
| 19 #include "ipc/ipc_channel.h" | |
| 20 #include "ipc/mach_port_attachment_mac.h" | |
| 21 | |
| 22 namespace IPC { | |
| 23 | |
| 24 AttachmentBrokerPrivilegedMac::AttachmentBrokerPrivilegedMac( | |
| 25 base::PortProvider* port_provider) | |
| 26 : port_provider_(port_provider) { | |
| 27 port_provider_->AddObserver(this); | |
| 28 } | |
| 29 | |
| 30 AttachmentBrokerPrivilegedMac::~AttachmentBrokerPrivilegedMac() { | |
| 31 port_provider_->RemoveObserver(this); | |
| 32 { | |
| 33 base::AutoLock l(precursors_lock_); | |
| 34 for (auto it : precursors_) | |
| 35 delete it.second; | |
| 36 } | |
| 37 { | |
| 38 base::AutoLock l(extractors_lock_); | |
| 39 for (auto it : extractors_) | |
| 40 delete it.second; | |
| 41 } | |
| 42 } | |
| 43 | |
| 44 bool AttachmentBrokerPrivilegedMac::SendAttachmentToProcess( | |
| 45 const scoped_refptr<IPC::BrokerableAttachment>& attachment, | |
| 46 base::ProcessId destination_process) { | |
| 47 switch (attachment->GetBrokerableType()) { | |
| 48 case BrokerableAttachment::MACH_PORT: { | |
| 49 internal::MachPortAttachmentMac* mach_port_attachment = | |
| 50 static_cast<internal::MachPortAttachmentMac*>(attachment.get()); | |
| 51 MachPortWireFormat wire_format = | |
| 52 mach_port_attachment->GetWireFormat(destination_process); | |
| 53 AddPrecursor(wire_format.destination_process, | |
| 54 base::mac::ScopedMachSendRight(wire_format.mach_port), | |
| 55 wire_format.attachment_id); | |
| 56 mach_port_attachment->reset_mach_port_ownership(); | |
| 57 SendPrecursorsForProcess(wire_format.destination_process, true); | |
| 58 return true; | |
| 59 } | |
| 60 default: | |
| 61 NOTREACHED(); | |
| 62 return false; | |
| 63 } | |
| 64 return false; | |
| 65 } | |
| 66 | |
| 67 void AttachmentBrokerPrivilegedMac::DeregisterCommunicationChannel( | |
| 68 Endpoint* endpoint) { | |
| 69 AttachmentBrokerPrivileged::DeregisterCommunicationChannel(endpoint); | |
| 70 | |
| 71 if (!endpoint) | |
| 72 return; | |
| 73 | |
| 74 base::ProcessId pid = endpoint->GetPeerPID(); | |
| 75 if (pid == base::kNullProcessId) | |
| 76 return; | |
| 77 | |
| 78 { | |
| 79 base::AutoLock l(precursors_lock_); | |
| 80 auto it = precursors_.find(pid); | |
| 81 if (it != precursors_.end()) { | |
| 82 delete it->second; | |
| 83 precursors_.erase(pid); | |
| 84 } | |
| 85 } | |
| 86 | |
| 87 { | |
| 88 base::AutoLock l(extractors_lock_); | |
| 89 auto it = extractors_.find(pid); | |
| 90 if (it != extractors_.end()) { | |
| 91 delete it->second; | |
| 92 extractors_.erase(pid); | |
| 93 } | |
| 94 } | |
| 95 } | |
| 96 | |
| 97 void AttachmentBrokerPrivilegedMac::ReceivedPeerPid(base::ProcessId peer_pid) { | |
| 98 ProcessExtractorsForProcess(peer_pid, false); | |
| 99 SendPrecursorsForProcess(peer_pid, false); | |
| 100 } | |
| 101 | |
| 102 bool AttachmentBrokerPrivilegedMac::OnMessageReceived(const Message& msg) { | |
| 103 bool handled = true; | |
| 104 switch (msg.type()) { | |
| 105 IPC_MESSAGE_HANDLER_GENERIC(AttachmentBrokerMsg_DuplicateMachPort, | |
| 106 OnDuplicateMachPort(msg)) | |
| 107 IPC_MESSAGE_UNHANDLED(handled = false) | |
| 108 } | |
| 109 return handled; | |
| 110 } | |
| 111 | |
| 112 void AttachmentBrokerPrivilegedMac::OnReceivedTaskPort( | |
| 113 base::ProcessHandle process) { | |
| 114 SendPrecursorsForProcess(process, true); | |
| 115 } | |
| 116 | |
| 117 AttachmentBrokerPrivilegedMac::AttachmentPrecursor::AttachmentPrecursor( | |
| 118 const base::ProcessId& pid, | |
| 119 base::mac::ScopedMachSendRight port, | |
| 120 const BrokerableAttachment::AttachmentId& id) | |
| 121 : pid_(pid), port_(port.release()), id_(id) {} | |
| 122 | |
| 123 AttachmentBrokerPrivilegedMac::AttachmentPrecursor::~AttachmentPrecursor() {} | |
| 124 | |
| 125 base::mac::ScopedMachSendRight | |
| 126 AttachmentBrokerPrivilegedMac::AttachmentPrecursor::TakePort() { | |
| 127 return base::mac::ScopedMachSendRight(port_.release()); | |
| 128 } | |
| 129 | |
| 130 AttachmentBrokerPrivilegedMac::AttachmentExtractor::AttachmentExtractor( | |
| 131 const base::ProcessId& source_pid, | |
| 132 const base::ProcessId& dest_pid, | |
| 133 mach_port_name_t port, | |
| 134 const BrokerableAttachment::AttachmentId& id) | |
| 135 : source_pid_(source_pid), | |
| 136 dest_pid_(dest_pid), | |
| 137 port_to_extract_(port), | |
| 138 id_(id) {} | |
| 139 | |
| 140 AttachmentBrokerPrivilegedMac::AttachmentExtractor::~AttachmentExtractor() {} | |
| 141 | |
| 142 void AttachmentBrokerPrivilegedMac::OnDuplicateMachPort( | |
| 143 const IPC::Message& message) { | |
| 144 DCHECK_NE(0, message.get_sender_pid()); | |
| 145 AttachmentBrokerMsg_DuplicateMachPort::Param param; | |
| 146 if (!AttachmentBrokerMsg_DuplicateMachPort::Read(&message, ¶m)) { | |
| 147 LogError(ERROR_PARSE_DUPLICATE_MACH_PORT_MESSAGE); | |
| 148 return; | |
| 149 } | |
| 150 IPC::internal::MachPortAttachmentMac::WireFormat wire_format = | |
| 151 std::get<0>(param); | |
| 152 | |
| 153 if (wire_format.destination_process == base::kNullProcessId) { | |
| 154 LogError(NO_DESTINATION); | |
| 155 return; | |
| 156 } | |
| 157 | |
| 158 AddExtractor(message.get_sender_pid(), wire_format.destination_process, | |
| 159 wire_format.mach_port, wire_format.attachment_id); | |
| 160 ProcessExtractorsForProcess(message.get_sender_pid(), true); | |
| 161 } | |
| 162 | |
| 163 void AttachmentBrokerPrivilegedMac::RoutePrecursorToSelf( | |
| 164 AttachmentPrecursor* precursor) { | |
| 165 DCHECK_EQ(base::Process::Current().Pid(), precursor->pid()); | |
| 166 | |
| 167 // Intentionally leak the port, since the attachment takes ownership. | |
| 168 internal::MachPortAttachmentMac::WireFormat wire_format( | |
| 169 precursor->TakePort().release(), precursor->pid(), precursor->id()); | |
| 170 scoped_refptr<BrokerableAttachment> attachment( | |
| 171 new internal::MachPortAttachmentMac(wire_format)); | |
| 172 HandleReceivedAttachment(attachment); | |
| 173 } | |
| 174 | |
| 175 bool AttachmentBrokerPrivilegedMac::RouteWireFormatToAnother( | |
| 176 const MachPortWireFormat& wire_format) { | |
| 177 DCHECK_NE(wire_format.destination_process, base::Process::Current().Pid()); | |
| 178 | |
| 179 // Another process is the destination. | |
| 180 base::ProcessId dest = wire_format.destination_process; | |
| 181 base::AutoLock auto_lock(*get_lock()); | |
| 182 AttachmentBrokerPrivileged::EndpointRunnerPair pair = | |
| 183 GetSenderWithProcessId(dest); | |
| 184 if (!pair.first) { | |
| 185 // The extractor was successfully processed, which implies that the | |
| 186 // communication channel was established. This implies that the | |
| 187 // communication was taken down in the interim. | |
| 188 LOG(ERROR) << "Failed to deliver brokerable attachment to process with id: " | |
| 189 << dest; | |
| 190 LogError(DESTINATION_NOT_FOUND); | |
| 191 return false; | |
| 192 } | |
| 193 | |
| 194 LogError(DESTINATION_FOUND); | |
| 195 SendMessageToEndpoint( | |
| 196 pair, new AttachmentBrokerMsg_MachPortHasBeenDuplicated(wire_format)); | |
| 197 return true; | |
| 198 } | |
| 199 | |
| 200 base::mac::ScopedMachSendRight AttachmentBrokerPrivilegedMac::ExtractNamedRight( | |
| 201 mach_port_t task_port, | |
| 202 mach_port_name_t named_right) { | |
| 203 if (named_right == MACH_PORT_NULL) | |
| 204 return base::mac::ScopedMachSendRight(MACH_PORT_NULL); | |
| 205 | |
| 206 mach_port_t extracted_right = MACH_PORT_NULL; | |
| 207 mach_msg_type_name_t extracted_right_type; | |
| 208 kern_return_t kr = | |
| 209 mach_port_extract_right(task_port, named_right, MACH_MSG_TYPE_MOVE_SEND, | |
| 210 &extracted_right, &extracted_right_type); | |
| 211 if (kr != KERN_SUCCESS) { | |
| 212 LogError(ERROR_EXTRACT_SOURCE_RIGHT); | |
| 213 return base::mac::ScopedMachSendRight(MACH_PORT_NULL); | |
| 214 } | |
| 215 | |
| 216 DCHECK_EQ(static_cast<mach_msg_type_name_t>(MACH_MSG_TYPE_PORT_SEND), | |
| 217 extracted_right_type); | |
| 218 | |
| 219 return base::mac::ScopedMachSendRight(extracted_right); | |
| 220 } | |
| 221 | |
| 222 AttachmentBrokerPrivilegedMac::MachPortWireFormat | |
| 223 AttachmentBrokerPrivilegedMac::CopyWireFormat( | |
| 224 const MachPortWireFormat& wire_format, | |
| 225 uint32_t mach_port) { | |
| 226 return MachPortWireFormat(mach_port, wire_format.destination_process, | |
| 227 wire_format.attachment_id); | |
| 228 } | |
| 229 | |
| 230 void AttachmentBrokerPrivilegedMac::SendPrecursorsForProcess( | |
| 231 base::ProcessId pid, | |
| 232 bool store_on_failure) { | |
| 233 base::AutoLock l(precursors_lock_); | |
| 234 auto it = precursors_.find(pid); | |
| 235 if (it == precursors_.end()) | |
| 236 return; | |
| 237 | |
| 238 // Whether this process is the destination process. | |
| 239 bool to_self = pid == base::GetCurrentProcId(); | |
| 240 | |
| 241 if (!to_self) { | |
| 242 base::AutoLock auto_lock(*get_lock()); | |
| 243 AttachmentBrokerPrivileged::EndpointRunnerPair pair = | |
| 244 GetSenderWithProcessId(pid); | |
| 245 if (!pair.first) { | |
| 246 // Try again later. | |
| 247 if (store_on_failure) | |
| 248 return; | |
| 249 | |
| 250 // If there is no sender, then permanently fail. | |
| 251 LogError(DESTINATION_NOT_FOUND); | |
| 252 delete it->second; | |
| 253 precursors_.erase(it); | |
| 254 return; | |
| 255 } | |
| 256 } | |
| 257 | |
| 258 mach_port_t task_port = port_provider_->TaskForPid(pid); | |
| 259 | |
| 260 // It's possible that the destination process has not yet provided the | |
| 261 // privileged process with its task port. | |
| 262 if (!to_self && task_port == MACH_PORT_NULL) | |
| 263 return; | |
| 264 | |
| 265 while (!it->second->empty()) { | |
| 266 auto precursor_it = it->second->begin(); | |
| 267 if (to_self) { | |
| 268 RoutePrecursorToSelf(*precursor_it); | |
| 269 } else { | |
| 270 if (!SendPrecursor(*precursor_it, task_port)) | |
| 271 break; | |
| 272 } | |
| 273 it->second->erase(precursor_it); | |
| 274 } | |
| 275 | |
| 276 delete it->second; | |
| 277 precursors_.erase(it); | |
| 278 } | |
| 279 | |
| 280 bool AttachmentBrokerPrivilegedMac::SendPrecursor( | |
| 281 AttachmentPrecursor* precursor, | |
| 282 mach_port_t task_port) { | |
| 283 DCHECK(task_port); | |
| 284 internal::MachPortAttachmentMac::WireFormat wire_format( | |
| 285 MACH_PORT_NULL, precursor->pid(), precursor->id()); | |
| 286 base::mac::ScopedMachSendRight port_to_insert = precursor->TakePort(); | |
| 287 mach_port_name_t intermediate_port = MACH_PORT_NULL; | |
| 288 if (port_to_insert.get() != MACH_PORT_NULL) { | |
| 289 base::MachCreateError error_code; | |
| 290 intermediate_port = base::CreateIntermediateMachPort( | |
| 291 task_port, base::mac::ScopedMachSendRight(port_to_insert.release()), | |
| 292 &error_code); | |
| 293 if (intermediate_port == MACH_PORT_NULL) { | |
| 294 UMAError uma_error; | |
| 295 switch (error_code) { | |
| 296 case base::MachCreateError::ERROR_MAKE_RECEIVE_PORT: | |
| 297 uma_error = ERROR_MAKE_RECEIVE_PORT; | |
| 298 break; | |
| 299 case base::MachCreateError::ERROR_SET_ATTRIBUTES: | |
| 300 uma_error = ERROR_SET_ATTRIBUTES; | |
| 301 break; | |
| 302 case base::MachCreateError::ERROR_EXTRACT_DEST_RIGHT: | |
| 303 uma_error = ERROR_EXTRACT_DEST_RIGHT; | |
| 304 break; | |
| 305 case base::MachCreateError::ERROR_SEND_MACH_PORT: | |
| 306 uma_error = ERROR_SEND_MACH_PORT; | |
| 307 break; | |
| 308 } | |
| 309 LogError(uma_error); | |
| 310 } | |
| 311 } | |
| 312 return RouteWireFormatToAnother( | |
| 313 CopyWireFormat(wire_format, intermediate_port)); | |
| 314 } | |
| 315 | |
| 316 void AttachmentBrokerPrivilegedMac::AddPrecursor( | |
| 317 base::ProcessId pid, | |
| 318 base::mac::ScopedMachSendRight port, | |
| 319 const BrokerableAttachment::AttachmentId& id) { | |
| 320 base::AutoLock l(precursors_lock_); | |
| 321 auto it = precursors_.find(pid); | |
| 322 if (it == precursors_.end()) | |
| 323 precursors_[pid] = new ScopedVector<AttachmentPrecursor>; | |
| 324 | |
| 325 precursors_[pid]->push_back(new AttachmentPrecursor( | |
| 326 pid, base::mac::ScopedMachSendRight(port.release()), id)); | |
| 327 } | |
| 328 | |
| 329 void AttachmentBrokerPrivilegedMac::ProcessExtractorsForProcess( | |
| 330 base::ProcessId pid, | |
| 331 bool store_on_failure) { | |
| 332 base::AutoLock l(extractors_lock_); | |
| 333 auto it = extractors_.find(pid); | |
| 334 if (it == extractors_.end()) | |
| 335 return; | |
| 336 | |
| 337 { | |
| 338 base::AutoLock auto_lock(*get_lock()); | |
| 339 AttachmentBrokerPrivileged::EndpointRunnerPair pair = | |
| 340 GetSenderWithProcessId(pid); | |
| 341 if (!pair.first) { | |
| 342 // If there is no sender, then the communication channel with the source | |
| 343 // process has not yet been established. Try again later. | |
| 344 if (store_on_failure) | |
| 345 return; | |
| 346 | |
| 347 // There is no sender. Permanently fail. | |
| 348 LogError(ERROR_SOURCE_NOT_FOUND); | |
| 349 delete it->second; | |
| 350 extractors_.erase(it); | |
| 351 return; | |
| 352 } | |
| 353 } | |
| 354 | |
| 355 mach_port_t task_port = port_provider_->TaskForPid(pid); | |
| 356 | |
| 357 // It's possible that the source process has not yet provided the privileged | |
| 358 // process with its task port. | |
| 359 if (task_port == MACH_PORT_NULL) | |
| 360 return; | |
| 361 | |
| 362 while (!it->second->empty()) { | |
| 363 auto extractor_it = it->second->begin(); | |
| 364 ProcessExtractor(*extractor_it, task_port); | |
| 365 it->second->erase(extractor_it); | |
| 366 } | |
| 367 | |
| 368 delete it->second; | |
| 369 extractors_.erase(it); | |
| 370 } | |
| 371 | |
| 372 void AttachmentBrokerPrivilegedMac::ProcessExtractor( | |
| 373 AttachmentExtractor* extractor, | |
| 374 mach_port_t task_port) { | |
| 375 DCHECK(task_port); | |
| 376 base::mac::ScopedMachSendRight send_right = | |
| 377 ExtractNamedRight(task_port, extractor->port()); | |
| 378 AddPrecursor(extractor->dest_pid(), | |
| 379 base::mac::ScopedMachSendRight(send_right.release()), | |
| 380 extractor->id()); | |
| 381 SendPrecursorsForProcess(extractor->dest_pid(), true); | |
| 382 } | |
| 383 | |
| 384 void AttachmentBrokerPrivilegedMac::AddExtractor( | |
| 385 base::ProcessId source_pid, | |
| 386 base::ProcessId dest_pid, | |
| 387 mach_port_name_t port, | |
| 388 const BrokerableAttachment::AttachmentId& id) { | |
| 389 base::AutoLock l(extractors_lock_); | |
| 390 DCHECK_NE(base::GetCurrentProcId(), source_pid); | |
| 391 | |
| 392 auto it = extractors_.find(source_pid); | |
| 393 if (it == extractors_.end()) | |
| 394 extractors_[source_pid] = new ScopedVector<AttachmentExtractor>; | |
| 395 | |
| 396 extractors_[source_pid]->push_back( | |
| 397 new AttachmentExtractor(source_pid, dest_pid, port, id)); | |
| 398 } | |
| 399 | |
| 400 } // namespace IPC | |
| OLD | NEW |